mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
Merge pull request #16212 from supabase/hf/add-navigator-lock-feature-flag
feat: add feature flag for enabling GoTrue navigator lock
This commit is contained in:
5 files changed
+96
-18
No files matched your search
@@ -10,9 +10,11 @@ const debug =
|
||||
process.env.NEXT_PUBLIC_IS_PLATFORM === 'true' &&
|
||||
globalThis?.localStorage?.getItem(AUTH_DEBUG_KEY) === 'true'
|
||||
|
||||
const navigatorLockEnabled =
|
||||
const navigatorLockEnabled = !!(
|
||||
process.env.NEXT_PUBLIC_IS_PLATFORM === 'true' &&
|
||||
globalThis?.localStorage?.getItem(AUTH_NAVIGATOR_LOCK_KEY) === 'true'
|
||||
globalThis?.localStorage?.getItem(AUTH_NAVIGATOR_LOCK_KEY) === 'true' &&
|
||||
globalThis?.navigator?.locks
|
||||
)
|
||||
|
||||
export const gotrueClient = new GoTrueClient({
|
||||
url: process.env.NEXT_PUBLIC_GOTRUE_URL,
|
||||
|
||||
@@ -5,8 +5,7 @@ import * as configcat from 'configcat-js'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import FlagContext from './FlagContext'
|
||||
import { useUser } from 'lib/auth'
|
||||
|
||||
let client: configcat.IConfigCatClient
|
||||
import { getFlags } from 'lib/configcat'
|
||||
|
||||
const FlagProvider = ({ children }: PropsWithChildren<{}>) => {
|
||||
const user = useUser()
|
||||
@@ -14,20 +13,10 @@ const FlagProvider = ({ children }: PropsWithChildren<{}>) => {
|
||||
const { Provider } = FlagContext
|
||||
const [store, setStore] = useState({})
|
||||
|
||||
const getFlags = async (user?: User) => {
|
||||
if (!client) {
|
||||
client = configcat.getClient(
|
||||
process.env.NEXT_PUBLIC_CONFIGCAT_SDK_KEY ?? '',
|
||||
configcat.PollingMode.AutoPoll,
|
||||
{ pollIntervalSeconds: 600 }
|
||||
)
|
||||
}
|
||||
|
||||
const processFlags = async (user?: User) => {
|
||||
const flagStore: any = {}
|
||||
const flagValues =
|
||||
user?.email !== undefined
|
||||
? await client.getAllValuesAsync(new configcat.User(user.email))
|
||||
: await client.getAllValuesAsync()
|
||||
const flagValues = await getFlags(user)
|
||||
|
||||
flagValues.forEach((item: any) => {
|
||||
flagStore[item.settingKey] = item.settingValue
|
||||
})
|
||||
@@ -39,7 +28,7 @@ const FlagProvider = ({ children }: PropsWithChildren<{}>) => {
|
||||
// as per https://configcat.com/docs/sdk-reference/js/#polling-modes:
|
||||
// The polling downloads the config.json at the set interval and are stored in the internal cache
|
||||
// which subsequently all getValueAsync() calls are served from there
|
||||
if (IS_PLATFORM) getFlags(user ?? undefined)
|
||||
if (IS_PLATFORM) processFlags(user ?? undefined)
|
||||
}, [user])
|
||||
|
||||
return <Provider value={store}>{children}</Provider>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { User } from '@supabase/supabase-js'
|
||||
import * as configcat from 'configcat-js'
|
||||
|
||||
let client: configcat.IConfigCatClient
|
||||
|
||||
export function getClient() {
|
||||
if (client) {
|
||||
return client
|
||||
}
|
||||
|
||||
client = configcat.getClient(
|
||||
process.env.NEXT_PUBLIC_CONFIGCAT_SDK_KEY ?? '',
|
||||
configcat.PollingMode.AutoPoll,
|
||||
{ pollIntervalSeconds: 600 }
|
||||
)
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
export async function getFlags(user?: User) {
|
||||
return user?.email !== undefined
|
||||
? await getClient().getAllValuesAsync(new configcat.User(user.email))
|
||||
: await getClient().getAllValuesAsync()
|
||||
}
|
||||
@@ -1,5 +1,38 @@
|
||||
import { IS_PLATFORM } from './constants'
|
||||
import { User } from '@supabase/gotrue-js'
|
||||
import { gotrueClient } from 'common'
|
||||
import { getFlags } from './configcat'
|
||||
import { getNavigatorLockFeatureFlagThreshold, setNavigatorLockEnabled } from './local-storage'
|
||||
|
||||
// The first time this file is imported, ConfigCat will be asked for all
|
||||
// available feature flags. The client that this is running in will have
|
||||
// determined and saved a random number [0, 100) under
|
||||
// `supabase.dashboard.ff.threshold.navigatorLock`. If there is a number-valued
|
||||
// feature flag `navigatorLockThreshold`, the
|
||||
// `supabase.dashboard.auth.navigatorLock.enabled` localStorage key will be set
|
||||
// to true if the value chosen by the browser is <= the value in the feature
|
||||
// flag.On the _following_ refresh of the page, `packages/common/gotrue.ts`
|
||||
// will read this value and enable the GoTrueClient navigatorLock.
|
||||
// ConfigCat does not have a native way to do this, as percent-based rollouts
|
||||
// are only available when ConfigCat has a user ID, and not without one, which
|
||||
// can be the case here (GoTrue is used when not authenticated too).
|
||||
async function determineNavigatorLockFeatureFlag() {
|
||||
const flags = await getFlags()
|
||||
const value = flags.find((flag) => flag.settingKey === 'navigatorLockThreshold')?.settingValue
|
||||
|
||||
if (typeof value === 'number' && value > 0) {
|
||||
const threshold = getNavigatorLockFeatureFlagThreshold()
|
||||
|
||||
if (typeof threshold === 'number') {
|
||||
setNavigatorLockEnabled(threshold <= value)
|
||||
} else {
|
||||
setNavigatorLockEnabled(false)
|
||||
}
|
||||
} else {
|
||||
setNavigatorLockEnabled(false)
|
||||
}
|
||||
}
|
||||
|
||||
export { STORAGE_KEY } from 'common'
|
||||
|
||||
export const auth = gotrueClient
|
||||
@@ -62,3 +95,7 @@ export const getReturnToPath = (fallback = '/projects') => {
|
||||
|
||||
return validReturnTo + (remainingSearchParams ? `?${remainingSearchParams}` : '')
|
||||
}
|
||||
|
||||
if (IS_PLATFORM && globalThis.window) {
|
||||
determineNavigatorLockFeatureFlag()
|
||||
}
|
||||
@@ -6,6 +6,8 @@ export const LOCAL_STORAGE_KEYS_ALLOWLIST = [
|
||||
'supabaseDarkMode',
|
||||
'supabase.dashboard.sign_in_clicks',
|
||||
'supabase.dashboard.auth.debug',
|
||||
'supabase.dashboard.auth.navigatorLock.enabled',
|
||||
'supabase.dashboard.auth.ff.threshold.navigatorLock',
|
||||
]
|
||||
|
||||
export function clearLocalStorage() {
|
||||
@@ -55,7 +57,31 @@ export function resetSignInClicks(): number {
|
||||
return clicks
|
||||
}
|
||||
|
||||
export function getNavigatorLockFeatureFlagThreshold() {
|
||||
const str = localStorage.getItem('supabase.dashboard.auth.ff.threshold.navigatorLock')
|
||||
|
||||
return str ? parseInt(str) : null
|
||||
}
|
||||
|
||||
function determineNavigatorLockFeatureFlagThreshold() {
|
||||
if (getNavigatorLockFeatureFlagThreshold()) {
|
||||
return
|
||||
}
|
||||
|
||||
localStorage.setItem(
|
||||
'supabase.dashboard.auth.ff.threshold.navigatorLock',
|
||||
`${Math.floor(Math.random() * 100)}`
|
||||
)
|
||||
}
|
||||
|
||||
export function setNavigatorLockEnabled(enabled: boolean) {
|
||||
localStorage.setItem('supabase.dashboard.auth.navigatorLock.enabled', enabled ? 'true' : 'false')
|
||||
}
|
||||
|
||||
if (globalThis && globalThis.localStorage && IS_PLATFORM) {
|
||||
// populate the value based on the current local storage state
|
||||
inferSignInClicks()
|
||||
|
||||
// setup the navigator lock group on initial load
|
||||
determineNavigatorLockFeatureFlagThreshold()
|
||||
}
|
||||
Reference in new issue
Block a user