{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n  type Attributes,\n  type ClientOptions,\n  type FeatureApiResponse,\n  GrowthBookClient,\n  type InitOptions,\n  type StickyAssignmentsDocument,\n  type StickyBucketService,\n  type TrackingCallback,\n  type TrackingCallbackWithUser,\n  type UserContext,\n} from '@growthbook/growthbook';\nimport { createClient } from '@vercel/edge-config';\nimport { AsyncLocalStorage } from 'async_hooks';\nimport type { Adapter } from 'flags';\n\nexport { getProviderData } from './provider';\nexport {\n  GrowthBookClient,\n  type Attributes,\n  type ClientOptions,\n  type InitOptions,\n  type UserContext,\n  type TrackingCallback,\n  type TrackingCallbackWithUser,\n  type FeatureApiResponse,\n  type StickyBucketService,\n  type StickyAssignmentsDocument,\n};\n\ntype EdgeConfig = {\n  connectionString: string;\n  /** Defaults to `options.clientKey` **/\n  itemKey?: string;\n};\n\ntype AdapterResponse = {\n  feature: <T>() => Adapter<T, Attributes>;\n  initialize: () => Promise<GrowthBookClient>;\n  refresh: () => Promise<void>;\n  setTrackingCallback: (cb: TrackingCallback) => void;\n  setStickyBucketService: (stickyBucketService: StickyBucketService) => void;\n  stickyBucketService?: StickyBucketService;\n  growthbook: GrowthBookClient;\n};\n\n/**\n * Create a GrowthBook adapter for use with the Flags SDK.\n */\nexport function createGrowthbookAdapter(options: {\n  /** GrowthBook SDK key **/\n  clientKey: string;\n  /** Callback to log experiment exposures **/\n  trackingCallback?: TrackingCallback;\n  /** Override the features API endpoint for self-hosted users **/\n  apiHost?: string;\n  /** Override the application URL for self-hosted users **/\n  appOrigin?: string;\n  /** Optional GrowthBook SDK constructor options **/\n  clientOptions?: ClientOptions;\n  /** Optional GrowthBook SDK init() options **/\n  initOptions?: InitOptions;\n  /** Optional StickyBucketService (reduces variation hopping, required for Bandits) **/\n  stickyBucketService?: StickyBucketService;\n  /** Provide Edge Config details to use the optional Edge Config adapter */\n  edgeConfig?: EdgeConfig;\n}): AdapterResponse {\n  let trackingCallback = options.trackingCallback;\n  let stickyBucketService = options.stickyBucketService;\n\n  const growthbook = new GrowthBookClient({\n    clientKey: options.clientKey,\n    apiHost: options.apiHost || 'https://cdn.growthbook.io',\n    ...(options.clientOptions || {}),\n  });\n\n  const edgeConfigClient = options.edgeConfig\n    ? createClient(options.edgeConfig.connectionString)\n    : null;\n  const edgeConfigKey = options.edgeConfig?.itemKey || options.clientKey;\n\n  const store = new AsyncLocalStorage<WeakKey>();\n  const cache = new WeakMap<WeakKey, Promise<FeatureApiResponse | null>>();\n\n  const getEdgePayload = async (): Promise<FeatureApiResponse | null> => {\n    if (!edgeConfigClient) return null;\n\n    // Only do this once per request using AsyncLocalStorage\n    const currentRequest = store.getStore();\n    if (currentRequest) {\n      const cached = cache.get(currentRequest);\n      if (cached) {\n        return cached;\n      }\n    }\n\n    // Fetch from Edge Config\n    const payloadPromise = edgeConfigClient\n      .get<FeatureApiResponse | string>(edgeConfigKey)\n      .then((payload) => {\n        if (!payload) {\n          console.error('No payload found in edge config');\n          return null;\n        } else if (typeof payload === 'string') {\n          // Older GrowthBook integrations use WebHooks directly to store\n          // data in Edge Config, but they store the data as a string.\n          //\n          // We need to parse the string to JSON before passing it to GrowthBook.\n          //\n          // https://docs.growthbook.io/app/webhooks/sdk-webhooks#vercel-edge-config\n          // https://github.com/vercel/flags/issues/209\n          try {\n            return JSON.parse(payload) as FeatureApiResponse;\n          } catch {\n            console.error('Invalid payload format');\n            return null;\n          }\n        } else {\n          return payload;\n        }\n      })\n      .catch((e) => {\n        console.error('Error fetching edge config', e);\n        return null;\n      });\n\n    if (currentRequest) cache.set(currentRequest, payloadPromise);\n    return payloadPromise;\n  };\n\n  const initializeGrowthBook = async (): Promise<void> => {\n    const payload = await getEdgePayload();\n    await growthbook.init({\n      streaming: false,\n      payload: payload ?? undefined,\n      ...(options.initOptions || {}),\n    });\n  };\n\n  let _initializePromise: Promise<void> | undefined;\n  /**\n   * Initialize the GrowthBook SDK.\n   *\n   * This must be called before checking feature flags or experiments.\n   * It is deduplicated to prevent multiple calls from being made.\n   * You can pre-initialize the SDK by calling `adapter.initialize()`,\n   * otherwise it will be initialized lazily when needed.\n   */\n  const initialize = async (): Promise<GrowthBookClient> => {\n    if (!_initializePromise) {\n      _initializePromise = initializeGrowthBook();\n    }\n    await _initializePromise;\n    return growthbook;\n  };\n\n  const refresh = async (): Promise<void> => {\n    if (options.edgeConfig) {\n      const payload = await getEdgePayload();\n      if (payload && payload !== growthbook.getPayload()) {\n        await growthbook.setPayload(payload);\n      }\n    } else {\n      // Init does a refresh with a stale-while-revalidate strategy\n      await growthbook.init();\n    }\n  };\n\n  function origin(prefix: string) {\n    return (key: string) => {\n      const appOrigin = options.appOrigin || 'https://app.growthbook.io';\n      return `${appOrigin}/${prefix}/${key}`;\n    };\n  }\n\n  /**\n   * Resolve a feature flag.\n   *\n   * Implements `decide` to resolve the feature with `GrowthBook.evalFeature`\n   * Implements `origin` to link to the flag in the GrowthBook app\n   */\n  function feature<T>(\n    opts: { exposureLogging?: boolean } = {\n      exposureLogging: true,\n    },\n  ): Adapter<T, Attributes> {\n    return {\n      origin: origin('features'),\n      decide: async ({ key, entities, defaultValue, headers }) => {\n        await store.run(headers, async () => {\n          await initialize();\n          await refresh();\n        });\n\n        const userContext: UserContext = {\n          attributes: entities as Attributes,\n          trackingCallback: opts.exposureLogging ? trackingCallback : undefined,\n        };\n        if (stickyBucketService && opts.exposureLogging) {\n          const { stickyBucketAssignmentDocs, saveStickyBucketAssignmentDoc } =\n            await growthbook.applyStickyBuckets(\n              userContext,\n              stickyBucketService,\n            );\n          return (growthbook.evalFeature<T>(key, {\n            ...userContext,\n            stickyBucketAssignmentDocs,\n            saveStickyBucketAssignmentDoc,\n          }).value ?? defaultValue) as T;\n        }\n        return (growthbook.evalFeature<T>(key, userContext).value ??\n          defaultValue) as T;\n      },\n    };\n  }\n\n  function setTrackingCallback(cb: TrackingCallback) {\n    trackingCallback = cb;\n  }\n\n  function setStickyBucketService(sbs: StickyBucketService) {\n    stickyBucketService = sbs;\n  }\n\n  return {\n    feature,\n    initialize,\n    refresh,\n    setTrackingCallback,\n    setStickyBucketService,\n    stickyBucketService,\n    growthbook,\n  };\n}\n\nlet defaultGrowthbookAdapter: AdapterResponse | undefined;\n\nexport function resetDefaultGrowthbookAdapter() {\n  defaultGrowthbookAdapter = undefined;\n}\n\n/**\n * Equivalent to `createGrowthbookAdapter` but with default environment variable names.\n *\n * Required:\n * - `GROWTHBOOK_CLIENT_KEY` - GrowthBook SDK key\n *\n * Optional:\n * - `GROWTHBOOK_API_HOST` - Override the SDK API endpoint for self-hosted users\n * - `GROWTHBOOK_APP_ORIGIN` - Override the application URL for self-hosted users\n * - `GROWTHBOOK_EDGE_CONNECTION_STRING` - Edge Config connection string\n * - `EXPERIMENTATION_CONFIG` - fallback for GROWTHBOOK_EDGE_CONNECTION_STRING\n * - `GROWTHBOOK_EDGE_CONFIG_ITEM_KEY` - Override the item key for Edge Config (defaults to GROWTHBOOK_CLIENT_KEY)\n */\nexport function getOrCreateDefaultGrowthbookAdapter(): AdapterResponse {\n  if (defaultGrowthbookAdapter) {\n    return defaultGrowthbookAdapter;\n  }\n  const clientKey = process.env.GROWTHBOOK_CLIENT_KEY || '';\n  if (!clientKey) {\n    console.error('Missing GROWTHBOOK_CLIENT_KEY env var');\n  }\n  const apiHost = process.env.GROWTHBOOK_API_HOST;\n  const appOrigin = process.env.GROWTHBOOK_APP_ORIGIN;\n  const connectionString =\n    process.env.GROWTHBOOK_EDGE_CONNECTION_STRING ||\n    process.env.EXPERIMENTATION_CONFIG;\n  const itemKey = process.env.GROWTHBOOK_EDGE_CONFIG_ITEM_KEY;\n\n  let edgeConfig: EdgeConfig | undefined;\n  if (connectionString) {\n    edgeConfig = {\n      connectionString,\n      itemKey,\n    };\n  }\n\n  defaultGrowthbookAdapter = createGrowthbookAdapter({\n    clientKey,\n    apiHost,\n    appOrigin,\n    edgeConfig,\n  });\n\n  return defaultGrowthbookAdapter;\n}\n\n/**\n * The default GrowthBook adapter.\n *\n * This is a convenience object that pre-initializes the GrowthBook SDK, provides\n * an adapter function for features, and provides a hook to set the experiment exposure\n * tracking callback.\n *\n * This is the recommended way to use the GrowthBook adapter.\n *\n * ```ts\n * // flags.ts\n * import { flag } from 'flags/next';\n * import { growthbookAdapter } from '@flags-sdk/growthbook';\n *\n * const flag = flag({\n *   key: 'my-flag',\n *   defaultValue: false,\n *   adapter: growthbookAdapter.feature(),\n * });\n * ```\n */\nexport const growthbookAdapter: AdapterResponse = {\n  feature: (...args) => getOrCreateDefaultGrowthbookAdapter().feature(...args),\n  initialize: () => getOrCreateDefaultGrowthbookAdapter().initialize(),\n  refresh: () => getOrCreateDefaultGrowthbookAdapter().refresh(),\n  setTrackingCallback: (...args) =>\n    getOrCreateDefaultGrowthbookAdapter().setTrackingCallback(...args),\n  setStickyBucketService: (...args) =>\n    getOrCreateDefaultGrowthbookAdapter().setStickyBucketService(...args),\n  growthbook: getOrCreateDefaultGrowthbookAdapter().growthbook,\n};\n"]}