mirror of
https://github.com/supabase/supabase.git
synced 2026-06-17 21:23:59 +08:00
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Refactor / performance. ## What is the current behavior? `packages/common/configcat.ts` does a two-step setup: a probe `fetch` to the ConfigCat proxy URL, followed by SDK client initialization with the proxy as `baseUrl` (or against the direct ConfigCat CDN if the probe fails). On the happy path this fires **two** network requests for the same JSON config on cold start — the probe, then the SDK's own initial AutoPoll fetch. ## What is the new behavior? The probe is removed. We initialize the proxy client directly and inspect the `ClientCacheState` returned by `waitForReady()`. On `NoFlagData` (proxy unreachable, no cache) we `dispose()` the proxy client and fall back to the direct SDK key client. Cold-start fetches drop from 2 to 1 when the proxy is healthy. Worst-case fallback delay is bounded by `maxInitWaitTimeSeconds` (5s default), comparable to today's probe timeout on a broken proxy. The unused exported \`fetchHandler\` is removed (no external importers — verified via grep). Tests in \`configcat.test.ts\` are updated to mock \`waitForReady\`/\`dispose\` and a new test covers the proxy-failure fallback path. ## Additional context Resolves FE-3174 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved ConfigCat client initialization with robust fallback handling when proxy is unavailable. * **Chores** * Removed `fetchHandler` export from ConfigCat module. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45939) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
82 lines
2.4 KiB
TypeScript
82 lines
2.4 KiB
TypeScript
import * as configcat from 'configcat-js'
|
|
|
|
let client: configcat.IConfigCatClient
|
|
|
|
/**
|
|
* To set up ConfigCat for another app
|
|
* - Declare `FeatureFlagProvider` at the _app level
|
|
* - Pass in `getFlags` as `getConfigCatFlags` into `FeatureFlagProvider`
|
|
* - [Joshen] Wondering if this should just be baked into FeatureFlagProvider, rather than passed as a prop
|
|
* - Ensure that your app has the `NEXT_PUBLIC_CONFIGCAT_PROXY_URL` env var
|
|
* - [Joshen] Wondering if we can just set a default value for each env var, so can skip setting up env var in Vercel
|
|
* - Verify that your flags are now loading by console logging `flagValues` in `FeatureFlagProvider`'s useEffect
|
|
* - Can now use ConfigCat feature flags with the `useFlag` hook
|
|
*/
|
|
|
|
async function getClient() {
|
|
if (client) return client
|
|
|
|
const proxyUrl = process.env.NEXT_PUBLIC_CONFIGCAT_PROXY_URL
|
|
const sdkKey = process.env.NEXT_PUBLIC_CONFIGCAT_SDK_KEY
|
|
|
|
if (!sdkKey && !proxyUrl) {
|
|
console.log('Skipping ConfigCat set up as env vars are not present')
|
|
return undefined
|
|
}
|
|
|
|
const options = { pollIntervalSeconds: 7 * 60 } // 7 minutes
|
|
|
|
try {
|
|
if (proxyUrl) {
|
|
const proxyClient = configcat.getClient(
|
|
'configcat-proxy/frontend-v2',
|
|
configcat.PollingMode.AutoPoll,
|
|
{ ...options, baseUrl: proxyUrl }
|
|
)
|
|
const cacheState = await proxyClient.waitForReady()
|
|
|
|
if (cacheState !== configcat.ClientCacheState.NoFlagData) {
|
|
client = proxyClient
|
|
return client
|
|
}
|
|
|
|
proxyClient.dispose()
|
|
}
|
|
|
|
if (sdkKey) {
|
|
client = configcat.getClient(sdkKey, configcat.PollingMode.AutoPoll, options)
|
|
return client
|
|
}
|
|
|
|
console.error('ConfigCat proxy unreachable and SDK key is missing')
|
|
return undefined
|
|
} catch (error: any) {
|
|
console.error(`Failed to get ConfigCat client: ${error.message}`)
|
|
return undefined
|
|
}
|
|
}
|
|
|
|
export async function getFlags(userEmail: string = '', customAttributes?: Record<string, string>) {
|
|
const client = await getClient()
|
|
const _customAttributes = {
|
|
...customAttributes,
|
|
is_staff: !!userEmail ? userEmail.includes('@supabase.').toString() : 'false',
|
|
}
|
|
|
|
if (!client) {
|
|
return []
|
|
}
|
|
|
|
await client.waitForReady()
|
|
|
|
if (userEmail) {
|
|
return client.getAllValuesAsync(
|
|
new configcat.User(userEmail, undefined, undefined, _customAttributes)
|
|
)
|
|
} else {
|
|
return client.getAllValuesAsync(
|
|
new configcat.User('anonymous', undefined, undefined, _customAttributes)
|
|
)
|
|
}
|
|
}
|