{"version":3,"sources":["../src/providers/cloud-api/mapper.ts","../src/providers/cloud-api/webhook-parser.ts","../src/providers/cloud-api/index.ts"],"names":["normalizePhoneNumber","ValidationError","assertNever","isRecord","hasProp","noopLogger","HttpClient","RateLimiter","ProviderError","response","verifyHmacSha256","UnsupportedFeatureError","MediaError"],"mappings":"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","file":"chunk-WC5POYR7.cjs","sourcesContent":["// ---------------------------------------------------------------------------\n// Cloud API mapper — unified types → Meta Graph API payloads\n// ---------------------------------------------------------------------------\n\nimport type { OutboundMessage } from '../../types/messages.js'\nimport type { MediaSource } from '../../types/common.js'\nimport { normalizePhoneNumber } from '../../utils/phone.js'\nimport { assertNever } from '../../utils/assert.js'\nimport { ValidationError } from '../../core/errors.js'\n\n/**\n * Map a unified OutboundMessage to the Cloud API request payload.\n * This is the canonical mapping — 360Dialog reuses it since their\n * payload format is identical.\n */\nexport function mapOutboundToCloudApi(message: OutboundMessage): Record<string, unknown> {\n  const to = normalizePhoneNumber(message.to)\n\n  const base: Record<string, unknown> = {\n    messaging_product: 'whatsapp',\n    recipient_type: 'individual',\n    to,\n  }\n\n  // Attach reply context if present\n  if ('context' in message && message.context?.messageId) {\n    base['context'] = { message_id: message.context.messageId }\n  }\n\n  switch (message.type) {\n    case 'text':\n      return {\n        ...base,\n        type: 'text',\n        text: {\n          body: message.text.body,\n          preview_url: message.text.previewUrl ?? false,\n        },\n      }\n\n    case 'template':\n      return {\n        ...base,\n        type: 'template',\n        template: {\n          name: message.template.name,\n          language: { code: message.template.language },\n          ...(message.template.components\n            ? { components: message.template.components }\n            : {}),\n        },\n      }\n\n    case 'image':\n      return {\n        ...base,\n        type: 'image',\n        image: {\n          ...mapMediaSource(message.image),\n          ...(message.image.caption ? { caption: message.image.caption } : {}),\n        },\n      }\n\n    case 'video':\n      return {\n        ...base,\n        type: 'video',\n        video: {\n          ...mapMediaSource(message.video),\n          ...(message.video.caption ? { caption: message.video.caption } : {}),\n        },\n      }\n\n    case 'audio':\n      return {\n        ...base,\n        type: 'audio',\n        audio: mapMediaSource(message.audio),\n      }\n\n    case 'document':\n      return {\n        ...base,\n        type: 'document',\n        document: {\n          ...mapMediaSource(message.document),\n          ...(message.document.caption ? { caption: message.document.caption } : {}),\n          ...(message.document.filename ? { filename: message.document.filename } : {}),\n        },\n      }\n\n    case 'sticker':\n      return {\n        ...base,\n        type: 'sticker',\n        sticker: mapMediaSource(message.sticker),\n      }\n\n    case 'location':\n      return {\n        ...base,\n        type: 'location',\n        location: {\n          latitude: message.location.latitude,\n          longitude: message.location.longitude,\n          ...(message.location.name ? { name: message.location.name } : {}),\n          ...(message.location.address ? { address: message.location.address } : {}),\n        },\n      }\n\n    case 'contacts':\n      return {\n        ...base,\n        type: 'contacts',\n        contacts: message.contacts,\n      }\n\n    case 'reaction':\n      return {\n        ...base,\n        type: 'reaction',\n        reaction: {\n          message_id: message.reaction.messageId,\n          emoji: message.reaction.emoji,\n        },\n      }\n\n    case 'interactive.button':\n      if (message.buttons.length > 3) {\n        throw new ValidationError({\n          message: `Interactive buttons: maximum 3 buttons allowed, got ${message.buttons.length}`,\n          provider: 'cloud-api',\n        })\n      }\n      return {\n        ...base,\n        type: 'interactive',\n        interactive: {\n          type: 'button',\n          ...(message.header ? { header: mapInteractiveHeader(message.header) } : {}),\n          body: { text: message.body },\n          ...(message.footer ? { footer: { text: message.footer } } : {}),\n          action: {\n            buttons: message.buttons.map(btn => ({\n              type: 'reply' as const,\n              reply: { id: btn.id, title: btn.title },\n            })),\n          },\n        },\n      }\n\n    case 'interactive.list': {\n      if (message.sections.length > 10) {\n        throw new ValidationError({\n          message: `Interactive list: maximum 10 sections allowed, got ${message.sections.length}`,\n          provider: 'cloud-api',\n        })\n      }\n      // WhatsApp's real binding limit is ≤ 10 rows TOTAL across all sections.\n      const totalRows = message.sections.reduce((sum, section) => sum + section.rows.length, 0)\n      if (totalRows > 10) {\n        throw new ValidationError({\n          message: `Interactive list: maximum 10 rows total across all sections, got ${totalRows}`,\n          provider: 'cloud-api',\n        })\n      }\n      return {\n        ...base,\n        type: 'interactive',\n        interactive: {\n          type: 'list',\n          ...(message.header ? { header: { type: 'text', text: message.header } } : {}),\n          body: { text: message.body },\n          ...(message.footer ? { footer: { text: message.footer } } : {}),\n          action: {\n            button: message.buttonText,\n            sections: message.sections.map(section => ({\n              title: section.title,\n              rows: section.rows.map(row => ({\n                id: row.id,\n                title: row.title,\n                ...(row.description ? { description: row.description } : {}),\n              })),\n            })),\n          },\n        },\n      }\n    }\n\n    default:\n      return assertNever(message)\n  }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction mapMediaSource(source: MediaSource): Record<string, string> {\n  if ('url' in source && source.url) {\n    return { link: source.url }\n  }\n  if ('id' in source && source.id) {\n    return { id: source.id }\n  }\n  throw new Error('MediaSource must have either url or id')\n}\n\nfunction mapInteractiveHeader(\n  header: NonNullable<Extract<OutboundMessage, { type: 'interactive.button' }>['header']>,\n): Record<string, unknown> {\n  switch (header.type) {\n    case 'text':\n      return { type: 'text', text: header.text }\n    case 'image':\n      return { type: 'image', image: mapMediaSource(header.image) }\n    case 'video':\n      return { type: 'video', video: mapMediaSource(header.video) }\n    case 'document':\n      return { type: 'document', document: mapMediaSource(header.document) }\n    default:\n      return assertNever(header)\n  }\n}\n","// ---------------------------------------------------------------------------\n// Cloud API webhook parser — normalizes Meta webhook payloads to unified events\n// ---------------------------------------------------------------------------\n\nimport type { ProviderName } from '../../types/common.js'\nimport type {\n  WebhookEvent,\n  IncomingMessage,\n  WebhookMetadata,\n} from '../../types/webhooks.js'\nimport type {\n  CloudApiWebhookPayload,\n  CloudApiWebhookValue,\n  CloudApiRawMessage,\n  CloudApiRawStatus,\n} from './types.js'\nimport { isRecord, hasProp } from '../../utils/assert.js'\n\n/**\n * Parse a raw Cloud API webhook payload into normalized WebhookEvent[].\n *\n * A single webhook POST can contain multiple entries and multiple changes,\n * each of which may contain multiple messages or statuses.\n * We flatten all of them into a single array.\n *\n * @param providerName - Allows 360Dialog to reuse this parser with its own name\n */\nexport function parseCloudApiWebhook(\n  body: unknown,\n  providerName: ProviderName = 'cloud-api',\n  options: { includeRaw?: boolean } = {},\n): WebhookEvent[] {\n  if (!isValidWebhookPayload(body)) return []\n\n  const events: WebhookEvent[] = []\n\n  for (const entry of body.entry) {\n    for (const change of entry.changes) {\n      if (change.field !== 'messages') continue\n\n      const value = change.value\n      const metadata = buildMetadata(value, options.includeRaw ? body : undefined, providerName)\n\n      // Parse incoming messages\n      if (value.messages) {\n        // Index contacts once per change instead of scanning per message.\n        // Keep the FIRST entry per wa_id to match the previous `find()` semantics.\n        const contacts = value.contacts ?? []\n        const contactsByWaId = new Map<string, (typeof contacts)[number]>()\n        for (const c of contacts) {\n          if (!contactsByWaId.has(c.wa_id)) contactsByWaId.set(c.wa_id, c)\n        }\n        const fallbackContact = contacts[0]\n        for (const msg of value.messages) {\n          const contact = contactsByWaId.get(msg.from) ?? fallbackContact\n          events.push({\n            type: 'message',\n            messageId: msg.id,\n            from: msg.from,\n            timestamp: new Date(parseInt(msg.timestamp, 10) * 1000),\n            message: parseIncomingMessage(msg),\n            contact: contact\n              ? { name: contact.profile.name, waId: contact.wa_id }\n              : undefined,\n            metadata,\n          })\n        }\n      }\n\n      // Parse status updates\n      if (value.statuses) {\n        for (const status of value.statuses) {\n          events.push(parseStatusEvent(status, metadata))\n        }\n      }\n\n      // Parse errors\n      if (value.errors) {\n        for (const error of value.errors) {\n          events.push({\n            type: 'error',\n            code: error.code,\n            title: error.title,\n            message: error.message,\n            metadata,\n          })\n        }\n      }\n    }\n  }\n\n  return events\n}\n\n// ---------------------------------------------------------------------------\n// Message type parsing\n// ---------------------------------------------------------------------------\n\nfunction parseIncomingMessage(msg: CloudApiRawMessage): IncomingMessage {\n  switch (msg.type) {\n    case 'text':\n      return { type: 'text', body: msg.text?.body ?? '' }\n\n    case 'image':\n      return {\n        type: 'image',\n        mediaId: msg.image?.id ?? '',\n        mimeType: msg.image?.mime_type ?? '',\n        sha256: msg.image?.sha256,\n        caption: msg.image?.caption,\n      }\n\n    case 'video':\n      return {\n        type: 'video',\n        mediaId: msg.video?.id ?? '',\n        mimeType: msg.video?.mime_type ?? '',\n        sha256: msg.video?.sha256,\n        caption: msg.video?.caption,\n      }\n\n    case 'audio':\n      return {\n        type: 'audio',\n        mediaId: msg.audio?.id ?? '',\n        mimeType: msg.audio?.mime_type ?? '',\n        sha256: msg.audio?.sha256,\n        voice: msg.audio?.voice,\n      }\n\n    case 'document':\n      return {\n        type: 'document',\n        mediaId: msg.document?.id ?? '',\n        mimeType: msg.document?.mime_type ?? '',\n        sha256: msg.document?.sha256,\n        filename: msg.document?.filename,\n        caption: msg.document?.caption,\n      }\n\n    case 'location':\n      return {\n        type: 'location',\n        latitude: msg.location?.latitude ?? 0,\n        longitude: msg.location?.longitude ?? 0,\n        name: msg.location?.name,\n        address: msg.location?.address,\n      }\n\n    case 'sticker':\n      return {\n        type: 'sticker',\n        mediaId: msg.sticker?.id ?? '',\n        mimeType: msg.sticker?.mime_type ?? '',\n        animated: msg.sticker?.animated ?? false,\n      }\n\n    case 'reaction':\n      return {\n        type: 'reaction',\n        emoji: msg.reaction?.emoji ?? '',\n        reactedMessageId: msg.reaction?.message_id ?? '',\n      }\n\n    case 'interactive':\n      if (msg.interactive?.type === 'button_reply' && msg.interactive.button_reply) {\n        return {\n          type: 'button_reply',\n          buttonId: msg.interactive.button_reply.id,\n          title: msg.interactive.button_reply.title,\n        }\n      }\n      if (msg.interactive?.type === 'list_reply' && msg.interactive.list_reply) {\n        return {\n          type: 'list_reply',\n          listId: msg.interactive.list_reply.id,\n          title: msg.interactive.list_reply.title,\n          description: msg.interactive.list_reply.description,\n        }\n      }\n      return { type: 'unknown', raw: msg }\n\n    case 'contacts':\n      return {\n        type: 'contacts',\n        contacts: msg.contacts ?? [],\n      }\n\n    default:\n      return { type: 'unknown', raw: msg }\n  }\n}\n\n// ---------------------------------------------------------------------------\n// Status event parsing\n// ---------------------------------------------------------------------------\n\nfunction parseStatusEvent(\n  status: CloudApiRawStatus,\n  metadata: WebhookMetadata,\n): WebhookEvent {\n  return {\n    type: 'status',\n    messageId: status.id,\n    status: status.status,\n    recipientId: status.recipient_id,\n    timestamp: new Date(parseInt(status.timestamp, 10) * 1000),\n    errors: status.errors,\n    metadata,\n  }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction buildMetadata(\n  value: CloudApiWebhookValue,\n  raw: unknown,\n  provider: ProviderName,\n): WebhookMetadata {\n  return {\n    provider,\n    phoneNumberId: value.metadata.phone_number_id,\n    displayPhoneNumber: value.metadata.display_phone_number,\n    ...(raw !== undefined ? { raw } : {}),\n  }\n}\n\nfunction isValidWebhookPayload(body: unknown): body is CloudApiWebhookPayload {\n  return (\n    isRecord(body) &&\n    hasProp(body, 'entry') &&\n    Array.isArray(body['entry'])\n  )\n}\n","// ---------------------------------------------------------------------------\n// Cloud API Provider — reference implementation\n// ---------------------------------------------------------------------------\n\nimport type { WhatsAppProviderAdapter, ProviderFeature } from '../../types/provider.js'\nimport type { SendResult, ProviderName } from '../../types/common.js'\nimport type { OutboundMessage } from '../../types/messages.js'\nimport type { MediaUpload, MediaUploadResult, MediaUrlResult, MediaDownloadResult } from '../../types/media.js'\nimport type { Template, CreateTemplateInput } from '../../types/templates.js'\nimport type { WebhookEvent } from '../../types/webhooks.js'\nimport type { CloudApiConfig, ClientOptions } from '../../types/config.js'\nimport type { CloudApiSendResponse, CloudApiMediaUploadResponse, CloudApiMediaUrlResponse, CloudApiTemplatesResponse, CloudApiRawTemplate, CloudApiCreateTemplateResponse } from './types.js'\nimport { HttpClient } from '../../core/http.js'\nimport { RateLimiter } from '../../core/rate-limiter.js'\nimport { noopLogger, type Logger } from '../../core/logger.js'\nimport { UnsupportedFeatureError, MediaError, ValidationError, ProviderError } from '../../core/errors.js'\nimport { mapOutboundToCloudApi } from './mapper.js'\nimport { parseCloudApiWebhook } from './webhook-parser.js'\nimport { verifyHmacSha256 } from '../../utils/crypto.js'\n\nconst DEFAULT_API_VERSION = 'v25.0'\nconst GRAPH_API_BASE = 'https://graph.facebook.com'\n\n/** All features supported by the Cloud API provider */\nconst SUPPORTED_FEATURES = new Set<ProviderFeature>([\n  'interactive.button',\n  'interactive.list',\n  'media.upload',\n  'media.download',\n  'media.delete',\n  'template.management',\n  'reaction',\n  'read_receipts',\n  'sticker',\n  'location',\n  'contacts',\n  'webhook.signature_verification',\n  'webhook.challenge',\n])\n\nexport class CloudApiProvider implements WhatsAppProviderAdapter {\n  readonly name = 'cloud-api' as const\n\n  protected readonly config: CloudApiConfig\n  protected readonly options: ClientOptions\n  protected readonly http: HttpClient\n  protected readonly logger: Logger\n\n  constructor(config: CloudApiConfig, options: ClientOptions = {}) {\n    this.config = config\n    this.options = options\n    this.logger = options.logger ?? noopLogger\n\n    const apiVersion = config.apiVersion ?? DEFAULT_API_VERSION\n\n    this.http = new HttpClient({\n      baseUrl: `${GRAPH_API_BASE}/${apiVersion}`,\n      defaultHeaders: {\n        Authorization: `Bearer ${config.accessToken}`,\n      },\n      timeout: options.timeout ?? 30_000,\n      provider: 'cloud-api',\n      logger: this.logger,\n      rateLimiter: new RateLimiter(options.rateLimit),\n      retry: options.retry ?? {},\n      hooks: options.hooks,\n    })\n  }\n\n  // -- Messaging ----------------------------------------------------------\n\n  async sendMessage(message: OutboundMessage): Promise<SendResult> {\n    const payload = mapOutboundToCloudApi(message)\n\n    const response = await this.http.request<CloudApiSendResponse>({\n      method: 'POST',\n      path: `/${this.config.phoneNumberId}/messages`,\n      body: payload,\n    })\n\n    const messageId = response.data.messages[0]?.id ?? ''\n\n    if (!messageId) {\n      throw new ProviderError({\n        message: 'Provider returned no message ID — the send may not have succeeded',\n        provider: this.name,\n        statusCode: response.status,\n        raw: response.data,\n      })\n    }\n\n    return {\n      messageId,\n      provider: this.name,\n      ...(this.options.includeRawResponse ? { raw: response.data } : {}),\n    }\n  }\n\n  async markAsRead(messageId: string): Promise<void> {\n    await this.http.request({\n      method: 'POST',\n      path: `/${this.config.phoneNumberId}/messages`,\n      body: {\n        messaging_product: 'whatsapp',\n        status: 'read',\n        message_id: messageId,\n      },\n    })\n  }\n\n  // -- Media --------------------------------------------------------------\n\n  async uploadMedia(params: MediaUpload): Promise<MediaUploadResult> {\n    const formData = new FormData()\n    formData.set('messaging_product', 'whatsapp')\n    formData.set('type', params.mimeType)\n\n    if (params.file instanceof Blob) {\n      formData.set('file', params.file, params.filename ?? 'file')\n    } else if (params.file instanceof ReadableStream) {\n      // The ReadableStream branch still buffers the whole stream into memory via\n      // `new Response(stream).blob()` — unavoidable with fetch FormData. Callers\n      // with very large media should prefer URL-based sends where supported.\n      const response = new Response(params.file)\n      const blob = await response.blob()\n      formData.set('file', blob, params.filename ?? 'file')\n    } else {\n      // Uint8Array — pass the view directly. Blob already copies the bytes, so an\n      // extra `.slice()` here would just double peak memory for no benefit. The\n      // cast is type-only (Uint8Array<ArrayBufferLike> → BlobPart); it copies nothing.\n      const blob = new Blob([params.file as BlobPart], { type: params.mimeType })\n      formData.set('file', blob, params.filename ?? 'file')\n    }\n\n    const response = await this.http.uploadRequest<CloudApiMediaUploadResponse>(\n      `/${this.config.phoneNumberId}/media`,\n      formData,\n    )\n\n    return { id: response.data.id }\n  }\n\n  async getMediaUrl(mediaId: string): Promise<MediaUrlResult> {\n    const response = await this.http.request<CloudApiMediaUrlResponse>({\n      method: 'GET',\n      path: `/${mediaId}`,\n    })\n\n    return {\n      url: response.data.url,\n      mimeType: response.data.mime_type,\n      sha256: response.data.sha256,\n      fileSize: response.data.file_size ? parseInt(response.data.file_size, 10) : undefined,\n    }\n  }\n\n  async downloadMedia(mediaIdOrUrl: string): Promise<MediaDownloadResult> {\n    // If it's a media ID, first get the download URL\n    let downloadUrl: string\n    let expectedMimeType: string | undefined\n\n    if (mediaIdOrUrl.startsWith('http://') || mediaIdOrUrl.startsWith('https://')) {\n      downloadUrl = mediaIdOrUrl\n    } else {\n      const mediaInfo = await this.getMediaUrl(mediaIdOrUrl)\n      downloadUrl = mediaInfo.url\n      expectedMimeType = mediaInfo.mimeType\n    }\n\n    const response = await this.http.rawRequest({\n      method: 'GET',\n      path: downloadUrl,\n    })\n\n    const stream = getResponseBodyStream(response, this.name)\n\n    const mimeType =\n      response.headers.get('content-type') ??\n      expectedMimeType ??\n      'application/octet-stream'\n\n    const contentLength = response.headers.get('content-length')\n\n    return {\n      stream,\n      mimeType,\n      contentLength: contentLength ? parseInt(contentLength, 10) : undefined,\n    }\n  }\n\n  async deleteMedia(mediaId: string): Promise<void> {\n    await this.http.request({\n      method: 'DELETE',\n      path: `/${mediaId}`,\n    })\n  }\n\n  // -- Webhooks -----------------------------------------------------------\n\n  parseWebhook(body: unknown): WebhookEvent[] {\n    return parseCloudApiWebhook(body, 'cloud-api', { includeRaw: this.options.includeRawWebhook ?? false })\n  }\n\n  async verifyWebhookSignature(body: string, signature: string): Promise<boolean> {\n    if (!this.config.appSecret) {\n      this.logger.warn('verifyWebhookSignature called but no appSecret configured')\n      return false\n    }\n    return verifyHmacSha256(body, signature, this.config.appSecret)\n  }\n\n  handleVerificationChallenge(query: Record<string, string>): string | null {\n    if (!this.config.webhookVerifyToken) {\n      this.logger.warn('handleVerificationChallenge called but no webhookVerifyToken configured')\n      return null\n    }\n\n    const mode = query['hub.mode']\n    const token = query['hub.verify_token']\n    const challenge = query['hub.challenge']\n\n    if (\n      mode === 'subscribe' &&\n      token === this.config.webhookVerifyToken &&\n      challenge\n    ) {\n      this.logger.info('Webhook verification challenge accepted')\n      return challenge\n    }\n\n    this.logger.warn('Webhook verification challenge rejected', { mode, token })\n    return null\n  }\n\n  // -- Templates ----------------------------------------------------------\n\n  /** Get the WABA ID for template operations, throwing if not configured */\n  private getWabaId(): string {\n    if (!this.config.wabaId) {\n      throw new ValidationError({\n        message: 'Template management requires wabaId in the Cloud API config. Set it from Meta Business Manager → WhatsApp → Business Account Settings.',\n        provider: this.name,\n      })\n    }\n    return this.config.wabaId\n  }\n\n  async listTemplates(): Promise<Template[]> {\n    const wabaId = this.getWabaId()\n    const templates: Template[] = []\n    let after: string | undefined\n\n    // Paginate through all pages — Meta returns max ~25 templates per page\n    do {\n      const query: Record<string, string> = {}\n      if (after) query['after'] = after\n\n      const response = await this.http.request<CloudApiTemplatesResponse>({\n        method: 'GET',\n        path: `/${wabaId}/message_templates`,\n        query,\n      })\n\n      templates.push(...response.data.data.map(mapRawTemplate))\n\n      // Continue only if there's a next page\n      after = response.data.paging?.next ? response.data.paging.cursors.after : undefined\n    } while (after)\n\n    return templates\n  }\n\n  async createTemplate(input: CreateTemplateInput): Promise<Template> {\n    const wabaId = this.getWabaId()\n\n    // Meta's CREATE template endpoint requires UPPERCASE enums for category,\n    // component `type`/`format`, and button `type` (e.g. BODY/HEADER, UTILITY,\n    // TEXT/IMAGE, QUICK_REPLY/URL). Send them AS-IS — lowercasing here makes Meta\n    // reject the request with a (#100) error. (The SEND path in mapper.ts uses\n    // lowercase, which is correct for that endpoint.) Extra/auth fields\n    // (add_security_recommendation, code_expiration_minutes, otp_type) flow\n    // through untouched.\n    const response = await this.http.request<CloudApiCreateTemplateResponse>({\n      method: 'POST',\n      path: `/${wabaId}/message_templates`,\n      body: {\n        name: input.name,\n        language: input.language,\n        category: input.category,\n        parameter_format: 'positional',\n        components: input.components,\n      },\n    })\n\n    return {\n      id: response.data.id,\n      name: input.name,\n      language: input.language,\n      status: toEnum(response.data.status, TEMPLATE_STATUSES, 'PENDING'),\n      category: toEnum(response.data.category, TEMPLATE_CATEGORIES, input.category),\n      components: input.components,\n    }\n  }\n\n  async deleteTemplate(name: string): Promise<void> {\n    const wabaId = this.getWabaId()\n\n    await this.http.request({\n      method: 'DELETE',\n      path: `/${wabaId}/message_templates`,\n      query: { name },\n    })\n  }\n\n  // -- Capabilities -------------------------------------------------------\n\n  supports(feature: ProviderFeature): boolean {\n    return SUPPORTED_FEATURES.has(feature)\n  }\n\n  // -- Lifecycle ----------------------------------------------------------\n\n  /** Release the rate limiter's pending timer and queued waiters. */\n  destroy(): void {\n    this.http.destroy()\n  }\n\n  // -- Utility for subclasses (360Dialog) ---------------------------------\n\n  /** Throws if the given feature is not supported by this provider */\n  protected assertSupported(feature: ProviderFeature): void {\n    if (!this.supports(feature)) {\n      throw new UnsupportedFeatureError({\n        message: `Feature \"${feature}\" is not supported by the ${this.name} provider`,\n        provider: this.name,\n      })\n    }\n  }\n}\n\n// ---------------------------------------------------------------------------\n// Module-level helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Extract the body stream from a Response, throwing if empty.\n * The fetch spec guarantees body emits Uint8Array chunks, but some runtimes\n * (Bun) type it as ReadableStream<any>. This function safely narrows the type.\n */\nexport function getResponseBodyStream(response: Response, providerName: ProviderName): ReadableStream<Uint8Array> {\n  if (!response.body) {\n    throw new MediaError({\n      message: 'Media download returned empty body',\n      provider: providerName,\n    })\n  }\n  // The fetch spec guarantees response.body is ReadableStream<Uint8Array>.\n  // Some runtimes type it as ReadableStream<any>, so we annotate the return type.\n  return response.body as ReadableStream<Uint8Array>\n}\n\n// ---------------------------------------------------------------------------\n// Type-safe template mapping helpers\n// ---------------------------------------------------------------------------\n\nconst TEMPLATE_STATUSES: readonly Template['status'][] = ['APPROVED', 'PENDING', 'REJECTED', 'DISABLED', 'PAUSED']\nconst TEMPLATE_CATEGORIES: readonly Template['category'][] = ['UTILITY', 'MARKETING', 'AUTHENTICATION']\nconst COMPONENT_TYPES: readonly ('HEADER' | 'BODY' | 'FOOTER' | 'BUTTONS')[] = ['HEADER', 'BODY', 'FOOTER', 'BUTTONS']\nconst BUTTON_TYPES: readonly ('PHONE_NUMBER' | 'URL' | 'QUICK_REPLY')[] = ['PHONE_NUMBER', 'URL', 'QUICK_REPLY']\nconst FORMAT_TYPES: readonly ('TEXT' | 'IMAGE' | 'VIDEO' | 'DOCUMENT')[] = ['TEXT', 'IMAGE', 'VIDEO', 'DOCUMENT']\n\n/** Coerce a raw string to a known enum value, falling back to a default */\nfunction toEnum<T extends string>(raw: string, valid: readonly T[], fallback: T): T {\n  return (valid as readonly string[]).includes(raw) ? (raw as T) : fallback\n}\n\n/** Map a raw Cloud API template response to a normalized Template */\nfunction mapRawTemplate(t: CloudApiRawTemplate): Template {\n  return {\n    id: t.id,\n    name: t.name,\n    language: t.language,\n    status: toEnum(t.status, TEMPLATE_STATUSES, 'PENDING'),\n    category: toEnum(t.category, TEMPLATE_CATEGORIES, 'UTILITY'),\n    components: (t.components ?? []).map(c => ({\n      type: toEnum(c.type, COMPONENT_TYPES, 'BODY'),\n      format: c.format ? toEnum(c.format, FORMAT_TYPES, 'TEXT') : undefined,\n      text: c.text,\n      buttons: c.buttons?.map(b => ({\n        type: toEnum(b.type, BUTTON_TYPES, 'QUICK_REPLY'),\n        text: b.text,\n        phone_number: b.phone_number,\n        url: b.url,\n        example: b.example,\n      })),\n      example: c.example,\n    })),\n  }\n}\n"]}