{"version":3,"sources":["../src/api/video.api.ts","../src/utils/getGatewayEndpoint.ts","../src/api/analytics.api.ts","../src/utils/startRefreshTokenOnInterval.ts","../src/utils/tokenStore.ts","../src/NaluriVideo.ts"],"names":["API_URL","SupportedEnvironments","VideoApi","options","roomName","url","version_default","response","ApiClient","error","NaluriVideoError","NaluriVideoErrorConstants","getGatewayEndpoint","environment","AnalyticsApi","userId","gatewayUrl","traits","event","properties","req","EVENTS","intervalId","TWENTY_MINUTES","startRefreshTokenOnInterval","accountApi","tokenStore","analyticsApi","onRefreshTokenError","refreshToken","NaluriRefreshTokenError","accessToken","err","stopRefreshTokenOnInterval","TokenStore","key","value","NaluriVideo","_NaluriVideo","apiKey","AccountApi","timeoutMs","invariant","VideoInstance","roomId","e","authorizationCode","user"],"mappings":"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","sourcesContent":["import { SupportedEnvironments } from '@/config/environments';\nimport { NaluriVideoError } from '@/errors';\nimport { ApiClient } from '@/utils/apiClient';\nimport type { TokenStore } from '@/utils/tokenStore';\nimport version from '@/utils/version';\nimport { NaluriVideoErrorConstants } from '..';\nimport { AccountApi } from './account.api';\n\nexport interface AuthTokens {\n  accessToken: string;\n  refreshToken: string;\n}\n\nconst API_URL = {\n  [SupportedEnvironments.DEV]: 'https://video-api.dev.naluri.net',\n  [SupportedEnvironments.SIT]: 'https://video-api.staging.naluri.net',\n  [SupportedEnvironments.PROD]: 'https://video-api.naluri.net',\n} as const;\n\nexport class VideoApi {\n  private readonly apiUrl: string;\n  private readonly apiKey: string;\n\n  private tokenStore: TokenStore;\n  private accountApi: AccountApi;\n  private onRefreshTokenError?: () => Promise<void>;\n\n  constructor(options: {\n    apiKey: string;\n    environment: SupportedEnvironments;\n    tokenStore: TokenStore;\n    accountApi: AccountApi;\n    onRefreshTokenError?: () => Promise<void>;\n  }) {\n    this.apiUrl = API_URL[options.environment];\n    this.apiKey = options.apiKey;\n\n    this.tokenStore = options.tokenStore;\n    this.accountApi = options.accountApi;\n    this.onRefreshTokenError = options.onRefreshTokenError;\n  }\n\n  /**\n   * @returns {string} token to connect to a room\n   * */\n  public async authorizeUserForRoom(roomName: string): Promise<string> {\n    const url = `${this.apiUrl}/rooms/${roomName}`;\n    const options = {\n      method: 'GET',\n      headers: {\n        'x-api-key': this.apiKey,\n        'x-nl-sdk-version': version,\n        'User-Agent': `Naluri Video SDK /JS (${version}})`,\n      },\n    };\n\n    const apiClient = new ApiClient(\n      this.tokenStore,\n      this.accountApi,\n      this.onRefreshTokenError,\n    );\n\n    const response = await apiClient.fetch(url, options);\n\n    if (!response.ok) {\n      const error = await response.json();\n      if ('statusCode' in error && 'message' in error) {\n        throw new NaluriVideoError({\n          message: error.message,\n          code: error.statusCode,\n          statusCode: response.status,\n        });\n      }\n\n      throw new NaluriVideoError({\n        message: `Authorization failed for room ${roomName} with error: ${error.message}`,\n        statusCode: response.status,\n        code: NaluriVideoErrorConstants.UNKNOWN_ERROR,\n      });\n    }\n\n    return await response.text();\n  }\n}\n","import { SupportedEnvironments } from '@/config/environments';\n\nexport function getGatewayEndpoint(environment: SupportedEnvironments) {\n  switch (environment) {\n    case SupportedEnvironments.DEV:\n      return 'https://video-api.dev.naluri.net';\n    case SupportedEnvironments.SIT:\n      return 'https://video-api.staging.naluri.net';\n    case SupportedEnvironments.PROD:\n      return 'https://video-api.naluri.net';\n    default:\n      throw new Error(`Environment ${environment} is not supported.`);\n  }\n}\n","import version from '@/utils/version';\n\nexport class AnalyticsApi {\n  private readonly queue: (() => Promise<Response>)[] = [];\n\n  private readonly FLUSH_INTERVAL = 1000;\n\n  private flushed = false;\n\n  private intervalId: number | NodeJS.Timeout;\n\n  constructor(\n    private readonly userId: string,\n    private readonly gatewayUrl: string,\n  ) {\n    this.intervalId = setInterval(() => {\n      if (this.queue.length || !this.flushed) {\n        this.flush();\n      }\n    }, this.FLUSH_INTERVAL);\n  }\n\n  identify(traits: Record<string, unknown> = {}): void {\n    this.queue.push(() =>\n      fetch(`${this.gatewayUrl}/analytics/identify`, {\n        method: 'POST',\n        headers: this.getDefaultHeaders(),\n        body: JSON.stringify({\n          userId: this.userId,\n          traits: {\n            // eslint-disable-next-line camelcase\n            sdk_version: version,\n            source: 'video_sdk',\n            ...traits,\n          },\n        }),\n      }),\n    );\n\n    this.flushed = false;\n  }\n\n  track(event: EVENTS, properties: Record<string, unknown> = {}): void {\n    this.queue.push(() =>\n      fetch(`${this.gatewayUrl}/analytics/track`, {\n        method: 'POST',\n        headers: this.getDefaultHeaders(),\n        body: JSON.stringify({\n          userId: this.userId,\n          event,\n          properties,\n        }),\n      }),\n    );\n\n    this.flushed = false;\n  }\n\n  private flush(): void {\n    this.flushed = true;\n    while (this.queue.length) {\n      const req = this.queue.shift();\n      if (req) {\n        req().catch(() => {\n          return;\n        });\n      }\n    }\n  }\n\n  private getDefaultHeaders() {\n    return {\n      Accept: 'application/json',\n      'Content-Type': 'application/json',\n      'User-Agent': `Naluri Video SDK /JS (${version}})`,\n      'x-nl-sdk-version': version,\n    };\n  }\n\n  cleanup(): void {\n    this.flush();\n    clearInterval(this.intervalId);\n  }\n}\n\nexport const EVENTS = {\n  LOGIN: 'login',\n  REFRESH: 'refresh',\n  LOGOUT: 'logout',\n  CONNECT_ROOM: 'connect_room',\n\n  // errors\n  LOGIN_ERROR: 'login_error',\n  LOGOUT_ERROR: 'logout_error',\n  REFRESH_ERROR: 'refresh_error',\n  CONNECT_ROOM_ERROR: 'connect_room_error',\n} as const;\n\nexport type EVENTS = (typeof EVENTS)[keyof typeof EVENTS];\n","import { AccountApi } from '@/api/account.api';\nimport { AnalyticsApi, EVENTS } from '@/api/analytics.api';\nimport { NaluriRefreshTokenError } from '@/errors';\nimport { TokenStore } from './tokenStore';\n\nlet intervalId: NodeJS.Timeout | string | number;\n\nconst TWENTY_MINUTES = 20 * 60 * 1000;\n\nexport const startRefreshTokenOnInterval = async (\n  accountApi: AccountApi,\n  tokenStore: TokenStore,\n  analyticsApi?: AnalyticsApi,\n  onRefreshTokenError?: () => Promise<void>,\n) => {\n  const refreshToken = tokenStore.getItem('refreshToken');\n\n  if (!refreshToken) {\n    if (onRefreshTokenError) {\n      await onRefreshTokenError();\n    } else {\n      throw new NaluriRefreshTokenError();\n    }\n\n    return;\n  }\n\n  if (intervalId) clearInterval(intervalId);\n\n  const refreshAccessToken = async () => {\n    try {\n      const { accessToken } = await accountApi.refresh(refreshToken);\n      tokenStore.setItem('accessToken', accessToken);\n\n      startRefreshTokenOnInterval(\n        accountApi,\n        tokenStore,\n        analyticsApi,\n        onRefreshTokenError,\n      );\n    } catch (err) {\n      if (analyticsApi) {\n        analyticsApi.track(EVENTS.REFRESH_ERROR, {\n          error: err,\n        });\n      }\n      clearInterval(intervalId);\n      if (onRefreshTokenError) {\n        await onRefreshTokenError();\n      } else {\n        throw new NaluriRefreshTokenError();\n      }\n    }\n  };\n\n  intervalId = setInterval(refreshAccessToken, TWENTY_MINUTES);\n};\n\nexport const stopRefreshTokenOnInterval = () => {\n  if (intervalId) clearInterval(intervalId);\n};\n","export type Storage<T> = {\n  getItem: (key: T) => string | null;\n  setItem: (key: T, value: string) => void;\n  removeItem: (key: T) => void;\n};\n\nexport type AuthStore = {\n  accessToken?: string;\n  refreshToken?: string;\n};\n\ntype AuthStoreKey = keyof AuthStore;\n\nexport class TokenStore implements Storage<AuthStoreKey> {\n  private readonly store: AuthStore;\n\n  constructor() {\n    this.store = {\n      accessToken: '',\n      refreshToken: '',\n    };\n  }\n\n  public getItem(key: AuthStoreKey): string | null {\n    return this.store[key] || null;\n  }\n\n  public setItem(key: AuthStoreKey, value: string): void {\n    this.store[key] = value;\n  }\n\n  public removeItem(key: AuthStoreKey): void {\n    delete this.store[key];\n  }\n\n  public clear(): void {\n    this.store.accessToken = '';\n    this.store.refreshToken = '';\n  }\n}\n","import { AccountApi } from '@/api/account.api';\nimport { VideoApi } from '@/api/video.api';\nimport { SupportedEnvironments } from '@/config/environments';\nimport { AccountUser, NaluriVideoLoginOptions } from '@/types';\nimport { getGatewayEndpoint } from '@/utils/getGatewayEndpoint';\nimport { invariant } from '@/utils/invariant';\nimport { AnalyticsApi, EVENTS } from './api/analytics.api';\nimport { NaluriVideoErrorConstants } from './constants/errors';\nimport { NaluriVideoError } from './errors';\nimport {\n  startRefreshTokenOnInterval,\n  stopRefreshTokenOnInterval,\n} from './utils/startRefreshTokenOnInterval';\nimport { TokenStore } from './utils/tokenStore';\n\nexport interface NaluriVideoOptions {\n  apiKey: string;\n  timeoutMs?: number;\n  environment?: SupportedEnvironments;\n  onRefreshTokenError?: () => Promise<void>;\n}\n\n// private\nlet analyticsApi: AnalyticsApi;\n\nconst tokenStore = new TokenStore();\n\nexport class NaluriVideo {\n  /**\n   * Api key of naluri video\n   */\n  public readonly apiKey: string;\n\n  /**\n   * Environment, default to SIT\n   */\n  public readonly environment: SupportedEnvironments;\n\n  /**\n   * Function to be called when refresh token fails\n   */\n  public readonly onRefreshTokenError?: () => Promise<void>;\n\n  /**\n   * @private\n   * Initialized Video instance\n   */\n  private static videoInstance?: NaluriVideo;\n\n  private accountInstance: AccountApi;\n\n  private videoApiInstance?: VideoApi;\n\n  private constructor({\n    apiKey,\n    environment,\n    onRefreshTokenError,\n  }: NaluriVideoOptions) {\n    this.apiKey = apiKey;\n\n    this.environment = environment ?? SupportedEnvironments.SIT;\n\n    if (onRefreshTokenError) {\n      this.onRefreshTokenError = onRefreshTokenError;\n    }\n\n    this.accountInstance = new AccountApi({\n      apiKey,\n      gatewayUrl: getGatewayEndpoint(this.environment),\n      tokenStore,\n    });\n  }\n\n  /**\n   * [IMPORTANT]: Initialise this first before using any other methods\n   * Initialize a new Naluri Video instance\n   * @returns {NaluriVideo}\n   */\n  public static initialize({\n    apiKey,\n    timeoutMs,\n    environment,\n    onRefreshTokenError,\n  }: NaluriVideoOptions): void {\n    invariant(\n      typeof apiKey === 'string' && apiKey,\n      'Cannot initialize Naluri Video without api key',\n    );\n\n    if (this.videoInstance) {\n      return;\n    }\n\n    const VideoInstance = new NaluriVideo({\n      apiKey,\n      environment,\n      timeoutMs,\n      onRefreshTokenError,\n    });\n\n    this.videoInstance = VideoInstance;\n  }\n\n  /**\n   * Gets a new Naluri Video instance\n   * @returns {NaluriVideo}\n   */\n  public static getInstance(): NaluriVideo {\n    invariant(\n      !!this.videoInstance,\n      'Naluri video instance is not initialized. Please use the initialize method first.',\n    );\n\n    return this.videoInstance;\n  }\n\n  /**\n   * @throws {NaluriVideoError}\n   * @returns {string} access token for video room\n   */\n  public async connectRoom(roomId: string): Promise<string> {\n    invariant(\n      !!this.videoApiInstance,\n      'Naluri video instance is not initialized. Please use the initialize and login method first.',\n    );\n\n    if (analyticsApi) analyticsApi.track(EVENTS.CONNECT_ROOM, { roomId });\n\n    try {\n      const token = await this.videoApiInstance.authorizeUserForRoom(roomId);\n      return token;\n    } catch (e) {\n      if (analyticsApi)\n        analyticsApi.track(EVENTS.CONNECT_ROOM_ERROR, {\n          error: e,\n          message: (e as Error).message,\n        });\n      throw e;\n    }\n  }\n\n  /**\n   * Login user to video\n   * @param {NaluriVideoLoginOptions} options\n   * @returns {PromiseLike<NaluriVideoLoginResponse>}\n   */\n  async login({\n    authorizationCode,\n  }: NaluriVideoLoginOptions): Promise<AccountUser> {\n    const { user } = await this.accountInstance.login(authorizationCode);\n\n    if (this.environment !== SupportedEnvironments.DEV) {\n      analyticsApi = new AnalyticsApi(\n        user.id,\n        getGatewayEndpoint(this.environment),\n      );\n\n      analyticsApi.identify({\n        tenant_id: user.tenantId,\n        country: user.country,\n        language: user.preferredLanguage,\n      });\n    }\n\n    this.videoApiInstance = new VideoApi({\n      apiKey: this.apiKey,\n      environment: this.environment,\n      tokenStore,\n      accountApi: this.accountInstance,\n    });\n\n    await startRefreshTokenOnInterval(\n      this.accountInstance,\n      tokenStore,\n      analyticsApi,\n      this.onRefreshTokenError,\n    );\n\n    return user;\n  }\n\n  public get isInitialized(): boolean {\n    return !!this.videoApiInstance;\n  }\n\n  public async logout() {\n    if (analyticsApi) analyticsApi.track(EVENTS.LOGOUT);\n    const refreshToken = tokenStore.getItem('refreshToken');\n\n    try {\n      if (refreshToken) await this.accountInstance.logout(refreshToken);\n    } catch (err) {\n      if (analyticsApi) analyticsApi.track(EVENTS.LOGOUT_ERROR, { error: err });\n\n      throw new NaluriVideoError({\n        message: (err as Error).message || 'Logout failed',\n        code: NaluriVideoErrorConstants.LOGOUT_FAILED,\n        statusCode: 500,\n      });\n    } finally {\n      if (analyticsApi) analyticsApi.cleanup();\n      tokenStore.clear();\n      stopRefreshTokenOnInterval();\n    }\n\n    return { success: true };\n  }\n\n  destroy() {\n    NaluriVideo.videoInstance = undefined;\n  }\n}\n"]}