{"version":3,"file":"EmbraceDynamicConfigManager.cjs","names":["diag","getConfigURL","DEFAULT_CONFIG","LOCAL_STORAGE_REMOTE_CONFIG_KEY"],"sources":["../../../src/managers/EmbraceConfigManager/EmbraceDynamicConfigManager.ts"],"sourcesContent":["import type { DiagLogger } from '@opentelemetry/api';\nimport { diag } from '@opentelemetry/api';\nimport type {\n  DynamicConfigManager,\n  DynamicSDKConfig,\n} from '../../sdk/index.ts';\nimport {\n  DEFAULT_CONFIG,\n  LOCAL_STORAGE_REMOTE_CONFIG_KEY,\n} from './constants.ts';\nimport type {\n  EmbraceDynamicConfigManagerArgs,\n  RemoteConfig,\n  StoredRemoteConfig,\n} from './types.ts';\nimport { getConfigURL } from './utils.ts';\n\nconst parseRemoteConfig = (remoteConfig: RemoteConfig): DynamicSDKConfig => {\n  const parsed: DynamicSDKConfig = {\n    samplingPct: remoteConfig.threshold,\n  };\n\n  if (remoteConfig.network_span_forwarding !== undefined) {\n    parsed.networkSpansForwardingThreshold =\n      remoteConfig.network_span_forwarding.pct_enabled;\n  }\n\n  if (remoteConfig.empty_session_avoidance_enabled_pct !== undefined) {\n    parsed.emptySessionAvoidanceEnabledPct =\n      remoteConfig.empty_session_avoidance_enabled_pct;\n  }\n\n  return parsed;\n};\n\nexport class EmbraceDynamicConfigManager implements DynamicConfigManager {\n  // Set to null if appID is not provided, in that case only rely on local config\n  private readonly _remoteConfigURL: string | null = null;\n  private readonly _diag: DiagLogger;\n  private readonly _storage: Storage;\n\n  private _sdkConfig: DynamicSDKConfig;\n  private _etag: string | null = null;\n\n  public constructor({\n    appID,\n    appVersion,\n    deviceId,\n    diag: diagParam = diag.createComponentLogger({\n      namespace: 'embrace-config-manager',\n    }),\n    storage = window.localStorage,\n    // Allow users to provide a default config\n    defaultConfig = {},\n    embraceConfigURL,\n  }: EmbraceDynamicConfigManagerArgs = {}) {\n    if (appID && appVersion && deviceId) {\n      this._remoteConfigURL = getConfigURL(\n        appID,\n        {\n          appVersion,\n          deviceId,\n          // TODO: Replace with actual OS version once we start capturing it\n          osVersion: '1',\n        },\n        embraceConfigURL,\n      );\n    }\n\n    this._diag = diagParam;\n    this._storage = storage;\n\n    const storedRemoteConfig = this._getRemoteConfigFromStorage();\n\n    if (storedRemoteConfig) {\n      this._etag = storedRemoteConfig.etag;\n    }\n\n    this._sdkConfig = {\n      // Merge the default config with any user-provided defaults\n      // making sure user-provided values take precedence\n      ...DEFAULT_CONFIG,\n      ...defaultConfig,\n      // Stored remote config values will override both defaults and user-provided defaults\n      ...(storedRemoteConfig\n        ? parseRemoteConfig(storedRemoteConfig.config)\n        : {}),\n    };\n  }\n\n  public setConfig(config: Partial<DynamicSDKConfig>): void {\n    this._sdkConfig = {\n      ...this._sdkConfig,\n      ...config,\n    };\n  }\n\n  public getConfig(): DynamicSDKConfig {\n    return this._sdkConfig;\n  }\n\n  // No-op if not sending data to embrace\n  public async refreshRemoteConfig(): Promise<void> {\n    if (!this._remoteConfigURL) {\n      return;\n    }\n\n    try {\n      const remoteConfigResponse = await this._fetchRemoteConfig(\n        this._remoteConfigURL,\n      );\n\n      if (!remoteConfigResponse) {\n        this._diag.debug('No changes in remote config, skipping update');\n        return;\n      }\n\n      const [remoteConfig, etag] = remoteConfigResponse;\n      this._storage.setItem(\n        LOCAL_STORAGE_REMOTE_CONFIG_KEY,\n        JSON.stringify({\n          config: remoteConfig,\n          etag,\n        } as StoredRemoteConfig),\n      );\n\n      this._sdkConfig = parseRemoteConfig(remoteConfig);\n      this._etag = etag;\n    } catch (error: unknown) {\n      this._diag.warn(\n        `Failed to refresh remote config: ${error instanceof Error ? error.message : String(error)}`,\n      );\n    }\n  }\n\n  private _getRemoteConfigFromStorage(): StoredRemoteConfig | null {\n    try {\n      const configString = this._storage.getItem(\n        LOCAL_STORAGE_REMOTE_CONFIG_KEY,\n      );\n\n      if (configString) {\n        return JSON.parse(configString) as StoredRemoteConfig;\n      }\n\n      return null;\n    } catch (error) {\n      this._diag.warn(\n        `Failed to parse remote config from storage: ${error instanceof Error ? error.message : String(error)}`,\n      );\n\n      return null;\n    }\n  }\n\n  private async _fetchRemoteConfig(\n    url: string,\n  ): Promise<[RemoteConfig, string | null] | null> {\n    const response = await fetch(url, {\n      headers: this._etag ? { 'If-None-Match': this._etag } : {},\n    });\n\n    const etag = response.headers.get('etag');\n\n    // Nothing changed, return null\n    if (response.status === 304) {\n      return null;\n    }\n\n    if (!response.ok) {\n      this._diag.warn(\n        `Failed to fetch remote config from ${url}: ${response.statusText}`,\n      );\n\n      return null;\n    }\n\n    const remoteConfig = (await response.json()) as RemoteConfig;\n\n    return [remoteConfig, etag];\n  }\n}\n"],"mappings":";;;;;;AAiBA,MAAM,qBAAqB,iBAAiD;CAC1E,MAAM,SAA2B,EAC/B,aAAa,aAAa,WAC3B;AAED,KAAI,aAAa,4BAA4B,KAAA,EAC3C,QAAO,kCACL,aAAa,wBAAwB;AAGzC,KAAI,aAAa,wCAAwC,KAAA,EACvD,QAAO,kCACL,aAAa;AAGjB,QAAO;;AAGT,IAAa,8BAAb,MAAyE;CAEvE,mBAAmD;CACnD;CACA;CAEA;CACA,QAA+B;CAE/B,YAAmB,EACjB,OACA,YACA,UACA,MAAM,YAAYA,mBAAAA,KAAK,sBAAsB,EAC3C,WAAW,0BACZ,CAAC,EACF,UAAU,OAAO,cAEjB,gBAAgB,EAAE,EAClB,qBACmC,EAAE,EAAE;AACvC,MAAI,SAAS,cAAc,SACzB,MAAK,mBAAmBC,4CAAAA,aACtB,OACA;GACE;GACA;GAEA,WAAW;GACZ,EACD,iBACD;AAGH,OAAK,QAAQ;AACb,OAAK,WAAW;EAEhB,MAAM,qBAAqB,KAAK,6BAA6B;AAE7D,MAAI,mBACF,MAAK,QAAQ,mBAAmB;AAGlC,OAAK,aAAa;GAGhB,GAAGC,gDAAAA;GACH,GAAG;GAEH,GAAI,qBACA,kBAAkB,mBAAmB,OAAO,GAC5C,EAAE;GACP;;CAGH,UAAiB,QAAyC;AACxD,OAAK,aAAa;GAChB,GAAG,KAAK;GACR,GAAG;GACJ;;CAGH,YAAqC;AACnC,SAAO,KAAK;;CAId,MAAa,sBAAqC;AAChD,MAAI,CAAC,KAAK,iBACR;AAGF,MAAI;GACF,MAAM,uBAAuB,MAAM,KAAK,mBACtC,KAAK,iBACN;AAED,OAAI,CAAC,sBAAsB;AACzB,SAAK,MAAM,MAAM,+CAA+C;AAChE;;GAGF,MAAM,CAAC,cAAc,QAAQ;AAC7B,QAAK,SAAS,QACZC,gDAAAA,iCACA,KAAK,UAAU;IACb,QAAQ;IACR;IACD,CAAuB,CACzB;AAED,QAAK,aAAa,kBAAkB,aAAa;AACjD,QAAK,QAAQ;WACN,OAAgB;AACvB,QAAK,MAAM,KACT,oCAAoC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,GAC3F;;;CAIL,8BAAiE;AAC/D,MAAI;GACF,MAAM,eAAe,KAAK,SAAS,QACjCA,gDAAAA,gCACD;AAED,OAAI,aACF,QAAO,KAAK,MAAM,aAAa;AAGjC,UAAO;WACA,OAAO;AACd,QAAK,MAAM,KACT,+CAA+C,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,GACtG;AAED,UAAO;;;CAIX,MAAc,mBACZ,KAC+C;EAC/C,MAAM,WAAW,MAAM,MAAM,KAAK,EAChC,SAAS,KAAK,QAAQ,EAAE,iBAAiB,KAAK,OAAO,GAAG,EAAE,EAC3D,CAAC;EAEF,MAAM,OAAO,SAAS,QAAQ,IAAI,OAAO;AAGzC,MAAI,SAAS,WAAW,IACtB,QAAO;AAGT,MAAI,CAAC,SAAS,IAAI;AAChB,QAAK,MAAM,KACT,sCAAsC,IAAI,IAAI,SAAS,aACxD;AAED,UAAO;;AAKT,SAAO,CAFe,MAAM,SAAS,MAAM,EAErB,KAAK"}