fix: ssr feature flags (#1119)

## Description

Feature flags are broken on SSR due to this error

```
TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11731:11)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
  cause: RequestContentLengthMismatchError: Request body length does not match content-length header
      at write (node:internal/deps/undici/undici:8590:41)
      at _resume (node:internal/deps/undici/undici:8563:33)
      at resume (node:internal/deps/undici/undici:8459:7)
      at [dispatch] (node:internal/deps/undici/undici:7704:11)
      at Client.Intercept (node:internal/deps/undici/undici:7377:20)
      at Client.dispatch (node:internal/deps/undici/undici:6023:44)
      at [dispatch] (node:internal/deps/undici/undici:6254:32)
      at Pool.dispatch (node:internal/deps/undici/undici:6023:44)
      at [dispatch] (node:internal/deps/undici/undici:9343:27)
      at Agent.Intercept (node:internal/deps/undici/undici:7377:20) {
    code: 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH'
  }
}
```

I've removed content-length header since it isn't mandatory to my
knowledge for get requests.

## Changes

- Add fallback local flags when individual flag request fails
- Add error logging
- Remove `content-length` from headers being passed to Posthog
This commit is contained in:
David Nguyen
2024-04-26 16:01:09 +07:00
committed by GitHub
parent 9bc5818d19
commit 20edee7f1a

View File

@ -17,6 +17,7 @@ export const getFlag = async (
options?: GetFlagOptions, options?: GetFlagOptions,
): Promise<TFeatureFlagValue> => { ): Promise<TFeatureFlagValue> => {
const requestHeaders = options?.requestHeaders ?? {}; const requestHeaders = options?.requestHeaders ?? {};
delete requestHeaders['content-length'];
if (!isFeatureFlagEnabled()) { if (!isFeatureFlagEnabled()) {
return LOCAL_FEATURE_FLAGS[flag] ?? true; return LOCAL_FEATURE_FLAGS[flag] ?? true;
@ -25,7 +26,7 @@ export const getFlag = async (
const url = new URL(`${APP_BASE_URL()}/api/feature-flag/get`); const url = new URL(`${APP_BASE_URL()}/api/feature-flag/get`);
url.searchParams.set('flag', flag); url.searchParams.set('flag', flag);
const response = await fetch(url, { return await fetch(url, {
headers: { headers: {
...requestHeaders, ...requestHeaders,
}, },
@ -35,9 +36,10 @@ export const getFlag = async (
}) })
.then(async (res) => res.json()) .then(async (res) => res.json())
.then((res) => ZFeatureFlagValueSchema.parse(res)) .then((res) => ZFeatureFlagValueSchema.parse(res))
.catch(() => false); .catch((err) => {
console.error(err);
return response; return LOCAL_FEATURE_FLAGS[flag] ?? false;
});
}; };
/** /**
@ -50,6 +52,7 @@ export const getAllFlags = async (
options?: GetFlagOptions, options?: GetFlagOptions,
): Promise<Record<string, TFeatureFlagValue>> => { ): Promise<Record<string, TFeatureFlagValue>> => {
const requestHeaders = options?.requestHeaders ?? {}; const requestHeaders = options?.requestHeaders ?? {};
delete requestHeaders['content-length'];
if (!isFeatureFlagEnabled()) { if (!isFeatureFlagEnabled()) {
return LOCAL_FEATURE_FLAGS; return LOCAL_FEATURE_FLAGS;
@ -67,7 +70,10 @@ export const getAllFlags = async (
}) })
.then(async (res) => res.json()) .then(async (res) => res.json())
.then((res) => z.record(z.string(), ZFeatureFlagValueSchema).parse(res)) .then((res) => z.record(z.string(), ZFeatureFlagValueSchema).parse(res))
.catch(() => LOCAL_FEATURE_FLAGS); .catch((err) => {
console.error(err);
return LOCAL_FEATURE_FLAGS;
});
}; };
/** /**
@ -89,7 +95,10 @@ export const getAllAnonymousFlags = async (): Promise<Record<string, TFeatureFla
}) })
.then(async (res) => res.json()) .then(async (res) => res.json())
.then((res) => z.record(z.string(), ZFeatureFlagValueSchema).parse(res)) .then((res) => z.record(z.string(), ZFeatureFlagValueSchema).parse(res))
.catch(() => LOCAL_FEATURE_FLAGS); .catch((err) => {
console.error(err);
return LOCAL_FEATURE_FLAGS;
});
}; };
interface GetFlagOptions { interface GetFlagOptions {