{"version":3,"sources":["../src/core/constants.ts","../src/core/errors.ts","../src/core/http-client.ts","../src/utils/message-validators.ts","../src/resources/send.ts","../src/resources/attachments.ts","../src/resources/moderation.ts","../src/utils/validators.ts","../src/resources/templates.ts","../src/resources/profile.ts","../src/resources/conversations.ts","../src/client.ts","../src/types/webhooks/base-types.ts","../src/types/webhooks/message-edits.ts","../src/types/webhooks/message-reactions.ts","../src/types/webhooks/message-reads.ts","../src/types/webhooks/messaging-postbacks.ts","../src/types/webhooks/messaging-feedback.ts","../src/types/webhooks/feed.ts","../src/types/webhooks/videos.ts","../src/types/webhooks/live-videos.ts","../src/types/webhooks/messages.ts","../src/types/webhooks/webhook-events.ts"],"names":["DEFAULT_API_VERSION","BASE_URL","API_ENDPOINTS","MESSAGE_LIMITS","ATTACHMENT_LIMITS","TEMPLATE_LIMITS","MessengerAPIError","error","statusCode","response","MessengerNetworkError","message","cause","MessengerTimeoutError","timeout","MessengerConfigError","HTTPClient","config","options","url","lastError","attempt","path","query","accessTokenOverride","accessToken","key","value","controller","timeoutId","fetchOptions","isJson","errorData","text","ms","resolve","MessageValidationError","validateTextMessage","SendAPI","httpClient","request","recipientId","action","body","state","content","messageId","apiOptions","AttachmentsAPI","ModerationAPI","userIds","user_ids","id","TemplateValidationError","validateGenericTemplate","elements","element","index","validateGenericElement","isHttpsUrl","validateButtons","validateButtonTemplate","buttons","validateMediaTemplate","context","button","validateButton","TemplatesAPI","payload","ProfileAPI","psid","fields","queryParams","ConversationsAPI","pageId","params","conversationId","messagePromises","msg","userId","platform","Messenger","clientConfig","WebhookEventType","hasUserId","sender","extractEvents","events","entry","extractPageEvents","extractBaseContext","event","isIdentifiedUser","getPageWebhookEventTypes","eventTypes","change","isMessageEditEvent","extractMessageEditContext","MESSAGE_EDIT_CONSTANTS","MessageReactionType","MessageReactionAction","isMessageReadsEvent","extractMessageReadsContext","isMessageRead","messageTimestamp","watermark","getReadMessages","messages","getReadMessageCount","MESSAGE_READS_CONSTANTS","isMessagingPostbackEvent","hasReferralData","isIdentifiedSender","extractPostbackContext","isReferred","COMMON_POSTBACK_PAYLOADS","POSTBACK_CONSTANTS","FeedbackType","CSATDisplayOption","NPSDisplayOption","CESDisplayOption","FollowUpType","isMessagingFeedbackEvent","extractMessagingFeedbackContext","allResponses","screen","questionId","question","getFeedbackScoresByType","scoresByType","score","existingScores","extractTextFeedback","textFeedback","MESSAGING_FEEDBACK_CONSTANTS","isValidFeedbackScore","feedbackType","range","isValidQuestionId","isValidTextFeedback","FeedItemType","FeedActionVerb","isFeedEvent","isPostCreated","isComment","isPhoto","isVideo","isReaction","hasMessage","extractFeedContext","timestamp","extractPhotos","photos","FEED_CONSTANTS","VideoStatus","isVideoEvent","isProcessing","isReady","hasError","extractVideoContext","isCompletingEncoding","fromStatus","toStatus","isEncodingFailed","VIDEO_CONSTANTS","LiveVideoStatus","isLiveVideoEvent","isLive","isScheduled","hasEnded","isVODReady","extractLiveVideoContext","isGoingLive","isEndingLive","LIVE_VIDEO_CONSTANTS","AttachmentType","ReferralType","ReferralSource","isMessageEvent","isTextMessage","hasAttachments","hasQuickReply","isReplyMessage","hasReferral","isAttachmentType","attachment","type","extractMessageContext","getAttachmentsByType","getAttachmentUrls","MESSAGE_CONSTANTS","ATTACHMENT_MIME_TYPES","getWebhookEventType","getWebhookPayloadEventTypes","extractWebhookEvents","addDiscriminator","processWebhookEvents","handlers","rawEvent","exhaustiveCheck","verifyWebhookSubscription","verifyToken","verifyWebhookSignature","rawBody","signature","appSecret","crypto","receivedHash","expectedSignature","receivedBuffer","expectedBuffer","isValid"],"mappings":"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","file":"index.cjs","sourcesContent":["export const DEFAULT_API_VERSION = 'v23.0';\nexport const BASE_URL = 'https://graph.facebook.com';\nexport const DEFAULT_TIMEOUT = 30000; // 30 seconds\nexport const MAX_RETRY_ATTEMPTS = 3;\nexport const RETRY_DELAY_MS = 1000;\n\nexport const API_ENDPOINTS = {\n  MESSAGES: '/me/messages',\n  MESSAGE_ATTACHMENTS: '/me/message_attachments',\n  MODERATE_CONVERSATIONS: '/me/moderate_conversations',\n  USER_PROFILE: '', // Dynamic endpoint: /{PSID}\n} as const;\n\n// Validation constants\nexport const MESSAGE_LIMITS = {\n  // Text messages\n  TEXT_MESSAGE_MAX_CHARS: 2000,\n} as const;\n\nexport const ATTACHMENT_LIMITS = {\n  // File size limits in bytes\n  IMAGE_MAX_SIZE: 8 * 1024 * 1024, // 8MB\n  OTHER_MAX_SIZE: 25 * 1024 * 1024, // 25MB (video, audio, file)\n  \n  // Timeout limits in seconds\n  VIDEO_TIMEOUT: 75,\n  OTHER_TIMEOUT: 10,\n} as const;\n\nexport const TEMPLATE_LIMITS = {\n  // Generic Template\n  GENERIC_ELEMENTS_MAX: 10,\n  GENERIC_TITLE_MAX_CHARS: 80,\n  GENERIC_SUBTITLE_MAX_CHARS: 80,\n  \n  // Button Template  \n  BUTTON_TEXT_MAX_CHARS: 640,\n  BUTTONS_MAX_COUNT: 3,\n  BUTTON_TITLE_MAX_CHARS: 20,\n  \n  // All Templates\n  POSTBACK_PAYLOAD_MAX_CHARS: 1000,\n  \n  // Media Template\n  MEDIA_ELEMENTS_COUNT: 1, // Exactly 1 element required\n  MEDIA_BUTTONS_MAX_COUNT: 3,\n} as const;","import type { MessengerError } from '../types/responses.js';\n\nexport class MessengerAPIError extends Error {\n  public readonly code: number;\n  public readonly type: string;\n  public readonly subcode?: number;\n  public readonly fbtrace_id?: string;\n  public readonly statusCode: number;\n  public readonly response?: any;\n\n  constructor(error: MessengerError, statusCode: number, response?: any) {\n    super(error.message);\n    this.name = 'MessengerAPIError';\n    this.code = error.code;\n    this.type = error.type;\n    this.subcode = error.error_subcode;\n    this.fbtrace_id = error.fbtrace_id;\n    this.statusCode = statusCode;\n    this.response = response;\n  }\n}\n\nexport class MessengerNetworkError extends Error {\n  public readonly cause?: Error;\n\n  constructor(message: string, cause?: Error) {\n    super(message);\n    this.name = 'MessengerNetworkError';\n    this.cause = cause;\n  }\n}\n\nexport class MessengerTimeoutError extends Error {\n  public readonly timeout: number;\n\n  constructor(timeout: number) {\n    super(`Request timed out after ${timeout}ms`);\n    this.name = 'MessengerTimeoutError';\n    this.timeout = timeout;\n  }\n}\n\nexport class MessengerConfigError extends Error {\n  constructor(message: string) {\n    super(message);\n    this.name = 'MessengerConfigError';\n  }\n}","import { BASE_URL, DEFAULT_TIMEOUT, MAX_RETRY_ATTEMPTS, RETRY_DELAY_MS } from './constants.js';\nimport { MessengerAPIError, MessengerNetworkError, MessengerTimeoutError } from './errors.js';\nimport type { ErrorResponse } from '../types/responses.js';\n\nexport interface ClientConfig {\n  accessToken?: string;\n  version: string;\n  baseUrl?: string;\n  timeout?: number;\n  maxRetries?: number;\n}\n\nexport interface APIOptions {\n  accessToken?: string;\n}\n\nexport interface RequestOptions {\n  method: 'GET' | 'POST' | 'DELETE';\n  path: string;\n  body?: any;\n  query?: Record<string, string | number | boolean>;\n  accessToken?: string;\n}\n\nexport class HTTPClient {\n  private readonly config: Required<Omit<ClientConfig, 'accessToken'>> & { accessToken?: string };\n\n  constructor(config: ClientConfig) {\n    this.config = {\n      accessToken: config.accessToken,\n      version: config.version,\n      baseUrl: config.baseUrl || BASE_URL,\n      timeout: config.timeout || DEFAULT_TIMEOUT,\n      maxRetries: config.maxRetries || MAX_RETRY_ATTEMPTS,\n    };\n  }\n\n  async request<T>(options: RequestOptions): Promise<T> {\n    const url = this.buildUrl(options.path, options.query, options.accessToken);\n    let lastError: Error | undefined;\n\n    for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n      try {\n        const response = await this.makeRequest(url, options);\n        return await this.handleResponse<T>(response);\n      } catch (error) {\n        lastError = error as Error;\n\n        // Don't retry on client errors (4xx)\n        if (\n          error instanceof MessengerAPIError &&\n          error.statusCode >= 400 &&\n          error.statusCode < 500\n        ) {\n          throw error;\n        }\n\n        // Don't retry on timeout for the last attempt\n        if (attempt === this.config.maxRetries) {\n          throw error;\n        }\n\n        // Wait before retrying\n        await this.delay(RETRY_DELAY_MS * (attempt + 1));\n      }\n    }\n\n    throw lastError || new Error('Unknown error occurred');\n  }\n\n  private buildUrl(\n    path: string,\n    query?: Record<string, string | number | boolean>,\n    accessTokenOverride?: string,\n  ): string {\n    const url = new URL(`${this.config.baseUrl}/${this.config.version}${path}`);\n\n    // Use override token if provided, otherwise use config token\n    const accessToken = accessTokenOverride || this.config.accessToken;\n\n    if (!accessToken) {\n      throw new Error('Access token is required. Provide it in constructor or method options.');\n    }\n\n    url.searchParams.append('access_token', accessToken);\n\n    // Add additional query parameters\n    if (query) {\n      Object.entries(query).forEach(([key, value]) => {\n        url.searchParams.append(key, String(value));\n      });\n    }\n\n    return url.toString();\n  }\n\n  private async makeRequest(url: string, options: RequestOptions): Promise<Response> {\n    const controller = new AbortController();\n    const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n    try {\n      const fetchOptions: RequestInit = {\n        method: options.method,\n        headers: {\n          'Content-Type': 'application/json',\n        },\n        signal: controller.signal,\n      };\n\n      if (options.body) {\n        fetchOptions.body = JSON.stringify(options.body);\n      }\n\n      const response = await fetch(url, fetchOptions);\n      return response;\n    } catch (error) {\n      if (error instanceof Error) {\n        if (error.name === 'AbortError') {\n          throw new MessengerTimeoutError(this.config.timeout);\n        }\n        throw new MessengerNetworkError(`Network request failed: ${error.message}`, error);\n      }\n      throw error;\n    } finally {\n      clearTimeout(timeoutId);\n    }\n  }\n\n  private async handleResponse<T>(response: Response): Promise<T> {\n    const contentType = response.headers.get('content-type');\n    const isJson = contentType?.includes('application/json');\n\n    if (!response.ok) {\n      if (isJson) {\n        const errorData = (await response.json()) as ErrorResponse;\n        throw new MessengerAPIError(errorData.error, response.status, errorData);\n      } else {\n        const text = await response.text();\n        throw new MessengerAPIError(\n          {\n            message: text || `HTTP ${response.status} ${response.statusText}`,\n            type: 'http_error',\n            code: response.status,\n            fbtrace_id: '',\n          },\n          response.status,\n          text,\n        );\n      }\n    }\n\n    if (isJson) {\n      return (await response.json()) as T;\n    }\n\n    // For non-JSON responses, return the text\n    return (await response.text()) as unknown as T;\n  }\n\n  private delay(ms: number): Promise<void> {\n    return new Promise((resolve) => setTimeout(resolve, ms));\n  }\n}\n","import { MESSAGE_LIMITS } from '../core/constants.js';\n\nexport class MessageValidationError extends Error {\n  constructor(message: string) {\n    super(message);\n    this.name = 'MessageValidationError';\n  }\n}\n\nexport function validateTextMessage(text: string): void {\n  if (!text || text.trim() === '') {\n    throw new MessageValidationError('Text message cannot be empty');\n  }\n\n  if (text.length > MESSAGE_LIMITS.TEXT_MESSAGE_MAX_CHARS) {\n    throw new MessageValidationError(\n      `Text message cannot exceed ${MESSAGE_LIMITS.TEXT_MESSAGE_MAX_CHARS} characters`\n    );\n  }\n}","import type { HTTPClient, APIOptions } from '../core/http-client.js';\nimport { API_ENDPOINTS } from '../core/constants.js';\nimport type { SendMessageRequest, SenderAction, Recipient, ReactionPayload } from '../types/messages.js';\nimport type { SendMessageResponse } from '../types/responses.js';\nimport type { AttachmentType } from '../types/attachments.js';\nimport { validateTextMessage } from '../utils/message-validators.js';\n\nexport class SendAPI {\n  constructor(private httpClient: HTTPClient) { }\n\n  async message(request: SendMessageRequest, options?: APIOptions): Promise<SendMessageResponse> {\n    // Validate text message length if present\n    if (request.message?.text) {\n      validateTextMessage(request.message.text);\n    }\n\n    return this.httpClient.request<SendMessageResponse>({\n      method: 'POST',\n      path: API_ENDPOINTS.MESSAGES,\n      body: request,\n      accessToken: options?.accessToken,\n    });\n  }\n\n  async action(recipientId: string, action: SenderAction, options?: APIOptions & { payload?: ReactionPayload }): Promise<SendMessageResponse> {\n    const body: any = {\n      recipient: { id: recipientId },\n      messaging_type: 'RESPONSE',\n      sender_action: action,\n    };\n\n    if (options?.payload) {\n      body.payload = options.payload;\n    }\n\n    return this.httpClient.request<SendMessageResponse>({\n      method: 'POST',\n      path: API_ENDPOINTS.MESSAGES,\n      body,\n      accessToken: options?.accessToken,\n    });\n  }\n\n  async typingOn(recipientId: string, options?: APIOptions): Promise<SendMessageResponse> {\n    return this.action(recipientId, 'typing_on', options);\n  }\n\n  async typingOff(recipientId: string, options?: APIOptions): Promise<SendMessageResponse> {\n    return this.action(recipientId, 'typing_off', options);\n  }\n\n  async markSeen(recipientId: string, options?: APIOptions): Promise<SendMessageResponse> {\n    return this.action(recipientId, 'mark_seen', options);\n  }\n\n  async setTyping(recipientId: string, state: boolean, options?: APIOptions): Promise<SendMessageResponse> {\n    return state ? this.typingOn(recipientId, options) : this.typingOff(recipientId, options);\n  }\n\n  async markRead(recipientId: string, options?: APIOptions): Promise<SendMessageResponse> {\n    return this.markSeen(recipientId, options);\n  }\n\n  async addReaction(recipientId: string, content: { messageId: string, emoji: string }, options?: APIOptions): Promise<SendMessageResponse> {\n    return this.action(recipientId, 'react', {\n      ...options,\n      payload: {\n        message_id: content.messageId,\n        reaction: content.emoji\n      }\n    });\n  }\n\n  async removeReaction(recipientId: string, messageId: string, options?: APIOptions): Promise<SendMessageResponse> {\n    return this.action(recipientId, 'unreact', {\n      ...options,\n      payload: {\n        message_id: messageId\n      }\n    });\n  }\n\n  // Convenience methods for sending attachments\n\n  /**\n   * Send an attachment using a previously uploaded attachment_id\n   */\n  async attachment(options: {\n    recipient: Recipient;\n    type: AttachmentType;\n    attachment_id: string;\n    messaging_type?: 'RESPONSE' | 'UPDATE' | 'MESSAGE_TAG';\n  }, apiOptions?: APIOptions): Promise<SendMessageResponse> {\n    return this.message({\n      recipient: options.recipient,\n      messaging_type: options.messaging_type ?? 'RESPONSE',\n      message: {\n        attachment: {\n          type: options.type,\n          payload: {\n            attachment_id: options.attachment_id,\n          },\n        },\n      },\n    }, apiOptions);\n  }\n\n  /**\n   * Upload and send an attachment from URL in a single request\n   */\n  async attachmentFromUrl(options: {\n    recipient: Recipient;\n    type: AttachmentType;\n    url: string;\n    messaging_type?: 'RESPONSE' | 'UPDATE' | 'MESSAGE_TAG';\n  }, apiOptions?: APIOptions): Promise<SendMessageResponse> {\n    return this.message({\n      recipient: options.recipient,\n      messaging_type: options.messaging_type ?? 'RESPONSE',\n      message: {\n        attachment: {\n          type: options.type,\n          payload: {\n            url: options.url,\n          },\n        },\n      },\n    }, apiOptions);\n  }\n}","import type { HTTPClient, APIOptions } from '../core/http-client.js';\nimport { API_ENDPOINTS } from '../core/constants.js';\nimport type { AttachmentUploadRequest, AttachmentUploadResponse } from '../types/attachments.js';\n\nexport class AttachmentsAPI {\n  constructor(private httpClient: HTTPClient) {}\n\n  async upload(\n    request: AttachmentUploadRequest,\n    options?: APIOptions,\n  ): Promise<AttachmentUploadResponse> {\n    // Format according to official API - no message wrapper needed\n    const body = {\n      message: {\n        attachment: {\n          type: request.type,\n          payload: {\n            url: request.url,\n            is_reusable: request.is_reusable ?? true,\n          },\n        },\n      },\n    };\n\n    return this.httpClient.request<AttachmentUploadResponse>({\n      method: 'POST',\n      path: API_ENDPOINTS.MESSAGE_ATTACHMENTS,\n      body,\n      accessToken: options?.accessToken,\n    });\n  }\n}\n","import type { HTTPClient, APIOptions } from '../core/http-client.js';\nimport { API_ENDPOINTS } from '../core/constants.js';\nimport type { \n  ModerateConversationsRequest,\n  ModerateConversationsResponse\n} from '../types/moderation.js';\n\nexport class ModerationAPI {\n  constructor(private httpClient: HTTPClient) {}\n\n  /**\n   * Moderate conversations with specified actions\n   * Up to 10 user IDs and up to 2 actions per request\n   */\n  async moderate(request: ModerateConversationsRequest, options?: APIOptions): Promise<ModerateConversationsResponse> {\n    return this.httpClient.request<ModerateConversationsResponse>({\n      method: 'POST',\n      path: API_ENDPOINTS.MODERATE_CONVERSATIONS,\n      body: request,\n      accessToken: options?.accessToken,\n    });\n  }\n\n  /**\n   * Block a user from messaging the page\n   * Prevents messaging but user can still interact with page content on Facebook\n   */\n  async blockUser(userIds: string | string[], options?: APIOptions): Promise<ModerateConversationsResponse> {\n    const user_ids = Array.isArray(userIds) \n      ? userIds.map(id => ({ id }))\n      : [{ id: userIds }];\n\n    return this.moderate({\n      user_ids,\n      actions: ['block_user'],\n    }, options);\n  }\n\n  /**\n   * Unblock a user to allow messaging again\n   */\n  async unblockUser(userIds: string | string[], options?: APIOptions): Promise<ModerateConversationsResponse> {\n    const user_ids = Array.isArray(userIds)\n      ? userIds.map(id => ({ id }))\n      : [{ id: userIds }];\n\n    return this.moderate({\n      user_ids,\n      actions: ['unblock_user'],\n    }, options);\n  }\n\n  /**\n   * Ban a user from both messaging and Facebook interactions\n   * More restrictive than blocking - prevents all interactions\n   * Note: Cannot ban user who was unbanned in last 48 hours\n   */\n  async banUser(userIds: string | string[], options?: APIOptions): Promise<ModerateConversationsResponse> {\n    const user_ids = Array.isArray(userIds)\n      ? userIds.map(id => ({ id }))\n      : [{ id: userIds }];\n\n    return this.moderate({\n      user_ids,\n      actions: ['ban_user'],\n    }, options);\n  }\n\n  /**\n   * Unban a user to restore all interactions\n   * Note: Banned user cannot be unblocked, they must be unbanned first\n   */\n  async unbanUser(userIds: string | string[], options?: APIOptions): Promise<ModerateConversationsResponse> {\n    const user_ids = Array.isArray(userIds)\n      ? userIds.map(id => ({ id }))\n      : [{ id: userIds }];\n\n    return this.moderate({\n      user_ids,\n      actions: ['unban_user'],\n    }, options);\n  }\n\n  /**\n   * Move conversation to spam folder in Meta Business Suite Inbox\n   */\n  async moveToSpam(userIds: string | string[], options?: APIOptions): Promise<ModerateConversationsResponse> {\n    const user_ids = Array.isArray(userIds)\n      ? userIds.map(id => ({ id }))\n      : [{ id: userIds }];\n\n    return this.moderate({\n      user_ids,\n      actions: ['move_to_spam'],\n    }, options);\n  }\n\n  /**\n   * Block user and move to spam (common moderation action)\n   */\n  async blockAndSpam(userIds: string | string[], options?: APIOptions): Promise<ModerateConversationsResponse> {\n    const user_ids = Array.isArray(userIds)\n      ? userIds.map(id => ({ id }))\n      : [{ id: userIds }];\n\n    return this.moderate({\n      user_ids,\n      actions: ['block_user', 'move_to_spam'],\n    }, options);\n  }\n}","import { TEMPLATE_LIMITS } from '../core/constants.js';\nimport type { Button, GenericTemplateElement, MediaTemplateElement } from '../types/templates.js';\n\nexport class TemplateValidationError extends Error {\n  constructor(message: string) {\n    super(message);\n    this.name = 'TemplateValidationError';\n  }\n}\n\nexport function validateGenericTemplate(elements: GenericTemplateElement[]): void {\n  if (elements.length === 0) {\n    throw new TemplateValidationError('Generic template must have at least 1 element');\n  }\n\n  if (elements.length > TEMPLATE_LIMITS.GENERIC_ELEMENTS_MAX) {\n    throw new TemplateValidationError(\n      `Generic template cannot have more than ${TEMPLATE_LIMITS.GENERIC_ELEMENTS_MAX} elements`\n    );\n  }\n\n  elements.forEach((element, index) => {\n    validateGenericElement(element, index);\n  });\n}\n\nexport function validateGenericElement(element: GenericTemplateElement, index: number): void {\n  if (!element.title || element.title.trim() === '') {\n    throw new TemplateValidationError(`Element ${index}: title is required`);\n  }\n\n  if (element.title.length > TEMPLATE_LIMITS.GENERIC_TITLE_MAX_CHARS) {\n    throw new TemplateValidationError(\n      `Element ${index}: title cannot exceed ${TEMPLATE_LIMITS.GENERIC_TITLE_MAX_CHARS} characters`\n    );\n  }\n\n  if (element.subtitle && element.subtitle.length > TEMPLATE_LIMITS.GENERIC_SUBTITLE_MAX_CHARS) {\n    throw new TemplateValidationError(\n      `Element ${index}: subtitle cannot exceed ${TEMPLATE_LIMITS.GENERIC_SUBTITLE_MAX_CHARS} characters`\n    );\n  }\n\n  if (element.image_url && !isHttpsUrl(element.image_url)) {\n    throw new TemplateValidationError(`Element ${index}: image_url must be HTTPS`);\n  }\n\n  if (element.buttons) {\n    validateButtons(element.buttons, `Element ${index}`);\n  }\n\n  // Validate that element has at least one property beyond title\n  const hasAdditionalProperty = !!(\n    element.subtitle ||\n    element.image_url ||\n    element.default_action ||\n    (element.buttons && element.buttons.length > 0)\n  );\n\n  if (!hasAdditionalProperty) {\n    throw new TemplateValidationError(\n      `Element ${index}: must have at least one additional property beyond title`\n    );\n  }\n}\n\nexport function validateButtonTemplate(text: string, buttons: Button[]): void {\n  if (!text || text.trim() === '') {\n    throw new TemplateValidationError('Button template text is required');\n  }\n\n  if (text.length > TEMPLATE_LIMITS.BUTTON_TEXT_MAX_CHARS) {\n    throw new TemplateValidationError(\n      `Button template text cannot exceed ${TEMPLATE_LIMITS.BUTTON_TEXT_MAX_CHARS} characters`\n    );\n  }\n\n  if (buttons.length === 0) {\n    throw new TemplateValidationError('Button template must have at least 1 button');\n  }\n\n  validateButtons(buttons, 'Button template');\n}\n\nexport function validateMediaTemplate(element: MediaTemplateElement): void {\n  if (!element.media_type) {\n    throw new TemplateValidationError('Media template element must have media_type');\n  }\n\n  if (!element.url && !element.attachment_id) {\n    throw new TemplateValidationError('Media template element must have either url or attachment_id');\n  }\n\n  if (element.url && element.attachment_id) {\n    throw new TemplateValidationError(\n      'Media template element cannot have both url and attachment_id'\n    );\n  }\n\n  if (element.url && !isHttpsUrl(element.url)) {\n    throw new TemplateValidationError('Media template url must be HTTPS');\n  }\n\n  if (element.buttons) {\n    if (element.buttons.length > TEMPLATE_LIMITS.MEDIA_BUTTONS_MAX_COUNT) {\n      throw new TemplateValidationError(\n        `Media template cannot have more than ${TEMPLATE_LIMITS.MEDIA_BUTTONS_MAX_COUNT} buttons`\n      );\n    }\n    validateButtons(element.buttons, 'Media template');\n  }\n}\n\nexport function validateButtons(buttons: Button[], context: string): void {\n  if (buttons.length > TEMPLATE_LIMITS.BUTTONS_MAX_COUNT) {\n    throw new TemplateValidationError(\n      `${context} cannot have more than ${TEMPLATE_LIMITS.BUTTONS_MAX_COUNT} buttons`\n    );\n  }\n\n  buttons.forEach((button, index) => {\n    validateButton(button, `${context} button ${index}`);\n  });\n}\n\nexport function validateButton(button: Button, context: string): void {\n  if (!button.type) {\n    throw new TemplateValidationError(`${context}: type is required`);\n  }\n\n  // Title is required for most button types (not for account_unlink)\n  if (button.type !== 'account_unlink' && (!button.title || button.title.trim() === '')) {\n    throw new TemplateValidationError(`${context}: title is required for ${button.type} buttons`);\n  }\n\n  if (button.title && button.title.length > TEMPLATE_LIMITS.BUTTON_TITLE_MAX_CHARS) {\n    throw new TemplateValidationError(\n      `${context}: title cannot exceed ${TEMPLATE_LIMITS.BUTTON_TITLE_MAX_CHARS} characters`\n    );\n  }\n\n  // Type-specific validations\n  switch (button.type) {\n    case 'web_url':\n      if (!button.url) {\n        throw new TemplateValidationError(`${context}: url is required for web_url buttons`);\n      }\n      if (!isHttpsUrl(button.url)) {\n        throw new TemplateValidationError(`${context}: url must be HTTPS for web_url buttons`);\n      }\n      break;\n\n    case 'postback':\n      if (!button.payload) {\n        throw new TemplateValidationError(`${context}: payload is required for postback buttons`);\n      }\n      if (button.payload.length > TEMPLATE_LIMITS.POSTBACK_PAYLOAD_MAX_CHARS) {\n        throw new TemplateValidationError(\n          `${context}: payload cannot exceed ${TEMPLATE_LIMITS.POSTBACK_PAYLOAD_MAX_CHARS} characters`\n        );\n      }\n      break;\n\n    case 'phone_number':\n      if (!button.payload) {\n        throw new TemplateValidationError(`${context}: payload is required for phone_number buttons`);\n      }\n      // Basic phone number validation (starts with +)\n      if (!button.payload.startsWith('+')) {\n        throw new TemplateValidationError(\n          `${context}: phone_number payload must start with + (e.g., +1234567890)`\n        );\n      }\n      break;\n\n    case 'game_play':\n      // game_play buttons may have optional game_metadata\n      break;\n\n    case 'account_link':\n      if (!button.url) {\n        throw new TemplateValidationError(`${context}: url is required for account_link buttons`);\n      }\n      if (!isHttpsUrl(button.url)) {\n        throw new TemplateValidationError(`${context}: url must be HTTPS for account_link buttons`);\n      }\n      break;\n\n    case 'account_unlink':\n      // account_unlink buttons don't require additional properties\n      break;\n  }\n\n  // Validate webview properties for web_url buttons\n  if (button.type === 'web_url' && button.messenger_extensions && button.fallback_url) {\n    if (!isHttpsUrl(button.fallback_url)) {\n      throw new TemplateValidationError(`${context}: fallback_url must be HTTPS`);\n    }\n  }\n}\n\nfunction isHttpsUrl(url: string): boolean {\n  try {\n    const parsedUrl = new URL(url);\n    return parsedUrl.protocol === 'https:';\n  } catch {\n    return false;\n  }\n}","import type { HTTPClient, APIOptions } from '../core/http-client.js';\nimport { API_ENDPOINTS } from '../core/constants.js';\nimport type { Recipient, SendMessageRequest, MessagingType } from '../types/messages.js';\nimport type { SendMessageResponse } from '../types/responses.js';\nimport { validateGenericTemplate, validateButtonTemplate, validateMediaTemplate } from '../utils/validators.js';\nimport type {\n  GenericTemplatePayload,\n  ButtonTemplatePayload,\n  MediaTemplatePayload,\n  ProductTemplatePayload,\n  GenericTemplateElement,\n  Button,\n  MediaTemplateElement,\n  ProductTemplateElement,\n} from '../types/templates.js';\n\nexport class TemplatesAPI {\n  constructor(private httpClient: HTTPClient) {}\n\n  async generic(options: {\n    recipient: Recipient;\n    elements: GenericTemplateElement[];\n    messaging_type?: MessagingType;\n    image_aspect_ratio?: 'horizontal' | 'square';\n    notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';\n    tag?: string;\n  }, apiOptions?: APIOptions): Promise<SendMessageResponse> {\n    // Validate template\n    validateGenericTemplate(options.elements);\n\n    const payload: GenericTemplatePayload = {\n      template_type: 'generic',\n      elements: options.elements,\n      image_aspect_ratio: options.image_aspect_ratio,\n    };\n\n    const request: SendMessageRequest = {\n      recipient: options.recipient,\n      messaging_type: options.messaging_type || 'UPDATE',\n      message: {\n        attachment: {\n          type: 'template',\n          payload,\n        },\n      },\n      notification_type: options.notification_type,\n      tag: options.tag,\n    };\n\n    return this.httpClient.request<SendMessageResponse>({\n      method: 'POST',\n      path: API_ENDPOINTS.MESSAGES,\n      body: request,\n      accessToken: apiOptions?.accessToken,\n    });\n  }\n\n  async button(options: {\n    recipient: Recipient;\n    text: string;\n    buttons: Button[];\n    messaging_type?: MessagingType;\n    notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';\n    tag?: string;\n  }, apiOptions?: APIOptions): Promise<SendMessageResponse> {\n    // Validate template\n    validateButtonTemplate(options.text, options.buttons);\n\n    const payload: ButtonTemplatePayload = {\n      template_type: 'button',\n      text: options.text,\n      buttons: options.buttons,\n    };\n\n    const request: SendMessageRequest = {\n      recipient: options.recipient,\n      messaging_type: options.messaging_type || 'UPDATE',\n      message: {\n        attachment: {\n          type: 'template',\n          payload,\n        },\n      },\n      notification_type: options.notification_type,\n      tag: options.tag,\n    };\n\n    return this.httpClient.request<SendMessageResponse>({\n      method: 'POST',\n      path: API_ENDPOINTS.MESSAGES,\n      body: request,\n      accessToken: apiOptions?.accessToken,\n    });\n  }\n\n  async media(options: {\n    recipient: Recipient;\n    element: MediaTemplateElement;\n    messaging_type?: MessagingType;\n    notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';\n    tag?: string;\n  }, apiOptions?: APIOptions): Promise<SendMessageResponse> {\n    // Validate template\n    validateMediaTemplate(options.element);\n\n    const payload: MediaTemplatePayload = {\n      template_type: 'media',\n      elements: [options.element],\n    };\n\n    const request: SendMessageRequest = {\n      recipient: options.recipient,\n      messaging_type: options.messaging_type || 'UPDATE',\n      message: {\n        attachment: {\n          type: 'template',\n          payload,\n        },\n      },\n      notification_type: options.notification_type,\n      tag: options.tag,\n    };\n\n    return this.httpClient.request<SendMessageResponse>({\n      method: 'POST',\n      path: API_ENDPOINTS.MESSAGES,\n      body: request,\n      accessToken: apiOptions?.accessToken,\n    });\n  }\n\n  async product(options: {\n    recipient: Recipient;\n    elements: ProductTemplateElement[];\n    messaging_type?: MessagingType;\n    notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';\n    tag?: string;\n  }, apiOptions?: APIOptions): Promise<SendMessageResponse> {\n    const payload: ProductTemplatePayload = {\n      template_type: 'product',\n      elements: options.elements,\n    };\n\n    const request: SendMessageRequest = {\n      recipient: options.recipient,\n      messaging_type: options.messaging_type || 'UPDATE',\n      message: {\n        attachment: {\n          type: 'template',\n          payload,\n        },\n      },\n      notification_type: options.notification_type,\n      tag: options.tag,\n    };\n\n    return this.httpClient.request<SendMessageResponse>({\n      method: 'POST',\n      path: API_ENDPOINTS.MESSAGES,\n      body: request,\n      accessToken: apiOptions?.accessToken,\n    });\n  }\n}","import type { HTTPClient, APIOptions } from '../core/http-client.js';\nimport type { \n  GetProfileRequest,\n  UserProfile\n} from '../types/profile.js';\n\nexport class ProfileAPI {\n  constructor(private httpClient: HTTPClient) {}\n\n  /**\n   * Get user profile information using PSID\n   * Requires \"Advanced User Profile Access\" feature\n   */\n  async get(request: GetProfileRequest, options?: APIOptions): Promise<UserProfile> {\n    const { psid, fields = ['first_name', 'last_name'] } = request;\n    \n    const queryParams = new URLSearchParams({\n      fields: fields.join(','),\n    });\n\n    return this.httpClient.request<UserProfile>({\n      method: 'GET',\n      path: `/${psid}?${queryParams.toString()}`,\n      body: undefined,\n      accessToken: options?.accessToken,\n    });\n  }\n\n  /**\n   * Get user profile with default fields (first_name, last_name, profile_pic)\n   */\n  async getBasic(psid: string, options?: APIOptions): Promise<UserProfile> {\n    return this.get({\n      psid,\n      fields: ['first_name', 'last_name', 'profile_pic'],\n    }, options);\n  }\n\n  /**\n   * Get comprehensive user profile with all available fields\n   */\n  async getFull(psid: string, options?: APIOptions): Promise<UserProfile> {\n    return this.get({\n      psid,\n      fields: ['id', 'name', 'first_name', 'last_name', 'profile_pic', 'locale', 'timezone', 'gender'],\n    }, options);\n  }\n\n  /**\n   * Get user's name (first_name and last_name)\n   */\n  async getName(psid: string, options?: APIOptions): Promise<UserProfile> {\n    return this.get({\n      psid,\n      fields: ['first_name', 'last_name'],\n    }, options);\n  }\n\n  /**\n   * Get user's profile picture URL\n   */\n  async getProfilePicture(psid: string, options?: APIOptions): Promise<UserProfile> {\n    return this.get({\n      psid,\n      fields: ['profile_pic'],\n    }, options);\n  }\n}","/**\n * Conversations API Resource\n *\n * Handles retrieving conversations and messages between users and Pages/Instagram Business accounts.\n *\n * @see https://developers.facebook.com/docs/messenger-platform/conversations\n */\n\nimport type { HTTPClient, APIOptions } from '../core/http-client.js';\nimport { MessengerConfigError } from '../core/errors.js';\nimport type {\n  ListConversationsParams,\n  ListConversationsResponse,\n  GetConversationParams,\n  ConversationDetail,\n  GetMessageParams,\n  Message,\n  ListMessagesResponse,\n} from '../types/conversations.js';\n\n/**\n * Conversations API class for retrieving conversation and message data\n *\n * @example\n * ```typescript\n * const messenger = new Messenger({ accessToken: 'PAGE_TOKEN' });\n *\n * // List all conversations\n * const conversations = await messenger.conversations.list('PAGE_ID', {\n *   platform: 'messenger'\n * });\n *\n * // Get conversation details\n * const conversation = await messenger.conversations.get('CONVERSATION_ID');\n *\n * // Get message details\n * const message = await messenger.conversations.getMessage('MESSAGE_ID');\n * ```\n */\nexport class ConversationsAPI {\n  constructor(private httpClient: HTTPClient) {}\n\n  /**\n   * Get a list of conversations for a Page or Instagram Business Account\n   *\n   * @param pageId - The Page ID or Instagram Business Account ID\n   * @param params - Optional parameters for filtering and pagination\n   * @param options - Optional request options (e.g., token override)\n   * @returns List of conversations\n   *\n   * @example\n   * ```typescript\n   * // List Messenger conversations\n   * const conversations = await messenger.conversations.list('PAGE_ID', {\n   *   platform: 'messenger',\n   *   limit: 25\n   * });\n   *\n   * // Find conversation with specific user\n   * const userConvos = await messenger.conversations.list('PAGE_ID', {\n   *   platform: 'instagram',\n   *   user_id: 'USER_INSTAGRAM_SCOPED_ID'\n   * });\n   *\n   * // Paginate through conversations\n   * const nextPage = await messenger.conversations.list('PAGE_ID', {\n   *   platform: 'messenger',\n   *   after: conversations.paging?.cursors?.after\n   * });\n   * ```\n   */\n  async list(\n    pageId: string,\n    params?: ListConversationsParams,\n    options?: APIOptions\n  ): Promise<ListConversationsResponse> {\n    if (!pageId) {\n      throw new MessengerConfigError('Page ID is required');\n    }\n\n    const queryParams: Record<string, string> = {};\n\n    if (params?.platform) {\n      queryParams.platform = params.platform;\n    }\n\n    if (params?.user_id) {\n      queryParams.user_id = params.user_id;\n    }\n\n    if (params?.folder) {\n      queryParams.folder = params.folder;\n    }\n\n    if (params?.limit) {\n      queryParams.limit = params.limit.toString();\n    }\n\n    if (params?.after) {\n      queryParams.after = params.after;\n    }\n\n    if (params?.before) {\n      queryParams.before = params.before;\n    }\n\n    return this.httpClient.request<ListConversationsResponse>({\n      method: 'GET',\n      path: `/${pageId}/conversations`,\n      query: queryParams,\n      accessToken: options?.accessToken,\n    });\n  }\n\n  /**\n   * Get details about a specific conversation\n   *\n   * @param conversationId - The conversation ID\n   * @param params - Optional parameters for fields and pagination\n   * @param options - Optional request options (e.g., token override)\n   * @returns Conversation details\n   *\n   * @example\n   * ```typescript\n   * // Get conversation with messages\n   * const conversation = await messenger.conversations.get('CONVERSATION_ID', {\n   *   fields: ['messages', 'participants']\n   * });\n   *\n   * // Get only participants\n   * const participants = await messenger.conversations.get('CONVERSATION_ID', {\n   *   fields: ['participants']\n   * });\n   * ```\n   */\n  async get(\n    conversationId: string,\n    params?: GetConversationParams,\n    options?: APIOptions\n  ): Promise<ConversationDetail> {\n    if (!conversationId) {\n      throw new MessengerConfigError('Conversation ID is required');\n    }\n\n    const queryParams: Record<string, string> = {};\n\n    if (params?.fields && params.fields.length > 0) {\n      queryParams.fields = params.fields.join(',');\n    }\n\n    if (params?.limit) {\n      queryParams.limit = params.limit.toString();\n    }\n\n    if (params?.after) {\n      queryParams.after = params.after;\n    }\n\n    if (params?.before) {\n      queryParams.before = params.before;\n    }\n\n    return this.httpClient.request<ConversationDetail>({\n      method: 'GET',\n      path: `/${conversationId}`,\n      query: queryParams,\n      accessToken: options?.accessToken,\n    });\n  }\n\n  /**\n   * Get messages in a conversation\n   *\n   * @param conversationId - The conversation ID\n   * @param params - Optional parameters for pagination\n   * @param options - Optional request options (e.g., token override)\n   * @returns List of messages\n   *\n   * @example\n   * ```typescript\n   * // Get messages in a conversation\n   * const messages = await messenger.conversations.getMessages('CONVERSATION_ID', {\n   *   limit: 20\n   * });\n   *\n   * // Paginate through messages\n   * const nextPage = await messenger.conversations.getMessages('CONVERSATION_ID', {\n   *   after: messages.paging?.cursors?.after\n   * });\n   * ```\n   */\n  async getMessages(\n    conversationId: string,\n    params?: { limit?: number; after?: string; before?: string },\n    options?: APIOptions\n  ): Promise<ListMessagesResponse> {\n    if (!conversationId) {\n      throw new MessengerConfigError('Conversation ID is required');\n    }\n\n    const queryParams: Record<string, string> = {\n      fields: 'messages',\n    };\n\n    if (params?.limit) {\n      queryParams.limit = params.limit.toString();\n    }\n\n    if (params?.after) {\n      queryParams.after = params.after;\n    }\n\n    if (params?.before) {\n      queryParams.before = params.before;\n    }\n\n    const response = await this.httpClient.request<ConversationDetail>({\n      method: 'GET',\n      path: `/${conversationId}`,\n      query: queryParams,\n      accessToken: options?.accessToken,\n    });\n\n    return {\n      data: response.messages?.data || [],\n      paging: response.messages?.paging,\n    };\n  }\n\n  /**\n   * Get details about a specific message\n   *\n   * Note: You can only retrieve details for the 20 most recent messages in a conversation.\n   * Older messages will return an error indicating the message was deleted.\n   *\n   * @param messageId - The message ID\n   * @param params - Optional parameters for fields to retrieve\n   * @param options - Optional request options (e.g., token override)\n   * @returns Message details\n   *\n   * @example\n   * ```typescript\n   * // Get full message details\n   * const message = await messenger.conversations.getMessage('MESSAGE_ID', {\n   *   fields: ['id', 'created_time', 'from', 'to', 'message', 'attachments', 'reactions']\n   * });\n   *\n   * // Get basic message info\n   * const basicMessage = await messenger.conversations.getMessage('MESSAGE_ID');\n   * ```\n   */\n  async getMessage(\n    messageId: string,\n    params?: GetMessageParams,\n    options?: APIOptions\n  ): Promise<Message> {\n    if (!messageId) {\n      throw new MessengerConfigError('Message ID is required');\n    }\n\n    const queryParams: Record<string, string> = {};\n\n    if (params?.fields && params.fields.length > 0) {\n      queryParams.fields = params.fields.join(',');\n    } else {\n      // Default fields for message details\n      queryParams.fields = 'id,created_time,from,to,message,attachments,reactions,reply_to';\n    }\n\n    return this.httpClient.request<Message>({\n      method: 'GET',\n      path: `/${messageId}`,\n      query: queryParams,\n      accessToken: options?.accessToken,\n    });\n  }\n\n  /**\n   * Get the 20 most recent messages in a conversation with full details\n   *\n   * This is a convenience method that retrieves message IDs and then fetches\n   * full details for each message. Note that only the 20 most recent messages\n   * can have their details retrieved.\n   *\n   * @param conversationId - The conversation ID\n   * @param options - Optional request options (e.g., token override)\n   * @returns Array of detailed messages\n   *\n   * @example\n   * ```typescript\n   * // Get recent messages with full details\n   * const messages = await messenger.conversations.getRecentMessages('CONVERSATION_ID');\n   *\n   * for (const message of messages) {\n   *   console.log(`${message.from?.username}: ${message.message}`);\n   * }\n   * ```\n   */\n  async getRecentMessages(\n    conversationId: string,\n    options?: APIOptions\n  ): Promise<Message[]> {\n    // First, get the list of message IDs (limited to 20)\n    const messagesList = await this.getMessages(\n      conversationId,\n      { limit: 20 },\n      options\n    );\n\n    // Then fetch details for each message\n    const messagePromises = messagesList.data.map((msg) =>\n      this.getMessage(msg.id, undefined, options)\n    );\n\n    return Promise.all(messagePromises);\n  }\n\n  /**\n   * Find a conversation between a Page and a specific user\n   *\n   * This is a convenience method that finds a conversation with a specific user.\n   *\n   * @param pageId - The Page ID or Instagram Business Account ID\n   * @param userId - The user's Instagram-scoped ID or Page-scoped ID\n   * @param platform - The platform ('instagram' or 'messenger')\n   * @param options - Optional request options (e.g., token override)\n   * @returns The conversation ID, or null if not found\n   *\n   * @example\n   * ```typescript\n   * // Find conversation with Instagram user\n   * const conversationId = await messenger.conversations.findByUser(\n   *   'PAGE_ID',\n   *   'USER_INSTAGRAM_SCOPED_ID',\n   *   'instagram'\n   * );\n   *\n   * if (conversationId) {\n   *   const messages = await messenger.conversations.getRecentMessages(conversationId);\n   * }\n   * ```\n   */\n  async findByUser(\n    pageId: string,\n    userId: string,\n    platform: 'instagram' | 'messenger',\n    options?: APIOptions\n  ): Promise<string | null> {\n    const response = await this.list(\n      pageId,\n      {\n        platform,\n        user_id: userId,\n      },\n      options\n    );\n\n    if (response.data && response.data.length > 0 && response.data[0]) {\n      return response.data[0].id;\n    }\n\n    return null;\n  }\n}\n","import { HTTPClient, type ClientConfig } from './core/http-client.js';\nimport { DEFAULT_API_VERSION } from './core/constants.js';\nimport { MessengerConfigError } from './core/errors.js';\nimport { SendAPI } from './resources/send.js';\nimport { AttachmentsAPI } from './resources/attachments.js';\nimport { ModerationAPI } from './resources/moderation.js';\nimport { TemplatesAPI } from './resources/templates.js';\nimport { ProfileAPI } from './resources/profile.js';\nimport { ConversationsAPI } from './resources/conversations.js';\n\nexport interface MessengerConfig {\n  accessToken?: string;\n  version?: string;\n  baseUrl?: string;\n  timeout?: number;\n  maxRetries?: number;\n}\n\nexport class Messenger {\n  public readonly send: SendAPI;\n  public readonly attachments: AttachmentsAPI;\n  public readonly moderation: ModerationAPI;\n  public readonly templates: TemplatesAPI;\n  public readonly profile: ProfileAPI;\n  public readonly conversations: ConversationsAPI;\n\n  private readonly httpClient: HTTPClient;\n\n  constructor(config: MessengerConfig = {}) {\n    this.validateConfig(config);\n\n    const clientConfig: ClientConfig = {\n      accessToken: config.accessToken,\n      version: config.version || DEFAULT_API_VERSION,\n      baseUrl: config.baseUrl,\n      timeout: config.timeout,\n      maxRetries: config.maxRetries,\n    };\n\n    this.httpClient = new HTTPClient(clientConfig);\n\n    // Initialize API resources\n    this.send = new SendAPI(this.httpClient);\n    this.attachments = new AttachmentsAPI(this.httpClient);\n    this.moderation = new ModerationAPI(this.httpClient);\n    this.templates = new TemplatesAPI(this.httpClient);\n    this.profile = new ProfileAPI(this.httpClient);\n    this.conversations = new ConversationsAPI(this.httpClient);\n  }\n\n  private validateConfig(config: MessengerConfig): void {\n    if (config.accessToken !== undefined) {\n      if (typeof config.accessToken !== 'string' || config.accessToken.trim() === '') {\n        throw new MessengerConfigError('Access token must be a non-empty string');\n      }\n    }\n\n    if (config.version && typeof config.version !== 'string') {\n      throw new MessengerConfigError('API version must be a string');\n    }\n\n    if (config.timeout && (typeof config.timeout !== 'number' || config.timeout <= 0)) {\n      throw new MessengerConfigError('Timeout must be a positive number');\n    }\n\n    if (config.maxRetries && (typeof config.maxRetries !== 'number' || config.maxRetries < 0)) {\n      throw new MessengerConfigError('Max retries must be a non-negative number');\n    }\n  }\n}","/**\n * Facebook Messenger Platform - Base Webhook Types\n * \n * This file contains the common base types and interfaces shared across\n * all webhook event types. It provides the foundation for a properly\n * structured type system with inheritance and discriminated unions.\n * \n * @module webhooks/base-types\n */\n\n/**\n * Common sender interface for all webhook events.\n * Represents the user who initiated the action.\n */\nexport interface WebhookSender {\n  /** \n   * Page-scoped ID (PSID) of the user.\n   * This is the unique identifier for the user within the context of your page.\n   */\n  id: string;\n  \n  /** \n   * User reference provided by the chat plugin, if applicable.\n   * Only present for chat plugin events where the user hasn't been identified yet.\n   */\n  user_ref?: string;\n}\n\n/**\n * Common recipient interface for all webhook events.\n * Represents the Facebook Page that received the event.\n */\nexport interface WebhookRecipient {\n  /** Facebook Page ID that received the event */\n  id: string;\n}\n\n/**\n * Base interface for all webhook events.\n * Contains the common properties shared by all event types.\n */\nexport interface BaseWebhookEvent {\n  /** Information about the user who initiated the event */\n  sender: WebhookSender;\n  \n  /** Information about the page that received the event */\n  recipient: WebhookRecipient;\n  \n  /** \n   * Unix timestamp when the event occurred (in milliseconds since epoch).\n   * Represents when the action was performed, not when the webhook was sent.\n   */\n  timestamp: number;\n}\n\n/**\n * Webhook event types enum with discriminator values.\n * Used for type narrowing in discriminated unions.\n */\nexport enum WebhookEventType {\n  // Messenger Platform Events (entry[].messaging[])\n  MESSAGE = 'message',\n  MESSAGE_ECHO = 'message_echo',\n  MESSAGE_EDIT = 'message_edit',\n  MESSAGE_REACTION = 'reaction',\n  MESSAGE_READ = 'read',\n  MESSAGING_FEEDBACK = 'messaging_feedback',\n  MESSAGING_POSTBACK = 'postback',\n\n  // Page Webhook Events (entry[].changes[])\n  FEED = 'feed',\n  VIDEOS = 'videos',\n  LIVE_VIDEOS = 'live_videos',\n}\n\n/**\n * Generic webhook entry structure.\n * Represents a single entry in the webhook payload.\n */\nexport interface WebhookEntry<T extends BaseWebhookEvent = BaseWebhookEvent> {\n  /** Unique ID of the page */\n  id: string;\n  \n  /** Time of update (epoch time in milliseconds) */\n  time: number;\n  \n  /** Array of messaging events */\n  messaging: T[];\n}\n\n/**\n * Generic webhook payload structure.\n * This is the top-level structure received from Facebook webhooks.\n */\nexport interface WebhookPayload<T extends BaseWebhookEvent = BaseWebhookEvent> {\n  /** Always 'page' for Messenger webhooks */\n  object: 'page';\n  \n  /** Array of entry objects containing the actual events */\n  entry: WebhookEntry<T>[];\n}\n\n/**\n * Type guard to check if an object has the base webhook event structure\n * \n * @param obj - The object to check\n * @returns True if the object has the base webhook event properties\n */\nexport function isBaseWebhookEvent(obj: any): obj is BaseWebhookEvent {\n  return (\n    obj &&\n    typeof obj === 'object' &&\n    'sender' in obj &&\n    'recipient' in obj &&\n    'timestamp' in obj &&\n    typeof obj.sender === 'object' &&\n    typeof obj.recipient === 'object' &&\n    typeof obj.timestamp === 'number'\n  );\n}\n\n/**\n * Type guard to check if a sender has a PSID (is identified)\n * \n * @param sender - The sender object to check\n * @returns True if sender has a valid PSID\n */\nexport function hasUserId(sender: WebhookSender): sender is WebhookSender & { id: string } {\n  return typeof sender.id === 'string' && sender.id.length > 0;\n}\n\n/**\n * Type guard to check if a sender has a user reference (anonymous)\n * \n * @param sender - The sender object to check\n * @returns True if sender has a user_ref\n */\nexport function hasUserRef(sender: WebhookSender): sender is WebhookSender & { user_ref: string } {\n  return typeof sender.user_ref === 'string' && sender.user_ref.length > 0;\n}\n\n/**\n * Generic webhook entry structure for Page webhooks (uses 'changes' instead of 'messaging').\n * Represents a single entry in a Page webhook payload.\n */\nexport interface PageWebhookEntry<T = any> {\n  /** Unique ID of the page */\n  id: string;\n\n  /** Time of update (epoch time in milliseconds) */\n  time: number;\n\n  /** Array of change events */\n  changes: T[];\n}\n\n/**\n * Generic webhook payload structure for Page webhooks.\n * This is the top-level structure received from Facebook Page webhooks.\n */\nexport interface PageWebhookPayload<T = any> {\n  /** Always 'page' for Page webhooks */\n  object: 'page';\n\n  /** Array of entry objects containing the actual events */\n  entry: PageWebhookEntry<T>[];\n}\n\n/**\n * Extract all events from a generic webhook payload\n *\n * @param payload - The webhook payload to extract events from\n * @returns Array of webhook events\n */\nexport function extractEvents<T extends BaseWebhookEvent>(\n  payload: WebhookPayload<T>\n): T[] {\n  const events: T[] = [];\n\n  if (payload.object === 'page' && Array.isArray(payload.entry)) {\n    for (const entry of payload.entry) {\n      if (Array.isArray(entry.messaging)) {\n        events.push(...entry.messaging);\n      }\n    }\n  }\n\n  return events;\n}\n\n/**\n * Extract all events from a Page webhook payload (uses 'changes' array)\n *\n * @param payload - The Page webhook payload to extract events from\n * @returns Array of Page webhook events\n */\nexport function extractPageEvents<T>(payload: PageWebhookPayload<T>): T[] {\n  const events: T[] = [];\n\n  if (payload.object === 'page' && Array.isArray(payload.entry)) {\n    for (const entry of payload.entry) {\n      if (Array.isArray(entry.changes)) {\n        events.push(...entry.changes);\n      }\n    }\n  }\n\n  return events;\n}\n\n/**\n * Common processing context for all webhook events\n */\nexport interface BaseProcessingContext {\n  /** The user who initiated the event (PSID or user_ref) */\n  senderId?: string;\n  \n  /** User reference for anonymous users */\n  userRef?: string;\n  \n  /** The page that received the event */\n  recipientId: string;\n  \n  /** When the event occurred */\n  timestamp: number;\n  \n  /** Whether the sender is identified (has PSID) */\n  isIdentifiedUser: boolean;\n  \n  /** Human-readable datetime for the event timestamp */\n  eventDate: Date;\n}\n\n/**\n * Extract base processing context from any webhook event\n *\n * @param event - The webhook event to extract context from\n * @returns Base processing context\n */\nexport function extractBaseContext(event: BaseWebhookEvent): BaseProcessingContext {\n  const isIdentifiedUser = hasUserId(event.sender);\n\n  return {\n    senderId: event.sender.id,\n    userRef: event.sender.user_ref,\n    recipientId: event.recipient.id,\n    timestamp: event.timestamp,\n    isIdentifiedUser,\n    eventDate: new Date(event.timestamp),\n  };\n}\n\n/**\n * Get event types from a Page webhook payload (uses 'changes' array)\n *\n * @param payload - The Page webhook payload to extract event types from\n * @returns Array of unique WebhookEventType values found in the payload\n *\n * @example\n * ```typescript\n * const eventTypes = getPageWebhookEventTypes(payload);\n * console.log('Page events:', eventTypes); // [WebhookEventType.FEED, WebhookEventType.VIDEOS]\n *\n * if (eventTypes.includes(WebhookEventType.FEED)) {\n *   // Process feed events\n * }\n * ```\n */\nexport function getPageWebhookEventTypes(payload: PageWebhookPayload): WebhookEventType[] {\n  const eventTypes = new Set<WebhookEventType>();\n\n  if (payload.object === 'page' && Array.isArray(payload.entry)) {\n    for (const entry of payload.entry) {\n      if (Array.isArray(entry.changes)) {\n        for (const change of entry.changes) {\n          if (change && typeof change === 'object' && 'field' in change) {\n            const field = change.field as string;\n            // Map field value to WebhookEventType enum\n            switch (field) {\n              case 'feed':\n                eventTypes.add(WebhookEventType.FEED);\n                break;\n              case 'videos':\n                eventTypes.add(WebhookEventType.VIDEOS);\n                break;\n              case 'live_videos':\n                eventTypes.add(WebhookEventType.LIVE_VIDEOS);\n                break;\n            }\n          }\n        }\n      }\n    }\n  }\n\n  return Array.from(eventTypes);\n}","/**\n * Facebook Messenger Platform - Message Edits Webhook Types\n * \n * These types represent the webhook event structure for message_edits events.\n * Triggered when a user edits a previously sent message.\n * \n * @see https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/message-edits/\n */\n\nimport {\n  BaseWebhookEvent,\n  WebhookEventType,\n  WebhookPayload,\n  BaseProcessingContext,\n  extractBaseContext,\n} from './base-types';\n\n// Note: MessageEditSender and MessageEditRecipient are now replaced by\n// WebhookSender and WebhookRecipient from base-types.ts\n// Keeping these as deprecated aliases for backward compatibility\n\nimport { WebhookSender as MessageEditSender } from './base-types';\nimport { WebhookRecipient as MessageEditRecipient } from './base-types';\nexport { MessageEditSender, MessageEditRecipient };\n\n/**\n * Represents the edited message information\n */\nexport interface MessageEdit {\n  /** \n   * Unique message identifier for the edited message \n   */\n  mid: string;\n  \n  /** \n   * New message content after the edit.\n   * Contains the updated text of the message.\n   */\n  text: string;\n  \n  /** \n   * Number of times the message has been edited.\n   * Maximum value is 5 (client-side constraint).\n   */\n  num_edit: number;\n}\n\n/**\n * Main webhook event structure for message edits with discriminator\n * \n * This event is triggered when a user edits a previously sent message.\n * The webhook provides the updated message content and edit count.\n * \n * @example\n * ```json\n * {\n *   \"type\": \"message_edit\",\n *   \"sender\": {\n *     \"id\": \"1234567890123456\"\n *   },\n *   \"recipient\": {\n *     \"id\": \"9876543210987654\"\n *   },\n *   \"timestamp\": 1458668856463,\n *   \"message_edit\": {\n *     \"mid\": \"mid.1458668856218:ed81099e15d3f4f233\",\n *     \"text\": \"This is the updated message content\",\n *     \"num_edit\": 2\n *   }\n * }\n * ```\n */\nexport interface MessageEditWebhookEvent extends BaseWebhookEvent {\n  /** Discriminator for type narrowing */\n  type: WebhookEventType.MESSAGE_EDIT;\n  \n  /** Details about the edited message */\n  message_edit: MessageEdit;\n}\n\n/**\n * Complete webhook payload structure that includes the message edit event\n * along with other webhook metadata\n */\nexport interface MessageEditWebhookPayload extends WebhookPayload<MessageEditWebhookEvent> {}\n\n/**\n * Type guard to check if a webhook event is a message edit event\n * \n * @param event - The webhook event to check\n * @returns True if the event contains a message_edit property\n * \n * @example\n * ```typescript\n * if (isMessageEditEvent(event)) {\n *   // TypeScript now knows event has message_edit property\n *   console.log(`Message edited ${event.message_edit.num_edit} times`);\n * }\n * ```\n */\nexport function isMessageEditEvent(event: any): event is MessageEditWebhookEvent {\n  return event && typeof event === 'object' && 'message_edit' in event;\n}\n\n/**\n * Utility type for extracting just the message edit data from a webhook event\n */\nexport type MessageEditData = MessageEdit;\n\n/**\n * Utility type for common message edit properties that might be used in processing\n */\nexport interface MessageEditProcessingContext extends BaseProcessingContext {\n  /** The edited message ID */\n  messageId: string;\n  \n  /** Updated message content */\n  updatedText: string;\n  \n  /** Number of edits made */\n  editCount: number;\n}\n\n/**\n * Helper function to extract processing context from a message edit event\n * \n * @param event - The message edit webhook event\n * @returns Simplified processing context\n * \n * @example\n * ```typescript\n * const context = extractMessageEditContext(webhookEvent);\n * console.log(`User ${context.senderId} edited message to: \"${context.updatedText}\"`);\n * ```\n */\nexport function extractMessageEditContext(event: MessageEditWebhookEvent): MessageEditProcessingContext {\n  const baseContext = extractBaseContext(event);\n  \n  return {\n    ...baseContext,\n    messageId: event.message_edit.mid,\n    updatedText: event.message_edit.text,\n    editCount: event.message_edit.num_edit,\n  };\n}\n\n/**\n * Constants related to message editing limits and constraints\n */\nexport const MESSAGE_EDIT_CONSTANTS = {\n  /** Maximum number of edits allowed per message */\n  MAX_EDITS: 5,\n  \n  /** Webhook event type identifier */\n  EVENT_TYPE: 'message_edit' as const,\n} as const;\n\n","/**\n * Facebook Messenger Platform Message Reactions Webhook Types\n * \n * These types define the structure of webhook events received when users\n * react to messages in Messenger conversations.\n * \n * @see https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/message-reactions\n */\n\nimport {\n  BaseWebhookEvent,\n  WebhookEventType,\n  WebhookPayload,\n} from './base-types';\n\n/**\n * Types of reactions that can be applied to messages in Messenger.\n * These are the predefined reaction types supported by Facebook.\n */\nexport enum MessageReactionType {\n  /** Standard like reaction */\n  LIKE = 'like',\n  /** Dislike reaction */\n  DISLIKE = 'dislike',\n  /** Love reaction (heart) */\n  LOVE = 'love',\n  /** Sad reaction */\n  SAD = 'sad',\n  /** Angry reaction */\n  ANGRY = 'angry',\n  /** Wow/surprised reaction */\n  WOW = 'wow',\n  /** Smile/laugh reaction */\n  SMILE = 'smile',\n  /** Other/unrecognized emoji reactions */\n  OTHER = 'other'\n}\n\n/**\n * Actions that can be performed on message reactions.\n */\nexport enum MessageReactionAction {\n  /** Adding a reaction to a message */\n  REACT = 'react',\n  /** Removing a reaction from a message */\n  UNREACT = 'unreact'\n}\n\n// Note: MessageReactionSender and MessageReactionRecipient are now replaced by\n// WebhookSender and WebhookRecipient from base-types.ts\n// Keeping these as deprecated aliases for backward compatibility\n\nimport { WebhookSender as MessageReactionSender } from './base-types';\nimport { WebhookRecipient as MessageReactionRecipient } from './base-types';\nexport { MessageReactionSender, MessageReactionRecipient };\n\n/**\n * Contains the detailed information about the reaction.\n */\nexport interface MessageReactionData {\n  /** \n   * The type of reaction applied to the message.\n   * Can be one of the predefined types or \"other\" for unrecognized emojis.\n   */\n  reaction: MessageReactionType;\n  \n  /** \n   * The UTF-8 emoji representation of the reaction (optional).\n   * Example: \"\\u{2764}\\u{FE0F}\" for heart emoji\n   */\n  emoji?: string;\n  \n  /** \n   * The action performed - either adding or removing the reaction.\n   */\n  action: MessageReactionAction;\n  \n  /** \n   * The message ID that the reaction was applied to.\n   * This corresponds to the 'mid' field of the original message.\n   */\n  mid: string;\n}\n\n/**\n * Complete webhook event structure for message reactions with discriminator.\n * This is the main payload received when a user reacts to a message.\n */\nexport interface MessageReactionWebhookEvent extends BaseWebhookEvent {\n  /** Discriminator for type narrowing */\n  type: WebhookEventType.MESSAGE_REACTION;\n  \n  /** Detailed information about the reaction */\n  reaction: MessageReactionData;\n}\n\n/**\n * The complete webhook payload containing the message reaction event.\n * This matches the structure of the webhook POST request body.\n */\nexport interface MessageReactionWebhookPayload extends WebhookPayload<MessageReactionWebhookEvent> {}\n\n/**\n * Context object for processing message reaction webhooks.\n * Useful for handlers that need additional processing information.\n */\nexport interface MessageReactionProcessingContext {\n  /** The original webhook event */\n  event: MessageReactionWebhookEvent;\n  \n  /** Page ID that received the reaction */\n  pageId: string;\n  \n  /** User ID who performed the reaction */\n  userId: string;\n  \n  /** ID of the message that was reacted to */\n  messageId: string;\n  \n  /** Whether this is a new reaction (true) or removal (false) */\n  isReactionAdded: boolean;\n  \n  /** The type of reaction */\n  reactionType: MessageReactionType;\n  \n  /** Raw emoji string if available */\n  emoji?: string;\n  \n  /** Timestamp when the reaction occurred */\n  timestamp: Date;\n}\n\n/**\n * Helper type for reaction statistics and aggregation.\n * Useful for tracking reaction counts on messages.\n */\nexport interface MessageReactionStats {\n  /** The message ID these stats apply to */\n  messageId: string;\n  \n  /** Count of each reaction type */\n  reactions: {\n    [K in MessageReactionType]?: number;\n  };\n  \n  /** Total number of reactions */\n  totalReactions: number;\n  \n  /** Last updated timestamp */\n  lastUpdated: Date;\n}\n\n/**\n * Configuration options for handling message reaction webhooks.\n */\nexport interface MessageReactionWebhookConfig {\n  /** Whether to track reaction statistics */\n  enableStats?: boolean;\n  \n  /** Whether to handle emoji reactions beyond predefined types */\n  handleCustomEmojis?: boolean;\n  \n  /** Maximum age of reactions to process (in milliseconds) */\n  maxReactionAge?: number;\n  \n  /** Whether to validate webhook signatures */\n  validateSignature?: boolean;\n}\n\n/* Example webhook payload structure:\n{\n  \"object\": \"page\",\n  \"entry\": [\n    {\n      \"id\": \"PAGE_ID\",\n      \"time\": 1458668856463,\n      \"messaging\": [\n        {\n          \"sender\": {\n            \"id\": \"USER_PSID\"\n          },\n          \"recipient\": {\n            \"id\": \"PAGE_ID\"\n          },\n          \"timestamp\": 1458668856463,\n          \"reaction\": {\n            \"reaction\": \"love\",\n            \"emoji\": \"\\u{2764}\\u{FE0F}\",\n            \"action\": \"react\",\n            \"mid\": \"MESSAGE_ID\"\n          }\n        }\n      ]\n    }\n  ]\n}\n*/\n\n/* Example of removing a reaction:\n{\n  \"object\": \"page\",\n  \"entry\": [\n    {\n      \"id\": \"PAGE_ID\", \n      \"time\": 1458668856463,\n      \"messaging\": [\n        {\n          \"sender\": {\n            \"id\": \"USER_PSID\"\n          },\n          \"recipient\": {\n            \"id\": \"PAGE_ID\"\n          },\n          \"timestamp\": 1458668856463,\n          \"reaction\": {\n            \"reaction\": \"love\",\n            \"action\": \"unreact\",\n            \"mid\": \"MESSAGE_ID\"\n          }\n        }\n      ]\n    }\n  ]\n}\n*/","/**\n * Facebook Messenger Platform - Message Reads Webhook Types\n * \n * These types represent the webhook event structure for message_reads events.\n * Triggered when a user reads messages sent by a Page.\n * \n * The message_reads webhook event indicates that all messages up to a certain \n * watermark timestamp have been read by the recipient.\n * \n * @see https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/message-reads/\n */\n\nimport {\n  BaseWebhookEvent,\n  WebhookEventType,\n  WebhookPayload,\n} from './base-types';\n\n// Note: MessageReadsSender and MessageReadsRecipient are now replaced by\n// WebhookSender and WebhookRecipient from base-types.ts\n// Keeping these as deprecated aliases for backward compatibility\n\nimport { WebhookSender as MessageReadsSender } from './base-types';\nimport { WebhookRecipient as MessageReadsRecipient } from './base-types';\nexport { MessageReadsSender, MessageReadsRecipient };\n\n/**\n * Represents the read receipt information\n */\nexport interface MessageRead {\n  /** \n   * Watermark timestamp indicating all messages up to this point have been read.\n   * This is a Unix timestamp in milliseconds.\n   * All messages with a timestamp less than or equal to this value have been read.\n   */\n  watermark: number;\n}\n\n/**\n * Main webhook event structure for message reads with discriminator\n * \n * This event is triggered when a user reads messages sent by a Page.\n * The watermark indicates the timestamp up to which all messages have been read.\n * \n * @example\n * ```json\n * {\n *   \"type\": \"read\",\n *   \"sender\": {\n *     \"id\": \"1234567890123456\"\n *   },\n *   \"recipient\": {\n *     \"id\": \"9876543210987654\"\n *   },\n *   \"timestamp\": 1458668856463,\n *   \"read\": {\n *     \"watermark\": 1458668856253\n *   }\n * }\n * ```\n */\nexport interface MessageReadsWebhookEvent extends BaseWebhookEvent {\n  /** Discriminator for type narrowing */\n  type: WebhookEventType.MESSAGE_READ;\n  \n  /** Read receipt information containing the watermark */\n  read: MessageRead;\n}\n\n/**\n * Complete webhook payload structure that includes the message reads event\n * along with other webhook metadata\n */\nexport interface MessageReadsWebhookPayload extends WebhookPayload<MessageReadsWebhookEvent> {}\n\n/**\n * Type guard to check if a webhook event is a message reads event\n * \n * @param event - The webhook event to check\n * @returns True if the event contains a read property\n * \n * @example\n * ```typescript\n * if (isMessageReadsEvent(event)) {\n *   // TypeScript now knows event has read property\n *   console.log(`Messages read up to timestamp: ${event.read.watermark}`);\n * }\n * ```\n */\nexport function isMessageReadsEvent(event: any): event is MessageReadsWebhookEvent {\n  return event && typeof event === 'object' && 'read' in event;\n}\n\n/**\n * Utility type for extracting just the read data from a webhook event\n */\nexport type MessageReadData = MessageRead;\n\n/**\n * Utility type for common message reads properties that might be used in processing\n */\nexport interface MessageReadsProcessingContext {\n  /** The user who read the messages */\n  senderId: string;\n  \n  /** The page that sent the messages */\n  recipientId: string;\n  \n  /** Timestamp up to which all messages have been read */\n  watermarkTimestamp: number;\n  \n  /** When the read event occurred */\n  readTimestamp: number;\n  \n  /** \n   * Human-readable datetime for the watermark timestamp.\n   * Useful for logging and debugging.\n   */\n  watermarkDate: Date;\n  \n  /** \n   * Human-readable datetime for the read event timestamp.\n   * Useful for logging and debugging.\n   */\n  readDate: Date;\n}\n\n/**\n * Helper function to extract processing context from a message reads event\n * \n * @param event - The message reads webhook event\n * @returns Simplified processing context with additional computed fields\n * \n * @example\n * ```typescript\n * const context = extractMessageReadsContext(webhookEvent);\n * console.log(`User ${context.senderId} read messages up to ${context.watermarkDate.toISOString()}`);\n * ```\n */\nexport function extractMessageReadsContext(event: MessageReadsWebhookEvent): MessageReadsProcessingContext {\n  return {\n    senderId: event.sender.id,\n    recipientId: event.recipient.id,\n    watermarkTimestamp: event.read.watermark,\n    readTimestamp: event.timestamp,\n    watermarkDate: new Date(event.read.watermark),\n    readDate: new Date(event.timestamp),\n  };\n}\n\n/**\n * Helper function to check if a specific message timestamp was read\n * \n * @param messageTimestamp - The timestamp of the message to check\n * @param watermark - The watermark timestamp from the read event\n * @returns True if the message with the given timestamp has been read\n * \n * @example\n * ```typescript\n * const messageTime = 1458668855000;\n * const watermark = 1458668856253;\n * \n * if (isMessageRead(messageTime, watermark)) {\n *   console.log('This message has been read');\n * }\n * ```\n */\nexport function isMessageRead(messageTimestamp: number, watermark: number): boolean {\n  return messageTimestamp <= watermark;\n}\n\n/**\n * Helper function to determine which messages in a list have been read\n * \n * @param messages - Array of messages with timestamp property\n * @param watermark - The watermark timestamp from the read event\n * @returns Array of messages that have been read\n * \n * @example\n * ```typescript\n * const messages = [\n *   { id: '1', timestamp: 1458668855000, text: 'Hello' },\n *   { id: '2', timestamp: 1458668857000, text: 'World' }\n * ];\n * const watermark = 1458668856253;\n * \n * const readMessages = getReadMessages(messages, watermark);\n * // Returns only the first message as it's before the watermark\n * ```\n */\nexport function getReadMessages<T extends { timestamp: number }>(\n  messages: T[], \n  watermark: number\n): T[] {\n  return messages.filter(message => isMessageRead(message.timestamp, watermark));\n}\n\n/**\n * Helper function to get the count of read messages from a list\n * \n * @param messages - Array of messages with timestamp property\n * @param watermark - The watermark timestamp from the read event\n * @returns Number of messages that have been read\n * \n * @example\n * ```typescript\n * const messages = [\n *   { id: '1', timestamp: 1458668855000 },\n *   { id: '2', timestamp: 1458668857000 }\n * ];\n * const watermark = 1458668856253;\n * \n * const readCount = getReadMessageCount(messages, watermark);\n * // Returns 1\n * ```\n */\nexport function getReadMessageCount<T extends { timestamp: number }>(\n  messages: T[], \n  watermark: number\n): number {\n  return getReadMessages(messages, watermark).length;\n}\n\n/**\n * Constants related to message reads functionality\n */\nexport const MESSAGE_READS_CONSTANTS = {\n  /** Webhook event type identifier */\n  EVENT_TYPE: 'message_reads' as const,\n  \n  /** \n   * Property name in the webhook event that contains read data.\n   * Used for type guards and event identification.\n   */\n  READ_PROPERTY: 'read' as const,\n} as const;\n\n/**\n * Type for the watermark timestamp\n * Represents a Unix timestamp in milliseconds indicating read status\n */\nexport type WatermarkTimestamp = number;\n\n/**\n * Interface for objects that have a watermark (used in generic functions)\n */\nexport interface HasWatermark {\n  /** Watermark timestamp */\n  watermark: WatermarkTimestamp;\n}\n\n/**\n * Interface for objects that have a timestamp (used in message filtering)\n */\nexport interface HasTimestamp {\n  /** Message timestamp */\n  timestamp: number;\n}","/**\n * Facebook Messenger Platform - Messaging Postbacks Webhook Types\n * \n * These types represent the webhook event structure for messaging_postbacks events.\n * Triggered when a user clicks on a postback button, Get Started button, or persistent menu item.\n * \n * @see https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/messaging_postbacks\n */\n\nimport {\n  BaseWebhookEvent,\n  WebhookEventType,\n  WebhookPayload,\n  WebhookSender,\n  WebhookRecipient,\n} from './base-types';\n\n// Note: PostbackSender and PostbackRecipient are now replaced by\n// WebhookSender and WebhookRecipient from base-types.ts\n// Keeping these as deprecated aliases for backward compatibility\n\nexport { WebhookSender as PostbackSender };\nexport { WebhookRecipient as PostbackRecipient };\n\n/**\n * Represents referral information for postbacks that originated from external sources\n * \n * This object is included when a postback is triggered as part of a conversation\n * that was started via m.me links, Click to Messenger ads, Messenger QR codes,\n * or the Welcome Screen.\n */\nexport interface PostbackReferral {\n  /** \n   * Arbitrary data that was included in the original referral.\n   * This is the custom parameter you set when creating the referral link.\n   */\n  ref?: string;\n\n  /** \n   * Source of the referral. Indicates how the conversation was initiated.\n   * Common values include:\n   * - \"SHORTLINK\" - from m.me links\n   * - \"ADS\" - from Click to Messenger ads\n   * - \"MESSENGER_CODE\" - from Messenger QR codes\n   */\n  source?: string;\n\n  ad_id?: string;\n  ads_context_data?: {\n    ad_title?: string;\n    photo_url?: string;\n    video_url?: string;\n    post_id?: string;\n  };\n\n  /** \n   * Type of referral action that initiated the conversation.\n   * Common value is \"OPEN_THREAD\" for most referral types.\n   */\n  type?: string;\n}\n\n/**\n * Represents the postback data in a messaging postback webhook event\n */\nexport interface PostbackData {\n  /** \n   * Message ID associated with the postback.\n   * Unique identifier for the message that contained the postback button.\n   */\n  mid?: string;\n\n  /** \n   * Title of the postback button that was clicked.\n   * This is the user-visible text that was displayed on the button.\n   */\n  title?: string;\n\n  /** \n   * Developer-defined payload that was associated with the postback button.\n   * This contains the custom data you specified when creating the button.\n   * Maximum length is 1000 characters.\n   */\n  payload: string;\n\n  /** \n   * Referral information if the postback is part of a referred conversation.\n   * Only present when the conversation was initiated through external sources\n   * like m.me links, ads, QR codes, or Welcome Screen.\n   */\n  referral?: PostbackReferral;\n}\n\n/**\n * Main webhook event structure for messaging postbacks with discriminator\n * \n * This event is triggered when a user interacts with postback buttons,\n * including regular postback buttons, Get Started button, and persistent menu items.\n * \n * @example\n * Basic postback from a button click:\n * ```json\n * {\n *   \"type\": \"postback\",\n *   \"sender\": {\n *     \"id\": \"1234567890123456\"\n *   },\n *   \"recipient\": {\n *     \"id\": \"9876543210987654\"\n *   },\n *   \"timestamp\": 1527459824,\n *   \"postback\": {\n *     \"mid\": \"m_AG5Hz2Uq7tuwNEhXfYYKj8mJEM_QPpz5jdHtHaW\",\n *     \"title\": \"Get Started\",\n *     \"payload\": \"GET_STARTED_PAYLOAD\"\n *   }\n * }\n * ```\n * \n * @example\n * Postback with referral data from m.me link:\n * ```json\n * {\n *   \"type\": \"postback\",\n *   \"sender\": {\n *     \"user_ref\": \"unique_ref_param\"\n *   },\n *   \"recipient\": {\n *     \"id\": \"9876543210987654\"\n *   },\n *   \"timestamp\": 1527459824,\n *   \"postback\": {\n *     \"title\": \"Contact Sales\",\n *     \"payload\": \"CONTACT_SALES\",\n *     \"referral\": {\n *       \"ref\": \"landing_page_ad_campaign\",\n *       \"source\": \"SHORTLINK\",\n *       \"type\": \"OPEN_THREAD\"\n *     }\n *   }\n * }\n * ```\n */\nexport interface MessagingPostbackWebhookEvent extends BaseWebhookEvent {\n  /** Discriminator for type narrowing */\n  type: WebhookEventType.MESSAGING_POSTBACK;\n\n  /** Details about the postback that was triggered */\n  postback: PostbackData;\n}\n\n/**\n * Complete webhook payload structure that includes the messaging postback event\n * along with other webhook metadata\n */\nexport interface MessagingPostbackWebhookPayload extends WebhookPayload<MessagingPostbackWebhookEvent> { }\n\n/**\n * Type guard to check if a webhook event is a messaging postback event\n * \n * @param event - The webhook event to check\n * @returns True if the event contains a postback property\n * \n * @example\n * ```typescript\n * if (isMessagingPostbackEvent(event)) {\n *   // TypeScript now knows event has postback property\n *   console.log(`User clicked: ${event.postback.title}`);\n *   console.log(`Payload: ${event.postback.payload}`);\n * }\n * ```\n */\nexport function isMessagingPostbackEvent(event: any): event is MessagingPostbackWebhookEvent {\n  return event && typeof event === 'object' && 'postback' in event;\n}\n\n/**\n * Type guard to check if a postback event includes referral data\n * \n * @param event - The messaging postback event to check\n * @returns True if the event contains referral information\n * \n * @example\n * ```typescript\n * if (hasReferralData(event)) {\n *   // Handle referred conversation\n *   console.log(`Referred from: ${event.postback.referral.source}`);\n *   console.log(`Ref parameter: ${event.postback.referral.ref}`);\n * }\n * ```\n */\nexport function hasReferralData(event: MessagingPostbackWebhookEvent): event is MessagingPostbackWebhookEvent & {\n  postback: PostbackData & { referral: PostbackReferral };\n} {\n  return event.postback && 'referral' in event.postback && event.postback.referral != null;\n}\n\n/**\n * Type guard to check if sender is identified (has PSID) vs anonymous (has user_ref)\n * \n * @param sender - The sender object to check\n * @returns True if sender has a PSID (is identified)\n * \n * @example\n * ```typescript\n * if (isIdentifiedSender(event.sender)) {\n *   // User has been identified and has a PSID\n *   console.log(`User PSID: ${event.sender.id}`);\n * } else {\n *   // Anonymous user with user_ref (likely from chat plugin)\n *   console.log(`Anonymous user ref: ${event.sender.user_ref}`);\n * }\n * ```\n */\nexport function isIdentifiedSender(sender: WebhookSender): sender is WebhookSender & { id: string } {\n  return sender && typeof sender.id === 'string' && sender.id.length > 0;\n}\n\n/**\n * Utility type for extracting just the postback data from a webhook event\n */\nexport type PostbackEventData = PostbackData;\n\n/**\n * Utility type for common postback properties that might be used in processing\n */\nexport interface PostbackProcessingContext {\n  /** The postback payload data */\n  payload: string;\n\n  /** The user who triggered the postback (PSID or user_ref) */\n  senderId?: string;\n\n  /** User reference for anonymous users */\n  userRef?: string;\n\n  /** The page that received the postback */\n  recipientId: string;\n\n  /** Button title if available */\n  buttonTitle?: string;\n\n  /** Message ID if available */\n  messageId?: string;\n\n  /** When the postback occurred */\n  timestamp: number;\n\n  /** Referral context if present */\n  referralContext?: {\n    ref?: string;\n    source?: string;\n    type?: string;\n  };\n\n  /** Whether this is from a referred conversation */\n  isReferred: boolean;\n\n  /** Whether the sender is identified (has PSID) */\n  isIdentifiedUser: boolean;\n}\n\n/**\n * Helper function to extract processing context from a messaging postback event\n * \n * @param event - The messaging postback webhook event\n * @returns Simplified processing context with all relevant data\n * \n * @example\n * ```typescript\n * const context = extractPostbackContext(webhookEvent);\n * \n * if (context.isReferred) {\n *   console.log(`New conversation from ${context.referralContext?.source}`);\n * }\n * \n * if (context.isIdentifiedUser) {\n *   console.log(`Known user ${context.senderId} clicked: ${context.payload}`);\n * } else {\n *   console.log(`Anonymous user ${context.userRef} clicked: ${context.payload}`);\n * }\n * ```\n */\nexport function extractPostbackContext(event: MessagingPostbackWebhookEvent): PostbackProcessingContext {\n  const isReferred = hasReferralData(event);\n  const isIdentifiedUser = isIdentifiedSender(event.sender);\n\n  return {\n    payload: event.postback.payload,\n    senderId: event.sender.id,\n    userRef: event.sender.user_ref,\n    recipientId: event.recipient.id,\n    buttonTitle: event.postback.title,\n    messageId: event.postback.mid,\n    timestamp: event.timestamp,\n    referralContext: isReferred ? {\n      ref: event.postback.referral.ref,\n      source: event.postback.referral.source,\n      type: event.postback.referral.type,\n    } : undefined,\n    isReferred,\n    isIdentifiedUser,\n  };\n}\n\n/**\n * Common postback payload patterns used in Messenger bots\n */\nexport const COMMON_POSTBACK_PAYLOADS = {\n  /** Get Started button payload */\n  GET_STARTED: 'GET_STARTED',\n\n  /** Main menu navigation */\n  MAIN_MENU: 'MAIN_MENU',\n\n  /** Help/Support options */\n  HELP: 'HELP',\n  SUPPORT: 'SUPPORT',\n\n  /** Contact information */\n  CONTACT: 'CONTACT',\n  CONTACT_SALES: 'CONTACT_SALES',\n  CONTACT_SUPPORT: 'CONTACT_SUPPORT',\n\n  /** Navigation actions */\n  BACK: 'BACK',\n  NEXT: 'NEXT',\n  CANCEL: 'CANCEL',\n\n  /** User preferences */\n  SETTINGS: 'SETTINGS',\n  PREFERENCES: 'PREFERENCES',\n} as const;\n\n/**\n * Constants related to postback events and constraints\n */\nexport const POSTBACK_CONSTANTS = {\n  /** Maximum payload length in characters */\n  MAX_PAYLOAD_LENGTH: 1000,\n\n  /** Webhook event type identifier */\n  EVENT_TYPE: 'postback' as const,\n\n  /** Common referral sources */\n  REFERRAL_SOURCES: {\n    SHORTLINK: 'SHORTLINK',\n    ADS: 'ADS',\n    MESSENGER_CODE: 'MESSENGER_CODE',\n  } as const,\n\n  /** Common referral types */\n  REFERRAL_TYPES: {\n    OPEN_THREAD: 'OPEN_THREAD',\n  } as const,\n} as const;\n\n/**\n * Type for postback payload values - can be custom strings or common patterns\n */\nexport type PostbackPayload = string | typeof COMMON_POSTBACK_PAYLOADS[keyof typeof COMMON_POSTBACK_PAYLOADS];\n\n/**\n * Type for referral sources\n */\nexport type ReferralSource = typeof POSTBACK_CONSTANTS.REFERRAL_SOURCES[keyof typeof POSTBACK_CONSTANTS.REFERRAL_SOURCES] | string;\n\n/**\n * Type for referral types  \n */\nexport type ReferralType = typeof POSTBACK_CONSTANTS.REFERRAL_TYPES[keyof typeof POSTBACK_CONSTANTS.REFERRAL_TYPES] | string;","/**\n * Facebook Messenger Platform - Customer Feedback Webhook Types\n * \n * These types represent the webhook event structure for messaging_feedback events.\n * Triggered when a user submits feedback through a Customer Feedback Template.\n * \n * @see https://developers.facebook.com/docs/messenger-platform/send-messages/templates/customer-feedback-template\n */\n\nimport {\n  BaseWebhookEvent,\n  WebhookEventType,\n  WebhookPayload,\n} from './base-types';\n\n/**\n * Available feedback types for customer feedback templates\n */\nexport enum FeedbackType {\n  /** Customer Satisfaction - Score range 1-5 */\n  CSAT = 'csat',\n  /** Net Promoter Score - Score range 0-10 */\n  NPS = 'nps',\n  /** Customer Effort Score - Score range 1-7 */\n  CES = 'ces',\n}\n\n/**\n * Available display options for CSAT feedback type\n */\nexport enum CSATDisplayOption {\n  /** Numeric scale from 1 to 5 */\n  ONE_TO_FIVE = 'one_to_five',\n  /** Five star rating display */\n  FIVE_STARS = 'five_stars',\n  /** Five emoji rating display */\n  FIVE_EMOJIS = 'five_emojis',\n}\n\n/**\n * Available display options for NPS feedback type\n */\nexport enum NPSDisplayOption {\n  /** Numeric scale from 0 to 10 */\n  ZERO_TO_TEN = 'zero_to_ten',\n}\n\n/**\n * Available display options for CES feedback type\n */\nexport enum CESDisplayOption {\n  /** Numeric scale from 1 to 7 */\n  ONE_TO_SEVEN = 'one_to_seven',\n}\n\n/**\n * Follow-up feedback type for optional text input\n */\nexport enum FollowUpType {\n  /** Free-form text input (max 400 characters) */\n  FREE_FORM = 'free_form',\n}\n\n// Note: MessagingFeedbackSender and MessagingFeedbackRecipient are now replaced by\n// WebhookSender and WebhookRecipient from base-types.ts\n// Keeping these as deprecated aliases for backward compatibility\n\nimport { WebhookSender as MessagingFeedbackSender } from './base-types';\nimport { WebhookRecipient as MessagingFeedbackRecipient } from './base-types';\nexport { MessagingFeedbackSender, MessagingFeedbackRecipient };\n\n/**\n * Represents optional follow-up feedback data\n */\nexport interface FeedbackFollowUp {\n  /** Type of follow-up feedback - currently only supports free_form */\n  type: FollowUpType.FREE_FORM;\n  \n  /** \n   * User-provided text feedback.\n   * Limited to 400 characters maximum.\n   */\n  payload: string;\n}\n\n/**\n * Represents individual question feedback data within a screen\n */\nexport interface FeedbackQuestion {\n  /** \n   * Type of feedback question (CSAT, NPS, or CES).\n   * Determines the scoring range and display format.\n   */\n  type: FeedbackType;\n  \n  /** \n   * Numeric score provided by the user.\n   * Range depends on feedback type:\n   * - CSAT: 1-5\n   * - NPS: 0-10  \n   * - CES: 1-7\n   */\n  payload: string;\n  \n  /** \n   * Optional follow-up text feedback from the user.\n   * Only present if the template included a text input field.\n   */\n  follow_up?: FeedbackFollowUp;\n}\n\n/**\n * Represents a feedback screen containing questions and responses\n */\nexport interface FeedbackScreen {\n  /** \n   * Screen identifier within the feedback template.\n   * Typically 0 for single-screen templates.\n   */\n  screen_id: number;\n  \n  /** \n   * Map of question IDs to their corresponding feedback responses.\n   * Question IDs are defined when creating the feedback template.\n   */\n  questions: Record<string, FeedbackQuestion>;\n}\n\n/**\n * Main messaging feedback data structure\n */\nexport interface MessagingFeedbackData {\n  /** \n   * Array of feedback screens with user responses.\n   * Each screen contains questions and their answers.\n   */\n  feedback_screens: FeedbackScreen[];\n}\n\n/**\n * Main webhook event structure for messaging feedback with discriminator\n * \n * This event is triggered when a user submits feedback through a \n * Customer Feedback Template. The webhook provides the user's\n * scores and optional text feedback.\n * \n * @example\n * ```json\n * {\n *   \"type\": \"messaging_feedback\",\n *   \"sender\": {\n *     \"id\": \"1234567890123456\"\n *   },\n *   \"recipient\": {\n *     \"id\": \"9876543210987654\"\n *   },\n *   \"timestamp\": 1458668856463,\n *   \"messaging_feedback\": {\n *     \"feedback_screens\": [{\n *       \"screen_id\": 0,\n *       \"questions\": {\n *         \"satisfaction_q1\": {\n *           \"type\": \"csat\",\n *           \"payload\": \"4\",\n *           \"follow_up\": {\n *             \"type\": \"free_form\",\n *             \"payload\": \"Good service overall!\"\n *           }\n *         }\n *       }\n *     }]\n *   }\n * }\n * ```\n */\nexport interface MessagingFeedbackWebhookEvent extends BaseWebhookEvent {\n  /** Discriminator for type narrowing */\n  type: WebhookEventType.MESSAGING_FEEDBACK;\n  \n  /** The actual feedback data containing user responses */\n  messaging_feedback: MessagingFeedbackData;\n}\n\n/**\n * Complete webhook payload structure that includes the messaging feedback event\n * along with other webhook metadata\n */\nexport interface MessagingFeedbackWebhookPayload extends WebhookPayload<MessagingFeedbackWebhookEvent> {}\n\n/**\n * Type guard to check if a webhook event is a messaging feedback event\n * \n * @param event - The webhook event to check\n * @returns True if the event contains a messaging_feedback property\n * \n * @example\n * ```typescript\n * if (isMessagingFeedbackEvent(event)) {\n *   // TypeScript now knows event has messaging_feedback property\n *   console.log(`Received feedback with ${event.messaging_feedback.feedback_screens.length} screens`);\n * }\n * ```\n */\nexport function isMessagingFeedbackEvent(event: any): event is MessagingFeedbackWebhookEvent {\n  return event && typeof event === 'object' && 'messaging_feedback' in event;\n}\n\n/**\n * Utility type for extracting just the feedback data from a webhook event\n */\nexport type MessagingFeedbackData_Extract = MessagingFeedbackData;\n\n/**\n * Utility type for common feedback properties that might be used in processing\n */\nexport interface MessagingFeedbackProcessingContext {\n  /** The user who submitted the feedback */\n  senderId: string;\n  \n  /** The page that received the feedback */\n  recipientId: string;\n  \n  /** When the feedback was submitted */\n  submissionTimestamp: number;\n  \n  /** Total number of feedback screens */\n  screenCount: number;\n  \n  /** All question responses flattened from all screens */\n  allResponses: Array<{\n    questionId: string;\n    feedbackType: FeedbackType;\n    score: number;\n    textFeedback?: string;\n    screenId: number;\n  }>;\n}\n\n/**\n * Helper function to extract processing context from a messaging feedback event\n * \n * @param event - The messaging feedback webhook event\n * @returns Simplified processing context with flattened responses\n * \n * @example\n * ```typescript\n * const context = extractMessagingFeedbackContext(webhookEvent);\n * console.log(`User ${context.senderId} submitted ${context.allResponses.length} feedback responses`);\n * context.allResponses.forEach(response => {\n *   console.log(`${response.questionId}: ${response.score}/10 (${response.feedbackType})`);\n * });\n * ```\n */\nexport function extractMessagingFeedbackContext(event: MessagingFeedbackWebhookEvent): MessagingFeedbackProcessingContext {\n  const allResponses: MessagingFeedbackProcessingContext['allResponses'] = [];\n  \n  // Flatten all responses from all screens\n  event.messaging_feedback.feedback_screens.forEach(screen => {\n    Object.entries(screen.questions).forEach(([questionId, question]) => {\n      allResponses.push({\n        questionId,\n        feedbackType: question.type,\n        score: parseInt(question.payload, 10),\n        textFeedback: question.follow_up?.payload,\n        screenId: screen.screen_id,\n      });\n    });\n  });\n  \n  return {\n    senderId: event.sender.id,\n    recipientId: event.recipient.id,\n    submissionTimestamp: event.timestamp,\n    screenCount: event.messaging_feedback.feedback_screens.length,\n    allResponses,\n  };\n}\n\n/**\n * Helper function to get feedback scores by type from an event\n * \n * @param event - The messaging feedback webhook event\n * @returns Map of feedback types to their scores\n * \n * @example\n * ```typescript\n * const scores = getFeedbackScoresByType(webhookEvent);\n * const csatScore = scores.get(FeedbackType.CSAT); // number | undefined\n * const npsScore = scores.get(FeedbackType.NPS);   // number | undefined\n * ```\n */\nexport function getFeedbackScoresByType(event: MessagingFeedbackWebhookEvent): Map<FeedbackType, number[]> {\n  const scoresByType = new Map<FeedbackType, number[]>();\n  \n  event.messaging_feedback.feedback_screens.forEach(screen => {\n    Object.values(screen.questions).forEach(question => {\n      const score = parseInt(question.payload, 10);\n      const existingScores = scoresByType.get(question.type) || [];\n      scoresByType.set(question.type, [...existingScores, score]);\n    });\n  });\n  \n  return scoresByType;\n}\n\n/**\n * Helper function to extract all text feedback from an event\n * \n * @param event - The messaging feedback webhook event\n * @returns Array of text feedback strings\n * \n * @example\n * ```typescript\n * const textFeedback = extractTextFeedback(webhookEvent);\n * textFeedback.forEach(feedback => {\n *   console.log(`User comment: \"${feedback}\"`);\n * });\n * ```\n */\nexport function extractTextFeedback(event: MessagingFeedbackWebhookEvent): string[] {\n  const textFeedback: string[] = [];\n  \n  event.messaging_feedback.feedback_screens.forEach(screen => {\n    Object.values(screen.questions).forEach(question => {\n      if (question.follow_up?.payload) {\n        textFeedback.push(question.follow_up.payload);\n      }\n    });\n  });\n  \n  return textFeedback;\n}\n\n/**\n * Constants related to customer feedback constraints and limits\n */\nexport const MESSAGING_FEEDBACK_CONSTANTS = {\n  /** Maximum characters allowed in free-form text feedback */\n  MAX_TEXT_FEEDBACK_LENGTH: 400,\n  \n  /** Score ranges for different feedback types */\n  SCORE_RANGES: {\n    [FeedbackType.CSAT]: { min: 1, max: 5 },\n    [FeedbackType.NPS]: { min: 0, max: 10 },\n    [FeedbackType.CES]: { min: 1, max: 7 },\n  },\n  \n  /** Template expiry constraints */\n  TEMPLATE_EXPIRY: {\n    /** Minimum expiry days */\n    MIN_DAYS: 1,\n    /** Maximum expiry days */\n    MAX_DAYS: 7,\n    /** Default expiry days */\n    DEFAULT_DAYS: 1,\n  },\n  \n  /** Question ID constraints */\n  QUESTION_ID: {\n    /** Maximum length for question IDs */\n    MAX_LENGTH: 80,\n    /** Valid characters pattern (alphanumeric) */\n    VALID_PATTERN: /^[a-zA-Z0-9_]+$/,\n  },\n  \n  /** Template limits */\n  TEMPLATE_LIMITS: {\n    /** Maximum number of titles per template */\n    MAX_TITLES: 1,\n    /** Maximum number of scoring components per template */\n    MAX_SCORING_COMPONENTS: 1,\n  },\n  \n  /** Webhook event type identifier */\n  EVENT_TYPE: 'messaging_feedback' as const,\n} as const;\n\n/**\n * Validation helper to check if a score is valid for a given feedback type\n * \n * @param feedbackType - The type of feedback being validated\n * @param score - The score to validate\n * @returns True if the score is within the valid range for the feedback type\n * \n * @example\n * ```typescript\n * const isValid = isValidFeedbackScore(FeedbackType.CSAT, 4); // true\n * const isInvalid = isValidFeedbackScore(FeedbackType.NPS, 15); // false\n * ```\n */\nexport function isValidFeedbackScore(feedbackType: FeedbackType, score: number): boolean {\n  const range = MESSAGING_FEEDBACK_CONSTANTS.SCORE_RANGES[feedbackType];\n  return Number.isInteger(score) && score >= range.min && score <= range.max;\n}\n\n/**\n * Validation helper to check if a question ID is valid\n * \n * @param questionId - The question ID to validate\n * @returns True if the question ID meets the format requirements\n * \n * @example\n * ```typescript\n * const isValid = isValidQuestionId('satisfaction_q1'); // true\n * const isInvalid = isValidQuestionId('invalid-id!'); // false\n * ```\n */\nexport function isValidQuestionId(questionId: string): boolean {\n  return questionId.length <= MESSAGING_FEEDBACK_CONSTANTS.QUESTION_ID.MAX_LENGTH &&\n         MESSAGING_FEEDBACK_CONSTANTS.QUESTION_ID.VALID_PATTERN.test(questionId);\n}\n\n/**\n * Validation helper to check if text feedback is within character limits\n * \n * @param textFeedback - The text feedback to validate\n * @returns True if the text is within the character limit\n * \n * @example\n * ```typescript\n * const isValid = isValidTextFeedback('Great service!'); // true\n * const isInvalid = isValidTextFeedback('a'.repeat(500)); // false\n * ```\n */\nexport function isValidTextFeedback(textFeedback: string): boolean {\n  return textFeedback.length <= MESSAGING_FEEDBACK_CONSTANTS.MAX_TEXT_FEEDBACK_LENGTH;\n}","/**\n * Facebook Page - Feed Webhook Types\n *\n * These types represent the webhook event structure for feed events.\n * Triggered when there are changes to a Page's feed, such as Posts, shares,\n * likes, comments, etc. Webhooks are not sent for Ad Posts, but are sent\n * for Comments on Ad Posts. Notifications for Page likes will only be sent\n * for Pages that have fewer than 10K likes.\n *\n * @see https://developers.facebook.com/docs/graph-api/webhooks/reference/page/#feed\n */\n\nimport { PageWebhookPayload } from './base-types';\n\n/**\n * Enumeration of item types in feed events\n */\nexport enum FeedItemType {\n  ALBUM = 'album',\n  ADDRESS = 'address',\n  COMMENT = 'comment',\n  CONNECTION = 'connection',\n  COUPON = 'coupon',\n  EVENT = 'event',\n  EXPERIENCE = 'experience',\n  GROUP = 'group',\n  GROUP_MESSAGE = 'group_message',\n  INTEREST = 'interest',\n  LINK = 'link',\n  MENTION = 'mention',\n  MILESTONE = 'milestone',\n  NOTE = 'note',\n  PAGE = 'page',\n  PICTURE = 'picture',\n  PLATFORM_STORY = 'platform-story',\n  PHOTO = 'photo',\n  PHOTO_ALBUM = 'photo-album',\n  POST = 'post',\n  PROFILE = 'profile',\n  QUESTION = 'question',\n  RATING = 'rating',\n  REACTION = 'reaction',\n  RELATIONSHIP_STATUS = 'relationship-status',\n  SHARE = 'share',\n  STATUS = 'status',\n  STORY = 'story',\n  TIMELINE_COVER = 'timeline cover',\n  TAG = 'tag',\n  VIDEO = 'video',\n}\n\n/**\n * Enumeration of action verbs in feed events\n */\nexport enum FeedActionVerb {\n  ADD = 'add',\n  BLOCK = 'block',\n  EDIT = 'edit',\n  EDITED = 'edited',\n  DELETE = 'delete',\n  FOLLOW = 'follow',\n  HIDE = 'hide',\n  MUTE = 'mute',\n  REMOVE = 'remove',\n  UNBLOCK = 'unblock',\n  UNHIDE = 'unhide',\n  UPDATE = 'update',\n}\n\n/**\n * Sender information in feed events\n */\nexport interface FeedSender {\n  /** The ID of the sender */\n  id: string;\n\n  /** The name of the sender */\n  name?: string;\n}\n\n/**\n * Page post additional information\n */\nexport interface FeedPagePost {\n  /** Type of the post (e.g., photo, video) */\n  type?: string;\n\n  /** Status type (e.g., added_photos) */\n  status_type?: string;\n\n  /** Whether the post is published */\n  is_published?: boolean;\n\n  /** Timestamp of when the post was last updated */\n  updated_time?: string;\n\n  /** Permanent static URL to the post */\n  permalink_url?: string;\n\n  /** Promotion status (e.g., inactive, extendable) */\n  promotion_status?: string;\n}\n\n/**\n * Feed event value data\n */\nexport interface FeedEventValue {\n  /** Edited time (datetime) */\n  edited_time?: string;\n\n  /** The sender information */\n  from?: FeedSender;\n\n  /** Additional post content information */\n  post?: FeedPagePost;\n\n  /** Description of the type of a status update */\n  status_type?: string;\n\n  /** Whether a scheduled post was published */\n  is_published?: boolean;\n\n  /** The time the post was last updated */\n  updated_time?: string;\n\n  /** The permanent static URL to the post on facebook.com */\n  permalink_url?: string;\n\n  /** Whether the post is hidden or not */\n  is_hidden?: boolean;\n\n  /** The link to attached content */\n  link?: string;\n\n  /** The message that is part of the content */\n  message?: string;\n\n  /** The link to an attached photo */\n  photo?: string;\n\n  /** The IDs of the photos that were added to an album */\n  photo_ids?: string[];\n\n  /** The links to any attached photos */\n  photos?: string[];\n\n  /** The post ID */\n  post_id?: string;\n\n  /** The story—only logged for a milestone item */\n  story?: string;\n\n  /** The title—only logged for a milestone item */\n  title?: string;\n\n  /** The link to an attached video */\n  video?: string;\n\n  /** The code why the video is flagged */\n  video_flag_reason?: number;\n\n  /** The type of action taken */\n  action?: string;\n\n  /** The album ID */\n  album_id?: string;\n\n  /** The comment ID */\n  comment_id?: string;\n\n  /** The timestamp of when the object was created */\n  created_time?: string;\n\n  /** The ID of the event, if the feed post is an event creation story */\n  event_id?: string;\n\n  /** The type of item */\n  item?: FeedItemType;\n\n  /** The ID of the open graph object */\n  open_graph_story_id?: string;\n\n  /** The parent ID */\n  parent_id?: string;\n\n  /** The photo ID */\n  photo_id?: string;\n\n  /** The type of the user reaction */\n  reaction_type?: string;\n\n  /** Whether the post is published */\n  published?: number;\n\n  /** The recipient ID */\n  recipient_id?: string;\n\n  /** The share ID */\n  share_id?: string;\n\n  /** The type of action taken */\n  verb?: FeedActionVerb;\n\n  /** The video ID */\n  video_id?: string;\n}\n\n/**\n * Main webhook event structure for feed events\n *\n * This event is triggered when there are changes to a Page's feed.\n * The webhook provides information about posts, comments, likes, shares, etc.\n *\n * @example Post created:\n * ```json\n * {\n *   \"field\": \"feed\",\n *   \"value\": {\n *     \"from\": {\n *       \"id\": \"123456789\",\n *       \"name\": \"Page Name\"\n *     },\n *     \"post_id\": \"123456789_987654321\",\n *     \"verb\": \"add\",\n *     \"item\": \"post\",\n *     \"created_time\": \"1234567890\",\n *     \"message\": \"Hello World!\"\n *   }\n * }\n * ```\n */\nexport interface FeedWebhookEvent {\n  /** Name of the updated field */\n  field: 'feed';\n\n  /** The contents of the update */\n  value: FeedEventValue;\n}\n\n/**\n * Complete webhook payload structure for feed events\n */\nexport interface FeedWebhookPayload extends PageWebhookPayload<FeedWebhookEvent> {}\n\n/**\n * Type guard to check if a webhook event is a feed event\n *\n * @param event - The webhook event to check\n * @returns True if the event is a feed event\n *\n * @example\n * ```typescript\n * if (isFeedEvent(event)) {\n *   console.log(`Feed event: ${event.value.verb} ${event.value.item}`);\n * }\n * ```\n */\nexport function isFeedEvent(event: any): event is FeedWebhookEvent {\n  return event && typeof event === 'object' && event.field === 'feed';\n}\n\n/**\n * Type guard to check if a feed event is a post creation\n *\n * @param value - The feed event value to check\n * @returns True if the event is a post creation\n */\nexport function isPostCreated(value: FeedEventValue): boolean {\n  return value.verb === FeedActionVerb.ADD && value.item === FeedItemType.POST;\n}\n\n/**\n * Type guard to check if a feed event is a comment\n *\n * @param value - The feed event value to check\n * @returns True if the event is a comment\n */\nexport function isComment(value: FeedEventValue): boolean {\n  return value.item === FeedItemType.COMMENT;\n}\n\n/**\n * Type guard to check if a feed event is a photo\n *\n * @param value - The feed event value to check\n * @returns True if the event is a photo\n */\nexport function isPhoto(value: FeedEventValue): boolean {\n  return value.item === FeedItemType.PHOTO || value.item === FeedItemType.PHOTO_ALBUM;\n}\n\n/**\n * Type guard to check if a feed event is a video\n *\n * @param value - The feed event value to check\n * @returns True if the event is a video\n */\nexport function isVideo(value: FeedEventValue): boolean {\n  return value.item === FeedItemType.VIDEO;\n}\n\n/**\n * Type guard to check if a feed event is a reaction\n *\n * @param value - The feed event value to check\n * @returns True if the event is a reaction\n */\nexport function isReaction(value: FeedEventValue): boolean {\n  return value.item === FeedItemType.REACTION;\n}\n\n/**\n * Type guard to check if a feed event has a message\n *\n * @param value - The feed event value to check\n * @returns True if the event has a message\n */\nexport function hasMessage(value: FeedEventValue): value is FeedEventValue & { message: string } {\n  return typeof value.message === 'string' && value.message.length > 0;\n}\n\n/**\n * Utility type for extracting just the feed event data\n */\nexport type FeedEventData = FeedEventValue;\n\n/**\n * Processing context for feed events\n */\nexport interface FeedProcessingContext {\n  /** The page ID */\n  pageId: string;\n\n  /** When the event occurred */\n  timestamp: number;\n\n  /** Human-readable datetime for the event timestamp */\n  eventDate: Date;\n\n  /** The sender information */\n  sender?: FeedSender;\n\n  /** Post ID if available */\n  postId?: string;\n\n  /** Comment ID if available */\n  commentId?: string;\n\n  /** The action verb */\n  verb?: FeedActionVerb;\n\n  /** The item type */\n  item?: FeedItemType;\n\n  /** Message content if available */\n  message?: string;\n\n  /** Whether this is a post creation */\n  isPostCreated: boolean;\n\n  /** Whether this is a comment */\n  isComment: boolean;\n\n  /** Whether this is a photo */\n  isPhoto: boolean;\n\n  /** Whether this is a video */\n  isVideo: boolean;\n\n  /** Whether this is a reaction */\n  isReaction: boolean;\n}\n\n/**\n * Helper function to extract processing context from a feed event\n *\n * @param pageId - The page ID from the webhook entry\n * @param timestamp - The timestamp from the webhook entry\n * @param event - The feed webhook event\n * @returns Simplified processing context\n *\n * @example\n * ```typescript\n * const context = extractFeedContext(entry.id, entry.time, event);\n * console.log(`Feed event: ${context.verb} ${context.item}`);\n * if (context.isPostCreated) {\n *   console.log(`New post created: ${context.message}`);\n * }\n * ```\n */\nexport function extractFeedContext(\n  pageId: string,\n  timestamp: number,\n  event: FeedWebhookEvent\n): FeedProcessingContext {\n  const { value } = event;\n\n  return {\n    pageId,\n    timestamp,\n    eventDate: new Date(timestamp),\n    sender: value.from,\n    postId: value.post_id,\n    commentId: value.comment_id,\n    verb: value.verb,\n    item: value.item,\n    message: value.message,\n    isPostCreated: isPostCreated(value),\n    isComment: isComment(value),\n    isPhoto: isPhoto(value),\n    isVideo: isVideo(value),\n    isReaction: isReaction(value),\n  };\n}\n\n/**\n * Helper function to extract all photos from a feed event\n *\n * @param value - The feed event value\n * @returns Array of photo URLs and IDs\n *\n * @example\n * ```typescript\n * const photos = extractPhotos(event.value);\n * console.log(`Found ${photos.length} photo(s)`);\n * ```\n */\nexport function extractPhotos(value: FeedEventValue): Array<{ url?: string; id?: string }> {\n  const photos: Array<{ url?: string; id?: string }> = [];\n\n  if (value.photo) {\n    photos.push({ url: value.photo, id: value.photo_id });\n  }\n\n  if (value.photos && Array.isArray(value.photos)) {\n    photos.push(...value.photos.map((url, index) => ({\n      url,\n      id: value.photo_ids?.[index],\n    })));\n  }\n\n  return photos;\n}\n\n/**\n * Constants related to feed events\n */\nexport const FEED_CONSTANTS = {\n  /** Webhook field name */\n  FIELD_NAME: 'feed' as const,\n\n  /** Maximum Page likes threshold for notifications */\n  MAX_PAGE_LIKES_FOR_NOTIFICATIONS: 10000,\n} as const;\n","/**\n * Facebook Page - Videos Webhook Types\n *\n * These types represent the webhook event structure for video encoding events.\n * Triggered when there are changes to the encoding status of a video on a page.\n *\n * @see https://developers.facebook.com/docs/graph-api/webhooks/reference/page/#videos\n */\n\nimport { PageWebhookPayload } from './base-types';\n\n/**\n * Enumeration of video encoding statuses\n */\nexport enum VideoStatus {\n  /** Video encoding is in progress */\n  PROCESSING = 'processing',\n\n  /** Video encoding is complete and ready */\n  READY = 'ready',\n\n  /** Video encoding failed */\n  ERROR = 'error',\n}\n\n/**\n * Video status information\n */\nexport interface VideoStatusInfo {\n  /** Current status of the video encoding */\n  video_status: VideoStatus;\n}\n\n/**\n * Video event value data\n */\nexport interface VideoEventValue {\n  /** The ID of the video */\n  id: string;\n\n  /** Status information of the video encoding */\n  status: VideoStatusInfo;\n}\n\n/**\n * Main webhook event structure for videos\n *\n * This event is triggered when there are changes to a video's encoding status.\n * The webhook provides information about the video processing state.\n *\n * @example Video processing:\n * ```json\n * {\n *   \"field\": \"videos\",\n *   \"value\": {\n *     \"id\": \"123456789\",\n *     \"status\": {\n *       \"video_status\": \"processing\"\n *     }\n *   }\n * }\n * ```\n *\n * @example Video ready:\n * ```json\n * {\n *   \"field\": \"videos\",\n *   \"value\": {\n *     \"id\": \"123456789\",\n *     \"status\": {\n *       \"video_status\": \"ready\"\n *     }\n *   }\n * }\n * ```\n *\n * @example Video error:\n * ```json\n * {\n *   \"field\": \"videos\",\n *   \"value\": {\n *     \"id\": \"123456789\",\n *     \"status\": {\n *       \"video_status\": \"error\"\n *     }\n *   }\n * }\n * ```\n */\nexport interface VideoWebhookEvent {\n  /** Name of the updated field */\n  field: 'videos';\n\n  /** The contents of the update */\n  value: VideoEventValue;\n}\n\n/**\n * Complete webhook payload structure for video events\n */\nexport interface VideoWebhookPayload extends PageWebhookPayload<VideoWebhookEvent> {}\n\n/**\n * Type guard to check if a webhook event is a video event\n *\n * @param event - The webhook event to check\n * @returns True if the event is a video event\n *\n * @example\n * ```typescript\n * if (isVideoEvent(event)) {\n *   console.log(`Video ${event.value.id} status: ${event.value.status.video_status}`);\n * }\n * ```\n */\nexport function isVideoEvent(event: any): event is VideoWebhookEvent {\n  return event && typeof event === 'object' && event.field === 'videos';\n}\n\n/**\n * Type guard to check if a video is processing\n *\n * @param value - The video event value to check\n * @returns True if the video is being processed\n */\nexport function isProcessing(value: VideoEventValue): boolean {\n  return value.status.video_status === VideoStatus.PROCESSING;\n}\n\n/**\n * Type guard to check if a video is ready\n *\n * @param value - The video event value to check\n * @returns True if the video encoding is complete\n */\nexport function isReady(value: VideoEventValue): boolean {\n  return value.status.video_status === VideoStatus.READY;\n}\n\n/**\n * Type guard to check if a video encoding failed\n *\n * @param value - The video event value to check\n * @returns True if the video encoding failed\n */\nexport function hasError(value: VideoEventValue): boolean {\n  return value.status.video_status === VideoStatus.ERROR;\n}\n\n/**\n * Utility type for extracting just the video event data\n */\nexport type VideoEventData = VideoEventValue;\n\n/**\n * Processing context for video events\n */\nexport interface VideoProcessingContext {\n  /** The page ID */\n  pageId: string;\n\n  /** When the event occurred */\n  timestamp: number;\n\n  /** Human-readable datetime for the event timestamp */\n  eventDate: Date;\n\n  /** The video ID */\n  videoId: string;\n\n  /** Current video status */\n  status: VideoStatus;\n\n  /** Whether the video is being processed */\n  isProcessing: boolean;\n\n  /** Whether the video is ready */\n  isReady: boolean;\n\n  /** Whether the video encoding failed */\n  hasError: boolean;\n}\n\n/**\n * Helper function to extract processing context from a video event\n *\n * @param pageId - The page ID from the webhook entry\n * @param timestamp - The timestamp from the webhook entry\n * @param event - The video webhook event\n * @returns Simplified processing context\n *\n * @example\n * ```typescript\n * const context = extractVideoContext(entry.id, entry.time, event);\n * console.log(`Video ${context.videoId} is ${context.status}`);\n * if (context.isReady) {\n *   console.log('Video is ready to play!');\n * } else if (context.hasError) {\n *   console.log('Video encoding failed');\n * }\n * ```\n */\nexport function extractVideoContext(\n  pageId: string,\n  timestamp: number,\n  event: VideoWebhookEvent\n): VideoProcessingContext {\n  const { value } = event;\n\n  return {\n    pageId,\n    timestamp,\n    eventDate: new Date(timestamp),\n    videoId: value.id,\n    status: value.status.video_status,\n    isProcessing: isProcessing(value),\n    isReady: isReady(value),\n    hasError: hasError(value),\n  };\n}\n\n/**\n * Helper function to determine if a status change is a transition to ready\n *\n * @param fromStatus - The previous status\n * @param toStatus - The new status\n * @returns True if this represents completing encoding\n *\n * @example\n * ```typescript\n * if (isCompletingEncoding(previousStatus, event.value.status.video_status)) {\n *   console.log('Video encoding just completed!');\n * }\n * ```\n */\nexport function isCompletingEncoding(fromStatus: VideoStatus | undefined, toStatus: VideoStatus): boolean {\n  return fromStatus === VideoStatus.PROCESSING && toStatus === VideoStatus.READY;\n}\n\n/**\n * Helper function to determine if a status change is a transition to error\n *\n * @param fromStatus - The previous status\n * @param toStatus - The new status\n * @returns True if this represents encoding failure\n *\n * @example\n * ```typescript\n * if (isEncodingFailed(previousStatus, event.value.status.video_status)) {\n *   console.log('Video encoding failed');\n * }\n * ```\n */\nexport function isEncodingFailed(fromStatus: VideoStatus | undefined, toStatus: VideoStatus): boolean {\n  return fromStatus === VideoStatus.PROCESSING && toStatus === VideoStatus.ERROR;\n}\n\n/**\n * Constants related to video events\n */\nexport const VIDEO_CONSTANTS = {\n  /** Webhook field name */\n  FIELD_NAME: 'videos' as const,\n\n  /** All possible video statuses */\n  STATUSES: Object.values(VideoStatus),\n} as const;\n","/**\n * Facebook Messenger Platform - Live Videos Webhook Types\n *\n * These types represent the webhook event structure for live video events.\n * Triggered when there are changes to a page's live video status, such as\n * when a live video starts, ends, or has status updates.\n *\n * @see https://developers.facebook.com/docs/graph-api/webhooks/reference/page/#live_videos\n */\n\nimport { PageWebhookPayload } from './base-types';\n\n/**\n * Enumeration of live video broadcast statuses\n * Based on Facebook Graph API BroadcastStatus enum\n *\n * @see https://developers.facebook.com/docs/graph-api/reference/live-video/\n */\nexport enum LiveVideoStatus {\n  /** Live broadcast is currently streaming */\n  LIVE = 'LIVE',\n\n  /** Live broadcast has stopped */\n  LIVE_STOPPED = 'LIVE_STOPPED',\n\n  /** Live broadcast is currently being processed */\n  PROCESSING = 'PROCESSING',\n\n  /** Scheduled broadcast was canceled */\n  SCHEDULED_CANCELED = 'SCHEDULED_CANCELED',\n\n  /** Scheduled broadcast has expired */\n  SCHEDULED_EXPIRED = 'SCHEDULED_EXPIRED',\n\n  /** Live broadcast is scheduled and published */\n  SCHEDULED_LIVE = 'SCHEDULED_LIVE',\n\n  /** Live broadcast is scheduled but unpublished */\n  SCHEDULED_UNPUBLISHED = 'SCHEDULED_UNPUBLISHED',\n\n  /** Live broadcast is unpublished */\n  UNPUBLISHED = 'UNPUBLISHED',\n\n  /** Live broadcast video on demand (VOD) is ready */\n  VOD = 'VOD',\n}\n\n/**\n * Live video event value data\n */\nexport interface LiveVideoEventValue {\n  /** The ID of the live video */\n  id: string;\n\n  /** Status of the live video (enum value directly) */\n  status: LiveVideoStatus;\n}\n\n/**\n * Main webhook event structure for live videos\n *\n * This event is triggered when there are changes to a page's live video status.\n * The webhook provides information about the live video state changes.\n *\n * @example Live video started:\n * ```json\n * {\n *   \"field\": \"live_videos\",\n *   \"value\": {\n *     \"id\": \"123456789\",\n *     \"status\": \"LIVE\"\n *   }\n * }\n * ```\n *\n * @example Live video ended:\n * ```json\n * {\n *   \"field\": \"live_videos\",\n *   \"value\": {\n *     \"id\": \"123456789\",\n *     \"status\": \"LIVE_STOPPED\"\n *   }\n * }\n * ```\n */\nexport interface LiveVideoWebhookEvent {\n  /** Name of the updated field */\n  field: 'live_videos';\n\n  /** The contents of the update */\n  value: LiveVideoEventValue;\n}\n\n/**\n * Complete webhook payload structure for live video events\n */\nexport interface LiveVideoWebhookPayload extends PageWebhookPayload<LiveVideoWebhookEvent> {}\n\n/**\n * Type guard to check if a webhook event is a live video event\n *\n * @param event - The webhook event to check\n * @returns True if the event is a live video event\n *\n * @example\n * ```typescript\n * if (isLiveVideoEvent(event)) {\n *   console.log(`Live video ${event.value.id} status: ${event.value.status}`);\n * }\n * ```\n */\nexport function isLiveVideoEvent(event: any): event is LiveVideoWebhookEvent {\n  return event && typeof event === 'object' && event.field === 'live_videos';\n}\n\n/**\n * Type guard to check if a live video is currently live\n *\n * @param value - The live video event value to check\n * @returns True if the live video is currently streaming\n */\nexport function isLive(value: LiveVideoEventValue): boolean {\n  return value.status === LiveVideoStatus.LIVE;\n}\n\n/**\n * Type guard to check if a live video is scheduled\n *\n * @param value - The live video event value to check\n * @returns True if the live video is scheduled\n */\nexport function isScheduled(value: LiveVideoEventValue): boolean {\n  return (\n    value.status === LiveVideoStatus.SCHEDULED_UNPUBLISHED ||\n    value.status === LiveVideoStatus.SCHEDULED_LIVE\n  );\n}\n\n/**\n * Type guard to check if a live video is processing\n *\n * @param value - The live video event value to check\n * @returns True if the live video is being processed\n */\nexport function isProcessing(value: LiveVideoEventValue): boolean {\n  return value.status === LiveVideoStatus.PROCESSING;\n}\n\n/**\n * Type guard to check if a live video has ended\n *\n * @param value - The live video event value to check\n * @returns True if the live video has stopped, was cancelled, or expired\n */\nexport function hasEnded(value: LiveVideoEventValue): boolean {\n  return (\n    value.status === LiveVideoStatus.LIVE_STOPPED ||\n    value.status === LiveVideoStatus.SCHEDULED_CANCELED ||\n    value.status === LiveVideoStatus.SCHEDULED_EXPIRED\n  );\n}\n\n/**\n * Type guard to check if a live video VOD is ready\n *\n * @param value - The live video event value to check\n * @returns True if the video on demand is ready\n */\nexport function isVODReady(value: LiveVideoEventValue): boolean {\n  return value.status === LiveVideoStatus.VOD;\n}\n\n/**\n * Utility type for extracting just the live video event data\n */\nexport type LiveVideoEventData = LiveVideoEventValue;\n\n/**\n * Processing context for live video events\n */\nexport interface LiveVideoProcessingContext {\n  /** The page ID */\n  pageId: string;\n\n  /** When the event occurred */\n  timestamp: number;\n\n  /** Human-readable datetime for the event timestamp */\n  eventDate: Date;\n\n  /** The live video ID */\n  videoId: string;\n\n  /** Current video status */\n  status: LiveVideoStatus;\n\n  /** Whether the video is currently live */\n  isLive: boolean;\n\n  /** Whether the video is scheduled */\n  isScheduled: boolean;\n\n  /** Whether the video is being processed */\n  isProcessing: boolean;\n\n  /** Whether the video has ended */\n  hasEnded: boolean;\n\n  /** Whether the VOD is ready */\n  isVODReady: boolean;\n}\n\n/**\n * Helper function to extract processing context from a live video event\n *\n * @param pageId - The page ID from the webhook entry\n * @param timestamp - The timestamp from the webhook entry\n * @param event - The live video webhook event\n * @returns Simplified processing context\n *\n * @example\n * ```typescript\n * const context = extractLiveVideoContext(entry.id, entry.time, event);\n * console.log(`Live video ${context.videoId} is ${context.status}`);\n * if (context.isLive) {\n *   console.log('Stream is currently live!');\n * } else if (context.hasEnded) {\n *   console.log('Stream has ended');\n * }\n * ```\n */\nexport function extractLiveVideoContext(\n  pageId: string,\n  timestamp: number,\n  event: LiveVideoWebhookEvent\n): LiveVideoProcessingContext {\n  const { value } = event;\n\n  return {\n    pageId,\n    timestamp,\n    eventDate: new Date(timestamp),\n    videoId: value.id,\n    status: value.status,\n    isLive: isLive(value),\n    isScheduled: isScheduled(value),\n    isProcessing: isProcessing(value),\n    hasEnded: hasEnded(value),\n    isVODReady: isVODReady(value),\n  };\n}\n\n/**\n * Helper function to determine if a status change is a transition to live\n *\n * @param fromStatus - The previous status\n * @param toStatus - The new status\n * @returns True if this represents going live\n *\n * @example\n * ```typescript\n * if (isGoingLive(previousStatus, event.value.status)) {\n *   console.log('Video just went live!');\n * }\n * ```\n */\nexport function isGoingLive(fromStatus: LiveVideoStatus | undefined, toStatus: LiveVideoStatus): boolean {\n  return fromStatus !== LiveVideoStatus.LIVE && toStatus === LiveVideoStatus.LIVE;\n}\n\n/**\n * Helper function to determine if a status change is a transition from live to ended\n *\n * @param fromStatus - The previous status\n * @param toStatus - The new status\n * @returns True if this represents ending a live stream\n *\n * @example\n * ```typescript\n * if (isEndingLive(previousStatus, event.value.status)) {\n *   console.log('Live stream has ended');\n * }\n * ```\n */\nexport function isEndingLive(fromStatus: LiveVideoStatus | undefined, toStatus: LiveVideoStatus): boolean {\n  return (\n    fromStatus === LiveVideoStatus.LIVE &&\n    (toStatus === LiveVideoStatus.LIVE_STOPPED ||\n     toStatus === LiveVideoStatus.SCHEDULED_CANCELED ||\n     toStatus === LiveVideoStatus.SCHEDULED_EXPIRED)\n  );\n}\n\n/**\n * Constants related to live video events\n */\nexport const LIVE_VIDEO_CONSTANTS = {\n  /** Webhook field name */\n  FIELD_NAME: 'live_videos' as const,\n\n  /** All possible video statuses */\n  STATUSES: Object.values(LiveVideoStatus),\n} as const;\n","/**\n * Facebook Messenger Platform - Messages Webhook Types\n * \n * These types represent the webhook event structure for messages events.\n * Triggered when a user sends a message to your page.\n * \n * @see https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/messages\n */\n\nimport {\n  BaseWebhookEvent,\n  WebhookEventType,\n  WebhookPayload,\n  BaseProcessingContext,\n  extractBaseContext,\n} from './base-types';\n\n/**\n * Enumeration of attachment types supported by the Messenger Platform\n */\nexport enum AttachmentType {\n  AUDIO = 'audio',\n  FILE = 'file',\n  IMAGE = 'image',\n  VIDEO = 'video',\n  FALLBACK = 'fallback',\n  REEL = 'reel',\n  IG_REEL = 'ig_reel',\n}\n\n/**\n * Enumeration of referral types for message referrals\n */\nexport enum ReferralType {\n  OPEN_THREAD = 'OPEN_THREAD',\n  PRODUCT = 'product',\n  ADS = 'ads',\n}\n\n/**\n * Enumeration of referral sources\n */\nexport enum ReferralSource {\n  MESSENGER_CODE = 'MESSENGER_CODE',\n  DISCOVER_TAB = 'DISCOVER_TAB',\n  ADS = 'ADS',\n  SHORTLINK = 'SHORTLINK',\n  CUSTOMER_CHAT_PLUGIN = 'CUSTOMER_CHAT_PLUGIN',\n}\n\n// Note: MessageSender and MessageRecipient are now replaced by\n// WebhookSender and WebhookRecipient from base-types.ts\n// Keeping these as deprecated aliases for backward compatibility\n\nimport { WebhookSender as MessageSender } from './base-types';\nimport { WebhookRecipient as MessageRecipient } from './base-types';\nexport { MessageSender, MessageRecipient };\n\n/**\n * Represents a quick reply payload in a message\n */\nexport interface QuickReply {\n  /** \n   * The payload string that was defined when the quick reply was sent.\n   * Maximum 1000 characters.\n   */\n  payload: string;\n}\n\n/**\n * Represents the reply-to information when a message is a reply\n */\nexport interface ReplyTo {\n  /** \n   * Message ID of the message being replied to \n   */\n  mid: string;\n\n  is_self_reply?: boolean;\n}\n\n/**\n * Base attachment payload interface\n */\nexport interface BaseAttachmentPayload {\n  /** URL to the attachment file */\n  url: string;\n}\n\n/**\n * Attachment payload for media files (audio, image, video, file)\n */\nexport interface MediaAttachmentPayload extends BaseAttachmentPayload {\n  /** URL to the attachment file */\n  url: string;\n  \n  /** Title of the attachment, if available */\n  title?: string;\n}\n\n/**\n * Attachment payload for sticker attachments\n */\nexport interface StickerAttachmentPayload extends BaseAttachmentPayload {\n  /** URL to the sticker image */\n  url: string;\n  \n  /** Sticker ID for the sent sticker */\n  sticker_id: number;\n}\n\n/**\n * Attachment payload for reel attachments (Instagram Reels, Facebook Reels)\n */\nexport interface ReelAttachmentPayload extends BaseAttachmentPayload {\n  /** URL to the reel */\n  url: string;\n  \n  /** Video ID of the reel */\n  reel_video_id?: number;\n}\n\n/**\n * Attachment payload for fallback attachments\n */\nexport interface FallbackAttachmentPayload extends BaseAttachmentPayload {\n  /** URL to the attachment */\n  url: string;\n  \n  /** Title of the fallback attachment */\n  title?: string;\n}\n\n/**\n * Union type for all possible attachment payload types\n */\nexport type AttachmentPayload = \n  | MediaAttachmentPayload \n  | StickerAttachmentPayload \n  | ReelAttachmentPayload \n  | FallbackAttachmentPayload;\n\n/**\n * Represents an attachment in a message\n */\nexport interface MessageAttachment {\n  /** The type of attachment */\n  type: AttachmentType;\n  \n  /** The attachment payload containing the actual attachment data */\n  payload: AttachmentPayload;\n}\n\n/**\n * Represents referral data in a message (for referral campaigns, ads, etc.)\n */\nexport interface MessageReferral {\n  /** The source of the referral */\n  source: ReferralSource;\n  \n  /** The type of referral */\n  type: ReferralType;\n  \n  /** \n   * The optional ref parameter passed in the referral.\n   * Maximum 250 characters.\n   */\n  ref?: string;\n  \n  /** \n   * URL of the website where the referral was triggered.\n   * Only present for CUSTOMER_CHAT_PLUGIN source.\n   */\n  referer_uri?: string;\n  \n  /** \n   * Indicates whether the referral is from a guest user.\n   * Only present for CUSTOMER_CHAT_PLUGIN source.\n   */\n  is_guest_user?: boolean;\n  \n  /** \n   * Product information for product referrals.\n   * Only present when type is 'product'.\n   */\n  product?: {\n    /** Product ID */\n    id: string;\n  };\n  \n  /** \n   * Ad information for ad referrals.\n   * Only present when type is 'ads'.\n   */\n  ads?: {\n    /** Ad ID */\n    id: string;\n    \n    /** Ad title */\n    title?: string;\n    \n    /** Ad image URL */\n    image_url?: string;\n  };\n}\n\n/**\n * Represents a command in a message (for bot commands)\n */\nexport interface MessageCommand {\n  /** The name of the command */\n  name: string;\n}\n\n/**\n * Represents the main message content in a webhook event\n */\nexport interface Message {\n  /** \n   * Unique message identifier \n   */\n  mid: string;\n\n  is_echo?: boolean;\n  app_id?: string | number;\n  metadata?: string;\n  \n  /** \n   * Text content of the message.\n   * Present for text messages and messages with quick replies.\n   * Maximum 2000 UTF-8 characters.\n   */\n  text?: string;\n  \n  /** \n   * Quick reply payload, if the message was sent as a response to a quick reply.\n   * Only present when the user taps a quick reply button.\n   */\n  quick_reply?: QuickReply;\n  \n  /** \n   * Reply-to information, if this message is a reply to another message.\n   * Only present when the user replies to a specific message.\n   */\n  reply_to?: ReplyTo;\n  \n  /** \n   * Array of attachments sent with the message.\n   * Can include images, audio, video, files, location, etc.\n   */\n  attachments?: MessageAttachment[];\n  \n  /** \n   * Referral information, if the message came from a referral.\n   * Present when users click on ads, m.me links, etc.\n   */\n  referral?: MessageReferral;\n  \n  /** \n   * Array of commands, if the message contains bot commands.\n   * Present when users send commands like /start, /help, etc.\n   */\n  commands?: MessageCommand[];\n}\n\n/**\n * Main webhook event structure for messages with discriminator\n * \n * This event is triggered when a user sends a message to your page.\n * The webhook provides the message content and metadata.\n * \n * @example Text message:\n * ```json\n * {\n *   \"type\": \"message\",\n *   \"sender\": {\n *     \"id\": \"1234567890123456\"\n *   },\n *   \"recipient\": {\n *     \"id\": \"9876543210987654\"\n *   },\n *   \"timestamp\": 1458668856463,\n *   \"message\": {\n *     \"mid\": \"mid.1458668856218:ed81099e15d3f4f233\",\n *     \"text\": \"Hello, world!\"\n *   }\n * }\n * ```\n * \n * @example Message with attachment:\n * ```json\n * {\n *   \"type\": \"message\",\n *   \"sender\": {\n *     \"id\": \"1234567890123456\"\n *   },\n *   \"recipient\": {\n *     \"id\": \"9876543210987654\"\n *   },\n *   \"timestamp\": 1458668856463,\n *   \"message\": {\n *     \"mid\": \"mid.1458668856218:ed81099e15d3f4f233\",\n *     \"attachments\": [\n *       {\n *         \"type\": \"image\",\n *         \"payload\": {\n *           \"url\": \"https://scontent.xx.fbcdn.net/v/image.jpg\"\n *         }\n *       }\n *     ]\n *   }\n * }\n * ```\n * \n * @example Message with quick reply:\n * ```json\n * {\n *   \"type\": \"message\",\n *   \"sender\": {\n *     \"id\": \"1234567890123456\"\n *   },\n *   \"recipient\": {\n *     \"id\": \"9876543210987654\"\n *   },\n *   \"timestamp\": 1458668856463,\n *   \"message\": {\n *     \"mid\": \"mid.1458668856218:ed81099e15d3f4f233\",\n *     \"text\": \"Yes\",\n *     \"quick_reply\": {\n *       \"payload\": \"YES_PAYLOAD\"\n *     }\n *   }\n * }\n * ```\n */\nexport interface MessageWebhookEvent extends BaseWebhookEvent {\n  /** Discriminator for type narrowing */\n  type: WebhookEventType.MESSAGE;\n  \n  /** The message content and metadata */\n  message: Message;\n}\n\n/**\n * Complete webhook payload structure that includes the message event\n * along with other webhook metadata\n */\nexport interface MessageWebhookPayload extends WebhookPayload<MessageWebhookEvent> {}\n\n/**\n * Type guard to check if a webhook event is a message event\n * \n * @param event - The webhook event to check\n * @returns True if the event contains a message property\n * \n * @example\n * ```typescript\n * if (isMessageEvent(event)) {\n *   // TypeScript now knows event has message property\n *   console.log(`Received message: ${event.message.text || '[attachment]'}`);\n * }\n * ```\n */\nexport function isMessageEvent(event: any): event is MessageWebhookEvent {\n  return event && typeof event === 'object' && 'message' in event;\n}\n\n/**\n * Type guard to check if a message has text content\n * \n * @param message - The message to check\n * @returns True if the message has text content\n */\nexport function isTextMessage(message: Message): message is Message & { text: string } {\n  return typeof message.text === 'string' && message.text.length > 0;\n}\n\n/**\n * Type guard to check if a message has attachments\n * \n * @param message - The message to check\n * @returns True if the message has attachments\n */\nexport function hasAttachments(message: Message): message is Message & { attachments: MessageAttachment[] } {\n  return Array.isArray(message.attachments) && message.attachments.length > 0;\n}\n\n/**\n * Type guard to check if a message has a quick reply\n * \n * @param message - The message to check\n * @returns True if the message has a quick reply\n */\nexport function hasQuickReply(message: Message): message is Message & { quick_reply: QuickReply } {\n  return message.quick_reply !== undefined;\n}\n\n/**\n * Type guard to check if a message is a reply to another message\n * \n * @param message - The message to check\n * @returns True if the message is a reply\n */\nexport function isReplyMessage(message: Message): message is Message & { reply_to: ReplyTo } {\n  return message.reply_to !== undefined;\n}\n\n/**\n * Type guard to check if a message has referral data\n * \n * @param message - The message to check\n * @returns True if the message has referral data\n */\nexport function hasReferral(message: Message): message is Message & { referral: MessageReferral } {\n  return message.referral !== undefined;\n}\n\n/**\n * Type guard to check if an attachment is a specific type\n * \n * @param attachment - The attachment to check\n * @param type - The attachment type to check for\n * @returns True if the attachment is of the specified type\n */\nexport function isAttachmentType<T extends AttachmentType>(\n  attachment: MessageAttachment, \n  type: T\n): attachment is MessageAttachment & { type: T } {\n  return attachment.type === type;\n}\n\n/**\n * Utility type for extracting just the message data from a webhook event\n */\nexport type MessageData = Message;\n\n/**\n * Utility type for common message properties that might be used in processing\n */\nexport interface MessageProcessingContext extends BaseProcessingContext {\n  /** The message ID */\n  messageId: string;\n  \n  /** Message text content, if available */\n  text?: string;\n  \n  /** Whether the message has attachments */\n  hasAttachments: boolean;\n  \n  /** Whether the message is a quick reply */\n  isQuickReply: boolean;\n  \n  /** Whether the message is a reply to another message */\n  isReply: boolean;\n  \n  /** Whether the message has referral data */\n  hasReferral: boolean;\n  \n  /** Quick reply payload, if available */\n  quickReplyPayload?: string;\n  \n  /** Replied message ID, if this is a reply */\n  repliedToMessageId?: string;\n}\n\n/**\n * Helper function to extract processing context from a message event\n * \n * @param event - The message webhook event\n * @returns Simplified processing context\n * \n * @example\n * ```typescript\n * const context = extractMessageContext(webhookEvent);\n * console.log(`User ${context.senderId} sent: \"${context.text || '[attachment]'}\"`);\n * if (context.isQuickReply) {\n *   console.log(`Quick reply payload: ${context.quickReplyPayload}`);\n * }\n * ```\n */\nexport function extractMessageContext(event: MessageWebhookEvent): MessageProcessingContext {\n  const { message } = event;\n  const baseContext = extractBaseContext(event);\n  \n  return {\n    ...baseContext,\n    messageId: message.mid,\n    text: message.text,\n    hasAttachments: hasAttachments(message),\n    isQuickReply: hasQuickReply(message),\n    isReply: isReplyMessage(message),\n    hasReferral: hasReferral(message),\n    quickReplyPayload: message.quick_reply?.payload,\n    repliedToMessageId: message.reply_to?.mid,\n  };\n}\n\n/**\n * Helper function to get attachments of a specific type from a message\n * \n * @param message - The message to extract attachments from\n * @param type - The attachment type to filter by\n * @returns Array of attachments of the specified type\n * \n * @example\n * ```typescript\n * const images = getAttachmentsByType(message, AttachmentType.IMAGE);\n * console.log(`Message contains ${images.length} image(s)`);\n * ```\n */\nexport function getAttachmentsByType<T extends AttachmentType>(\n  message: Message, \n  type: T\n): Array<MessageAttachment & { type: T }> {\n  if (!hasAttachments(message)) {\n    return [];\n  }\n  \n  return message.attachments.filter((attachment): attachment is MessageAttachment & { type: T } => \n    isAttachmentType(attachment, type)\n  );\n}\n\n/**\n * Helper function to extract all URLs from message attachments\n * \n * @param message - The message to extract URLs from\n * @returns Array of attachment URLs\n * \n * @example\n * ```typescript\n * const urls = getAttachmentUrls(message);\n * console.log(`Message contains ${urls.length} attachment(s)`);\n * ```\n */\nexport function getAttachmentUrls(message: Message): string[] {\n  if (!hasAttachments(message)) {\n    return [];\n  }\n  \n  return message.attachments.map(attachment => attachment.payload.url);\n}\n\n/**\n * Constants related to message limits and constraints\n */\nexport const MESSAGE_CONSTANTS = {\n  /** Maximum length of message text */\n  MAX_TEXT_LENGTH: 2000,\n  \n  /** Maximum length of quick reply payload */\n  MAX_QUICK_REPLY_PAYLOAD_LENGTH: 1000,\n  \n  /** Maximum length of referral ref parameter */\n  MAX_REFERRAL_REF_LENGTH: 250,\n  \n  /** Webhook event type identifier */\n  EVENT_TYPE: 'message' as const,\n} as const;\n\n/**\n * Common attachment MIME types for validation\n */\nexport const ATTACHMENT_MIME_TYPES = {\n  [AttachmentType.IMAGE]: [\n    'image/jpeg',\n    'image/png',\n    'image/gif',\n    'image/webp',\n  ],\n  [AttachmentType.VIDEO]: [\n    'video/mp4',\n    'video/avi',\n    'video/quicktime',\n    'video/webm',\n  ],\n  [AttachmentType.AUDIO]: [\n    'audio/mpeg',\n    'audio/mp4',\n    'audio/wav',\n    'audio/ogg',\n  ],\n  [AttachmentType.FILE]: [\n    'application/pdf',\n    'application/msword',\n    'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n    'text/plain',\n  ],\n} as const;","/**\n * Facebook Messenger Webhook Events - Main Entry Point\n * \n * This file provides the unified type system for all webhook events supported \n * by the Messenger Platform. It uses discriminated unions with proper type\n * narrowing to ensure type safety.\n * \n * @module webhooks/webhook-events\n */\n\nimport {\n  WebhookEventType,\n  WebhookPayload as GenericWebhookPayload,\n  extractEvents,\n} from './base-types';\n\nimport {\n  MessageEditWebhookEvent,\n  MessageEditWebhookPayload,\n} from './message-edits';\n\nimport {\n  MessageReactionWebhookEvent,\n  MessageReactionWebhookPayload,\n} from './message-reactions';\n\nimport {\n  MessageWebhookEvent,\n  MessageWebhookPayload,\n} from './messages';\n\nimport {\n  MessageEchoWebhookEvent,\n  MessageEchoWebhookPayload,\n} from './message-echoes';\n\nimport {\n  MessageReadsWebhookEvent,\n  MessageReadsWebhookPayload,\n} from './message-reads';\n\nimport {\n  MessagingFeedbackWebhookEvent,\n  MessagingFeedbackWebhookPayload,\n} from './messaging-feedback';\n\nimport {\n  MessagingPostbackWebhookEvent,\n  MessagingPostbackWebhookPayload,\n} from './messaging-postbacks';\n\n// Re-export base types for convenience\nexport {\n  WebhookEventType,\n  WebhookSender,\n  WebhookRecipient,\n  WebhookEntry,\n  WebhookPayload,\n} from './base-types';\n\n// Re-export GenericWebhookPayload as an alias\nexport type { WebhookPayload as GenericWebhookPayload } from './base-types';\n\n/**\n * Discriminated union type of all possible webhook events.\n * Each event has a 'type' field that allows TypeScript to narrow the type.\n */\nexport type MessengerWebhookEvent =\n  | MessageEditWebhookEvent\n  | MessageReactionWebhookEvent\n  | MessageWebhookEvent\n  | MessageEchoWebhookEvent\n  | MessageReadsWebhookEvent\n  | MessagingFeedbackWebhookEvent\n  | MessagingPostbackWebhookEvent;\n\n/**\n * Union type of all possible webhook payloads\n */\nexport type MessengerWebhookPayload =\n  | MessageEditWebhookPayload\n  | MessageReactionWebhookPayload\n  | MessageWebhookPayload\n  | MessageEchoWebhookPayload\n  | MessageReadsWebhookPayload\n  | MessagingFeedbackWebhookPayload\n  | MessagingPostbackWebhookPayload;\n\n/**\n * Type guard to check webhook event type for a SINGLE event.\n * This function now properly handles individual events from the messaging array.\n * \n * @param event - A single webhook event from the messaging array\n * @returns The event type or null if unknown\n * \n * @example\n * ```typescript\n * const events = extractWebhookEvents(payload);\n * for (const event of events) {\n *   const eventType = getWebhookEventType(event);\n *   console.log(`Event type: ${eventType}`);\n * }\n * ```\n */\nexport function getWebhookEventType(event: MessengerWebhookEvent | any): WebhookEventType | null {\n  if (!event || typeof event !== 'object') {\n    return null;\n  }\n\n  // Check for discriminator field if it exists (new structure)\n  if ('type' in event && Object.values(WebhookEventType).includes(event.type)) {\n    return event.type as WebhookEventType;\n  }\n\n  // Fallback to property-based detection for backward compatibility\n  if (\n    'message' in event &&\n    event.message &&\n    typeof event.message === 'object' &&\n    event.message.is_echo === true\n  ) {\n    return WebhookEventType.MESSAGE_ECHO;\n  }\n  if ('message' in event) {\n    return WebhookEventType.MESSAGE;\n  }\n  if ('message_edit' in event) {\n    return WebhookEventType.MESSAGE_EDIT;\n  }\n  if ('reaction' in event) {\n    return WebhookEventType.MESSAGE_REACTION;\n  }\n  if ('read' in event) {\n    return WebhookEventType.MESSAGE_READ;\n  }\n  if ('messaging_feedback' in event) {\n    return WebhookEventType.MESSAGING_FEEDBACK;\n  }\n  if ('postback' in event) {\n    return WebhookEventType.MESSAGING_POSTBACK;\n  }\n\n  return null;\n}\n\n/**\n * Extract event types from a complete webhook payload.\n * This is the correct function to use when processing the full webhook payload.\n * \n * @param payload - The complete webhook payload from Facebook\n * @returns Array of unique event types found in the payload\n * \n * @example\n * ```typescript\n * app.post('/webhook', (req, res) => {\n *   const payload = req.body;\n *   const eventTypes = getWebhookPayloadEventTypes(payload);\n *   \n *   if (eventTypes.includes(WebhookEventType.MESSAGE)) {\n *     // Process message events\n *   }\n * });\n * ```\n */\nexport function getWebhookPayloadEventTypes(payload: GenericWebhookPayload): WebhookEventType[] {\n  const eventTypes = new Set<WebhookEventType>();\n  \n  if (payload.object === 'page' && Array.isArray(payload.entry)) {\n    for (const entry of payload.entry) {\n      if (Array.isArray(entry.messaging)) {\n        for (const event of entry.messaging) {\n          const type = getWebhookEventType(event);\n          if (type) {\n            eventTypes.add(type);\n          }\n        }\n      }\n    }\n  }\n  \n  return Array.from(eventTypes);\n}\n\n/**\n * Extract all events from a webhook payload.\n * This properly extracts individual events from the nested structure.\n * \n * @param payload - The complete webhook payload\n * @returns Array of individual webhook events\n * \n * @example\n * ```typescript\n * const events = extractWebhookEvents(payload);\n * events.forEach(event => {\n *   const type = getWebhookEventType(event);\n *   console.log(`Processing ${type} event`);\n * });\n * ```\n */\nexport function extractWebhookEvents(payload: GenericWebhookPayload): MessengerWebhookEvent[] {\n  return extractEvents(payload) as MessengerWebhookEvent[];\n}\n\n/**\n * Add discriminator to events that don't have it (for backward compatibility).\n * This ensures all events have the 'type' field for proper type narrowing.\n * \n * @param event - The webhook event to enhance\n * @returns The event with added type discriminator\n */\nfunction addDiscriminator(event: any): MessengerWebhookEvent | null {\n  const type = getWebhookEventType(event);\n  if (!type) return null;\n  \n  // Add the type field if it doesn't exist\n  if (!('type' in event)) {\n    return { ...event, type } as MessengerWebhookEvent;\n  }\n  \n  return event as MessengerWebhookEvent;\n}\n\n/**\n * Process webhook events by type with proper type narrowing.\n * This uses the discriminated union for automatic type narrowing.\n * \n * @param payload - The complete webhook payload\n * @param handlers - Object with handler functions for each event type\n * \n * @example\n * ```typescript\n * processWebhookEvents(payload, {\n *   onMessage: async (event) => {\n *     // TypeScript knows event is MessageWebhookEvent\n *     console.log(`Message: ${event.message.text}`);\n *   },\n *   onMessageEdit: async (event) => {\n *     // TypeScript knows event is MessageEditWebhookEvent\n *     console.log(`Edited to: ${event.message_edit.text}`);\n *   }\n * });\n * ```\n */\nexport interface WebhookEventHandlers {\n  onMessage?: (event: MessageWebhookEvent) => void | Promise<void>;\n  onMessageEcho?: (event: MessageEchoWebhookEvent) => void | Promise<void>;\n  onMessageEdit?: (event: MessageEditWebhookEvent) => void | Promise<void>;\n  onMessageReaction?: (event: MessageReactionWebhookEvent) => void | Promise<void>;\n  onMessageRead?: (event: MessageReadsWebhookEvent) => void | Promise<void>;\n  onMessagingFeedback?: (event: MessagingFeedbackWebhookEvent) => void | Promise<void>;\n  onMessagingPostback?: (event: MessagingPostbackWebhookEvent) => void | Promise<void>;\n  onUnknown?: (event: any) => void | Promise<void>;\n}\n\nexport async function processWebhookEvents(\n  payload: GenericWebhookPayload,\n  handlers: WebhookEventHandlers\n): Promise<void> {\n  const events = extractWebhookEvents(payload);\n  \n  for (const rawEvent of events) {\n    // Ensure event has discriminator\n    const event = addDiscriminator(rawEvent);\n    if (!event) {\n      if (handlers.onUnknown) {\n        await handlers.onUnknown(rawEvent);\n      }\n      continue;\n    }\n    \n    // Use discriminated union for type narrowing\n    switch (event.type) {\n      case WebhookEventType.MESSAGE:\n        if (handlers.onMessage) {\n          await handlers.onMessage(event);\n        }\n        break;\n\n      case WebhookEventType.MESSAGE_ECHO:\n        if (handlers.onMessageEcho) {\n          await handlers.onMessageEcho(event);\n        }\n        break;\n        \n      case WebhookEventType.MESSAGE_EDIT:\n        if (handlers.onMessageEdit) {\n          await handlers.onMessageEdit(event);\n        }\n        break;\n        \n      case WebhookEventType.MESSAGE_REACTION:\n        if (handlers.onMessageReaction) {\n          await handlers.onMessageReaction(event);\n        }\n        break;\n        \n      case WebhookEventType.MESSAGE_READ:\n        if (handlers.onMessageRead) {\n          await handlers.onMessageRead(event);\n        }\n        break;\n        \n      case WebhookEventType.MESSAGING_FEEDBACK:\n        if (handlers.onMessagingFeedback) {\n          await handlers.onMessagingFeedback(event);\n        }\n        break;\n        \n      case WebhookEventType.MESSAGING_POSTBACK:\n        if (handlers.onMessagingPostback) {\n          await handlers.onMessagingPostback(event);\n        }\n        break;\n        \n      default:\n        // This should never happen with proper typing\n        const exhaustiveCheck: never = event;\n        if (handlers.onUnknown) {\n          await handlers.onUnknown(exhaustiveCheck);\n        }\n        break;\n    }\n  }\n}\n\n/**\n * Type predicate functions for each event type.\n * These enable proper type narrowing in conditional statements.\n */\n\nexport function isMessageEvent(event: MessengerWebhookEvent): event is MessageWebhookEvent {\n  return event.type === WebhookEventType.MESSAGE || 'message' in event;\n}\n\nexport function isMessageEchoEvent(event: MessengerWebhookEvent): event is MessageEchoWebhookEvent {\n  return (\n    event.type === WebhookEventType.MESSAGE_ECHO ||\n    ('message' in event && (event as any).message && (event as any).message.is_echo === true)\n  );\n}\n\nexport function isMessageEditEvent(event: MessengerWebhookEvent): event is MessageEditWebhookEvent {\n  return event.type === WebhookEventType.MESSAGE_EDIT || 'message_edit' in event;\n}\n\nexport function isMessageReactionEvent(event: MessengerWebhookEvent): event is MessageReactionWebhookEvent {\n  return event.type === WebhookEventType.MESSAGE_REACTION || 'reaction' in event;\n}\n\nexport function isMessageReadEvent(event: MessengerWebhookEvent): event is MessageReadsWebhookEvent {\n  return event.type === WebhookEventType.MESSAGE_READ || 'read' in event;\n}\n\nexport function isMessagingFeedbackEvent(event: MessengerWebhookEvent): event is MessagingFeedbackWebhookEvent {\n  return event.type === WebhookEventType.MESSAGING_FEEDBACK || 'messaging_feedback' in event;\n}\n\nexport function isMessagingPostbackEvent(event: MessengerWebhookEvent): event is MessagingPostbackWebhookEvent {\n  return event.type === WebhookEventType.MESSAGING_POSTBACK || 'postback' in event;\n}\n\n/**\n * Webhook verification parameters for subscription verification\n */\nexport interface WebhookVerificationParams {\n  'hub.mode': string;\n  'hub.verify_token': string;\n  'hub.challenge': string;\n}\n\n/**\n * Webhook signature verification result\n */\nexport interface WebhookSignatureVerificationResult {\n  isValid: boolean;\n  error?: string;\n}\n\n/**\n * Verify webhook subscription during initial setup\n * \n * @param params - Query parameters from Facebook's verification request\n * @param verifyToken - Your webhook verify token\n * @returns The challenge string if valid, null if invalid\n * \n * @example\n * ```typescript\n * app.get('/webhook', (req, res) => {\n *   const challenge = verifyWebhookSubscription(req.query, process.env.VERIFY_TOKEN);\n *   if (challenge) {\n *     res.send(challenge);\n *   } else {\n *     res.status(403).send('Forbidden');\n *   }\n * });\n * ```\n */\nexport function verifyWebhookSubscription(\n  params: WebhookVerificationParams,\n  verifyToken: string\n): string | null {\n  if (\n    params['hub.mode'] === 'subscribe' &&\n    params['hub.verify_token'] === verifyToken\n  ) {\n    return params['hub.challenge'];\n  }\n  return null;\n}\n\n/**\n * Verify webhook signature from Facebook\n * \n * **Note**: This function requires Node.js crypto module and is only supported in server-side environments.\n * For browser environments, you should handle signature verification on your backend.\n * \n * @param rawBody - The raw request body as Buffer\n * @param signature - The X-Hub-Signature-256 header value from Facebook\n * @param appSecret - Your Facebook app secret\n * @returns Promise that resolves to verification result with validity and optional error message\n * \n * @example\n * ```typescript\n * import express from 'express';\n * import { verifyWebhookSignature } from '@warriorteam/messenger-sdk';\n * \n * app.post('/webhook', express.raw({type: 'application/json'}), async (req, res) => {\n *   const signature = req.get('X-Hub-Signature-256');\n *   const result = await verifyWebhookSignature(req.body, signature, process.env.APP_SECRET);\n *   \n *   if (!result.isValid) {\n *     return res.status(401).json({error: result.error});\n *   }\n *   \n *   // Process webhook...\n *   const payload = JSON.parse(req.body.toString());\n *   // Handle webhook events...\n * });\n * ```\n */\nexport async function verifyWebhookSignature(\n  rawBody: Buffer,\n  signature: string | undefined,\n  appSecret: string\n): Promise<WebhookSignatureVerificationResult> {\n  if (!signature) {\n    return {\n      isValid: false,\n      error: 'Missing X-Hub-Signature-256 header'\n    };\n  }\n\n  if (!signature.startsWith('sha256=')) {\n    return {\n      isValid: false,\n      error: 'Invalid signature format. Expected sha256= prefix'\n    };\n  }\n\n  if (!appSecret) {\n    return {\n      isValid: false,\n      error: 'App secret is required for signature verification'\n    };\n  }\n\n  try {\n    // Check if we're in a Node.js environment\n    if (typeof Buffer === 'undefined') {\n      return {\n        isValid: false,\n        error: 'Signature verification is only supported in Node.js environments'\n      };\n    }\n\n    // Use dynamic import for ES6 compatibility\n    const crypto = await import('crypto');\n    \n    // Extract the hash from the signature\n    const receivedHash = signature.substring(7); // Remove 'sha256=' prefix\n    \n    // Compute the expected signature\n    const expectedSignature = crypto\n      .createHmac('sha256', appSecret)\n      .update(rawBody)\n      .digest('hex');\n\n    // Use timing-safe comparison to prevent timing attacks\n    const receivedBuffer = Buffer.from(receivedHash, 'hex');\n    const expectedBuffer = Buffer.from(expectedSignature, 'hex');\n\n    if (receivedBuffer.length !== expectedBuffer.length) {\n      return {\n        isValid: false,\n        error: 'Signature length mismatch'\n      };\n    }\n\n    const isValid = crypto.timingSafeEqual(receivedBuffer, expectedBuffer);\n    \n    return {\n      isValid,\n      error: isValid ? undefined : 'Signature verification failed'\n    };\n\n  } catch (error) {\n    return {\n      isValid: false,\n      error: `Signature verification error: ${error instanceof Error ? error.message : 'Unknown error'}`\n    };\n  }\n}\n\n/**\n * Helper to check if a payload contains specific event types\n * \n * @param payload - The webhook payload\n * @param eventTypes - Array of event types to check for\n * @returns True if payload contains any of the specified event types\n * \n * @example\n * ```typescript\n * if (payloadContainsEventTypes(payload, [WebhookEventType.MESSAGE, WebhookEventType.MESSAGING_POSTBACK])) {\n *   // Process message or postback events\n * }\n * ```\n */\nexport function payloadContainsEventTypes(\n  payload: GenericWebhookPayload,\n  eventTypes: WebhookEventType[]\n): boolean {\n  const foundTypes = getWebhookPayloadEventTypes(payload);\n  return eventTypes.some(type => foundTypes.includes(type));\n}\n\n/**\n * Filter events by type from a webhook payload\n * \n * @param payload - The webhook payload\n * @param eventType - The event type to filter for\n * @returns Array of events of the specified type\n * \n * @example\n * ```typescript\n * const messageEvents = filterEventsByType(payload, WebhookEventType.MESSAGE);\n * messageEvents.forEach(event => {\n *   console.log(`Message: ${event.message.text}`);\n * });\n * ```\n */\nexport function filterEventsByType<T extends MessengerWebhookEvent>(\n  payload: GenericWebhookPayload,\n  eventType: WebhookEventType\n): T[] {\n  const allEvents = extractWebhookEvents(payload);\n  return allEvents.filter(event => {\n    const type = getWebhookEventType(event);\n    return type === eventType;\n  }) as T[];\n}"]}