{"version":3,"sources":["../src/index.ts","../src/edge-runtime-hooks.ts"],"names":["Statsig","experiment","autotune","layer"],"mappings":"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","sourcesContent":["export { getProviderData } from './provider';\nimport type { Adapter } from 'flags';\nimport Statsig, {\n  type StatsigUser,\n  type StatsigOptions,\n  type DynamicConfig,\n  type Layer,\n} from 'statsig-node-lite';\nimport {\n  createEdgeConfigDataAdapter,\n  createSyncingHandler,\n} from './edge-runtime-hooks';\n\n// Export the Statsig instance\nexport {\n  Statsig,\n  type StatsigUser,\n  type StatsigOptions,\n  type DynamicConfig,\n  type Layer,\n};\n\nexport type FeatureGate = ReturnType<\n  typeof Statsig.getFeatureGateWithExposureLoggingDisabledSync\n>;\n\ntype AdapterFunction<O> = <T>(\n  getValue: (obj: O) => T,\n  opts?: { exposureLogging?: boolean },\n) => Adapter<T, StatsigUser>;\n\ntype AdapterResponse = {\n  featureGate: AdapterFunction<FeatureGate>;\n  dynamicConfig: AdapterFunction<DynamicConfig>;\n  experiment: AdapterFunction<DynamicConfig>;\n  autotune: AdapterFunction<DynamicConfig>;\n  layer: AdapterFunction<Layer>;\n  initialize: () => Promise<typeof Statsig>;\n};\n\n/**\n * Create a Statsig adapter for use with the Flags SDK.\n *\n * Can be used to define flags that are powered by Statsig's Feature Management\n * products including Feature Gates and Dynamic Configs.\n */\nexport function createStatsigAdapter(options: {\n  /** The Statsig server API key */\n  statsigServerApiKey: string;\n  /** Optionally override Statsig initialization options */\n  statsigOptions?: StatsigOptions;\n  /** Provide the project ID to allow links to the Statsig console in the Vercel Toolbar */\n  statsigProjectId?: string;\n  /** Provide Edge Config details to use the optional Edge Config adapter */\n  edgeConfig?: {\n    connectionString: string;\n    itemKey: string;\n  };\n}): AdapterResponse {\n  const initializeStatsig = async (): Promise<void> => {\n    let dataAdapter: StatsigOptions['dataAdapter'] | undefined;\n    if (options.edgeConfig) {\n      dataAdapter = await createEdgeConfigDataAdapter({\n        edgeConfigItemKey: options.edgeConfig.itemKey,\n        edgeConfigConnectionString: options.edgeConfig.connectionString,\n      });\n    }\n\n    await Statsig.initialize(options.statsigServerApiKey, {\n      dataAdapter,\n      // ID list syncing is disabled by default\n      // Can be opted in using `options.statsigOptions`\n      initStrategyForIDLists: 'none',\n      disableIdListsSync: true,\n      // Set a shorter interval during development so developers see changes earlier\n      rulesetsSyncIntervalMs:\n        process.env.NODE_ENV === 'development' ? 5_000 : undefined,\n      ...options.statsigOptions,\n    });\n  };\n  let _initializePromise: Promise<void> | undefined;\n\n  /**\n   * Initialize the Statsig SDK.\n   *\n   * This must be called before checking gates/configs or logging events.\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<typeof Statsig> => {\n    if (!_initializePromise) {\n      _initializePromise = initializeStatsig();\n    }\n    await _initializePromise;\n    return Statsig;\n  };\n\n  const isStatsigUser = (user: unknown): user is StatsigUser => {\n    return user != null && typeof user === 'object';\n  };\n\n  const minSyncDelayMs = options.edgeConfig ? 1_000 : 5_000;\n  const syncHandler = createSyncingHandler(minSyncDelayMs);\n\n  async function predecide(user?: StatsigUser): Promise<StatsigUser> {\n    await initialize();\n    syncHandler?.();\n    if (!isStatsigUser(user)) {\n      throw new Error(\n        '@flags-sdk/statsig: Invalid or missing statsigUser from identify. See https://flags-sdk.dev/concepts/identify',\n      );\n    }\n    return user;\n  }\n\n  function origin(prefix: string) {\n    if (!options.statsigProjectId) {\n      return () => undefined;\n    }\n    return (key: string) => {\n      // Allow unused suffix to be provided to flags to tell them apart.\n      // Used for different treatments of the same Statsig entities.\n      const keyPart = key.split('.')[0] ?? '';\n      return `https://console.statsig.com/${options.statsigProjectId}/${prefix}/${keyPart}`;\n    };\n  }\n\n  /**\n   * Resolve a flag powered by a Feature Gate.\n   *\n   * Implements `decide` to resolve the Feature Gate with `Statsig.getFeatureGateSync`\n   *\n   * If a function is provided, the return value of the function called\n   * with the feature gate is returned.\n   *\n   * Implements `origin` to link to the flag in the Flags Explorer\n   * if the adapter defines `statsigProjectId`\n   */\n  function featureGate<T>(\n    getValue: (gate: FeatureGate) => T,\n    opts?: {\n      exposureLogging?: boolean;\n    },\n  ): Adapter<T, StatsigUser> {\n    return {\n      origin: origin('gates'),\n      decide: async ({ key, entities }) => {\n        const user = await predecide(entities);\n        const gate = opts?.exposureLogging\n          ? Statsig.getFeatureGateSync(user, key)\n          : Statsig.getFeatureGateWithExposureLoggingDisabledSync(user, key);\n        return getValue(gate);\n      },\n    };\n  }\n\n  /**\n   * Resolve a flag powered by a Dynamic Config.\n   *\n   * Implements `decide` to resolve the Dynamic Config with `Statsig.getConfigSync`\n   *\n   * If a function is provided, the return value of the function called\n   * with the dynamic config is returned.\n   *\n   * Implements `origin` to link to the flag in the Flags Explorer\n   * if the adapter defines `statsigProjectId`\n   */\n  function dynamicConfig<T>(\n    getValue: (config: DynamicConfig) => T,\n    opts?: {\n      exposureLogging?: boolean;\n    },\n  ): Adapter<T, StatsigUser> {\n    return {\n      origin: origin('dynamic_configs'),\n      decide: async ({ key, entities }) => {\n        const user = await predecide(entities);\n        const configKey = key.split('.')[0] ?? '';\n        const config = opts?.exposureLogging\n          ? Statsig.getConfigSync(user, configKey)\n          : Statsig.getConfigWithExposureLoggingDisabledSync(user, configKey);\n        return getValue(config);\n      },\n    };\n  }\n\n  function experiment<T>(\n    getValue: (experiment: DynamicConfig) => T,\n    opts?: { exposureLogging?: boolean },\n  ): Adapter<T, StatsigUser> {\n    return {\n      origin: origin('experiments'),\n      decide: async ({ key, entities }) => {\n        const user = await predecide(entities);\n        const experiment = opts?.exposureLogging\n          ? Statsig.getExperimentSync(user, key)\n          : Statsig.getExperimentWithExposureLoggingDisabledSync(user, key);\n        return getValue(experiment);\n      },\n    };\n  }\n\n  function autotune<T>(\n    getValue: (autotune: DynamicConfig) => T,\n    opts?: { exposureLogging?: boolean },\n  ): Adapter<T, StatsigUser> {\n    return {\n      origin: origin('autotune'),\n      decide: async ({ key, entities }) => {\n        const user = await predecide(entities);\n        const autotune = opts?.exposureLogging\n          ? Statsig.getConfigSync(user, key)\n          : Statsig.getConfigWithExposureLoggingDisabledSync(user, key);\n        return getValue(autotune);\n      },\n    };\n  }\n\n  function layer<T>(\n    getValue: (layer: Layer) => T,\n    opts?: { exposureLogging?: boolean },\n  ): Adapter<T, StatsigUser> {\n    return {\n      origin: origin('layers'),\n      decide: async ({ key, entities }) => {\n        const user = await predecide(entities);\n        const layer = opts?.exposureLogging\n          ? Statsig.getLayerSync(user, key)\n          : Statsig.getLayerWithExposureLoggingDisabledSync(user, key);\n        return getValue(layer);\n      },\n    };\n  }\n\n  return {\n    featureGate,\n    dynamicConfig,\n    experiment,\n    autotune,\n    layer,\n    initialize,\n  };\n}\n\nlet defaultStatsigAdapter: AdapterResponse | undefined;\n\nexport function resetDefaultStatsigAdapter() {\n  defaultStatsigAdapter = undefined;\n}\n\n/**\n * Equivalent to `createStatsigAdapter` but with default environment variable names.\n *\n * Required:\n * - `STATSIG_SERVER_API_KEY` - Statsig secret server API key\n *\n * Optional:\n * - `STATSIG_PROJECT_ID` - Statsig project ID to enable link in Vercel's Flags Explorer\n * - `EXPERIMENTATION_CONFIG` - Vercel Edge Config connection string\n * - `EXPERIMENTATION_CONFIG_ITEM_KEY` - Vercel Edge Config item key where data is stored\n */\nexport function createDefaultStatsigAdapter(): AdapterResponse {\n  if (defaultStatsigAdapter) {\n    return defaultStatsigAdapter;\n  }\n  const statsigServerApiKey = process.env.STATSIG_SERVER_API_KEY as string;\n  const statsigProjectId = process.env.STATSIG_PROJECT_ID;\n  const edgeConfig = process.env.EXPERIMENTATION_CONFIG;\n  const edgeConfigItemKey = process.env.EXPERIMENTATION_CONFIG_ITEM_KEY;\n  if (!(edgeConfig && edgeConfigItemKey)) {\n    defaultStatsigAdapter = createStatsigAdapter({\n      statsigServerApiKey,\n      statsigProjectId,\n    });\n  } else {\n    defaultStatsigAdapter = createStatsigAdapter({\n      statsigServerApiKey,\n      edgeConfig: {\n        connectionString: edgeConfig,\n        itemKey: edgeConfigItemKey,\n      },\n      statsigProjectId,\n    });\n  }\n\n  return defaultStatsigAdapter;\n}\n\n/**\n * The default Statsig adapter.\n *\n * This is a convenience object that pre-initializes the Statsig SDK and provides\n * the adapter functions for the Feature Gates, Dynamic Configs, Experiments,\n * Autotunes, and Layers.\n *\n * This is the recommended way to use the Statsig adapter.\n *\n * ```ts\n * // flags.ts\n * import { flag } from 'flags/next';\n * import { statsigAdapter } from '@flags-sdk/statsig';\n *\n * const flag = flag({\n *   key: 'my-flag',\n *   defaultValue: false,\n *   adapter: statsigAdapter.featureGate((gate) => gate.value),\n * });\n * ```\n */\nexport const statsigAdapter: AdapterResponse = {\n  featureGate: (...args) => createDefaultStatsigAdapter().featureGate(...args),\n  dynamicConfig: (...args) =>\n    createDefaultStatsigAdapter().dynamicConfig(...args),\n  experiment: (...args) => createDefaultStatsigAdapter().experiment(...args),\n  autotune: (...args) => createDefaultStatsigAdapter().autotune(...args),\n  layer: (...args) => createDefaultStatsigAdapter().layer(...args),\n  initialize: () => createDefaultStatsigAdapter().initialize(),\n};\n","import Statsig from 'statsig-node-lite';\n\ndeclare global {\n  var EdgeRuntime: string | undefined;\n}\n\nexport const isEdgeRuntime = (): boolean => {\n  return EdgeRuntime !== undefined;\n};\n\n/**\n * The Edge Config Data Adapter is an optional peer dependency that allows\n * the Statsig SDK to retrieve its data from Edge Config instead of over the network.\n */\nexport async function createEdgeConfigDataAdapter(options: {\n  edgeConfigItemKey: string;\n  edgeConfigConnectionString: string;\n}) {\n  // Edge Config adapter requires `@vercel/edge-config` and `statsig-node-vercel`\n  // Since it is a peer dependency, we will import it dynamically\n  const { EdgeConfigDataAdapter } = await import('statsig-node-vercel');\n  const { createClient } = await import('@vercel/edge-config');\n  return new EdgeConfigDataAdapter({\n    edgeConfigItemKey: options.edgeConfigItemKey,\n    edgeConfigClient: createClient(options.edgeConfigConnectionString, {\n      // We disable the development cache as Statsig caches for 10 seconds internally,\n      // and we want to avoid situations where Statsig tries to read the latest value,\n      // but hits the development cache and then caches the outdated value for another 10 seconds,\n      // as this would lead to the developer having to wait 20 seconds to see the latest value.\n      disableDevelopmentCache: true,\n    }),\n  });\n}\n\n/**\n * Edge runtime does not support timers outside of a request context.\n *\n * Statsig syncs config specs outside of the request context,\n * so we will support it in triggering config spec synchronization in this case.\n */\nexport const createSyncingHandler = (\n  minSyncDelayMs: number,\n): null | (() => void) => {\n  // Syncing both in Edge Runtime and Node.js for now, as the sync is otherwise\n  // not working during local development.\n  //\n  // This needs to be fixed in statsig-node-lite in the future.\n  //\n  // Ideally the Statsig SDK would not sync at all and instead always read from Edge Config,\n  // this would provide two benefits:\n  // - changes would propagate immediately instead of being cached for 5s or 10s\n  // - the broken syncing due to issues in Date.now in Edge Runtime would be irrelevant\n  //\n  // if (typeof EdgeRuntime === 'undefined') return null;\n  let isSyncingConfigSpecs = false;\n  let nextConfigSpecSyncTime = Date.now() + minSyncDelayMs;\n  return (): void => {\n    if (Date.now() >= nextConfigSpecSyncTime && !isSyncingConfigSpecs) {\n      try {\n        isSyncingConfigSpecs = true;\n        const sync = Statsig.syncConfigSpecs().finally(() => {\n          isSyncingConfigSpecs = false;\n          nextConfigSpecSyncTime = Date.now() + minSyncDelayMs;\n        });\n        import('@vercel/functions').then(({ waitUntil }) => {\n          waitUntil(sync);\n        });\n      } catch (e) {\n        // continue\n      }\n    }\n  };\n};\n"]}