{"version":3,"sources":["../src/index.ts","../src/provider/index.ts"],"names":["result"],"mappings":"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","sourcesContent":["import { PostHog } from 'posthog-node';\nimport type { PostHogAdapter, PostHogEntities, JsonType } from './types';\n\nexport { getProviderData } from './provider';\nexport type { PostHogEntities, JsonType };\n\nexport function createPostHogAdapter({\n  postHogKey,\n  postHogOptions,\n}: {\n  postHogKey: ConstructorParameters<typeof PostHog>[0];\n  postHogOptions: ConstructorParameters<typeof PostHog>[1];\n}): PostHogAdapter {\n  const client = new PostHog(postHogKey, postHogOptions);\n\n  const result: PostHogAdapter = {\n    isFeatureEnabled: (options) => {\n      return {\n        async decide({ key, entities, defaultValue }): Promise<boolean> {\n          const parsedEntities = parseEntities(entities);\n          const result =\n            (await client.isFeatureEnabled(\n              trimKey(key),\n              parsedEntities.distinctId,\n              options,\n            )) ?? defaultValue;\n          if (result === undefined) {\n            throw new Error(\n              `PostHog Adapter isFeatureEnabled returned undefined for ${trimKey(key)} and no default value was provided.`,\n            );\n          }\n          return result;\n        },\n      };\n    },\n    featureFlagValue: (options) => {\n      return {\n        async decide({ key, entities, defaultValue }) {\n          const parsedEntities = parseEntities(entities);\n          const flagValue = await client.getFeatureFlag(\n            trimKey(key),\n            parsedEntities.distinctId,\n            options,\n          );\n          if (flagValue === undefined) {\n            if (typeof defaultValue !== 'undefined') {\n              return defaultValue;\n            }\n            throw new Error(\n              `PostHog Adapter featureFlagValue found undefined for ${trimKey(key)} and no default value was provided.`,\n            );\n          }\n          return flagValue;\n        },\n      };\n    },\n    featureFlagPayload: (getValue, options) => {\n      return {\n        async decide({ key, entities, defaultValue }) {\n          const parsedEntities = parseEntities(entities);\n          const payload = await client.getFeatureFlagPayload(\n            trimKey(key),\n            parsedEntities.distinctId,\n            undefined,\n            options,\n          );\n          if (!payload) {\n            if (typeof defaultValue !== 'undefined') {\n              return defaultValue;\n            }\n            throw new Error(\n              `PostHog Adapter featureFlagPayload found undefined for ${trimKey(key)} and no default value was provided.`,\n            );\n          }\n          return getValue(payload);\n        },\n      };\n    },\n  };\n\n  return result;\n}\n\nfunction parseEntities(entities?: PostHogEntities): PostHogEntities {\n  if (!entities) {\n    throw new Error(\n      'PostHog Adapter: Missing entities, ' +\n        'flag must be defined with an identify() function.',\n    );\n  }\n  return entities;\n}\n\nfunction assertEnv(name: string): string {\n  const value = process.env[name];\n  if (!value) {\n    throw new Error(`PostHog Adapter: Missing ${name} environment variable`);\n  }\n  return value;\n}\n\n// Read until the first `.`\n// This supports defining multiple flags with the same key\n// Ex. with my-flag.is-enabled, my-flag.variant and my-flag.payload\nfunction trimKey(key: string): string {\n  return key.split('.')[0] as string;\n}\n\nlet defaultPostHogAdapter: ReturnType<typeof createPostHogAdapter> | undefined;\nfunction getOrCreateDefaultAdapter() {\n  if (!defaultPostHogAdapter) {\n    defaultPostHogAdapter = createPostHogAdapter({\n      postHogKey: assertEnv('NEXT_PUBLIC_POSTHOG_KEY'),\n      postHogOptions: {\n        host: assertEnv('NEXT_PUBLIC_POSTHOG_HOST'),\n        personalApiKey: process.env.POSTHOG_PERSONAL_API_KEY,\n        featureFlagsPollingInterval: 10_000,\n        // Presumption: Server IP is likely not a good proxy for user location\n        disableGeoip: true,\n      },\n    });\n  }\n  return defaultPostHogAdapter;\n}\n\nexport const postHogAdapter: PostHogAdapter = {\n  isFeatureEnabled: (...args) =>\n    getOrCreateDefaultAdapter().isFeatureEnabled(...args),\n  featureFlagValue: (...args) =>\n    getOrCreateDefaultAdapter().featureFlagValue(...args),\n  featureFlagPayload: (...args) =>\n    getOrCreateDefaultAdapter().featureFlagPayload(...args),\n};\n","import type { FlagDefinitionsType, ProviderData } from 'flags';\n\n// See: https://posthog.com/docs/api/feature-flags#get-api-projects-project_id-feature_flags\ninterface ApiData {\n  count: number;\n  next?: string | null;\n  previous?: string | null;\n  results: {\n    id: number;\n    key: string;\n    name: string;\n    created_at: string;\n    description: string;\n    deleted: boolean;\n    active: boolean;\n    is_simple_flag: boolean;\n    filters: {\n      payloads?: Record<string, string>;\n      multivariate?: Record<string, unknown>;\n    };\n  }[];\n}\n\nexport async function getProviderData(options: {\n  personalApiKey: string;\n  projectId: string;\n  appHost?: string;\n}): Promise<ProviderData> {\n  const hints: Exclude<ProviderData['hints'], undefined> = [];\n\n  if (!options.personalApiKey) {\n    hints.push({\n      key: 'posthog/missing-personal-api-key',\n      text: 'Missing PostHog Personal API Key',\n    });\n  }\n\n  let host = options.appHost;\n  if (!host) {\n    try {\n      host = getAppHost();\n    } catch (e) {\n      hints.push({\n        key: 'posthog/missing-app-host',\n        text: 'Missing NEXT_PUBLIC_POSTHOG_HOST environment variable',\n      });\n    }\n  }\n\n  if (!options.projectId) {\n    hints.push({\n      key: 'posthog/missing-project-id',\n      text: 'Missing PostHog Project ID',\n    });\n  }\n\n  if (hints.length > 0) {\n    return { definitions: {}, hints };\n  }\n\n  const headers = {\n    Authorization: `Bearer ${options.personalApiKey}`,\n  };\n\n  const res = await fetch(\n    `${host}/api/projects/${options.projectId}/feature_flags?active=true`,\n    {\n      method: 'GET',\n      headers,\n      // @ts-expect-error used by some Next.js versions\n      cache: 'no-store',\n    },\n  );\n\n  if (res.status !== 200) {\n    return {\n      definitions: {},\n      hints: [\n        {\n          key: `posthog/response-not-ok/${options.projectId}`,\n          text: `Failed to fetch PostHog (Received ${res.status} response)`,\n        },\n      ],\n    };\n  }\n\n  try {\n    const data = (await res.json()) as ApiData;\n    const items: ApiData['results'] = [...data.results];\n\n    // paginate in a parallel request\n    for (let offset = 100; offset < data.count; offset += 100) {\n      const paginatedRes = await fetch(\n        `${host}/api/projects/${options.projectId}/feature_flags?active=true&offset=${offset}&limit=100`,\n        {\n          method: 'GET',\n          headers,\n          // @ts-expect-error used by some Next.js versions\n          cache: 'no-store',\n        },\n      );\n\n      if (paginatedRes.status === 200) {\n        const paginatedData = (await paginatedRes.json()) as ApiData;\n        items.push(...paginatedData.results);\n      } else {\n        hints.push({\n          key: `posthog/response-not-ok/${options.projectId}-${offset}`,\n          text: `Failed to fetch PostHog (Received ${paginatedRes.status} response)`,\n        });\n      }\n    }\n\n    return {\n      definitions: items.reduce<FlagDefinitionsType>((acc, item) => {\n        acc[item.key] = {\n          origin: `${host}/project/${options.projectId}/feature_flags/${item.id}`,\n          description: item.name,\n          createdAt: new Date(item.created_at).getTime(),\n          options: !item.filters.payloads\n            ? [{ value: false }, { value: true }]\n            : Object.entries(item.filters.payloads ?? {}).map(\n                ([key, value]) => ({\n                  value: JSON.parse(value),\n                  label: key,\n                }),\n              ),\n        };\n        return acc;\n      }, {}),\n      hints,\n    };\n  } catch (e) {\n    return {\n      definitions: {},\n      hints: [\n        {\n          key: `posthog/response-not-ok/${options.projectId}`,\n          text: 'Failed to fetch PostHog',\n        },\n      ],\n    };\n  }\n}\n\nexport const getAppHost = (apiHost?: string) => {\n  const host = apiHost ?? process.env.NEXT_PUBLIC_POSTHOG_HOST;\n\n  if (!host) {\n    throw new Error('NEXT_PUBLIC_POSTHOG_HOST is not set');\n  }\n\n  if (host.includes('us.i.posthog.com')) {\n    return 'https://us.posthog.com';\n  }\n\n  if (host.includes('eu.i.posthog.com')) {\n    return 'https://eu.posthog.com';\n  }\n\n  return host;\n};\n"]}