{"version":3,"file":"index.mjs","sources":["../src/types/courier-api-urls.ts","../src/types/socket/protocol/messages.ts","../src/utils/logger.ts","../src/utils/uuid.ts","../src/types/courier-user-agent.ts","../src/utils/request.ts","../src/client/client.ts","../src/client/brand-client.ts","../src/types/socket/protocol/errors.ts","../src/socket/version.ts","../src/socket/courier-socket.ts","../src/socket/courier-inbox-transaction-manager.ts","../src/socket/inbox-message-utils.ts","../src/socket/courier-inbox-socket.ts","../src/client/inbox-client.ts","../src/utils/coding.ts","../src/client/preference-client.ts","../src/client/token-client.ts","../src/client/list-client.ts","../src/client/tracking-client.ts","../src/utils/courier-user-agent.ts","../src/client/courier-client.ts","../src/shared/authentication-listener.ts","../src/shared/courier.ts"],"sourcesContent":["export interface CourierApiUrls {\n  courier: {\n    rest: string;\n    graphql: string;\n  },\n  inbox: {\n    graphql: string;\n    webSocket: string;\n  }\n}\n\nexport type CourierApiRegion = 'us' | 'eu';\n\nconst freezeCourierApiUrls = (urls: CourierApiUrls): Readonly<CourierApiUrls> => Object.freeze({\n  courier: Object.freeze({\n    ...urls.courier,\n  }),\n  inbox: Object.freeze({\n    ...urls.inbox,\n  }),\n});\n\nconst cloneCourierApiUrls = (urls: CourierApiUrls): CourierApiUrls => ({\n  courier: {\n    ...urls.courier,\n  },\n  inbox: {\n    ...urls.inbox,\n  },\n});\n\nconst COURIER_API_URLS_BY_REGION: Record<CourierApiRegion, Readonly<CourierApiUrls>> = {\n  us: freezeCourierApiUrls({\n    courier: {\n      rest: 'https://api.courier.com',\n      graphql: 'https://api.courier.com/client/q',\n    },\n    inbox: {\n      graphql: 'https://inbox.courier.com/q',\n      webSocket: 'wss://realtime.courier.io'\n    }\n  }),\n  eu: freezeCourierApiUrls({\n    courier: {\n      rest: 'https://api.eu.courier.com',\n      graphql: 'https://api.eu.courier.com/client/q',\n    },\n    inbox: {\n      graphql: 'https://inbox.eu.courier.io/q',\n      webSocket: 'wss://realtime.eu.courier.io'\n    }\n  }),\n};\n\nexport const DEFAULT_COURIER_API_URLS = COURIER_API_URLS_BY_REGION.us;\nexport const EU_COURIER_API_URLS = COURIER_API_URLS_BY_REGION.eu;\n\nexport const getCourierApiUrlsForRegion = (region: CourierApiRegion = 'us'): CourierApiUrls =>\n  cloneCourierApiUrls(COURIER_API_URLS_BY_REGION[region]);\n\nexport const getCourierApiUrls = (urls?: CourierApiUrls): CourierApiUrls => {\n  const defaultUrls = DEFAULT_COURIER_API_URLS;\n\n  return {\n    courier: {\n      rest: urls?.courier.rest || defaultUrls.courier.rest,\n      graphql: urls?.courier.graphql || defaultUrls.courier.graphql,\n    },\n    inbox: {\n      graphql: urls?.inbox.graphql || defaultUrls.inbox.graphql,\n      webSocket: urls?.inbox.webSocket || defaultUrls.inbox.webSocket\n    }\n  };\n};\n","import { InboxMessage } from \"../../inbox\";\n\n/** Client actions. */\nexport enum ClientAction {\n  /** Subscribe to various events for a particular channel. */\n  Subscribe = 'subscribe',\n\n  /** Unsubscribe from a channel. */\n  Unsubscribe = 'unsubscribe',\n\n  /** Pong response to a ping message from the server. */\n  Pong = 'pong',\n\n  /** Ping the server to keep the connection alive. */\n  Ping = 'ping',\n\n  /** Get the current configuration. */\n  GetConfig = 'get-config',\n}\n\n/** Client request envelope. */\nexport interface ClientMessageEnvelope {\n  /**\n   * Transaction ID.\n   *\n   * This is a UUID generated per-socket message.\n   *\n   * The server response should include the same transaction ID.\n   */\n  tid: string;\n\n  /** Requested action for the server to perform. */\n  action: ClientAction;\n\n  /** Optional: Statistics describing past requests and/or client state. */\n  stats?: Record<string, any>;\n\n  /** Optional: Payload for the request, varying by action. */\n  data?: Record<string, any>;\n}\n\nexport enum ServerAction {\n  /** Ping message from the server. */\n  Ping = 'ping',\n}\n\n/**\n * Server action envelope.\n *\n * This is a request for the client to perform an action and respond to the server.\n */\nexport interface ServerActionEnvelope {\n  /** Transaction ID. */\n  tid: string;\n\n  /** Action from the server. */\n  action: ServerAction;\n}\n\n/** Server response types. */\nexport enum ServerResponse {\n  /** Response to an action request. */\n  Ack = 'ack',\n\n  /** Response to a ping request. */\n  Pong = 'pong',\n}\n\n/**\n * Server response envelope.\n *\n * This is a response from the server to a {@link ClientAction} (ping, subscribe, get-config, etc.).\n */\nexport interface ServerResponseEnvelope {\n  /** Transaction ID. */\n  tid: string;\n\n  /** Response from the server. */\n  response: ServerResponse;\n\n  /** Optional: Payload for the response, varying by response. */\n  data?: Record<string, any>;\n}\n\n/** Message event types broadcast by the server. */\nexport enum InboxMessageEvent {\n  NewMessage = 'message',\n  Archive = 'archive',\n  ArchiveAll = 'archive-all',\n  ArchiveRead = 'archive-read',\n  Clicked = 'clicked',\n  MarkAllRead = 'mark-all-read',\n  Opened = 'opened',\n  Read = 'read',\n  Unarchive = 'unarchive',\n  Unopened = 'unopened',\n  Unread = 'unread',\n}\n\n/** Envelope for an inbox message event. */\nexport interface InboxMessageEventEnvelope {\n  /** Event type indicating a new message, or a mutation to one or more existing messages. */\n  event: InboxMessageEvent;\n\n  /**\n   * Optional:Message ID.\n   *\n   * messageId is present for events that mutate a single message (e.g. read, unread, archive, etc.).\n   */\n  messageId?: string;\n\n  /** Optional: Message data, varying by event.\n   *\n   * For {@link InboxMessageEvent.NewMessage}, this is an {@link InboxMessage}.\n   * For other events this is undefined.\n   */\n  data?: InboxMessage;\n}\n\n/** Message sent by the server to indicate that the client should reconnect. */\nexport interface ReconnectMessage {\n  /** Event type indicating a reconnection. */\n  event: 'reconnect';\n\n  /** Message describing the reason for the reconnection. */\n  message: string;\n\n  /** Seconds after which the client should retry the connection. */\n  retryAfter: number;\n\n  /** https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code */\n  code: number;\n}\n\n/** Configuration for the client. */\nexport interface Config {\n  /** The time interval in milliseconds between client ping messages to the server. */\n  pingInterval: number;\n\n  /**\n   * Maximum number of outstanding pings before the client should\n   * close the connection and retry connecting.\n   */\n  maxOutstandingPings: number;\n}\n\n/** Envelope for a config response. */\nexport interface ConfigResponseEnvelope {\n  /** Transaction ID. */\n  tid: string;\n\n  response: 'config';\n\n  /** Configuration data for the client. */\n  data: Config;\n}\n\nexport type ServerMessage =\n  | ConfigResponseEnvelope\n  | InboxMessageEventEnvelope\n  | ReconnectMessage\n  | ServerActionEnvelope\n  | ServerResponseEnvelope;\n","export class Logger {\n\n  private readonly PREFIX = '[COURIER]';\n\n  constructor(private readonly showLogs: boolean) { }\n\n  public warn(message: string, ...args: any[]): void {\n    if (this.showLogs) {\n      console.warn(`${this.PREFIX} ${message}`, ...args);\n    }\n  }\n\n  public log(message: string, ...args: any[]): void {\n    if (this.showLogs) {\n      console.log(`${this.PREFIX} ${message}`, ...args);\n    }\n  }\n\n  public error(message: string, ...args: any[]): void {\n    if (this.showLogs) {\n      console.error(`${this.PREFIX} ${message}`, ...args);\n    }\n  }\n\n  public debug(message: string, ...args: any[]): void {\n    if (this.showLogs) {\n      console.debug(`${this.PREFIX} ${message}`, ...args);\n    }\n  }\n\n  public info(message: string, ...args: any[]): void {\n    if (this.showLogs) {\n      console.info(`${this.PREFIX} ${message}`, ...args);\n    }\n  }\n}\n","export class UUID {\n\n  private static readonly ALPHABET = 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict';\n\n  /**\n   * nanoid\n   * Copyright 2017 Andrey Sitnik <andrey@sitnik.ru>\n   *\n   * https://github.com/ai/nanoid/blob/main/LICENSE\n   *\n   * @param size - The size of the UUID to generate.\n   * @returns A string representing the UUID.\n   */\n  static nanoid(size: number = 21): string {\n    let id = '';\n    let bytes = crypto.getRandomValues(new Uint8Array((size |= 0)));\n\n    while (size--) {\n      // Using the bitwise AND operator to \"cap\" the value of\n      // the random byte from 255 to 63, in that way we can make sure\n      // that the value will be a valid index for the \"chars\" string.\n      id += UUID.ALPHABET[bytes[size] & 63]\n    }\n    return id;\n  }\n\n}","/** HTTP Header key used to report the Courier User-Agent. */\nexport const HTTP_HEADER_KEY: string = \"x-courier-ua\" as const;\n\nexport const SDK_KEY = \"sdk\" as const;\nexport const SDK_VERSION_KEY = \"sdkv\" as const;\nexport const CLIENT_ID_KEY = \"cid\" as const;\n\n/**\n * Courier User Agent object, identifying:\n *  - the SDK name and version making a request\n *  - the pseudonymous client ID, which is not connected to a user ID or workspace\n *\n * This JSON-serializable object is sent as part of WebSocket messages under\n * the `stats` key or serialized to a string HTTP header value for HTTP requests.\n */\nexport interface CourierUserAgent {\n  [SDK_KEY]: string;\n  [SDK_VERSION_KEY]: string;\n  [CLIENT_ID_KEY]: string;\n}\n","import { CourierClientOptions } from \"../client/courier-client\";\nimport { Logger } from \"./logger\";\nimport { UUID } from \"./uuid\";\nimport * as CourierUserAgent from \"../types/courier-user-agent\";\n\nexport class CourierRequestError extends Error {\n  constructor(\n    public code: number,\n    message: string,\n    public type?: string\n  ) {\n    super(message);\n    this.name = 'CourierRequestError';\n  }\n}\n\nfunction logRequest(logger: Logger, uid: string, type: 'HTTP' | 'GraphQL', data: {\n  url: string;\n  method?: string;\n  headers: Record<string, string>;\n  body?: any;\n  query?: string;\n  variables?: Record<string, any>;\n}) {\n  logger.log(`\n📡 New Courier ${type} Request: ${uid}\nURL: ${data.url}\n${data.method ? `Method: ${data.method}` : ''}\n${data.query ? `Query: ${data.query}` : ''}\n${data.variables ? `Variables: ${JSON.stringify(data.variables, null, 2)}` : ''}\nHeaders: ${JSON.stringify(data.headers, null, 2)}\nBody: ${data.body ? JSON.stringify(data.body, null, 2) : 'Empty'}\n  `);\n}\n\nfunction logResponse(logger: Logger, uid: string, type: 'HTTP' | 'GraphQL', data: {\n  status: number;\n  response: any;\n}) {\n  logger.log(`\n📡 New Courier ${type} Response: ${uid}\nStatus Code: ${data.status}\nResponse JSON: ${JSON.stringify(data.response, null, 2)}\n  `);\n}\n\nexport async function http(props: {\n  url: string,\n  clientKey?: string,\n  options: CourierClientOptions,\n  method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH',\n  headers?: Record<string, string>,\n  body?: any,\n  validCodes?: number[]\n}): Promise<any> {\n  const validCodes = props.validCodes ?? [200];\n\n  // If logs are enabled, add a unique ID to the request and response to match them in the logs.\n  const uid = props.options.showLogs ? UUID.nanoid() : undefined;\n  const courierUserAgentHeader = props.options.courierUserAgent.toHttpHeaderValue();\n\n  // Create request\n  const request = new Request(props.url, {\n    method: props.method,\n    headers: {\n      'Content-Type': 'application/json',\n      [CourierUserAgent.HTTP_HEADER_KEY]: courierUserAgentHeader,\n      ...props.headers\n    },\n    body: props.body ? JSON.stringify(props.body) : undefined\n  });\n\n  // Log request if enabled\n  if (uid) {\n    logRequest(props.options.logger, uid, 'HTTP', {\n      url: request.url,\n      method: request.method,\n      headers: Object.fromEntries(request.headers.entries()),\n      body: props.body\n    });\n  }\n\n  // Perform request\n  const response = await fetch(request);\n\n  // Handle empty responses (like 204 No Content)\n  if (response.status === 204) {\n    return;\n  }\n\n  // Try to parse JSON response\n  let data;\n  try {\n    data = await response.json();\n  } catch (error) {\n\n    // Weird fallback for only tracking url events :facepalm:\n    if (response.status === 200) {\n      return;\n    }\n\n    throw new CourierRequestError(\n      response.status,\n      'Failed to parse response as JSON',\n      'PARSE_ERROR'\n    );\n  }\n\n  // Log response if enabled\n  if (uid) {\n    logResponse(props.options.logger, uid, 'HTTP', {\n      status: response.status,\n      response: data\n    });\n  }\n\n  // Handle invalid status codes\n  if (!validCodes.includes(response.status)) {\n    throw new CourierRequestError(\n      response.status,\n      data?.message || 'Unknown Error',\n      data?.type\n    );\n  }\n\n  return data;\n}\n\nexport async function graphql(props: {\n  url: string,\n  options: CourierClientOptions,\n  headers: Record<string, string>,\n  query: string,\n  variables?: Record<string, any>\n}): Promise<any> {\n  // If logs are enabled, add a unique ID to the request and response to match them in the logs.\n  const uid = props.options.showLogs ? UUID.nanoid() : undefined;\n  const courierUserAgentHeader = props.options.courierUserAgent.toHttpHeaderValue();\n\n  // Log request if enabled\n  if (uid) {\n    logRequest(props.options.logger, uid, 'GraphQL', {\n      url: props.url,\n      headers: props.headers,\n      query: props.query,\n      variables: props.variables\n    });\n  }\n\n  const response = await fetch(props.url, {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n      [CourierUserAgent.HTTP_HEADER_KEY]: courierUserAgentHeader,\n      ...props.headers\n    },\n    body: JSON.stringify({\n      query: props.query,\n      variables: props.variables\n    })\n  });\n\n  // Try to parse JSON response\n  let data;\n  try {\n    data = await response.json();\n  } catch (error) {\n    throw new CourierRequestError(\n      response.status,\n      'Failed to parse response as JSON',\n      'PARSE_ERROR'\n    );\n  }\n\n  // Log response if enabled\n  if (uid) {\n    logResponse(props.options.logger, uid, 'GraphQL', {\n      status: response.status,\n      response: data\n    });\n  }\n\n  if (!response.ok) {\n    throw new CourierRequestError(\n      response.status,\n      data?.message || 'Unknown Error',\n      data?.type\n    );\n  }\n\n  return data;\n}\n","import { CourierClientOptions } from \"./courier-client\";\n\nexport class Client {\n\n  constructor(public readonly options: CourierClientOptions) { }\n\n}\n","import { CourierBrand } from '../types/brands';\nimport { graphql } from '../utils/request';\nimport { Client } from './client';\n\nexport class BrandClient extends Client {\n\n  /**\n   * Get a brand by ID using GraphQL\n   * @param brandId - The ID of the brand to retrieve\n   * @returns Promise resolving to the requested brand\n   */\n  public async getBrand(props: { brandId: string }): Promise<CourierBrand> {\n    const query = `\n      query GetBrand {\n        brand(brandId: \"${props.brandId}\") {\n          settings {\n            colors {\n              primary\n              secondary\n              tertiary\n            }\n            inapp {\n              borderRadius\n              disableCourierFooter\n            }\n          }\n          logo {\n            href\n            image\n          }\n          links\n        }\n      }\n    `;\n\n    const json = await graphql({\n      options: this.options,\n      url: this.options.apiUrls.courier.graphql,\n      headers: {\n        'x-courier-user-id': this.options.userId,\n        'x-courier-client-key': 'empty', // Empty for now. Will be removed in future.\n        'Authorization': `Bearer ${this.options.accessToken}`\n      },\n      query,\n      variables: { brandId: props.brandId }\n    });\n\n    return json.data.brand as CourierBrand;\n  }\n\n}\n","/**\n * Connection close code for non-error conditions.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code\n */\nexport const CLOSE_CODE_NORMAL_CLOSURE = 1000;\n\n/**\n * Courier-specific close event.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent\n */\nexport interface CourierCloseEvent extends CloseEvent {\n  /** The number of seconds to wait before retrying the connection. */\n  retryAfterSeconds?: number;\n}\n","export const INBOX_WIRE_PROTOCOL_VERSION = 'v1';\n","import { CourierClientOptions } from \"../client/courier-client\";\nimport { CLOSE_CODE_NORMAL_CLOSURE, CourierCloseEvent } from \"../types/socket/protocol/errors\";\nimport { ServerMessage } from \"../types/socket/protocol/messages\";\nimport { Logger } from \"../utils/logger\";\nimport { CourierUserAgent } from \"../utils/courier-user-agent\";\nimport { INBOX_WIRE_PROTOCOL_VERSION } from \"./version\";\nimport { SDK_KEY, SDK_VERSION_KEY } from \"../types/courier-user-agent\";\n\n/**\n * Abstract base class for Courier WebSocket implementations.\n *\n * The base class handles the connection and close events, as well as retry logic.\n * Application-specific logic should be implemented in the concrete classes.\n */\nexport abstract class CourierSocket {\n  /**\n   * The jitter factor for the backoff intervals.\n   *\n   * Backoff with jitter is calculated as a random value in the range:\n   * [BACKOFF_INTERVAL - BACKOFF_JITTER_FACTOR * BACKOFF_INTERVAL,\n   *  BACKOFF_INTERVAL + BACKOFF_JITTER_FACTOR * BACKOFF_INTERVAL).\n   */\n  private static readonly BACKOFF_JITTER_FACTOR = 0.5;\n\n  /**\n   * The maximum number of retry attempts.\n   */\n  private static readonly MAX_RETRY_ATTEMPTS = 5;\n\n  /**\n   * Backoff intervals in milliseconds.\n   *\n   * Each represents an offset from the previous interval, rather than a\n   * absolute offset from the initial request time.\n   */\n  private static readonly BACKOFF_INTERVALS_IN_MILLIS = [\n    30_000,  // 30 seconds\n    60_000,  // 1 minute\n    120_000, // 2 minutes\n    240_000, // 4 minutes\n    480_000, // 8 minutes\n  ];\n\n  /**\n   * The key of the retry after time in the WebSocket close event reason.\n   *\n   * The Courier WebSocket server may send the close event reason in the following format:\n   *\n   * ```json\n   * {\n   *   \"Retry-After\": \"10\" // The retry after time in seconds\n   * }\n   * ```\n   *\n   * @see https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/reason\n   */\n  private static readonly RETRY_AFTER_KEY = 'Retry-After';\n\n  /** The WebSocket instance, which may be null if the connection is not established. */\n  private webSocket: WebSocket | null = null;\n\n  /** The number of connection retry attempts so far, reset after a successful connection. */\n  private retryAttempt: number = 0;\n\n  /** The timeout ID for the current connectionretry attempt, reset when we attempt to connect. */\n  private retryTimeoutId: number | null = null;\n\n  /**\n   * Flag indicating the application initiated a {@link CourierSocket#close} call.\n   *\n   * An application-initiated close may look like an abnormal closure (code 1006)\n   * if it occurs before the connection is established. We differentiate to\n   * prevent retrying the connection when the socket is closed intentionally.\n   */\n  private closeRequested: boolean = false;\n\n  private readonly url: string;\n  private readonly options: CourierClientOptions;\n\n  constructor(\n    options: CourierClientOptions\n  ) {\n    this.url = options.apiUrls.inbox.webSocket;\n    this.options = options;\n  }\n\n  /**\n   * Connects to the Courier WebSocket server.\n   *\n   * If the connection is already established, this is a no-op.\n   *\n   * @returns A promise that resolves when the connection is established or rejects if the connection could not be established.\n   */\n  public async connect(): Promise<void> {\n    if (this.isConnecting || this.isOpen) {\n      this.options.logger?.info(`Attempted to open a WebSocket connection, but one already exists in state '${this.webSocket?.readyState}'.`);\n\n      // This isn't necessarily an error (the result is a no-op), so we resolve the promise.\n      return Promise.resolve();\n    }\n\n    // If we're in the process of retrying, clear the timeout to prevent further retries.\n    this.clearRetryTimeout();\n\n    // Reset the close requested flag when we attempt to connect.\n    this.closeRequested = false;\n\n    return new Promise((resolve, reject) => {\n      this.webSocket = new WebSocket(this.getWebSocketUrl());\n\n      this.webSocket.addEventListener('open', (event: Event) => {\n        // Reset the retry attempt counter when the connection is established.\n        this.retryAttempt = 0;\n\n        this.onOpen(event);\n\n        // Resolve the promise when the WebSocket is opened (i.e. the connection is established)\n        resolve();\n      });\n\n      this.webSocket.addEventListener('message', async (event: MessageEvent) => {\n        try {\n          const json = JSON.parse(event.data) as ServerMessage;\n          if ('event' in json && json.event === 'reconnect') {\n            this.close(CLOSE_CODE_NORMAL_CLOSURE);\n            await this.retryConnection(json.retryAfter * 1000);\n            return;\n          }\n\n          this.onMessageReceived(json)\n        } catch (error) {\n          this.options.logger?.error('Error parsing socket message', error);\n        }\n      });\n\n      this.webSocket.addEventListener('close', (event: CloseEvent) => {\n        // Close events are fired when the connection is closed either normally or abnormally.\n        //\n        // The 'close' event triggers a retry if the 'close' is:\n        //   1) not a normal closure and,\n        //   2) the application did not request the close (see CourierSocket#closeRequested)\n        if (event.code !== CLOSE_CODE_NORMAL_CLOSURE && !this.closeRequested) {\n          const courierCloseEvent = CourierSocket.parseCloseEvent(event);\n\n          if (courierCloseEvent.retryAfterSeconds) {\n            this.retryConnection(courierCloseEvent.retryAfterSeconds * 1000);\n          } else {\n            this.retryConnection();\n          }\n        }\n\n        this.onClose(event);\n      });\n\n      this.webSocket.addEventListener('error', (event: Event) => {\n        // If the closure was requested by the application, don't retry the connection.\n        // The error event may be fired for a normal closure if it occurs before the connection is established.\n        if (!this.closeRequested) {\n          this.retryConnection();\n        }\n\n        this.onError(event);\n\n        // If the HTTP Upgrade request fails, the WebSocket API fires an error event,\n        // so we reject the promise to indicate that the connection could not be established.\n        reject(event);\n      });\n    });\n  }\n\n  /**\n   * Closes the WebSocket connection.\n   *\n   * See {@link https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close} for more details.\n   *\n   * @param code The WebSocket close code. Defaults to {@link CLOSE_CODE_NORMAL_CLOSURE}.\n   * @param reason The WebSocket close reason.\n   */\n  public close(code = CLOSE_CODE_NORMAL_CLOSURE, reason?: string): void {\n    if (this.webSocket === null) {\n      return;\n    }\n\n    this.closeRequested = true;\n\n    // Cancel any pending retries and reset the retry attempt counter.\n    this.clearRetryTimeout();\n    this.retryAttempt = 0;\n\n    this.webSocket.close(code, reason);\n\n  }\n\n  /**\n   * Sends a message to the Courier WebSocket server.\n   *\n   * @param message The message to send. The message will be serialized to a JSON string.\n   */\n  public send(message: Record<string, any>): void {\n    if (this.webSocket === null || this.isConnecting) {\n      this.options.logger?.info('Attempted to send a message, but the WebSocket is not yet open.');\n      return;\n    }\n\n    const json = JSON.stringify(message);\n    this.webSocket.send(json);\n  }\n\n  protected get userId(): string {\n    return this.options.userId;\n  }\n\n  /** The sub-tenant ID, if specified by the user. */\n  protected get subTenantId(): string | undefined {\n    return this.options.tenantId;\n  }\n\n  protected get logger(): Logger | undefined {\n    return this.options.logger;\n  }\n\n  protected get courierUserAgent(): CourierUserAgent {\n    return this.options.courierUserAgent;\n  }\n\n  /**\n   * Called when the WebSocket connection is established with the Courier WebSocket server.\n   *\n   * @param event The WebSocket open event.\n   */\n  public abstract onOpen(event: Event): Promise<void>;\n\n  /**\n   * Called when a message is received from the Courier WebSocket server.\n   *\n   * @param data The message received.\n   */\n  public abstract onMessageReceived(data: ServerMessage): Promise<void>;\n\n  /**\n   * Called when the WebSocket connection is closed.\n   *\n   * @param event The WebSocket close event.\n   */\n  public abstract onClose(event: CloseEvent): Promise<void>;\n\n  /**\n   * Called when an error occurs on the WebSocket connection.\n   *\n   * @param event The WebSocket error event.\n   */\n  public abstract onError(event: Event): Promise<void>;\n\n  /**\n   * Whether the WebSocket connection is currently being established.\n   */\n  public get isConnecting(): boolean {\n    return this.webSocket !== null && this.webSocket.readyState === WebSocket.CONNECTING;\n  }\n\n  /**\n   * Whether the WebSocket connection is currently open.\n   */\n  public get isOpen(): boolean {\n    return this.webSocket !== null && this.webSocket.readyState === WebSocket.OPEN;\n  }\n\n  /**\n   * Constructs the WebSocket URL for the Courier WebSocket server using context\n   * from the {@link CourierClientOptions} passed to the constructor.\n   *\n   * @returns The WebSocket URL\n   */\n  private getWebSocketUrl(): string {\n    const accessToken = this.options.accessToken;\n    const connectionId = this.options.connectionId;\n    const userId = this.userId;\n\n    // Courier User-Agent info\n    const sdkName = this.courierUserAgent.getUserAgentInfo()[SDK_KEY];\n    const sdkVersion = this.courierUserAgent.getUserAgentInfo()[SDK_VERSION_KEY];\n\n    return `${this.url}?`\n      + `auth=${accessToken}&`\n      + `cid=${connectionId}&`\n      + `iwpv=${INBOX_WIRE_PROTOCOL_VERSION}&`\n      + `userId=${userId}&`\n      + `${SDK_KEY}=${sdkName}&`\n      + `${SDK_VERSION_KEY}=${sdkVersion}`;\n  }\n\n  /**\n   * Parses the Retry-After time from the WebSocket close event reason,\n   * and returns a new {@link CourierCloseEvent} with the retry after time in seconds\n   * if present.\n   *\n   * The Courier WebSocket server may send the close event reason in the following format:\n   *\n   * ```json\n   * {\n   *   \"Retry-After\": \"10\" // The retry after time in seconds\n   * }\n   * ```\n   *\n   * @see https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/reason\n   *\n   * @param closeEvent The WebSocket close event.\n   * @returns The WebSocket close event with the retry after time in seconds.\n   */\n  private static parseCloseEvent(closeEvent: CloseEvent): CourierCloseEvent {\n    if (closeEvent.reason === null || closeEvent.reason === '') {\n      return closeEvent;\n    }\n\n    try {\n      const jsonReason = JSON.parse(closeEvent.reason);\n      if (!jsonReason[CourierSocket.RETRY_AFTER_KEY]) {\n        return closeEvent;\n      }\n\n      const retryAfterSeconds = parseInt(jsonReason[CourierSocket.RETRY_AFTER_KEY]);\n      if (Number.isNaN(retryAfterSeconds) || retryAfterSeconds < 0) {\n        return closeEvent;\n      }\n\n      return {\n        ...closeEvent,\n        retryAfterSeconds,\n      };\n    } catch (error) {\n      return closeEvent;\n    }\n  }\n\n  /**\n   * Calculates the retry backoff time in milliseconds based on the current retry attempt.\n   */\n  private getBackoffTimeInMillis(): number {\n    const backoffIntervalInMillis = CourierSocket.BACKOFF_INTERVALS_IN_MILLIS[this.retryAttempt];\n    const lowerBound = backoffIntervalInMillis - (backoffIntervalInMillis * CourierSocket.BACKOFF_JITTER_FACTOR);\n    const upperBound = backoffIntervalInMillis + (backoffIntervalInMillis * CourierSocket.BACKOFF_JITTER_FACTOR);\n\n    return Math.floor(Math.random() * (upperBound - lowerBound) + lowerBound);\n  }\n\n  /**\n   * Retries the connection to the Courier WebSocket server after\n   * either {@param suggestedBackoffTimeInMillis} or a random backoff time\n   * calculated using {@link getBackoffTimeInMillis}.\n   *\n   * @param suggestedBackoffTimeInMillis The suggested backoff time in milliseconds.\n   * @returns A promise that resolves when the connection is established or rejects if the connection could not be established.\n   */\n  protected async retryConnection(suggestedBackoffTimeInMillis?: number): Promise<void> {\n    if (this.retryTimeoutId !== null) {\n      this.logger?.debug('Skipping retry attempt because a previous retry is already scheduled.');\n      return;\n    }\n\n    if (this.retryAttempt >= CourierSocket.MAX_RETRY_ATTEMPTS) {\n      this.logger?.error(`Max retry attempts (${CourierSocket.MAX_RETRY_ATTEMPTS}) reached.`);\n      return;\n    }\n\n    const backoffTimeInMillis = suggestedBackoffTimeInMillis ?? this.getBackoffTimeInMillis();\n    this.retryTimeoutId = window.setTimeout(async () => {\n      try {\n        await this.connect();\n      } catch (error) {\n        // connect() will retry if applicable\n      }\n    }, backoffTimeInMillis);\n    this.logger?.debug(`Retrying connection in ${Math.floor(backoffTimeInMillis / 1000)}s. Retry attempt ${this.retryAttempt + 1} of ${CourierSocket.MAX_RETRY_ATTEMPTS}.`);\n\n    this.retryAttempt++;\n  }\n\n  /**\n   * Clears the retry timeout if it exists.\n   */\n  private clearRetryTimeout(): void {\n    if (this.retryTimeoutId !== null) {\n      window.clearTimeout(this.retryTimeoutId);\n      this.retryTimeoutId = null;\n    }\n  }\n}\n","import { ClientMessageEnvelope, ServerMessage } from \"../types/socket/protocol/messages\";\n\nexport class TransactionManager {\n  /**\n   * The map of <transactionId, Transaction> representing outstanding requests.\n   */\n  private readonly outstandingRequestsMap: Map<string, Transaction> = new Map();\n\n  /**\n   * The queue of completed requests. This is a FIFO queue of the last N completed requests,\n   * where N is {@link completedTransactionsToKeep}.\n   */\n  private readonly completedTransactionsQueue: Transaction[] = [];\n\n  /**\n   * Number of completed requests to keep in memory.\n   */\n  private readonly completedTransactionsToKeep: number;\n\n  constructor(completedTransactionsToKeep: number = 10) {\n    this.completedTransactionsToKeep = completedTransactionsToKeep;\n  }\n\n  public addOutstandingRequest(transactionId: string, request: ClientMessageEnvelope): void {\n    const isOutstanding = this.outstandingRequestsMap.has(transactionId);\n    if (isOutstanding) {\n      throw new Error(`Transaction [${transactionId}] already has an outstanding request`);\n    }\n\n    const transaction: Transaction = {\n      transactionId,\n      request,\n      response: null,\n      start: new Date(),\n      end: null,\n    };\n\n    this.outstandingRequestsMap.set(transactionId, transaction);\n  }\n\n  public addResponse(transactionId: string, response: ServerMessage): void {\n    const transaction = this.outstandingRequestsMap.get(transactionId);\n    if (transaction === undefined) {\n      throw new Error(`Transaction [${transactionId}] does not have an outstanding request`);\n    }\n\n    transaction.response = response;\n    transaction.end = new Date();\n\n    // Move the transaction from the outstanding requests to the completed requests.\n    this.outstandingRequestsMap.delete(transactionId);\n    this.addCompletedTransaction(transaction);\n  }\n\n  public get outstandingRequests(): Transaction[] {\n    return Array.from(this.outstandingRequestsMap.values());\n  }\n\n  public get completedTransactions(): Transaction[] {\n    return this.completedTransactionsQueue;\n  }\n\n  public clearOutstandingRequests(): void {\n    this.outstandingRequestsMap.clear();\n  }\n\n  /**\n   * Adds a completed request to the queue.\n   *\n   * If the number of completed requests exceeds the maximum number of completed requests to keep,\n   * remove the oldest completed request.\n   */\n  private addCompletedTransaction(transaction: Transaction): void {\n    this.completedTransactionsQueue.push(transaction);\n\n    if (this.completedTransactionsQueue.length > this.completedTransactionsToKeep) {\n      this.completedTransactionsQueue.shift();\n    }\n  }\n}\n\ninterface Transaction {\n  /**\n   * The transaction ID.\n   */\n  transactionId: string;\n\n  /**\n   * The request to the server.\n   */\n  request: ClientMessageEnvelope;\n\n  /**\n   * The response to the request.\n   *\n   * The response is null until the request is completed.\n   */\n  response: ServerMessage | null;\n\n  /**\n   * The start time of the transaction.\n   */\n  start: Date;\n\n  /**\n   * The end time of the transaction.\n   */\n  end: Date | null;\n}\n","import { InboxMessage } from \"../types/inbox\";\nimport { InboxMessageEvent, InboxMessageEventEnvelope } from \"../types/socket/protocol/messages\";\n\n/**\n * Ensure the `created` timestamp is set for a new message.\n *\n * New messages received from the WebSocket may not have a created time,\n * until they are retrieved from the GraphQL API.\n *\n * @param envelope - The envelope containing the message event.\n * @returns The envelope with the created time set.\n */\nfunction ensureCreatedTime(envelope: InboxMessageEventEnvelope): InboxMessageEventEnvelope {\n  if (envelope.event === InboxMessageEvent.NewMessage) {\n    const message = envelope.data as InboxMessage;\n\n    if (!message.created) {\n      message.created = new Date().toISOString();\n    }\n\n    return {\n      ...envelope,\n      data: message,\n    };\n  }\n\n  return envelope;\n}\n\n/**\n * Apply fixes to a message event envelope.\n *\n * @param envelope - The envelope containing the message event.\n * @returns The envelope with the fixes applied.\n */\nexport function fixMessageEventEnvelope(envelope: InboxMessageEventEnvelope): InboxMessageEventEnvelope {\n  // Apply any fixes to the message event envelope.\n  return ensureCreatedTime(envelope);\n}\n","import { CourierClientOptions } from '../client/courier-client';\nimport { ClientAction, ClientMessageEnvelope, Config, ConfigResponseEnvelope, InboxMessageEvent, InboxMessageEventEnvelope, ServerAction, ServerActionEnvelope, ServerMessage, ServerResponseEnvelope } from '../types/socket/protocol/messages';\nimport { CLOSE_CODE_NORMAL_CLOSURE } from '../types/socket/protocol/errors';\nimport { UUID } from '../utils/uuid';\nimport { CourierSocket } from './courier-socket';\nimport { TransactionManager } from './courier-inbox-transaction-manager';\nimport { fixMessageEventEnvelope } from './inbox-message-utils';\n\n/** Application-layer implementation of the Courier WebSocket API for Inbox messages. */\nexport class CourierInboxSocket extends CourierSocket {\n  /**\n   * The default interval in milliseconds at which to send a ping message to the server\n   * if no other message has been received from the server.\n   *\n   * Fallback when the server does not provide a config.\n   */\n  private static readonly DEFAULT_PING_INTERVAL_MILLIS = 60_000; // 1 minute\n\n  /**\n   * The default maximum number of outstanding pings before the client should\n   * close the connection and retry connecting.\n   *\n   * Fallback when the server does not provide a config.\n   */\n  private static readonly DEFAULT_MAX_OUTSTANDING_PINGS = 3;\n\n  /**\n   * The interval ID for the ping interval.\n   *\n   * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/setInterval\n   */\n  private pingIntervalId: number | null = null;\n\n  /**\n   * The list of message event listeners, called when a message event is received\n   * from the Courier WebSocket server.\n   */\n  private messageEventListeners: ((message: InboxMessageEventEnvelope) => void)[] = [];\n\n  /** Server-provided configuration for the client. */\n  private config: Config | null = null;\n\n  /**\n   * The transaction manager, used to track outstanding requests and responses.\n   */\n  private readonly pingTransactionManager: TransactionManager = new TransactionManager();\n\n  constructor(options: CourierClientOptions) {\n    super(options);\n  }\n\n  public onOpen(_: Event): Promise<void> {\n    // Clear any outstanding pings from the previous connection before starting to ping.\n    this.pingTransactionManager.clearOutstandingRequests();\n    this.restartPingInterval();\n\n    // Send a request for the client's configuration.\n    this.sendGetConfig();\n\n    // Subscribe to all events for the user.\n    this.sendSubscribe();\n\n    return Promise.resolve();\n  }\n\n  public onMessageReceived(data: ServerMessage): Promise<void> {\n    // ServerActionEnvelope\n    // Respond to pings.\n    if ('action' in data && data.action === ServerAction.Ping) {\n      const envelope: ServerActionEnvelope = data as ServerActionEnvelope;\n      this.sendPong(envelope);\n    }\n\n    // ServerResponseEnvelope\n    // Track pongs.\n    if ('response' in data && data.response === 'pong') {\n      const envelope: ServerResponseEnvelope = data as ServerResponseEnvelope;\n\n      // Keep track of the pong response and clear out any outstanding pings.\n      // We only need to keep track of the most recent missed pings.\n      this.pingTransactionManager.addResponse(envelope.tid, envelope);\n      this.pingTransactionManager.clearOutstandingRequests();\n    }\n\n    // ConfigResponseEnvelope\n    // Update the client's config.\n    if ('response' in data && data.response === 'config') {\n      const envelope: ConfigResponseEnvelope = data as ConfigResponseEnvelope;\n      this.setConfig(envelope.data);\n    }\n\n    // InboxMessageEventEnvelope\n    // Handle message events, calling all registered listeners.\n    if ('event' in data && CourierInboxSocket.isInboxMessageEvent(data.event)) {\n      const envelope: InboxMessageEventEnvelope = data as InboxMessageEventEnvelope;\n      const fixedEnvelope = fixMessageEventEnvelope(envelope);\n      for (const listener of this.messageEventListeners) {\n        listener(fixedEnvelope);\n      }\n    }\n\n    // Restart the ping interval if a message is received from the server.\n    this.restartPingInterval();\n\n    return Promise.resolve();\n  }\n\n  public onClose(_: CloseEvent): Promise<void> {\n    // Cancel scheduled pings.\n    this.clearPingInterval();\n\n    // Remove any message event listeners.\n    this.clearMessageEventListeners();\n\n    // Clear any outstanding pings.\n    this.pingTransactionManager.clearOutstandingRequests();\n\n    return Promise.resolve();\n  }\n\n  public onError(_: Event): Promise<void> {\n    return Promise.resolve();\n  }\n\n  /**\n   * Sends a subscribe message to the server.\n   *\n   * Subscribes to all events for the user.\n   */\n  public sendSubscribe(): void {\n    const data: Record<string, any> = {\n      channel: this.userId,\n      event: '*',\n    };\n\n    // Set accountId to the sub-tenant ID if it is specified.\n    if (this.subTenantId) {\n      data.accountId = this.subTenantId;\n    }\n\n    const envelope: ClientMessageEnvelope = {\n      tid: UUID.nanoid(),\n      action: ClientAction.Subscribe,\n      data,\n    };\n\n    this.send(envelope);\n  }\n\n  /**\n   * Sends an unsubscribe message to the server.\n   *\n   * Unsubscribes from all events for the user.\n   */\n  public sendUnsubscribe(): void {\n    const envelope: ClientMessageEnvelope = {\n      tid: UUID.nanoid(),\n      action: ClientAction.Unsubscribe,\n      data: {\n        channel: this.userId,\n      },\n    };\n\n    this.send(envelope);\n  }\n\n  /**\n   * Adds a message event listener, called when a message event is received\n   * from the Courier WebSocket server.\n   *\n   * @param listener The listener function\n   * @returns A function that can be called to remove this specific listener\n   */\n  public addMessageEventListener(listener: (message: InboxMessageEventEnvelope) => void): () => void {\n    this.messageEventListeners.push(listener);\n\n    // Return a function to remove this specific listener\n    return () => {\n      this.removeMessageEventListener(listener);\n    };\n  }\n\n  /**\n   * Send a ping message to the server.\n   *\n   * ping/pong is implemented at the application layer since the browser's\n   * WebSocket implementation does not support control-level ping/pong.\n   */\n  private sendPing(): void {\n    if (this.pingTransactionManager.outstandingRequests.length >= this.maxOutstandingPings) {\n      this.logger?.debug('Max outstanding pings reached, retrying connection.');\n      this.close(CLOSE_CODE_NORMAL_CLOSURE, 'Max outstanding pings reached, retrying connection.');\n      this.retryConnection();\n\n      return;\n    }\n\n    const envelope: ClientMessageEnvelope = {\n      tid: UUID.nanoid(),\n      action: ClientAction.Ping,\n    };\n\n    this.send(envelope);\n    this.pingTransactionManager.addOutstandingRequest(envelope.tid, envelope);\n  }\n\n  /**\n   * Send a pong response to the server.\n   *\n   * ping/pong is implemented at the application layer since the browser's\n   * WebSocket implementation does not support control-level ping/pong.\n   */\n  private sendPong(incomingMessage: ServerActionEnvelope): void {\n    const response: ClientMessageEnvelope = {\n      tid: incomingMessage.tid,\n      action: ClientAction.Pong,\n    };\n\n    this.send(response);\n  }\n\n  /**\n   * Send a request for the client's configuration.\n   */\n  private sendGetConfig(): void {\n    const envelope: ClientMessageEnvelope = {\n      tid: UUID.nanoid(),\n      action: ClientAction.GetConfig,\n    };\n\n    this.send(envelope);\n  }\n\n  /**\n   * Restart the ping interval, clearing the previous interval if it exists.\n   */\n  private restartPingInterval(): void {\n    this.clearPingInterval();\n\n    this.pingIntervalId = window.setInterval(() => {\n      this.sendPing();\n    }, this.pingInterval);\n  }\n\n  private clearPingInterval(): void {\n    if (this.pingIntervalId) {\n      window.clearInterval(this.pingIntervalId);\n    }\n  }\n\n  private get pingInterval(): number {\n    if (this.config) {\n      // Server-provided ping interval is in seconds.\n      return this.config.pingInterval * 1000;\n    }\n\n    return CourierInboxSocket.DEFAULT_PING_INTERVAL_MILLIS;\n  }\n\n  private get maxOutstandingPings(): number {\n    if (this.config) {\n      return this.config.maxOutstandingPings;\n    }\n\n    return CourierInboxSocket.DEFAULT_MAX_OUTSTANDING_PINGS;\n  }\n\n  private setConfig(config: Config): void {\n    this.config = config;\n  }\n\n  /**\n   * Removes all message event listeners.\n   */\n  private clearMessageEventListeners(): void {\n    while (this.messageEventListeners.length > 0) {\n      this.messageEventListeners.pop();\n    }\n  }\n\n  /**\n   * Remove the message event listener specified.\n   *\n   * This is the same listener function passed to {@link addMessageEventListener}.\n   */\n  private removeMessageEventListener(listener: (message: InboxMessageEventEnvelope) => void): void {\n    const index = this.messageEventListeners.indexOf(listener);\n\n    if (index > -1) {\n      this.messageEventListeners.splice(index, 1);\n    }\n  }\n\n  private static isInboxMessageEvent(event: string): event is InboxMessageEvent {\n    return Object.values(InboxMessageEvent).includes(event as InboxMessageEvent);\n  }\n}\n","import { CourierInboxSocket } from '../socket/courier-inbox-socket';\nimport { CourierGetInboxMessagesQueryFilter, CourierGetInboxMessagesResponse } from '../types/inbox';\nimport { graphql } from '../utils/request';\nimport { Client } from './client';\nimport { CourierClientOptions } from './courier-client';\n\nexport class InboxClient extends Client {\n\n  readonly socket: CourierInboxSocket;\n\n  constructor(options: CourierClientOptions) {\n    super(options);\n    this.socket = new CourierInboxSocket(options);\n  }\n\n  /**\n   * Get paginated messages\n   * @param paginationLimit - Number of messages to return per page (default: 24)\n   * @param startCursor - Cursor for pagination\n   * @returns Promise resolving to paginated messages response\n   */\n  public async getMessages(props?: {\n    paginationLimit?: number;\n    startCursor?: string;\n    filter?: CourierGetInboxMessagesQueryFilter;\n  }): Promise<CourierGetInboxMessagesResponse> {\n    const filter = props?.filter || {};\n    const filterParams = this.createFilterParams(filter);\n    const unreadCountFilterParams = this.createUnreadCountFilterParams(filter)\n\n    const query = `\n      query GetInboxMessages(\n        $params: FilterParamsInput = ${filterParams}\n        $unreadCountParams: FilterParamsInput = ${unreadCountFilterParams}\n        $limit: Int = ${props?.paginationLimit ?? 24}\n        $after: String ${props?.startCursor ? `= \"${props.startCursor}\"` : ''}\n      ) {\n        count: count(params: $params)\n        unreadCount: count(params: $unreadCountParams)\n        messages(params: $params, limit: $limit, after: $after) {\n          totalCount\n          pageInfo {\n            startCursor\n            hasNextPage\n          }\n          nodes {\n            messageId\n            read\n            archived\n            created\n            opened\n            title\n            preview\n            data\n            tags\n            trackingIds {\n              clickTrackingId\n            }\n            actions {\n              content\n              data\n              href\n            }\n          }\n        }\n      }\n    `;\n\n    return await graphql({\n      options: this.options,\n      query,\n      headers: {\n        'x-courier-user-id': this.options.userId,\n        'Authorization': `Bearer ${this.options.accessToken}`\n      },\n      url: this.options.apiUrls.inbox.graphql,\n    });\n  }\n\n  /**\n   * Get unread counts for multiple filters in a single query.\n   *\n   * @param filtersMap - Map of dataset ID to filter\n   * @returns Promise resolving to map of dataset ID to unread count\n   */\n  public async getUnreadCounts(\n    filtersMap: Record<string, CourierGetInboxMessagesQueryFilter>\n  ): Promise<Record<string, number>> {\n    const result: Record<string, number> = {};\n    \n    // Separate filters: those with status 'read' can be optimized to return 0,\n    // others need to be queried\n    const filtersToQuery: Record<string, CourierGetInboxMessagesQueryFilter> = {};\n    \n    for (const [datasetId, filter] of Object.entries(filtersMap)) {\n      if (filter.status === 'read') {\n        // Optimization: if status is 'read', unread count is always 0\n        // TODO: We should remove this at somepoint. There is a bug in the backend that is returning more than 0 for read messages.\n        result[datasetId] = 0;\n      } else {\n        // This filter needs to be queried\n        filtersToQuery[datasetId] = filter;\n      }\n    }\n\n    // If no filters need to be queried, return early\n    if (Object.keys(filtersToQuery).length === 0) {\n      return result;\n    }\n\n    // Build query variables and field aliases for remaining filters\n    const variables: string[] = [];\n    const fields: string[] = [];\n\n    // Map from the user-provided dataset ID to a GraphQL-safe alias.\n    // We keep track of this mapping so it can be reversed and we can return\n    // a mapping from user-provided dataset ID to unread count.\n    const sanitizedIdMapping: Record<string, string> = {};\n\n    for (const [datasetId, filter] of Object.entries(filtersToQuery)) {\n      const sanitizedId = InboxClient.sanitizeGraphQLIdentifier(datasetId);\n      sanitizedIdMapping[sanitizedId] = datasetId;\n\n      const unreadCountFilterParams = this.createUnreadCountFilterParams(filter);\n      variables.push(`$${sanitizedId}: FilterParamsInput = ${unreadCountFilterParams}`);\n      fields.push(`${sanitizedId}: count(params: $${sanitizedId})`);\n    }\n\n    const query = `\n      query GetUnreadCounts(\n        ${variables.join('\\n')}\n      ) {\n        ${fields.join('\\n')}\n      }\n    `;\n\n    const response = await graphql({\n      options: this.options,\n      query,\n      headers: {\n        'x-courier-user-id': this.options.userId,\n        'Authorization': `Bearer ${this.options.accessToken}`\n      },\n      url: this.options.apiUrls.inbox.graphql,\n    });\n\n    // Parse response data back into a map of user-provided ID to unread count\n    // from the GraphQL-safe aliases used in the query.\n    if (response.data) {\n      for (const [sanitizedId, originalId] of Object.entries(sanitizedIdMapping)) {\n        result[originalId] = response.data[sanitizedId] ?? 0;\n      }\n    }\n\n    return result;\n  }\n\n  /**\n   * Get paginated archived messages\n   * @param paginationLimit - Number of messages to return per page (default: 24)\n   * @param startCursor - Cursor for pagination\n   * @returns Promise resolving to paginated archived messages response\n   *\n   * @deprecated - replace usages with {@link InboxClient.getMessages}, passing the filter `{ archived: true }`\n   */\n  public async getArchivedMessages(props?: { paginationLimit?: number; startCursor?: string; }): Promise<CourierGetInboxMessagesResponse> {\n    return this.getMessages({\n      paginationLimit: props?.paginationLimit,\n      startCursor: props?.startCursor,\n      filter: { archived: true }\n    });\n  }\n\n  /**\n   * Get unread message count\n   * @returns Promise resolving to number of unread messages\n   */\n  public async getUnreadMessageCount(): Promise<number> {\n    const query = `\n      query GetMessages {\n        count(params: { status: \"unread\" ${this.options.tenantId ? `, accountId: \"${this.options.tenantId}\"` : ''} })\n      }\n    `;\n\n    const response = await graphql({\n      options: this.options,\n      query,\n      headers: {\n        'x-courier-user-id': this.options.userId,\n        'Authorization': `Bearer ${this.options.accessToken}`\n      },\n      url: this.options.apiUrls.inbox.graphql,\n    });\n\n    return response.data?.count ?? 0;\n  }\n\n  /**\n   * Track a click event\n   * @param messageId - ID of the message\n   * @param trackingId - ID for tracking the click\n   * @returns Promise resolving when click is tracked\n   */\n  public async click(props: { messageId: string, trackingId: string }): Promise<void> {\n    const query = `\n      mutation TrackEvent {\n        clicked(messageId: \"${props.messageId}\", trackingId: \"${props.trackingId}\")\n      }\n    `;\n\n    const headers: Record<string, string> = {\n      'x-courier-user-id': this.options.userId,\n      'Authorization': `Bearer ${this.options.accessToken}`\n    };\n\n    if (this.options.connectionId) {\n      headers['x-courier-client-source-id'] = this.options.connectionId;\n    }\n\n    await graphql({\n      options: this.options,\n      query,\n      headers,\n      url: this.options.apiUrls.inbox.graphql,\n    });\n  }\n\n  /**\n   * Mark a message as read\n   * @param messageId - ID of the message to mark as read\n   * @returns Promise resolving when message is marked as read\n   */\n  public async read(props: { messageId: string }): Promise<void> {\n    const query = `\n      mutation TrackEvent {\n        read(messageId: \"${props.messageId}\")\n      }\n    `;\n\n    const headers: Record<string, string> = {\n      'x-courier-user-id': this.options.userId,\n      'Authorization': `Bearer ${this.options.accessToken}`\n    };\n\n    if (this.options.connectionId) {\n      headers['x-courier-client-source-id'] = this.options.connectionId;\n    }\n\n    await graphql({\n      options: this.options,\n      query,\n      headers,\n      url: this.options.apiUrls.inbox.graphql,\n    });\n  }\n\n  /**\n   * Mark a message as unread\n   * @param messageId - ID of the message to mark as unread\n   * @returns Promise resolving when message is marked as unread\n   */\n  public async unread(props: { messageId: string }): Promise<void> {\n    const query = `\n      mutation TrackEvent {\n        unread(messageId: \"${props.messageId}\")\n      }\n    `;\n\n    const headers: Record<string, string> = {\n      'x-courier-user-id': this.options.userId,\n      'Authorization': `Bearer ${this.options.accessToken}`\n    };\n\n    if (this.options.connectionId) {\n      headers['x-courier-client-source-id'] = this.options.connectionId;\n    }\n\n    await graphql({\n      options: this.options,\n      query,\n      headers,\n      url: this.options.apiUrls.inbox.graphql,\n    });\n  }\n\n  /**\n   * Mark a message as opened\n   * @param messageId - ID of the message to mark as opened\n   * @returns Promise resolving when message is marked as opened\n   */\n  public async open(props: { messageId: string }): Promise<void> {\n    const query = `\n      mutation TrackEvent {\n        opened(messageId: \"${props.messageId}\")\n      }\n    `;\n\n    const headers: Record<string, string> = {\n      'x-courier-user-id': this.options.userId,\n      'Authorization': `Bearer ${this.options.accessToken}`\n    };\n\n    if (this.options.connectionId) {\n      headers['x-courier-client-source-id'] = this.options.connectionId;\n    }\n\n    await graphql({\n      options: this.options,\n      query,\n      headers,\n      url: this.options.apiUrls.inbox.graphql,\n    });\n  }\n\n  /**\n   * Mark multiple messages as opened in a single request.\n   * @param messageIds - IDs of the messages to mark as opened\n   * @returns Promise resolving when all messages are marked as opened\n   */\n  public async batchOpen(messageIds: string[]): Promise<void> {\n    if (messageIds.length === 0) return;\n\n    if (messageIds.length === 1) {\n      return this.open({ messageId: messageIds[0] });\n    }\n\n    const mutations = messageIds.map((id, index) =>\n      `open_${index}: opened(messageId: \"${id}\")`\n    );\n\n    const query = `\n      mutation BatchTrackEvents {\n        ${mutations.join('\\n        ')}\n      }\n    `;\n\n    const headers: Record<string, string> = {\n      'x-courier-user-id': this.options.userId,\n      'Authorization': `Bearer ${this.options.accessToken}`\n    };\n\n    if (this.options.connectionId) {\n      headers['x-courier-client-source-id'] = this.options.connectionId;\n    }\n\n    await graphql({\n      options: this.options,\n      query,\n      headers,\n      url: this.options.apiUrls.inbox.graphql,\n    });\n  }\n\n  /**\n   * Archive a message\n   * @param messageId - ID of the message to archive\n   * @returns Promise resolving when message is archived\n   */\n  public async archive(props: { messageId: string }): Promise<void> {\n    const query = `\n      mutation TrackEvent {\n        archive(messageId: \"${props.messageId}\")\n      }\n    `;\n\n    const headers: Record<string, string> = {\n      'x-courier-user-id': this.options.userId,\n      'Authorization': `Bearer ${this.options.accessToken}`\n    };\n\n    if (this.options.connectionId) {\n      headers['x-courier-client-source-id'] = this.options.connectionId;\n    }\n\n    await graphql({\n      options: this.options,\n      query,\n      headers,\n      url: this.options.apiUrls.inbox.graphql,\n    });\n  }\n\n  /**\n   * Unarchive a message\n   * @param messageId - ID of the message to unarchive\n   * @returns Promise resolving when message is unarchived\n   */\n  public async unarchive(props: { messageId: string }): Promise<void> {\n    const query = `\n      mutation TrackEvent {\n        unarchive(messageId: \"${props.messageId}\")\n      }\n    `;\n\n    const headers: Record<string, string> = {\n      'x-courier-user-id': this.options.userId,\n      'Authorization': `Bearer ${this.options.accessToken}`\n    };\n\n    if (this.options.connectionId) {\n      headers['x-courier-client-source-id'] = this.options.connectionId;\n    }\n\n    await graphql({\n      options: this.options,\n      query,\n      headers,\n      url: this.options.apiUrls.inbox.graphql,\n    });\n  }\n\n  /**\n   * Mark all messages as read\n   * @returns Promise resolving when all messages are marked as read\n   */\n  public async readAll(): Promise<void> {\n    const query = `\n      mutation TrackEvent {\n        markAllRead\n      }\n    `;\n\n    const headers: Record<string, string> = {\n      'x-courier-user-id': this.options.userId,\n      'Authorization': `Bearer ${this.options.accessToken}`\n    };\n\n    if (this.options.connectionId) {\n      headers['x-courier-client-source-id'] = this.options.connectionId;\n    }\n\n    await graphql({\n      options: this.options,\n      query,\n      headers,\n      url: this.options.apiUrls.inbox.graphql,\n    });\n  }\n\n  /**\n   * Archive all read messages.\n   */\n  public async archiveRead(): Promise<void> {\n    const query = `\n      mutation TrackEvent {\n        archiveRead\n      }\n    `;\n\n    const headers: Record<string, string> = {\n      'x-courier-user-id': this.options.userId,\n      'Authorization': `Bearer ${this.options.accessToken}`\n    };\n\n    if (this.options.connectionId) {\n      headers['x-courier-client-source-id'] = this.options.connectionId;\n    }\n\n    await graphql({\n      options: this.options,\n      query,\n      headers,\n      url: this.options.apiUrls.inbox.graphql,\n    });\n  }\n\n  /**\n   * Archive all read messages.\n   */\n  public async archiveAll(): Promise<void> {\n    const query = `\n      mutation TrackEvent {\n        archiveAll\n      }\n    `;\n\n    const headers: Record<string, string> = {\n      'x-courier-user-id': this.options.userId,\n      'Authorization': `Bearer ${this.options.accessToken}`\n    };\n\n    if (this.options.connectionId) {\n      headers['x-courier-client-source-id'] = this.options.connectionId;\n    }\n\n    await graphql({\n      options: this.options,\n      query,\n      headers,\n      url: this.options.apiUrls.inbox.graphql,\n    });\n  }\n\n  /**\n   * Create FilterParamsInput for the given filters.\n   *\n   * @param filter - the filtering options to include in the output\n   * @returns the FilterParamsInput to pass to a GraphQL query for messages\n   */\n  private createFilterParams(filter: CourierGetInboxMessagesQueryFilter) {\n    const parts = []\n\n    if (this.options.tenantId) {\n      parts.push(`accountId: \"${this.options.tenantId}\"`);\n    }\n\n    if (filter.tags) {\n      parts.push(`tags: [${filter.tags.map(tag => `\"${tag}\"`).join(',')}]`);\n    }\n\n    if (filter.status) {\n      parts.push(`status: \"${filter.status}\"`);\n    }\n\n    if (filter.archived) {\n      parts.push(`archived: ${filter.archived}`);\n    }\n\n    if (filter.from) {\n      parts.push(`from: \"${filter.from}\"`);\n    }\n\n    return `{ ${parts.join(',')} }`;\n  }\n\n  /**\n   * Create FilterParamsInput for the unread message count.\n   *\n   * The status: \"unread\" filter is only added if status is unset. This is because:\n   *  - If status is \"unread\", the params already include the filter that would be added.\n   *  - If status is \"read\", the unread count for the dataset would be a different set\n   *    of messages rather than a count of the unread subset.\n   */\n  private createUnreadCountFilterParams(filter: CourierGetInboxMessagesQueryFilter) {\n    if (!filter.status) {\n      return this.createFilterParams({ ...filter, status: 'unread' });\n    }\n\n    return this.createFilterParams(filter);\n  }\n\n  /**\n   * Sanitize dataset IDs for use as GraphQL identifiers.\n   *\n   * GraphQL identifiers must contain only alphanumerics/underscores and begin with a letter or underscore.\n   * https://spec.graphql.org/draft/#sec-Names\n   */\n  private static sanitizeGraphQLIdentifier(id: string): string {\n    // Prepend with id and\n    // replace _ (underscore) with double underscore (effectively escaping it) and\n    // replace - (hyphen) with underscore\n    return `id_${id.replace(/_/g, '__').replace(/-/g, '_')}`\n  }\n\n}\n","export function decode(clientKey: string): string {\n  const binaryString = atob(clientKey);\n  const bytes = new Uint8Array(binaryString.length);\n\n  for (let i = 0; i < binaryString.length; i++) {\n    bytes[i] = binaryString.charCodeAt(i);\n  }\n\n  return String.fromCharCode(...bytes);\n}\n\nexport function encode(key: string): string {\n  const bytes = new Uint8Array(key.length);\n\n  for (let i = 0; i < key.length; i++) {\n    bytes[i] = key.charCodeAt(i);\n  }\n\n  return btoa(String.fromCharCode(...bytes));\n}","import {\n  CourierDigestScheduleOption,\n  CourierPreferencePage,\n  CourierPreferencePageSection,\n  CourierPreferencePageTopic,\n  CourierUserPreferences,\n  CourierUserPreferencesChannel,\n  CourierUserPreferencesStatus,\n  CourierUserPreferencesTopic,\n  RecipientPreference,\n} from '../types/preference';\nimport { decode, encode } from '../utils/coding';\nimport { graphql } from '../utils/request';\nimport { Client } from './client';\n\nexport class PreferenceClient extends Client {\n  /**\n   * Get all preferences for a user\n   * @param paginationCursor - Optional cursor for pagination (not used in GraphQL implementation)\n   * @returns Promise resolving to user preferences\n   */\n  public async getUserPreferences(props?: { paginationCursor?: string; }): Promise<CourierUserPreferences> {\n    const query = `\n      query GetRecipientPreferences {\n        recipientPreferences${this.options.tenantId ? `(accountId: \"${this.options.tenantId}\")` : ''} {\n          nodes {\n            templateId\n            templateName\n            sectionId\n            sectionName\n            defaultStatus\n            status\n            hasCustomRouting\n            routingPreferences\n            digestSchedule\n          }\n        }\n      }\n    `;\n\n    const response = await graphql({\n      options: this.options,\n      url: this.options.apiUrls.courier.graphql,\n      query,\n      headers: {\n        'x-courier-user-id': this.options.userId,\n        'x-courier-client-key': 'empty', // Empty for now. Will be removed in future.\n        'Authorization': `Bearer ${this.options.accessToken}`\n      },\n    });\n\n    const nodes: RecipientPreference[] = response.data?.recipientPreferences?.nodes || [];\n\n    return {\n      items: nodes.map(node => this.transformToTopic(node)),\n      paging: {\n        cursor: props?.paginationCursor,\n        more: false // GraphQL returns all preferences at once\n      }\n    };\n  }\n\n  /**\n   * Get preferences for a specific topic\n   * @param topicId - The ID of the topic to get preferences for\n   * @returns Promise resolving to topic preferences\n   */\n  public async getUserPreferenceTopic(props: { topicId: string; }): Promise<CourierUserPreferencesTopic> {\n    const query = `\n      query GetRecipientPreferenceTopic {\n        recipientPreference(templateId: \"${props.topicId}\"${this.options.tenantId ? `, accountId: \"${this.options.tenantId}\"` : ''}) {\n          templateId\n          templateName\n          status\n          hasCustomRouting\n          routingPreferences\n          digestSchedule\n          sectionId\n          sectionName\n          defaultStatus\n        }\n      }\n    `;\n\n    const response = await graphql({\n      options: this.options,\n      url: this.options.apiUrls.courier.graphql,\n      query,\n      headers: {\n        'x-courier-user-id': this.options.userId,\n        'x-courier-client-key': 'empty', // Empty for now. Will be removed in future.\n        'Authorization': `Bearer ${this.options.accessToken}`\n      },\n    });\n\n    const node: RecipientPreference = response.data?.recipientPreference;\n\n    if (!node) {\n      throw new Error(`Preference topic not found: ${props.topicId}`);\n    }\n\n    return this.transformToTopic(node);\n  }\n\n  /**\n   * Update preferences for a specific topic\n   * @param topicId - The ID of the topic to update preferences for\n   * @param status - The new status for the topic\n   * @param hasCustomRouting - Whether the topic has custom routing\n   * @param customRouting - The custom routing channels for the topic\n   * @returns Promise resolving to the updated topic preferences\n   */\n  public async putUserPreferenceTopic(props: { topicId: string; status: CourierUserPreferencesStatus; hasCustomRouting: boolean; customRouting: CourierUserPreferencesChannel[]; digestSchedule?: string; }): Promise<CourierUserPreferencesTopic> {\n    const routingPreferences = props.customRouting.length > 0\n      ? `[${props.customRouting.join(', ')}]`\n      : '[]';\n\n    const digestScheduleLine = props.digestSchedule != null\n      ? `\\n            digestSchedule: \"${props.digestSchedule}\"`\n      : '';\n\n    const query = `\n      mutation UpdateRecipientPreferenceV2 {\n        updatePreferenceV2(\n          templateId: \"${props.topicId}\",\n          preferences: {\n            status: ${props.status},\n            hasCustomRouting: ${props.hasCustomRouting},\n            routingPreferences: ${routingPreferences}${digestScheduleLine}\n          }${this.options.tenantId ? `, accountId: \"${this.options.tenantId}\"` : ''}\n        ) {\n          templateId\n          templateName\n          status\n          hasCustomRouting\n          routingPreferences\n          digestSchedule\n          sectionId\n          sectionName\n          defaultStatus\n        }\n      }\n    `;\n\n    const response = await graphql({\n      options: this.options,\n      url: this.options.apiUrls.courier.graphql,\n      query,\n      headers: {\n        'x-courier-user-id': this.options.userId,\n        'x-courier-client-key': 'empty', // Empty for now. Will be removed in future.\n        'Authorization': `Bearer ${this.options.accessToken}`\n      },\n    });\n\n    const node: RecipientPreference = response.data?.updatePreferenceV2;\n    return this.transformToTopic(node);\n  }\n\n  /**\n   * Get the published preference page for the current workspace.\n   *\n   * Returns workspace-configured sections, topics, channel label mappings,\n   * and optional brand metadata. Combine with `getUserPreferences()` to\n   * overlay the user's current per-topic preferences (status, custom routing,\n   * digest schedule).\n   *\n   * @param accountId - Optional account/tenant ID. Falls back to the client's tenantId.\n   * @param brandId - Optional brand ID to resolve brand colors/logo/links inline.\n   * @returns The published preference page, or `null` if none is published.\n   */\n  public async getPreferencePage(props?: { accountId?: string; brandId?: string }): Promise<CourierPreferencePage | null> {\n    const accountId = props?.accountId ?? this.options.tenantId;\n    const brandId = props?.brandId;\n\n    const accountArg = accountId ? `(accountId: \"${accountId}\")` : '';\n    const brandFragment = `\n        brand${brandId ? `(brandId: \"${brandId}\")` : ''} {\n          settings {\n            colors {\n              primary\n            }\n          }\n          links\n          logo {\n            href\n            image\n          }\n        }`;\n\n    const query = `\n      query GetPreferencePage {\n        preferencePage${accountArg} {\n          showCourierFooter\n          ${brandFragment}\n          channelConfigs {\n            channelLabels {\n              channel\n              name\n            }\n          }\n          sections {\n            nodes {\n              name\n              sectionId\n              routingOptions\n              hasCustomRouting\n              topics {\n                nodes {\n                  data\n                  defaultStatus\n                  templateName\n                  templateId\n                  digestSchedules\n                }\n              }\n            }\n          }\n        }\n        recipientPreferences${accountId ? `(accountId: \"${accountId}\")` : ''} {\n          nodes {\n            templateId\n            status\n            hasCustomRouting\n            routingPreferences\n            digestSchedule\n          }\n        }\n      }\n    `;\n\n    const response = await graphql({\n      options: this.options,\n      url: this.options.apiUrls.courier.graphql,\n      query,\n      headers: {\n        'x-courier-user-id': this.options.userId,\n        'x-courier-client-key': 'empty',\n        'Authorization': `Bearer ${this.options.accessToken}`,\n      },\n    });\n\n    const page = response.data?.preferencePage;\n    if (!page) return null;\n\n    const recipientPreferences: RecipientPreference[] =\n      response.data?.recipientPreferences?.nodes || [];\n\n    return this.transformPreferencePage(page, recipientPreferences);\n  }\n\n  /**\n   * Get the available digest schedules for a specific topic\n   * @param topicId - The ID of the topic to get digest schedules for\n   * @returns Promise resolving to an array of available digest schedule options\n   */\n  public async getDigestSchedules(props: { topicId: string }): Promise<CourierDigestScheduleOption[]> {\n    const query = `\n      query GetDigestSchedulesForTopic {\n        digestSchedulesForTopic(templateId: \"${props.topicId}\") {\n          scheduleId\n          period\n          recurrence\n          repeat\n          repetition\n          start\n          default\n        }\n      }\n    `;\n\n    const response = await graphql({\n      options: this.options,\n      url: this.options.apiUrls.courier.graphql,\n      query,\n      headers: {\n        'x-courier-user-id': this.options.userId,\n        'x-courier-client-key': 'empty',\n        'Authorization': `Bearer ${this.options.accessToken}`\n      },\n    });\n\n    return response.data?.digestSchedulesForTopic || [];\n  }\n\n  /**\n   * @deprecated The clientKey parameter is deprecated and will be removed in a future release.\n   *\n   * Get the notification center URL\n   * @param clientKey - The client key to use for the URL\n   * @returns The notification center URL\n   */\n  public getNotificationCenterUrl(props: {\n    clientKey: string;\n  }): string {\n    this.options.logger.warn('Courier Warning: The clientKey parameter in getNotificationCenterUrl is deprecated and will be removed in a future release.');\n    const rootTenantId = decode(props.clientKey);\n    const url = encode(`${rootTenantId}#${this.options.userId}${this.options.tenantId ? `#${this.options.tenantId}` : \"\"}#${false}`);\n    return `https://view.notificationcenter.app/p/${url}`;\n  }\n\n  /**\n   * Transform a GraphQL RecipientPreference node to CourierUserPreferencesTopic\n   */\n  private transformToTopic(node: RecipientPreference): CourierUserPreferencesTopic {\n    return {\n      topicId: node.templateId,\n      topicName: node.templateName || '',\n      sectionId: node.sectionId || '',\n      sectionName: node.sectionName || '',\n      status: (node.status as CourierUserPreferencesStatus) || 'UNKNOWN',\n      defaultStatus: (node.defaultStatus as CourierUserPreferencesStatus) || 'UNKNOWN',\n      hasCustomRouting: node.hasCustomRouting || false,\n      customRouting: (node.routingPreferences || []) as CourierUserPreferencesChannel[],\n      digestSchedule: node.digestSchedule,\n    };\n  }\n\n  /**\n   * Transform a raw `preferencePage` GraphQL response into the public shape.\n   */\n  private transformPreferencePage(page: any, recipientPreferences: RecipientPreference[] = []): CourierPreferencePage {\n    const rawSections = page?.sections?.nodes ?? [];\n    const sections: CourierPreferencePageSection[] = rawSections.map((section: any) => {\n      const rawTopics = section?.topics?.nodes ?? [];\n      const topics: CourierPreferencePageTopic[] = rawTopics.map((topic: any) => ({\n        templateId: topic.templateId,\n        templateName: topic.templateName ?? '',\n        defaultStatus: (topic.defaultStatus as CourierUserPreferencesStatus) ?? 'UNKNOWN',\n        data: topic.data,\n        digestSchedules: (topic.digestSchedules ?? undefined) as CourierDigestScheduleOption[] | undefined,\n      }));\n      return {\n        sectionId: section.sectionId,\n        name: section.name ?? '',\n        hasCustomRouting: Boolean(section.hasCustomRouting),\n        routingOptions: (section.routingOptions ?? []) as CourierUserPreferencesChannel[],\n        topics,\n      };\n    });\n\n    return {\n      showCourierFooter: Boolean(page?.showCourierFooter),\n      brand: page?.brand ?? null,\n      channelConfigs: page?.channelConfigs ?? null,\n      sections,\n      recipientPreferences,\n    };\n  }\n}\n","import { CourierDevice } from '../types/token';\nimport { http } from '../utils/request';\nimport { Client } from './client';\n\nexport class TokenClient extends Client {\n\n  /**\n   * Store a push notification token for a user\n   * @param token - The push notification token\n   * @param provider - The provider of the token\n   * @param device - The device information\n   * @see https://www.courier.com/docs/api-reference/device-tokens/add-single-token-to-user\n   */\n  public async putUserToken(props: {\n    token: string;\n    provider: string;\n    device?: CourierDevice;\n  }): Promise<void> {\n    const payload = {\n      provider_key: props.provider,\n      ...(props.device && {\n        device: {\n          app_id: props.device.appId,\n          ad_id: props.device.adId,\n          device_id: props.device.deviceId,\n          platform: props.device.platform,\n          manufacturer: props.device.manufacturer,\n          model: props.device.model\n        }\n      })\n    };\n\n    await http({\n      options: this.options,\n      url: `${this.options.apiUrls.courier.rest}/users/${this.options.userId}/tokens/${props.token}`,\n      method: 'PUT',\n      headers: {\n        'Authorization': `Bearer ${this.options.accessToken}`\n      },\n      body: payload,\n      validCodes: [200, 204]\n    });\n  }\n\n  /**\n   * Delete a push notification token for a user\n   * @param token - The push notification token\n   * @returns Promise resolving when token is deleted\n   */\n  public async deleteUserToken(props: {\n    token: string;\n  }): Promise<void> {\n    await http({\n      options: this.options,\n      url: `${this.options.apiUrls.courier.rest}/users/${this.options.userId}/tokens/${props.token}`,\n      method: 'DELETE',\n      headers: {\n        'Authorization': `Bearer ${this.options.accessToken}`\n      },\n      validCodes: [200, 204]\n    });\n  }\n}\n","import { http } from '../utils/request';\nimport { Client } from './client';\n\nexport class ListClient extends Client {\n\n  /**\n   * @deprecated The clientKey parameter is deprecated and will be removed in a future release.\n   *\n   * Subscribe a user to a list\n   * @param listId - The ID of the list to subscribe to\n   * @param clientKey - The client key for your Courier project\n   * @returns Promise resolving when subscription is complete\n   * @see https://www.courier.com/docs/api-reference/lists/subscribe-user-profile-to-list\n   */\n  public async putSubscription(props: { listId: string; clientKey: string; }): Promise<void> {\n    this.options.logger.warn('Courier Warning: The clientKey parameter in putSubscription is deprecated and will be removed in a future release.');\n    return await http({\n      url: `${this.options.apiUrls.courier.rest}/client/lists/${props.listId}/subscribe/${this.options.userId}`,\n      options: this.options,\n      method: 'PUT',\n      headers: {\n        'x-courier-client-key': props.clientKey,\n        Authorization: `Bearer ${this.options.accessToken}`,\n      },\n    });\n  }\n\n  /**\n   * @deprecated The clientKey parameter is deprecated and will be removed in a future release.\n   *\n   * Unsubscribe a user from a list\n   * @param listId - The ID of the list to unsubscribe from\n   * @param clientKey - The client key for your Courier project\n   * @returns Promise resolving when unsubscription is complete\n   * @see https://www.courier.com/docs/api-reference/lists/unsubscribe-user-profile-from-list\n   */\n  public async deleteSubscription(props: { listId: string; clientKey: string; }): Promise<void> {\n    this.options.logger.warn('Courier Warning: The clientKey parameter in deleteSubscription is deprecated and will be removed in a future release.');\n    return await http({\n      url: `${this.options.apiUrls.courier.rest}/client/lists/${props.listId}/unsubscribe/${this.options.userId}`,\n      options: this.options,\n      method: 'DELETE',\n      headers: {\n        'x-courier-client-key': props.clientKey,\n        Authorization: `Bearer ${this.options.accessToken}`,\n      },\n    });\n  }\n\n}\n","import { CourierTrackingEvent } from '../types/tracking-event';\nimport { http } from '../utils/request';\nimport { Client } from './client';\n\nexport class TrackingClient extends Client {\n\n  /**\n   * @deprecated This method is deprecated and will be removed or changed significantly in a future release.\n   *\n   * Post an inbound courier event. This is typically used for tracking custom events\n   * related to a specific message in Courier.\n   * \n   * @param props - The event properties object containing:\n   *   - `clientKey`: The client key associated with your Courier project. \n   *     You can get your client key here: https://app.courier.com/settings/api-keys\n   *   - `event`: The name of the event (e.g., \"New Order Placed\").\n   *   - `messageId`: The unique ID of the message this event relates to.\n   *   - `type`: The type of event. Only supported value: \"track\".\n   *   - `properties`: (Optional) Additional custom properties for the event.\n   * @returns Promise resolving to an object containing the messageId.\n   * @see https://www.courier.com/docs/api-reference/inbound/courier-track-event\n   */\n  public async postInboundCourier(props: {\n    clientKey: string;\n    event: string;\n    messageId: string;\n    type: 'track';\n    properties?: Record<string, any>;\n  }): Promise<{ messageId: string }> {\n    const { clientKey, ...bodyProps } = props;\n    return await http({\n      url: `${this.options.apiUrls.courier.rest}/inbound/courier`,\n      options: this.options,\n      method: 'POST',\n      headers: {\n        'x-courier-client-key': clientKey,\n      },\n      body: {\n        ...bodyProps,\n        userId: this.options.userId\n      },\n      validCodes: [200, 202]\n    });\n  }\n\n  /**\n   * Post a tracking URL event\n   * These urls are found in messages sent from Courier\n   * @param url - The URL to post the event to\n   * @param event - The event type: Available options: \"click\", \"open\", \"unsubscribe\"\n   * @returns Promise resolving when the event is posted\n   */\n  public async postTrackingUrl(props: {\n    url: string;\n    event: CourierTrackingEvent;\n  }): Promise<void> {\n    return await http({\n      url: props.url,\n      options: this.options,\n      method: 'POST',\n      body: {\n        event: props.event\n      }\n    });\n  }\n\n}\n","import { CourierUserAgent as ICourierUserAgent, SDK_KEY, SDK_VERSION_KEY, CLIENT_ID_KEY } from \"../types/courier-user-agent\";\n\n/** Client info reportable to the Courier backend in WebSocket and HTTP requests. */\nexport class CourierUserAgent {\n  /**\n   * Create User Agent info\n   * @param clientId client ID for this session\n   * @param sdkName identifier of the SDK making requests to the Courier backend\n   * @param sdkVersion version of the SDK making requests to the Courier backend\n   */\n  constructor(\n    private readonly clientId: string,\n    private readonly sdkName: string,\n    private readonly sdkVersion: string) {}\n\n  /** Get the telemetry payload as a JSON-serializable object. */\n  public getUserAgentInfo(): ICourierUserAgent {\n    return {\n      [SDK_KEY]: this.sdkName,\n      [SDK_VERSION_KEY]: this.sdkVersion,\n      [CLIENT_ID_KEY]: this.clientId\n    };\n  }\n\n  /** Get the telemetry payload as a comma-separated string, where keys and values are joined by `=`. */\n  public toHttpHeaderValue(): string {\n    return Object.entries(this.getUserAgentInfo())\n      .map(([key, value]) => `${key}=${value}`)\n      .join(',');\n  }\n}\n","\nimport {\n  CourierApiUrls,\n  getCourierApiUrls,\n  getCourierApiUrlsForRegion\n} from '../types/courier-api-urls';\nimport { Logger } from '../utils/logger';\nimport { BrandClient } from './brand-client';\nimport { InboxClient } from './inbox-client';\nimport { PreferenceClient } from './preference-client';\nimport { TokenClient } from './token-client';\nimport { Client } from './client';\nimport { ListClient } from './list-client';\nimport { TrackingClient } from './tracking-client';\nimport { UUID } from '../utils/uuid';\nimport { CourierUserAgent } from '../utils/courier-user-agent';\n\nexport interface CourierProps {\n  /** User ID for the client. Normally matches the UID in your system */\n  userId: string;\n\n  /** JWT token for authentication: More info at https://www.courier.com/docs/api-reference/authentication/create-jwt */\n  jwt?: string;\n\n  /** Public API key for testing (use JWTs in prod) */\n  publicApiKey?: string;\n\n  /** Tenant ID. Used for multi-tenant apps */\n  tenantId?: string;\n\n  /** Flag to control logging. Logs are prefixed with [COURIER]. */\n  showLogs?: boolean;\n\n  /** Custom API URLs */\n  apiUrls?: CourierApiUrls;\n\n  /**\n   * Optional: The name of the SDK calling courier-js methods.\n   *\n   * This is an internal prop, intended to be set by other Courier SDKs.\n   * If undefined, this defaults to \"courier-js\".\n   * @internal\n   */\n  courierUserAgentName?: string;\n\n  /**\n   * Optional: The version of the SDK calling courier-js methods.\n   *\n   * This is an internal prop, intended to be set by other Courier SDKs.\n   * If undefined, this defaults to this package's version.\n   * @internal\n   */\n  courierUserAgentVersion?: string;\n}\n\nexport interface CourierClientOptions {\n  /** JWT token for authentication: More info at https://www.courier.com/docs/api-reference/authentication/create-jwt */\n  readonly jwt?: string;\n\n  /** Public API key for testing (use JWTs in prod) */\n  readonly publicApiKey?: string;\n\n  /** User ID for the client. Normally matches the UID in your system */\n  readonly userId: string;\n\n  /** Inbox Websocket connection ID */\n  readonly connectionId: string;\n\n  /** Tenant ID. Used for multi-tenant apps */\n  readonly tenantId?: string;\n\n  /** Flag to control logging. Logs are prefixed with [COURIER]. */\n  readonly showLogs?: boolean;\n\n  /** Combined authentication token (jwt or publicApiKey) */\n  readonly accessToken?: string;\n\n  /** Logger instance */\n  readonly logger: Logger;\n\n  /** Final API URLs configuration */\n  readonly apiUrls: CourierApiUrls;\n\n  /** User agent describing Courier SDK and browser UA. */\n  readonly courierUserAgent: CourierUserAgent;\n}\n\nexport class CourierClient extends Client {\n  /** User-agent reporting name of the courier-js package. */\n  private static readonly COURIER_JS_NAME = \"courier-js\";\n\n  /**\n   * User agent reporting version of the courier-js package.\n   * Inlined from package.json at build time.\n   */\n  private static readonly COURIER_JS_VERSION = __PACKAGE_VERSION__;\n\n  public readonly tokens: TokenClient;\n  public readonly brands: BrandClient;\n  public readonly preferences: PreferenceClient;\n  public readonly inbox: InboxClient;\n  public readonly lists: ListClient;\n  public readonly tracking: TrackingClient;\n\n  constructor(props: CourierProps) {\n    // Determine if we should show logs (default to false)\n    const showLogs = props.showLogs !== undefined ? props.showLogs : false;\n    const connectionId = UUID.nanoid();\n\n    // Setup base options with default values\n    const baseOptions = {\n      ...props,\n      showLogs,\n      connectionId,\n      apiUrls: props.apiUrls || getCourierApiUrlsForRegion('us'),\n      accessToken: props.jwt ?? props.publicApiKey\n    };\n\n    const courierUserAgent = new CourierUserAgent(\n      connectionId,\n      props.courierUserAgentName || CourierClient.COURIER_JS_NAME,\n      props.courierUserAgentVersion || CourierClient.COURIER_JS_VERSION\n    );\n\n    // Initialize base client with logger and URLs\n    super({\n      ...baseOptions,\n      logger: new Logger(baseOptions.showLogs),\n      courierUserAgent,\n      apiUrls: getCourierApiUrls(baseOptions.apiUrls)\n    });\n\n    // Initialize all subclients with the configured options\n    this.tokens = new TokenClient(this.options);\n    this.brands = new BrandClient(this.options);\n    this.preferences = new PreferenceClient(this.options);\n    this.inbox = new InboxClient(this.options);\n    this.lists = new ListClient(this.options);\n    this.tracking = new TrackingClient(this.options);\n\n    // Warn if no authentication method is provided\n    if (!this.options.jwt && !this.options.publicApiKey) {\n      this.options.logger.warn('Courier Client initialized with no authentication method. Please provide a JWT or public API key.');\n    }\n\n    // Warn about using public API key in production\n    if (this.options.publicApiKey) {\n      this.options.logger?.warn(\n        'Courier Warning: Public API Keys are for testing only. Please use JWTs for production.\\n' +\n        'You can generate a JWT with this endpoint: https://www.courier.com/docs/api-reference/authentication/create-jwt\\n' +\n        'This endpoint should be called from your backend server, not the SDK.'\n      );\n    }\n\n    // Warn if both authentication methods are provided\n    if (this.options.jwt && this.options.publicApiKey) {\n      this.options.logger?.warn(\n        'Courier Warning: Both a JWT and a Public API Key were provided. The Public API Key will be ignored.'\n      );\n    }\n  }\n}\n","import { Courier } from \"./courier\";\n\nexport class AuthenticationListener {\n  readonly callback: (props: { userId?: string }) => void;\n\n  constructor(callback: (props: { userId?: string }) => void) {\n    this.callback = callback;\n  }\n\n  public remove(): void {\n    Courier.shared.removeAuthenticationListener(this);\n  }\n\n}","import { CourierClient, CourierProps } from \"../client/courier-client\";\nimport { AuthenticationListener } from '../shared/authentication-listener';\nimport { UUID } from \"../utils/uuid\";\n\n/**\n * Courier is a singleton class that manages a shared Courier client instance and other resources.\n * UI components will automatically syncronize with this instance.\n * If you only need to call the Courier api, you should consider using the CourierClient directly.\n */\nexport class Courier {\n\n  /**\n   * The unique identifier for the Courier instance\n   */\n  public readonly id = UUID.nanoid();\n\n  /**\n   * The shared Courier instance\n   */\n  private static instance: Courier;\n\n  /**\n   * The Courier client instance\n   */\n  private instanceClient?: CourierClient;\n\n  /**\n   * Client's name reported in the user agent to the Courier backend.\n   *\n   * Other Courier SDKs calling APIs though the courier-js should set this property.\n   */\n  public courierUserAgentName?: string;\n\n  /**\n   * Client's version reported in the user agent to the Courier backend.\n   *\n   * Other Courier SDKs calling APIs though the courier-js should set this property.\n   */\n  public courierUserAgentVersion?: string;\n\n  /**\n   * The pagination limit (min: 1, max: 100)\n   */\n  private _paginationLimit = 24;\n\n  public get paginationLimit(): number {\n    return this._paginationLimit;\n  }\n\n  public set paginationLimit(value: number) {\n    this._paginationLimit = Math.min(Math.max(value, 1), 100);\n  }\n\n  /**\n   * Get the Courier client instance\n   * @returns The Courier client instance or undefined if not signed in\n   */\n  public get client(): CourierClient | undefined {\n    return this.instanceClient;\n  }\n\n  /**\n   * The authentication listeners\n   */\n  private authenticationListeners: AuthenticationListener[] = [];\n\n  /**\n   * Get the shared Courier instance\n   * @returns The shared Courier instance\n   */\n  public static get shared(): Courier {\n    if (!Courier.instance) {\n      Courier.instance = new Courier();\n    }\n    return Courier.instance;\n  }\n\n  /**\n   * Sign in to Courier\n   * @param options - The options for the Courier client\n   */\n  public signIn(props: CourierProps) {\n    // Sign out any existing user.\n    if (this.instanceClient) {\n      this.instanceClient.options.logger.warn('Sign in called but there is already a user signed in. Signing out the current user.');\n      this.signOut();\n    }\n\n    // Instantiate the client.\n    this.instanceClient = new CourierClient({\n      ...props,\n      courierUserAgentName: this.courierUserAgentName,\n      courierUserAgentVersion: this.courierUserAgentVersion\n    });\n    this.notifyAuthenticationListeners({ userId: props.userId });\n  }\n\n  /**\n   * Sign out of Courier\n   */\n  public signOut() {\n    // Close the socket client.\n    this.instanceClient?.inbox.socket?.close();\n\n    // Clear the client.\n    this.instanceClient = undefined;\n    this.notifyAuthenticationListeners({ userId: undefined });\n  }\n\n  /**\n   * Register a callback to be notified of authentication state changes\n   * @param callback - Function to be called when authentication state changes\n   * @returns AuthenticationListener instance that can be used to remove the listener\n   */\n  public addAuthenticationListener(callback: (props: { userId?: string }) => void): AuthenticationListener {\n    this.instanceClient?.options.logger.info('Adding authentication listener');\n    const listener = new AuthenticationListener(callback);\n    this.authenticationListeners.push(listener);\n    return listener;\n  }\n\n  /**\n   * Unregister an authentication state change listener\n   * @param listener - The AuthenticationListener instance to remove\n   */\n  public removeAuthenticationListener(listener: AuthenticationListener) {\n    this.instanceClient?.options.logger.info('Removing authentication listener');\n    this.authenticationListeners = this.authenticationListeners.filter(l => l !== listener);\n  }\n\n  /**\n   * Notify all authentication listeners\n   * @param props - The props to notify the listeners with\n   */\n  private notifyAuthenticationListeners(props: { userId?: string }) {\n    this.authenticationListeners.forEach(listener => listener.callback(props));\n  }\n\n}\n"],"names":["ClientAction","ServerAction","InboxMessageEvent","CourierUserAgent.HTTP_HEADER_KEY","_a"],"mappings":"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"}