@warriorteam/messenger-sdk 1.5.3 → 1.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"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","apiOptions","AttachmentsAPI","body","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","messageId","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":"AAAO,IAAMA,EAAAA,CAAsB,OAAA,CACtBC,EAAAA,CAAW,4BAAA,KAKXC,CAAAA,CAAgB,CAC3B,QAAA,CAAU,cAAA,CACV,mBAAA,CAAqB,yBAAA,CACrB,sBAAA,CAAwB,4BAE1B,CAAA,CAGaC,CAAAA,CAAiB,CAE5B,sBAAA,CAAwB,GAC1B,CAAA,CAEaC,EAAAA,CAAoB,CAE/B,cAAA,CAAgB,CAAA,CAAI,IAAA,CAAO,IAAA,CAC3B,cAAA,CAAgB,EAAA,CAAK,IAAA,CAAO,IAAA,CAG5B,cAAe,EAAA,CACf,aAAA,CAAe,EACjB,CAAA,CAEaC,CAAAA,CAAkB,CAE7B,oBAAA,CAAsB,EAAA,CACtB,wBAAyB,EAAA,CACzB,0BAAA,CAA4B,EAAA,CAG5B,qBAAA,CAAuB,GAAA,CACvB,iBAAA,CAAmB,CAAA,CACnB,sBAAA,CAAwB,GAGxB,0BAAA,CAA4B,GAAA,CAG5B,oBAAA,CAAsB,CAAA,CACtB,uBAAA,CAAyB,CAC3B,EC5CO,IAAMC,EAAN,cAAgC,KAAM,CAC3B,IAAA,CACA,KACA,OAAA,CACA,UAAA,CACA,UAAA,CACA,QAAA,CAEhB,YAAYC,CAAAA,CAAuBC,CAAAA,CAAoBC,CAAAA,CAAgB,CACrE,KAAA,CAAMF,CAAAA,CAAM,OAAO,CAAA,CACnB,KAAK,IAAA,CAAO,mBAAA,CACZ,IAAA,CAAK,IAAA,CAAOA,CAAAA,CAAM,IAAA,CAClB,IAAA,CAAK,IAAA,CAAOA,EAAM,IAAA,CAClB,IAAA,CAAK,OAAA,CAAUA,CAAAA,CAAM,aAAA,CACrB,IAAA,CAAK,UAAA,CAAaA,CAAAA,CAAM,WACxB,IAAA,CAAK,UAAA,CAAaC,CAAAA,CAClB,IAAA,CAAK,QAAA,CAAWC,EAClB,CACF,CAAA,CAEaC,EAAN,cAAoC,KAAM,CAC/B,KAAA,CAEhB,WAAA,CAAYC,CAAAA,CAAiBC,CAAAA,CAAe,CAC1C,MAAMD,CAAO,CAAA,CACb,IAAA,CAAK,IAAA,CAAO,uBAAA,CACZ,IAAA,CAAK,KAAA,CAAQC,EACf,CACF,CAAA,CAEaC,CAAAA,CAAN,cAAoC,KAAM,CAC/B,OAAA,CAEhB,WAAA,CAAYC,CAAAA,CAAiB,CAC3B,KAAA,CAAM,CAAA,wBAAA,EAA2BA,CAAO,CAAA,EAAA,CAAI,EAC5C,IAAA,CAAK,IAAA,CAAO,uBAAA,CACZ,IAAA,CAAK,QAAUA,EACjB,CACF,CAAA,CAEaC,CAAAA,CAAN,cAAmC,KAAM,CAC9C,WAAA,CAAYJ,EAAiB,CAC3B,KAAA,CAAMA,CAAO,CAAA,CACb,IAAA,CAAK,IAAA,CAAO,uBACd,CACF,ECvBO,IAAMK,CAAAA,CAAN,KAAiB,CACL,MAAA,CAEjB,WAAA,CAAYC,CAAAA,CAAsB,CAChC,KAAK,MAAA,CAAS,CACZ,WAAA,CAAaA,CAAAA,CAAO,WAAA,CACpB,OAAA,CAASA,CAAAA,CAAO,OAAA,CAChB,QAASA,CAAAA,CAAO,OAAA,EAAWhB,EAAAA,CAC3B,OAAA,CAASgB,CAAAA,CAAO,OAAA,EAAW,GAAA,CAC3B,UAAA,CAAYA,EAAO,UAAA,EAAc,CACnC,EACF,CAEA,MAAM,OAAA,CAAWC,CAAAA,CAAqC,CACpD,IAAMC,CAAAA,CAAM,IAAA,CAAK,QAAA,CAASD,CAAAA,CAAQ,IAAA,CAAMA,CAAAA,CAAQ,KAAA,CAAOA,CAAAA,CAAQ,WAAW,CAAA,CACtEE,CAAAA,CAEJ,IAAA,IAASC,CAAAA,CAAU,EAAGA,CAAAA,EAAW,IAAA,CAAK,MAAA,CAAO,UAAA,CAAYA,IACvD,GAAI,CACF,IAAMZ,CAAAA,CAAW,MAAM,IAAA,CAAK,WAAA,CAAYU,CAAAA,CAAKD,CAAO,CAAA,CACpD,OAAO,MAAM,IAAA,CAAK,cAAA,CAAkBT,CAAQ,CAC9C,CAAA,MAASF,EAAO,CAad,GAZAa,CAAAA,CAAYb,CAAAA,CAIVA,CAAAA,YAAiBD,CAAAA,EACjBC,CAAAA,CAAM,UAAA,EAAc,KACpBA,CAAAA,CAAM,UAAA,CAAa,GAAA,EAMjBc,CAAAA,GAAY,KAAK,MAAA,CAAO,UAAA,CAC1B,MAAMd,CAAAA,CAIR,MAAM,IAAA,CAAK,KAAA,CAAM,GAAA,EAAkBc,CAAAA,CAAU,CAAA,CAAE,EACjD,CAGF,MAAMD,GAAa,IAAI,KAAA,CAAM,wBAAwB,CACvD,CAEQ,QAAA,CACNE,CAAAA,CACAC,CAAAA,CACAC,EACQ,CACR,IAAML,CAAAA,CAAM,IAAI,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,OAAO,CAAA,CAAA,EAAI,IAAA,CAAK,MAAA,CAAO,OAAO,GAAGG,CAAI,CAAA,CAAE,CAAA,CAGpEG,CAAAA,CAAcD,GAAuB,IAAA,CAAK,MAAA,CAAO,WAAA,CAEvD,GAAI,CAACC,CAAAA,CACH,MAAM,IAAI,MAAM,wEAAwE,CAAA,CAG1F,OAAAN,CAAAA,CAAI,YAAA,CAAa,MAAA,CAAO,cAAA,CAAgBM,CAAW,EAG/CF,CAAAA,EACF,MAAA,CAAO,OAAA,CAAQA,CAAK,CAAA,CAAE,OAAA,CAAQ,CAAC,CAACG,EAAKC,CAAK,CAAA,GAAM,CAC9CR,CAAAA,CAAI,YAAA,CAAa,MAAA,CAAOO,CAAAA,CAAK,MAAA,CAAOC,CAAK,CAAC,EAC5C,CAAC,CAAA,CAGIR,CAAAA,CAAI,QAAA,EACb,CAEA,MAAc,WAAA,CAAYA,CAAAA,CAAaD,CAAAA,CAA4C,CACjF,IAAMU,CAAAA,CAAa,IAAI,eAAA,CACjBC,EAAY,UAAA,CAAW,IAAMD,CAAAA,CAAW,KAAA,EAAM,CAAG,IAAA,CAAK,MAAA,CAAO,OAAO,EAE1E,GAAI,CACF,IAAME,CAAAA,CAA4B,CAChC,MAAA,CAAQZ,CAAAA,CAAQ,MAAA,CAChB,OAAA,CAAS,CACP,cAAA,CAAgB,kBAClB,CAAA,CACA,MAAA,CAAQU,CAAAA,CAAW,MACrB,CAAA,CAEA,OAAIV,EAAQ,IAAA,GACVY,CAAAA,CAAa,IAAA,CAAO,IAAA,CAAK,SAAA,CAAUZ,CAAAA,CAAQ,IAAI,CAAA,CAAA,CAGhC,MAAM,KAAA,CAAMC,CAAAA,CAAKW,CAAY,CAEhD,CAAA,MAASvB,CAAAA,CAAO,CACd,MAAIA,aAAiB,KAAA,CACfA,CAAAA,CAAM,IAAA,GAAS,YAAA,CACX,IAAIM,CAAAA,CAAsB,IAAA,CAAK,MAAA,CAAO,OAAO,EAE/C,IAAIH,CAAAA,CAAsB,CAAA,wBAAA,EAA2BH,CAAAA,CAAM,OAAO,CAAA,CAAA,CAAIA,CAAK,CAAA,CAE7EA,CACR,CAAA,OAAE,CACA,YAAA,CAAasB,CAAS,EACxB,CACF,CAEA,MAAc,eAAkBpB,CAAAA,CAAgC,CAE9D,IAAMsB,CAAAA,CADctB,CAAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,cAAc,GAC3B,QAAA,CAAS,kBAAkB,CAAA,CAEvD,GAAI,CAACA,CAAAA,CAAS,EAAA,CACZ,GAAIsB,CAAAA,CAAQ,CACV,IAAMC,CAAAA,CAAa,MAAMvB,CAAAA,CAAS,IAAA,EAAK,CACvC,MAAM,IAAIH,EAAkB0B,CAAAA,CAAU,KAAA,CAAOvB,CAAAA,CAAS,MAAA,CAAQuB,CAAS,CACzE,CAAA,KAAO,CACL,IAAMC,CAAAA,CAAO,MAAMxB,CAAAA,CAAS,IAAA,EAAK,CACjC,MAAM,IAAIH,CAAAA,CACR,CACE,OAAA,CAAS2B,CAAAA,EAAQ,CAAA,KAAA,EAAQxB,CAAAA,CAAS,MAAM,CAAA,CAAA,EAAIA,CAAAA,CAAS,UAAU,GAC/D,IAAA,CAAM,YAAA,CACN,IAAA,CAAMA,CAAAA,CAAS,MAAA,CACf,UAAA,CAAY,EACd,CAAA,CACAA,EAAS,MAAA,CACTwB,CACF,CACF,CAGF,OAAIF,CAAAA,CACM,MAAMtB,CAAAA,CAAS,MAAK,CAItB,MAAMA,CAAAA,CAAS,IAAA,EACzB,CAEQ,KAAA,CAAMyB,CAAAA,CAA2B,CACvC,OAAO,IAAI,OAAA,CAASC,CAAAA,EAAY,WAAWA,CAAAA,CAASD,CAAE,CAAC,CACzD,CACF,CAAA,CChKO,IAAME,CAAAA,CAAN,cAAqC,KAAM,CAChD,WAAA,CAAYzB,CAAAA,CAAiB,CAC3B,KAAA,CAAMA,CAAO,CAAA,CACb,IAAA,CAAK,IAAA,CAAO,yBACd,CACF,EAEO,SAAS0B,EAAAA,CAAoBJ,CAAAA,CAAoB,CACtD,GAAI,CAACA,CAAAA,EAAQA,CAAAA,CAAK,IAAA,KAAW,EAAA,CAC3B,MAAM,IAAIG,CAAAA,CAAuB,8BAA8B,CAAA,CAGjE,GAAIH,CAAAA,CAAK,MAAA,CAAS9B,EAAe,sBAAA,CAC/B,MAAM,IAAIiC,CAAAA,CACR,CAAA,2BAAA,EAA8BjC,CAAAA,CAAe,sBAAsB,CAAA,WAAA,CACrE,CAEJ,CCZO,IAAMmC,CAAAA,CAAN,KAAc,CACnB,WAAA,CAAoBC,CAAAA,CAAwB,CAAxB,gBAAAA,EAAyB,CAE7C,MAAM,OAAA,CAAQC,CAAAA,CAA6BtB,CAAAA,CAAoD,CAE7F,OAAIsB,EAAQ,OAAA,EAAS,IAAA,EACnBH,EAAAA,CAAoBG,CAAAA,CAAQ,QAAQ,IAAI,CAAA,CAGnC,IAAA,CAAK,UAAA,CAAW,QAA6B,CAClD,MAAA,CAAQ,MAAA,CACR,IAAA,CAAMtC,CAAAA,CAAc,QAAA,CACpB,IAAA,CAAMsC,CAAAA,CACN,YAAatB,CAAAA,EAAS,WACxB,CAAC,CACH,CAEA,MAAM,MAAA,CAAOuB,CAAAA,CAAqBC,EAAsBxB,CAAAA,CAAoD,CAC1G,OAAO,IAAA,CAAK,UAAA,CAAW,OAAA,CAA6B,CAClD,MAAA,CAAQ,OACR,IAAA,CAAMhB,CAAAA,CAAc,QAAA,CACpB,IAAA,CAAM,CACJ,SAAA,CAAW,CAAE,EAAA,CAAIuC,CAAY,CAAA,CAC7B,cAAA,CAAgB,UAAA,CAChB,aAAA,CAAeC,CACjB,CAAA,CACA,WAAA,CAAaxB,CAAAA,EAAS,WACxB,CAAC,CACH,CAEA,MAAM,QAAA,CAASuB,CAAAA,CAAqBvB,CAAAA,CAAoD,CACtF,OAAO,IAAA,CAAK,MAAA,CAAOuB,CAAAA,CAAa,WAAA,CAAavB,CAAO,CACtD,CAEA,MAAM,UAAUuB,CAAAA,CAAqBvB,CAAAA,CAAoD,CACvF,OAAO,KAAK,MAAA,CAAOuB,CAAAA,CAAa,YAAA,CAAcvB,CAAO,CACvD,CAEA,MAAM,QAAA,CAASuB,CAAAA,CAAqBvB,CAAAA,CAAoD,CACtF,OAAO,IAAA,CAAK,OAAOuB,CAAAA,CAAa,WAAA,CAAavB,CAAO,CACtD,CAOA,MAAM,UAAA,CAAWA,CAAAA,CAKdyB,EAAuD,CACxD,OAAO,IAAA,CAAK,OAAA,CAAQ,CAClB,SAAA,CAAWzB,CAAAA,CAAQ,SAAA,CACnB,eAAgBA,CAAAA,CAAQ,cAAA,EAAkB,UAAA,CAC1C,OAAA,CAAS,CACP,UAAA,CAAY,CACV,IAAA,CAAMA,EAAQ,IAAA,CACd,OAAA,CAAS,CACP,aAAA,CAAeA,CAAAA,CAAQ,aACzB,CACF,CACF,CACF,CAAA,CAAGyB,CAAU,CACf,CAKA,MAAM,iBAAA,CAAkBzB,CAAAA,CAKrByB,CAAAA,CAAuD,CACxD,OAAO,IAAA,CAAK,OAAA,CAAQ,CAClB,SAAA,CAAWzB,CAAAA,CAAQ,SAAA,CACnB,cAAA,CAAgBA,EAAQ,cAAA,EAAkB,UAAA,CAC1C,OAAA,CAAS,CACP,WAAY,CACV,IAAA,CAAMA,CAAAA,CAAQ,IAAA,CACd,QAAS,CACP,GAAA,CAAKA,CAAAA,CAAQ,GACf,CACF,CACF,CACF,CAAA,CAAGyB,CAAU,CACf,CACF,EC5FO,IAAMC,CAAAA,CAAN,KAAqB,CAC1B,WAAA,CAAoBL,EAAwB,CAAxB,IAAA,CAAA,UAAA,CAAAA,EAAyB,CAE7C,MAAM,MAAA,CACJC,CAAAA,CACAtB,CAAAA,CACmC,CAEnC,IAAM2B,CAAAA,CAAO,CACX,OAAA,CAAS,CACP,UAAA,CAAY,CACV,IAAA,CAAML,EAAQ,IAAA,CACd,OAAA,CAAS,CACP,GAAA,CAAKA,CAAAA,CAAQ,GAAA,CACb,WAAA,CAAaA,CAAAA,CAAQ,aAAe,IACtC,CACF,CACF,CACF,CAAA,CAEA,OAAO,IAAA,CAAK,UAAA,CAAW,QAAkC,CACvD,MAAA,CAAQ,MAAA,CACR,IAAA,CAAMtC,CAAAA,CAAc,mBAAA,CACpB,IAAA,CAAA2C,CAAAA,CACA,YAAa3B,CAAAA,EAAS,WACxB,CAAC,CACH,CACF,ECxBO,IAAM4B,CAAAA,CAAN,KAAoB,CACzB,WAAA,CAAoBP,CAAAA,CAAwB,CAAxB,IAAA,CAAA,UAAA,CAAAA,EAAyB,CAM7C,MAAM,QAAA,CAASC,EAAuCtB,CAAAA,CAA8D,CAClH,OAAO,IAAA,CAAK,UAAA,CAAW,OAAA,CAAuC,CAC5D,MAAA,CAAQ,OACR,IAAA,CAAMhB,CAAAA,CAAc,sBAAA,CACpB,IAAA,CAAMsC,CAAAA,CACN,WAAA,CAAatB,CAAAA,EAAS,WACxB,CAAC,CACH,CAMA,MAAM,SAAA,CAAU6B,EAA4B7B,CAAAA,CAA8D,CACxG,IAAM8B,CAAAA,CAAW,MAAM,OAAA,CAAQD,CAAO,CAAA,CAClCA,CAAAA,CAAQ,GAAA,CAAIE,CAAAA,GAAO,CAAE,EAAA,CAAAA,CAAG,CAAA,CAAE,CAAA,CAC1B,CAAC,CAAE,EAAA,CAAIF,CAAQ,CAAC,CAAA,CAEpB,OAAO,IAAA,CAAK,QAAA,CAAS,CACnB,QAAA,CAAAC,CAAAA,CACA,OAAA,CAAS,CAAC,YAAY,CACxB,CAAA,CAAG9B,CAAO,CACZ,CAKA,MAAM,WAAA,CAAY6B,CAAAA,CAA4B7B,CAAAA,CAA8D,CAC1G,IAAM8B,CAAAA,CAAW,KAAA,CAAM,OAAA,CAAQD,CAAO,CAAA,CAClCA,CAAAA,CAAQ,GAAA,CAAIE,CAAAA,GAAO,CAAE,EAAA,CAAAA,CAAG,CAAA,CAAE,CAAA,CAC1B,CAAC,CAAE,EAAA,CAAIF,CAAQ,CAAC,CAAA,CAEpB,OAAO,IAAA,CAAK,QAAA,CAAS,CACnB,QAAA,CAAAC,CAAAA,CACA,OAAA,CAAS,CAAC,cAAc,CAC1B,CAAA,CAAG9B,CAAO,CACZ,CAOA,MAAM,OAAA,CAAQ6B,EAA4B7B,CAAAA,CAA8D,CACtG,IAAM8B,CAAAA,CAAW,KAAA,CAAM,OAAA,CAAQD,CAAO,CAAA,CAClCA,EAAQ,GAAA,CAAIE,CAAAA,GAAO,CAAE,EAAA,CAAAA,CAAG,CAAA,CAAE,CAAA,CAC1B,CAAC,CAAE,EAAA,CAAIF,CAAQ,CAAC,CAAA,CAEpB,OAAO,IAAA,CAAK,QAAA,CAAS,CACnB,SAAAC,CAAAA,CACA,OAAA,CAAS,CAAC,UAAU,CACtB,CAAA,CAAG9B,CAAO,CACZ,CAMA,MAAM,SAAA,CAAU6B,CAAAA,CAA4B7B,CAAAA,CAA8D,CACxG,IAAM8B,CAAAA,CAAW,KAAA,CAAM,OAAA,CAAQD,CAAO,CAAA,CAClCA,CAAAA,CAAQ,GAAA,CAAIE,CAAAA,GAAO,CAAE,EAAA,CAAAA,CAAG,CAAA,CAAE,EAC1B,CAAC,CAAE,EAAA,CAAIF,CAAQ,CAAC,CAAA,CAEpB,OAAO,IAAA,CAAK,SAAS,CACnB,QAAA,CAAAC,CAAAA,CACA,OAAA,CAAS,CAAC,YAAY,CACxB,CAAA,CAAG9B,CAAO,CACZ,CAKA,MAAM,UAAA,CAAW6B,CAAAA,CAA4B7B,CAAAA,CAA8D,CACzG,IAAM8B,CAAAA,CAAW,MAAM,OAAA,CAAQD,CAAO,CAAA,CAClCA,CAAAA,CAAQ,GAAA,CAAIE,CAAAA,GAAO,CAAE,EAAA,CAAAA,CAAG,CAAA,CAAE,CAAA,CAC1B,CAAC,CAAE,EAAA,CAAIF,CAAQ,CAAC,CAAA,CAEpB,OAAO,IAAA,CAAK,QAAA,CAAS,CACnB,QAAA,CAAAC,EACA,OAAA,CAAS,CAAC,cAAc,CAC1B,EAAG9B,CAAO,CACZ,CAKA,MAAM,YAAA,CAAa6B,CAAAA,CAA4B7B,CAAAA,CAA8D,CAC3G,IAAM8B,CAAAA,CAAW,KAAA,CAAM,OAAA,CAAQD,CAAO,CAAA,CAClCA,CAAAA,CAAQ,GAAA,CAAIE,CAAAA,GAAO,CAAE,EAAA,CAAAA,CAAG,CAAA,CAAE,CAAA,CAC1B,CAAC,CAAE,EAAA,CAAIF,CAAQ,CAAC,CAAA,CAEpB,OAAO,IAAA,CAAK,QAAA,CAAS,CACnB,QAAA,CAAAC,CAAAA,CACA,OAAA,CAAS,CAAC,YAAA,CAAc,cAAc,CACxC,CAAA,CAAG9B,CAAO,CACZ,CACF,MC3GagC,CAAAA,CAAN,cAAsC,KAAM,CACjD,WAAA,CAAYvC,CAAAA,CAAiB,CAC3B,KAAA,CAAMA,CAAO,CAAA,CACb,IAAA,CAAK,IAAA,CAAO,0BACd,CACF,EAEO,SAASwC,EAAAA,CAAwBC,EAA0C,CAChF,GAAIA,CAAAA,CAAS,MAAA,GAAW,EACtB,MAAM,IAAIF,CAAAA,CAAwB,+CAA+C,EAGnF,GAAIE,CAAAA,CAAS,MAAA,CAAS/C,CAAAA,CAAgB,oBAAA,CACpC,MAAM,IAAI6C,CAAAA,CACR,0CAA0C7C,CAAAA,CAAgB,oBAAoB,CAAA,SAAA,CAChF,CAAA,CAGF+C,CAAAA,CAAS,OAAA,CAAQ,CAACC,CAAAA,CAASC,IAAU,CACnCC,EAAAA,CAAuBF,CAAAA,CAASC,CAAK,EACvC,CAAC,EACH,CAEO,SAASC,EAAAA,CAAuBF,CAAAA,CAAiCC,CAAAA,CAAqB,CAC3F,GAAI,CAACD,CAAAA,CAAQ,KAAA,EAASA,CAAAA,CAAQ,MAAM,IAAA,EAAK,GAAM,EAAA,CAC7C,MAAM,IAAIH,CAAAA,CAAwB,CAAA,QAAA,EAAWI,CAAK,qBAAqB,CAAA,CAGzE,GAAID,CAAAA,CAAQ,KAAA,CAAM,MAAA,CAAShD,CAAAA,CAAgB,uBAAA,CACzC,MAAM,IAAI6C,CAAAA,CACR,CAAA,QAAA,EAAWI,CAAK,CAAA,sBAAA,EAAyBjD,CAAAA,CAAgB,uBAAuB,CAAA,WAAA,CAClF,CAAA,CAGF,GAAIgD,CAAAA,CAAQ,QAAA,EAAYA,CAAAA,CAAQ,QAAA,CAAS,OAAShD,CAAAA,CAAgB,0BAAA,CAChE,MAAM,IAAI6C,EACR,CAAA,QAAA,EAAWI,CAAK,CAAA,yBAAA,EAA4BjD,CAAAA,CAAgB,0BAA0B,CAAA,WAAA,CACxF,CAAA,CAGF,GAAIgD,EAAQ,SAAA,EAAa,CAACG,CAAAA,CAAWH,CAAAA,CAAQ,SAAS,CAAA,CACpD,MAAM,IAAIH,EAAwB,CAAA,QAAA,EAAWI,CAAK,CAAA,yBAAA,CAA2B,CAAA,CAe/E,GAZID,CAAAA,CAAQ,OAAA,EACVI,CAAAA,CAAgBJ,EAAQ,OAAA,CAAS,CAAA,QAAA,EAAWC,CAAK,CAAA,CAAE,CAAA,CAWjD,CAP0B,CAAC,EAC7BD,EAAQ,QAAA,EACRA,CAAAA,CAAQ,SAAA,EACRA,CAAAA,CAAQ,cAAA,EACPA,CAAAA,CAAQ,OAAA,EAAWA,CAAAA,CAAQ,QAAQ,MAAA,CAAS,CAAA,CAAA,CAI7C,MAAM,IAAIH,CAAAA,CACR,CAAA,QAAA,EAAWI,CAAK,CAAA,yDAAA,CAClB,CAEJ,CAEO,SAASI,EAAAA,CAAuBzB,CAAAA,CAAc0B,CAAAA,CAAyB,CAC5E,GAAI,CAAC1B,GAAQA,CAAAA,CAAK,IAAA,EAAK,GAAM,EAAA,CAC3B,MAAM,IAAIiB,CAAAA,CAAwB,kCAAkC,CAAA,CAGtE,GAAIjB,CAAAA,CAAK,MAAA,CAAS5B,CAAAA,CAAgB,qBAAA,CAChC,MAAM,IAAI6C,CAAAA,CACR,CAAA,mCAAA,EAAsC7C,EAAgB,qBAAqB,CAAA,WAAA,CAC7E,CAAA,CAGF,GAAIsD,CAAAA,CAAQ,MAAA,GAAW,CAAA,CACrB,MAAM,IAAIT,CAAAA,CAAwB,6CAA6C,CAAA,CAGjFO,CAAAA,CAAgBE,CAAAA,CAAS,iBAAiB,EAC5C,CAEO,SAASC,EAAAA,CAAsBP,CAAAA,CAAqC,CACzE,GAAI,CAACA,CAAAA,CAAQ,UAAA,CACX,MAAM,IAAIH,CAAAA,CAAwB,6CAA6C,CAAA,CAGjF,GAAI,CAACG,CAAAA,CAAQ,GAAA,EAAO,CAACA,EAAQ,aAAA,CAC3B,MAAM,IAAIH,CAAAA,CAAwB,8DAA8D,CAAA,CAGlG,GAAIG,CAAAA,CAAQ,KAAOA,CAAAA,CAAQ,aAAA,CACzB,MAAM,IAAIH,CAAAA,CACR,+DACF,CAAA,CAGF,GAAIG,EAAQ,GAAA,EAAO,CAACG,CAAAA,CAAWH,CAAAA,CAAQ,GAAG,CAAA,CACxC,MAAM,IAAIH,CAAAA,CAAwB,kCAAkC,CAAA,CAGtE,GAAIG,CAAAA,CAAQ,OAAA,CAAS,CACnB,GAAIA,CAAAA,CAAQ,OAAA,CAAQ,OAAShD,CAAAA,CAAgB,uBAAA,CAC3C,MAAM,IAAI6C,CAAAA,CACR,CAAA,qCAAA,EAAwC7C,CAAAA,CAAgB,uBAAuB,UACjF,CAAA,CAEFoD,CAAAA,CAAgBJ,CAAAA,CAAQ,OAAA,CAAS,gBAAgB,EACnD,CACF,CAEO,SAASI,CAAAA,CAAgBE,CAAAA,CAAmBE,CAAAA,CAAuB,CACxE,GAAIF,CAAAA,CAAQ,MAAA,CAAStD,CAAAA,CAAgB,kBACnC,MAAM,IAAI6C,CAAAA,CACR,CAAA,EAAGW,CAAO,CAAA,uBAAA,EAA0BxD,CAAAA,CAAgB,iBAAiB,UACvE,CAAA,CAGFsD,CAAAA,CAAQ,OAAA,CAAQ,CAACG,CAAAA,CAAQR,CAAAA,GAAU,CACjCS,EAAAA,CAAeD,EAAQ,CAAA,EAAGD,CAAO,CAAA,QAAA,EAAWP,CAAK,CAAA,CAAE,EACrD,CAAC,EACH,CAEO,SAASS,EAAAA,CAAeD,CAAAA,CAAgBD,CAAAA,CAAuB,CACpE,GAAI,CAACC,CAAAA,CAAO,IAAA,CACV,MAAM,IAAIZ,CAAAA,CAAwB,CAAA,EAAGW,CAAO,CAAA,kBAAA,CAAoB,CAAA,CAIlE,GAAIC,CAAAA,CAAO,OAAS,gBAAA,GAAqB,CAACA,CAAAA,CAAO,KAAA,EAASA,CAAAA,CAAO,KAAA,CAAM,IAAA,EAAK,GAAM,IAChF,MAAM,IAAIZ,CAAAA,CAAwB,CAAA,EAAGW,CAAO,CAAA,wBAAA,EAA2BC,CAAAA,CAAO,IAAI,UAAU,CAAA,CAG9F,GAAIA,CAAAA,CAAO,KAAA,EAASA,EAAO,KAAA,CAAM,MAAA,CAASzD,CAAAA,CAAgB,sBAAA,CACxD,MAAM,IAAI6C,CAAAA,CACR,CAAA,EAAGW,CAAO,CAAA,sBAAA,EAAyBxD,CAAAA,CAAgB,sBAAsB,CAAA,WAAA,CAC3E,EAIF,OAAQyD,CAAAA,CAAO,IAAA,EACb,KAAK,SAAA,CACH,GAAI,CAACA,EAAO,GAAA,CACV,MAAM,IAAIZ,CAAAA,CAAwB,CAAA,EAAGW,CAAO,CAAA,qCAAA,CAAuC,CAAA,CAErF,GAAI,CAACL,CAAAA,CAAWM,CAAAA,CAAO,GAAG,EACxB,MAAM,IAAIZ,CAAAA,CAAwB,CAAA,EAAGW,CAAO,CAAA,uCAAA,CAAyC,CAAA,CAEvF,MAEF,KAAK,UAAA,CACH,GAAI,CAACC,CAAAA,CAAO,QACV,MAAM,IAAIZ,CAAAA,CAAwB,CAAA,EAAGW,CAAO,CAAA,0CAAA,CAA4C,CAAA,CAE1F,GAAIC,EAAO,OAAA,CAAQ,MAAA,CAASzD,CAAAA,CAAgB,0BAAA,CAC1C,MAAM,IAAI6C,CAAAA,CACR,CAAA,EAAGW,CAAO,CAAA,wBAAA,EAA2BxD,CAAAA,CAAgB,0BAA0B,CAAA,WAAA,CACjF,CAAA,CAEF,MAEF,KAAK,cAAA,CACH,GAAI,CAACyD,CAAAA,CAAO,OAAA,CACV,MAAM,IAAIZ,CAAAA,CAAwB,CAAA,EAAGW,CAAO,gDAAgD,CAAA,CAG9F,GAAI,CAACC,CAAAA,CAAO,OAAA,CAAQ,UAAA,CAAW,GAAG,CAAA,CAChC,MAAM,IAAIZ,CAAAA,CACR,CAAA,EAAGW,CAAO,CAAA,4DAAA,CACZ,CAAA,CAEF,MAEF,KAAK,YAEH,MAEF,KAAK,cAAA,CACH,GAAI,CAACC,CAAAA,CAAO,GAAA,CACV,MAAM,IAAIZ,EAAwB,CAAA,EAAGW,CAAO,CAAA,0CAAA,CAA4C,CAAA,CAE1F,GAAI,CAACL,CAAAA,CAAWM,CAAAA,CAAO,GAAG,CAAA,CACxB,MAAM,IAAIZ,CAAAA,CAAwB,CAAA,EAAGW,CAAO,CAAA,4CAAA,CAA8C,CAAA,CAE5F,MAKJ,CAGA,GAAIC,CAAAA,CAAO,IAAA,GAAS,SAAA,EAAaA,EAAO,oBAAA,EAAwBA,CAAAA,CAAO,YAAA,EACjE,CAACN,EAAWM,CAAAA,CAAO,YAAY,CAAA,CACjC,MAAM,IAAIZ,CAAAA,CAAwB,CAAA,EAAGW,CAAO,CAAA,4BAAA,CAA8B,CAGhF,CAEA,SAASL,CAAAA,CAAWrC,EAAsB,CACxC,GAAI,CAEF,OADkB,IAAI,GAAA,CAAIA,CAAG,CAAA,CACZ,WAAa,QAChC,CAAA,KAAQ,CACN,OAAO,MACT,CACF,CChMO,IAAM6C,EAAN,KAAmB,CACxB,WAAA,CAAoBzB,CAAAA,CAAwB,CAAxB,IAAA,CAAA,UAAA,CAAAA,EAAyB,CAE7C,MAAM,QAAQrB,CAAAA,CAOXyB,CAAAA,CAAuD,CAExDQ,EAAAA,CAAwBjC,CAAAA,CAAQ,QAAQ,CAAA,CAExC,IAAM+C,EAAkC,CACtC,aAAA,CAAe,SAAA,CACf,QAAA,CAAU/C,CAAAA,CAAQ,QAAA,CAClB,kBAAA,CAAoBA,CAAAA,CAAQ,kBAC9B,CAAA,CAEMsB,CAAAA,CAA8B,CAClC,SAAA,CAAWtB,CAAAA,CAAQ,SAAA,CACnB,cAAA,CAAgBA,CAAAA,CAAQ,gBAAkB,QAAA,CAC1C,OAAA,CAAS,CACP,UAAA,CAAY,CACV,IAAA,CAAM,UAAA,CACN,OAAA,CAAA+C,CACF,CACF,CAAA,CACA,iBAAA,CAAmB/C,CAAAA,CAAQ,iBAAA,CAC3B,GAAA,CAAKA,CAAAA,CAAQ,GACf,EAEA,OAAO,IAAA,CAAK,UAAA,CAAW,OAAA,CAA6B,CAClD,MAAA,CAAQ,MAAA,CACR,IAAA,CAAMhB,EAAc,QAAA,CACpB,IAAA,CAAMsC,CAAAA,CACN,WAAA,CAAaG,CAAAA,EAAY,WAC3B,CAAC,CACH,CAEA,MAAM,MAAA,CAAOzB,CAAAA,CAOVyB,CAAAA,CAAuD,CAExDe,EAAAA,CAAuBxC,CAAAA,CAAQ,IAAA,CAAMA,CAAAA,CAAQ,OAAO,CAAA,CAEpD,IAAM+C,CAAAA,CAAiC,CACrC,aAAA,CAAe,QAAA,CACf,IAAA,CAAM/C,CAAAA,CAAQ,KACd,OAAA,CAASA,CAAAA,CAAQ,OACnB,CAAA,CAEMsB,CAAAA,CAA8B,CAClC,SAAA,CAAWtB,CAAAA,CAAQ,UACnB,cAAA,CAAgBA,CAAAA,CAAQ,cAAA,EAAkB,QAAA,CAC1C,OAAA,CAAS,CACP,UAAA,CAAY,CACV,KAAM,UAAA,CACN,OAAA,CAAA+C,CACF,CACF,EACA,iBAAA,CAAmB/C,CAAAA,CAAQ,iBAAA,CAC3B,GAAA,CAAKA,EAAQ,GACf,CAAA,CAEA,OAAO,IAAA,CAAK,UAAA,CAAW,OAAA,CAA6B,CAClD,MAAA,CAAQ,OACR,IAAA,CAAMhB,CAAAA,CAAc,QAAA,CACpB,IAAA,CAAMsC,CAAAA,CACN,WAAA,CAAaG,CAAAA,EAAY,WAC3B,CAAC,CACH,CAEA,MAAM,KAAA,CAAMzB,CAAAA,CAMTyB,CAAAA,CAAuD,CAExDiB,EAAAA,CAAsB1C,EAAQ,OAAO,CAAA,CAErC,IAAM+C,CAAAA,CAAgC,CACpC,aAAA,CAAe,OAAA,CACf,QAAA,CAAU,CAAC/C,EAAQ,OAAO,CAC5B,CAAA,CAEMsB,CAAAA,CAA8B,CAClC,SAAA,CAAWtB,CAAAA,CAAQ,SAAA,CACnB,eAAgBA,CAAAA,CAAQ,cAAA,EAAkB,QAAA,CAC1C,OAAA,CAAS,CACP,UAAA,CAAY,CACV,IAAA,CAAM,WACN,OAAA,CAAA+C,CACF,CACF,CAAA,CACA,iBAAA,CAAmB/C,CAAAA,CAAQ,iBAAA,CAC3B,GAAA,CAAKA,EAAQ,GACf,CAAA,CAEA,OAAO,IAAA,CAAK,UAAA,CAAW,OAAA,CAA6B,CAClD,MAAA,CAAQ,OACR,IAAA,CAAMhB,CAAAA,CAAc,QAAA,CACpB,IAAA,CAAMsC,CAAAA,CACN,WAAA,CAAaG,CAAAA,EAAY,WAC3B,CAAC,CACH,CAEA,MAAM,OAAA,CAAQzB,CAAAA,CAMXyB,CAAAA,CAAuD,CACxD,IAAMsB,EAAkC,CACtC,aAAA,CAAe,SAAA,CACf,QAAA,CAAU/C,CAAAA,CAAQ,QACpB,CAAA,CAEMsB,CAAAA,CAA8B,CAClC,SAAA,CAAWtB,CAAAA,CAAQ,SAAA,CACnB,cAAA,CAAgBA,EAAQ,cAAA,EAAkB,QAAA,CAC1C,OAAA,CAAS,CACP,WAAY,CACV,IAAA,CAAM,UAAA,CACN,OAAA,CAAA+C,CACF,CACF,CAAA,CACA,iBAAA,CAAmB/C,EAAQ,iBAAA,CAC3B,GAAA,CAAKA,CAAAA,CAAQ,GACf,CAAA,CAEA,OAAO,IAAA,CAAK,UAAA,CAAW,QAA6B,CAClD,MAAA,CAAQ,MAAA,CACR,IAAA,CAAMhB,CAAAA,CAAc,QAAA,CACpB,IAAA,CAAMsC,CAAAA,CACN,YAAaG,CAAAA,EAAY,WAC3B,CAAC,CACH,CACF,EC7JO,IAAMuB,CAAAA,CAAN,KAAiB,CACtB,WAAA,CAAoB3B,CAAAA,CAAwB,CAAxB,IAAA,CAAA,UAAA,CAAAA,EAAyB,CAM7C,MAAM,GAAA,CAAIC,EAA4BtB,CAAAA,CAA4C,CAChF,GAAM,CAAE,IAAA,CAAAiD,CAAAA,CAAM,MAAA,CAAAC,CAAAA,CAAS,CAAC,YAAA,CAAc,WAAW,CAAE,CAAA,CAAI5B,CAAAA,CAEjD6B,CAAAA,CAAc,IAAI,eAAA,CAAgB,CACtC,MAAA,CAAQD,CAAAA,CAAO,IAAA,CAAK,GAAG,CACzB,CAAC,CAAA,CAED,OAAO,IAAA,CAAK,WAAW,OAAA,CAAqB,CAC1C,MAAA,CAAQ,KAAA,CACR,IAAA,CAAM,CAAA,CAAA,EAAID,CAAI,CAAA,CAAA,EAAIE,EAAY,QAAA,EAAU,CAAA,CAAA,CACxC,IAAA,CAAM,MAAA,CACN,WAAA,CAAanD,CAAAA,EAAS,WACxB,CAAC,CACH,CAKA,MAAM,QAAA,CAASiD,CAAAA,CAAcjD,CAAAA,CAA4C,CACvE,OAAO,KAAK,GAAA,CAAI,CACd,IAAA,CAAAiD,CAAAA,CACA,MAAA,CAAQ,CAAC,YAAA,CAAc,WAAA,CAAa,aAAa,CACnD,CAAA,CAAGjD,CAAO,CACZ,CAKA,MAAM,OAAA,CAAQiD,CAAAA,CAAcjD,EAA4C,CACtE,OAAO,IAAA,CAAK,GAAA,CAAI,CACd,IAAA,CAAAiD,CAAAA,CACA,MAAA,CAAQ,CAAC,IAAA,CAAM,MAAA,CAAQ,YAAA,CAAc,WAAA,CAAa,aAAA,CAAe,QAAA,CAAU,UAAA,CAAY,QAAQ,CACjG,CAAA,CAAGjD,CAAO,CACZ,CAKA,MAAM,OAAA,CAAQiD,CAAAA,CAAcjD,CAAAA,CAA4C,CACtE,OAAO,IAAA,CAAK,GAAA,CAAI,CACd,IAAA,CAAAiD,CAAAA,CACA,MAAA,CAAQ,CAAC,YAAA,CAAc,WAAW,CACpC,CAAA,CAAGjD,CAAO,CACZ,CAKA,MAAM,iBAAA,CAAkBiD,CAAAA,CAAcjD,EAA4C,CAChF,OAAO,IAAA,CAAK,GAAA,CAAI,CACd,IAAA,CAAAiD,CAAAA,CACA,MAAA,CAAQ,CAAC,aAAa,CACxB,CAAA,CAAGjD,CAAO,CACZ,CACF,EC5BO,IAAMoD,CAAAA,CAAN,KAAuB,CAC5B,WAAA,CAAoB/B,CAAAA,CAAwB,CAAxB,IAAA,CAAA,UAAA,CAAAA,EAAyB,CA+B7C,MAAM,KACJgC,CAAAA,CACAC,CAAAA,CACAtD,CAAAA,CACoC,CACpC,GAAI,CAACqD,CAAAA,CACH,MAAM,IAAIxD,CAAAA,CAAqB,qBAAqB,CAAA,CAGtD,IAAMsD,CAAAA,CAAsC,EAAC,CAE7C,OAAIG,GAAQ,QAAA,GACVH,CAAAA,CAAY,QAAA,CAAWG,CAAAA,CAAO,UAG5BA,CAAAA,EAAQ,OAAA,GACVH,CAAAA,CAAY,OAAA,CAAUG,EAAO,OAAA,CAAA,CAG3BA,CAAAA,EAAQ,MAAA,GACVH,CAAAA,CAAY,MAAA,CAASG,CAAAA,CAAO,MAAA,CAAA,CAG1BA,CAAAA,EAAQ,QACVH,CAAAA,CAAY,KAAA,CAAQG,CAAAA,CAAO,KAAA,CAAM,QAAA,EAAS,CAAA,CAGxCA,CAAAA,EAAQ,KAAA,GACVH,EAAY,KAAA,CAAQG,CAAAA,CAAO,KAAA,CAAA,CAGzBA,CAAAA,EAAQ,MAAA,GACVH,CAAAA,CAAY,MAAA,CAASG,CAAAA,CAAO,QAGvB,IAAA,CAAK,UAAA,CAAW,OAAA,CAAmC,CACxD,MAAA,CAAQ,KAAA,CACR,IAAA,CAAM,CAAA,CAAA,EAAID,CAAM,CAAA,cAAA,CAAA,CAChB,KAAA,CAAOF,CAAAA,CACP,WAAA,CAAanD,CAAAA,EAAS,WACxB,CAAC,CACH,CAuBA,MAAM,GAAA,CACJuD,CAAAA,CACAD,CAAAA,CACAtD,CAAAA,CAC6B,CAC7B,GAAI,CAACuD,EACH,MAAM,IAAI1D,CAAAA,CAAqB,6BAA6B,CAAA,CAG9D,IAAMsD,CAAAA,CAAsC,GAE5C,OAAIG,CAAAA,EAAQ,MAAA,EAAUA,CAAAA,CAAO,OAAO,MAAA,CAAS,CAAA,GAC3CH,CAAAA,CAAY,MAAA,CAASG,EAAO,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA,CAAA,CAGzCA,CAAAA,EAAQ,KAAA,GACVH,CAAAA,CAAY,KAAA,CAAQG,EAAO,KAAA,CAAM,QAAA,EAAS,CAAA,CAGxCA,CAAAA,EAAQ,KAAA,GACVH,CAAAA,CAAY,KAAA,CAAQG,CAAAA,CAAO,OAGzBA,CAAAA,EAAQ,MAAA,GACVH,CAAAA,CAAY,MAAA,CAASG,CAAAA,CAAO,MAAA,CAAA,CAGvB,IAAA,CAAK,UAAA,CAAW,QAA4B,CACjD,MAAA,CAAQ,KAAA,CACR,IAAA,CAAM,IAAIC,CAAc,CAAA,CAAA,CACxB,KAAA,CAAOJ,CAAAA,CACP,YAAanD,CAAAA,EAAS,WACxB,CAAC,CACH,CAuBA,MAAM,WAAA,CACJuD,CAAAA,CACAD,EACAtD,CAAAA,CAC+B,CAC/B,GAAI,CAACuD,CAAAA,CACH,MAAM,IAAI1D,CAAAA,CAAqB,6BAA6B,CAAA,CAG9D,IAAMsD,CAAAA,CAAsC,CAC1C,MAAA,CAAQ,UACV,CAAA,CAEIG,CAAAA,EAAQ,QACVH,CAAAA,CAAY,KAAA,CAAQG,CAAAA,CAAO,KAAA,CAAM,UAAS,CAAA,CAGxCA,CAAAA,EAAQ,KAAA,GACVH,CAAAA,CAAY,MAAQG,CAAAA,CAAO,KAAA,CAAA,CAGzBA,CAAAA,EAAQ,MAAA,GACVH,CAAAA,CAAY,MAAA,CAASG,CAAAA,CAAO,MAAA,CAAA,CAG9B,IAAM/D,CAAAA,CAAW,MAAM,IAAA,CAAK,UAAA,CAAW,OAAA,CAA4B,CACjE,MAAA,CAAQ,KAAA,CACR,KAAM,CAAA,CAAA,EAAIgE,CAAc,CAAA,CAAA,CACxB,KAAA,CAAOJ,CAAAA,CACP,WAAA,CAAanD,CAAAA,EAAS,WACxB,CAAC,CAAA,CAED,OAAO,CACL,IAAA,CAAMT,CAAAA,CAAS,QAAA,EAAU,IAAA,EAAQ,GACjC,MAAA,CAAQA,CAAAA,CAAS,QAAA,EAAU,MAC7B,CACF,CAwBA,MAAM,UAAA,CACJiE,EACAF,CAAAA,CACAtD,CAAAA,CACkB,CAClB,GAAI,CAACwD,CAAAA,CACH,MAAM,IAAI3D,EAAqB,wBAAwB,CAAA,CAGzD,IAAMsD,CAAAA,CAAsC,EAAC,CAE7C,OAAIG,CAAAA,EAAQ,QAAUA,CAAAA,CAAO,MAAA,CAAO,MAAA,CAAS,CAAA,CAC3CH,EAAY,MAAA,CAASG,CAAAA,CAAO,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA,CAG3CH,CAAAA,CAAY,MAAA,CAAS,gEAAA,CAGhB,IAAA,CAAK,UAAA,CAAW,OAAA,CAAiB,CACtC,OAAQ,KAAA,CACR,IAAA,CAAM,CAAA,CAAA,EAAIK,CAAS,CAAA,CAAA,CACnB,KAAA,CAAOL,CAAAA,CACP,WAAA,CAAanD,GAAS,WACxB,CAAC,CACH,CAuBA,MAAM,iBAAA,CACJuD,CAAAA,CACAvD,CAAAA,CACoB,CASpB,IAAMyD,CAAAA,CAAAA,CAPe,MAAM,IAAA,CAAK,YAC9BF,CAAAA,CACA,CAAE,KAAA,CAAO,EAAG,EACZvD,CACF,CAAA,EAGqC,IAAA,CAAK,GAAA,CAAK0D,CAAAA,EAC7C,IAAA,CAAK,UAAA,CAAWA,CAAAA,CAAI,GAAI,MAAA,CAAW1D,CAAO,CAC5C,CAAA,CAEA,OAAO,OAAA,CAAQ,GAAA,CAAIyD,CAAe,CACpC,CA2BA,MAAM,UAAA,CACJJ,CAAAA,CACAM,CAAAA,CACAC,CAAAA,CACA5D,CAAAA,CACwB,CACxB,IAAMT,CAAAA,CAAW,MAAM,IAAA,CAAK,IAAA,CAC1B8D,EACA,CACE,QAAA,CAAAO,CAAAA,CACA,OAAA,CAASD,CACX,CAAA,CACA3D,CACF,CAAA,CAEA,OAAIT,CAAAA,CAAS,IAAA,EAAQA,CAAAA,CAAS,IAAA,CAAK,OAAS,CAAA,EAAKA,CAAAA,CAAS,IAAA,CAAK,CAAC,CAAA,CACvDA,CAAAA,CAAS,IAAA,CAAK,CAAC,EAAE,EAAA,CAGnB,IACT,CACF,ECzVO,IAAMsE,CAAAA,CAAN,KAAgB,CACL,KACA,WAAA,CACA,UAAA,CACA,SAAA,CACA,OAAA,CACA,aAAA,CAEC,UAAA,CAEjB,WAAA,CAAY9D,CAAAA,CAA0B,EAAC,CAAG,CACxC,IAAA,CAAK,cAAA,CAAeA,CAAM,CAAA,CAE1B,IAAM+D,CAAAA,CAA6B,CACjC,WAAA,CAAa/D,CAAAA,CAAO,WAAA,CACpB,OAAA,CAASA,CAAAA,CAAO,OAAA,EAAWjB,EAAAA,CAC3B,OAAA,CAASiB,EAAO,OAAA,CAChB,OAAA,CAASA,CAAAA,CAAO,OAAA,CAChB,UAAA,CAAYA,CAAAA,CAAO,UACrB,CAAA,CAEA,KAAK,UAAA,CAAa,IAAID,CAAAA,CAAWgE,CAAY,EAG7C,IAAA,CAAK,IAAA,CAAO,IAAI1C,CAAAA,CAAQ,KAAK,UAAU,CAAA,CACvC,IAAA,CAAK,WAAA,CAAc,IAAIM,CAAAA,CAAe,IAAA,CAAK,UAAU,EACrD,IAAA,CAAK,UAAA,CAAa,IAAIE,CAAAA,CAAc,IAAA,CAAK,UAAU,CAAA,CACnD,IAAA,CAAK,UAAY,IAAIkB,CAAAA,CAAa,IAAA,CAAK,UAAU,CAAA,CACjD,IAAA,CAAK,OAAA,CAAU,IAAIE,EAAW,IAAA,CAAK,UAAU,CAAA,CAC7C,IAAA,CAAK,aAAA,CAAgB,IAAII,CAAAA,CAAiB,IAAA,CAAK,UAAU,EAC3D,CAEQ,cAAA,CAAerD,CAAAA,CAA+B,CACpD,GAAIA,CAAAA,CAAO,WAAA,GAAgB,SACrB,OAAOA,CAAAA,CAAO,WAAA,EAAgB,QAAA,EAAYA,CAAAA,CAAO,WAAA,CAAY,IAAA,EAAK,GAAM,IAC1E,MAAM,IAAIF,CAAAA,CAAqB,yCAAyC,CAAA,CAI5E,GAAIE,CAAAA,CAAO,OAAA,EAAW,OAAOA,CAAAA,CAAO,OAAA,EAAY,QAAA,CAC9C,MAAM,IAAIF,CAAAA,CAAqB,8BAA8B,CAAA,CAG/D,GAAIE,EAAO,OAAA,GAAY,OAAOA,CAAAA,CAAO,OAAA,EAAY,QAAA,EAAYA,CAAAA,CAAO,OAAA,EAAW,CAAA,CAAA,CAC7E,MAAM,IAAIF,CAAAA,CAAqB,mCAAmC,CAAA,CAGpE,GAAIE,CAAAA,CAAO,UAAA,GAAe,OAAOA,EAAO,UAAA,EAAe,QAAA,EAAYA,CAAAA,CAAO,UAAA,CAAa,CAAA,CAAA,CACrF,MAAM,IAAIF,CAAAA,CAAqB,2CAA2C,CAE9E,CACF,ECVO,IAAKkE,CAAAA,CAAAA,CAAAA,CAAAA,GAEVA,CAAAA,CAAA,OAAA,CAAU,SAAA,CACVA,EAAA,YAAA,CAAe,cAAA,CACfA,CAAAA,CAAA,gBAAA,CAAmB,UAAA,CACnBA,CAAAA,CAAA,YAAA,CAAe,MAAA,CACfA,EAAA,kBAAA,CAAqB,oBAAA,CACrBA,CAAAA,CAAA,kBAAA,CAAqB,UAAA,CAGrBA,CAAAA,CAAA,IAAA,CAAO,MAAA,CACPA,EAAA,MAAA,CAAS,QAAA,CACTA,CAAAA,CAAA,WAAA,CAAc,aAAA,CAZJA,CAAAA,CAAAA,EAAAA,CAAAA,EAAA,EAAA,EAmEL,SAASC,GAAUC,CAAAA,CAAiE,CACzF,OAAO,OAAOA,EAAO,EAAA,EAAO,QAAA,EAAYA,CAAAA,CAAO,EAAA,CAAG,OAAS,CAC7D,CA6CO,SAASC,EAAAA,CACdnB,CAAAA,CACK,CACL,IAAMoB,CAAAA,CAAc,EAAC,CAErB,GAAIpB,CAAAA,CAAQ,MAAA,GAAW,MAAA,EAAU,KAAA,CAAM,OAAA,CAAQA,CAAAA,CAAQ,KAAK,CAAA,CAC1D,IAAA,IAAWqB,CAAAA,IAASrB,CAAAA,CAAQ,KAAA,CACtB,KAAA,CAAM,OAAA,CAAQqB,CAAAA,CAAM,SAAS,CAAA,EAC/BD,CAAAA,CAAO,IAAA,CAAK,GAAGC,EAAM,SAAS,CAAA,CAKpC,OAAOD,CACT,CAQO,SAASE,EAAAA,CAAqBtB,CAAAA,CAAqC,CACxE,IAAMoB,CAAAA,CAAc,EAAC,CAErB,GAAIpB,CAAAA,CAAQ,MAAA,GAAW,MAAA,EAAU,KAAA,CAAM,OAAA,CAAQA,CAAAA,CAAQ,KAAK,CAAA,CAC1D,QAAWqB,CAAAA,IAASrB,CAAAA,CAAQ,KAAA,CACtB,KAAA,CAAM,OAAA,CAAQqB,CAAAA,CAAM,OAAO,CAAA,EAC7BD,EAAO,IAAA,CAAK,GAAGC,CAAAA,CAAM,OAAO,EAKlC,OAAOD,CACT,CA+BO,SAASG,EAAmBC,CAAAA,CAAgD,CACjF,IAAMC,CAAAA,CAAmBR,EAAAA,CAAUO,CAAAA,CAAM,MAAM,CAAA,CAE/C,OAAO,CACL,QAAA,CAAUA,CAAAA,CAAM,MAAA,CAAO,EAAA,CACvB,OAAA,CAASA,CAAAA,CAAM,MAAA,CAAO,SACtB,WAAA,CAAaA,CAAAA,CAAM,SAAA,CAAU,EAAA,CAC7B,SAAA,CAAWA,CAAAA,CAAM,SAAA,CACjB,gBAAA,CAAAC,EACA,SAAA,CAAW,IAAI,IAAA,CAAKD,CAAAA,CAAM,SAAS,CACrC,CACF,CAkBO,SAASE,EAAAA,CAAyB1B,CAAAA,CAAiD,CACxF,IAAM2B,CAAAA,CAAa,IAAI,GAAA,CAEvB,GAAI3B,EAAQ,MAAA,GAAW,MAAA,EAAU,KAAA,CAAM,OAAA,CAAQA,CAAAA,CAAQ,KAAK,CAAA,CAAA,CAC1D,IAAA,IAAWqB,KAASrB,CAAAA,CAAQ,KAAA,CAC1B,GAAI,KAAA,CAAM,OAAA,CAAQqB,CAAAA,CAAM,OAAO,CAAA,CAAA,CAC7B,QAAWO,CAAAA,IAAUP,CAAAA,CAAM,OAAA,CACzB,GAAIO,GAAU,OAAOA,CAAAA,EAAW,QAAA,EAAY,OAAA,GAAWA,EAGrD,OAFcA,CAAAA,CAAO,KAAA,EAGnB,KAAK,MAAA,CACHD,CAAAA,CAAW,GAAA,CAAI,MAAqB,CAAA,CACpC,MACF,KAAK,QAAA,CACHA,CAAAA,CAAW,GAAA,CAAI,QAAuB,CAAA,CACtC,MACF,KAAK,aAAA,CACHA,CAAAA,CAAW,GAAA,CAAI,aAA4B,CAAA,CAC3C,KACJ,CAAA,CAAA,CAOV,OAAO,KAAA,CAAM,IAAA,CAAKA,CAAU,CAC9B,CCnMO,SAASE,EAAAA,CAAmBL,CAAAA,CAA8C,CAC/E,OAAOA,CAAAA,EAAS,OAAOA,CAAAA,EAAU,QAAA,EAAY,cAAA,GAAkBA,CACjE,CAiCO,SAASM,GAA0BN,CAAAA,CAA8D,CAGtG,OAAO,CACL,GAHkBD,CAAAA,CAAmBC,CAAK,CAAA,CAI1C,UAAWA,CAAAA,CAAM,YAAA,CAAa,GAAA,CAC9B,WAAA,CAAaA,CAAAA,CAAM,YAAA,CAAa,IAAA,CAChC,SAAA,CAAWA,EAAM,YAAA,CAAa,QAChC,CACF,KAKaO,EAAAA,CAAyB,CAEpC,SAAA,CAAW,CAAA,CAGX,WAAY,cACd,ECxIO,IAAKC,CAAAA,CAAAA,CAAAA,CAAAA,GAEVA,CAAAA,CAAA,IAAA,CAAO,MAAA,CAEPA,CAAAA,CAAA,QAAU,SAAA,CAEVA,CAAAA,CAAA,IAAA,CAAO,MAAA,CAEPA,CAAAA,CAAA,GAAA,CAAM,KAAA,CAENA,CAAAA,CAAA,MAAQ,OAAA,CAERA,CAAAA,CAAA,GAAA,CAAM,KAAA,CAENA,CAAAA,CAAA,KAAA,CAAQ,OAAA,CAERA,CAAAA,CAAA,MAAQ,OAAA,CAhBEA,CAAAA,CAAAA,EAAAA,CAAAA,EAAA,EAAA,CAAA,CAsBAC,CAAAA,CAAAA,CAAAA,CAAAA,GAEVA,CAAAA,CAAA,KAAA,CAAQ,OAAA,CAERA,CAAAA,CAAA,QAAU,SAAA,CAJAA,CAAAA,CAAAA,EAAAA,CAAAA,EAAA,EAAA,ECgDL,SAASC,EAAAA,CAAoBV,CAAAA,CAA+C,CACjF,OAAOA,GAAS,OAAOA,CAAAA,EAAU,QAAA,EAAY,MAAA,GAAUA,CACzD,CAgDO,SAASW,EAAAA,CAA2BX,EAAgE,CACzG,OAAO,CACL,QAAA,CAAUA,CAAAA,CAAM,MAAA,CAAO,EAAA,CACvB,WAAA,CAAaA,EAAM,SAAA,CAAU,EAAA,CAC7B,kBAAA,CAAoBA,CAAAA,CAAM,KAAK,SAAA,CAC/B,aAAA,CAAeA,CAAAA,CAAM,SAAA,CACrB,cAAe,IAAI,IAAA,CAAKA,CAAAA,CAAM,IAAA,CAAK,SAAS,CAAA,CAC5C,QAAA,CAAU,IAAI,KAAKA,CAAAA,CAAM,SAAS,CACpC,CACF,CAmBO,SAASY,EAAAA,CAAcC,CAAAA,CAA0BC,EAA4B,CAClF,OAAOD,CAAAA,EAAoBC,CAC7B,CAqBO,SAASC,EAAAA,CACdC,CAAAA,CACAF,EACK,CACL,OAAOE,CAAAA,CAAS,MAAA,CAAO9F,GAAW0F,EAAAA,CAAc1F,CAAAA,CAAQ,SAAA,CAAW4F,CAAS,CAAC,CAC/E,CAqBO,SAASG,EAAAA,CACdD,CAAAA,CACAF,CAAAA,CACQ,CACR,OAAOC,GAAgBC,CAAAA,CAAUF,CAAS,CAAA,CAAE,MAC9C,CAKO,IAAMI,EAAAA,CAA0B,CAErC,WAAY,eAAA,CAMZ,aAAA,CAAe,MACjB,ECvEO,SAASC,EAAAA,CAAyBnB,CAAAA,CAAoD,CAC3F,OAAOA,CAAAA,EAAS,OAAOA,CAAAA,EAAU,QAAA,EAAY,aAAcA,CAC7D,CAiBO,SAASoB,EAAAA,CAAgBpB,EAE9B,CACA,OAAOA,CAAAA,CAAM,QAAA,EAAY,UAAA,GAAcA,CAAAA,CAAM,QAAA,EAAYA,CAAAA,CAAM,SAAS,QAAA,EAAY,IACtF,CAmBO,SAASqB,EAAAA,CAAmB3B,CAAAA,CAAiE,CAClG,OAAOA,GAAU,OAAOA,CAAAA,CAAO,EAAA,EAAO,QAAA,EAAYA,CAAAA,CAAO,EAAA,CAAG,MAAA,CAAS,CACvE,CAmEO,SAAS4B,EAAAA,CAAuBtB,CAAAA,CAAiE,CACtG,IAAMuB,CAAAA,CAAaH,EAAAA,CAAgBpB,CAAK,EAClCC,CAAAA,CAAmBoB,EAAAA,CAAmBrB,CAAAA,CAAM,MAAM,CAAA,CAExD,OAAO,CACL,OAAA,CAASA,EAAM,QAAA,CAAS,OAAA,CACxB,QAAA,CAAUA,CAAAA,CAAM,MAAA,CAAO,EAAA,CACvB,OAAA,CAASA,CAAAA,CAAM,OAAO,QAAA,CACtB,WAAA,CAAaA,CAAAA,CAAM,SAAA,CAAU,EAAA,CAC7B,WAAA,CAAaA,CAAAA,CAAM,QAAA,CAAS,MAC5B,SAAA,CAAWA,CAAAA,CAAM,QAAA,CAAS,GAAA,CAC1B,UAAWA,CAAAA,CAAM,SAAA,CACjB,eAAA,CAAiBuB,CAAAA,CAAa,CAC5B,GAAA,CAAKvB,CAAAA,CAAM,QAAA,CAAS,QAAA,CAAS,GAAA,CAC7B,MAAA,CAAQA,CAAAA,CAAM,QAAA,CAAS,SAAS,MAAA,CAChC,IAAA,CAAMA,CAAAA,CAAM,QAAA,CAAS,QAAA,CAAS,IAChC,CAAA,CAAI,MAAA,CACJ,WAAAuB,CAAAA,CACA,gBAAA,CAAAtB,CACF,CACF,CAKO,IAAMuB,EAAAA,CAA2B,CAEtC,YAAa,aAAA,CAGb,SAAA,CAAW,WAAA,CAGX,IAAA,CAAM,OACN,OAAA,CAAS,SAAA,CAGT,OAAA,CAAS,SAAA,CACT,cAAe,eAAA,CACf,eAAA,CAAiB,iBAAA,CAGjB,IAAA,CAAM,MAAA,CACN,IAAA,CAAM,MAAA,CACN,MAAA,CAAQ,SAGR,QAAA,CAAU,UAAA,CACV,WAAA,CAAa,aACf,CAAA,CAKaC,EAAAA,CAAqB,CAEhC,kBAAA,CAAoB,IAGpB,UAAA,CAAY,UAAA,CAGZ,gBAAA,CAAkB,CAChB,SAAA,CAAW,WAAA,CACX,GAAA,CAAK,KAAA,CACL,eAAgB,gBAClB,CAAA,CAGA,cAAA,CAAgB,CACd,YAAa,aACf,CACF,ECzUO,IAAKC,OAEVA,CAAAA,CAAA,IAAA,CAAO,MAAA,CAEPA,CAAAA,CAAA,GAAA,CAAM,KAAA,CAENA,CAAAA,CAAA,GAAA,CAAM,MANIA,CAAAA,CAAAA,EAAAA,CAAAA,EAAA,EAAA,CAAA,CAYAC,CAAAA,CAAAA,CAAAA,CAAAA,GAEVA,CAAAA,CAAA,WAAA,CAAc,aAAA,CAEdA,CAAAA,CAAA,UAAA,CAAa,aAEbA,CAAAA,CAAA,WAAA,CAAc,aAAA,CANJA,CAAAA,CAAAA,EAAAA,CAAAA,EAAA,EAAA,CAAA,CAYAC,CAAAA,CAAAA,CAAAA,CAAAA,GAEVA,CAAAA,CAAA,WAAA,CAAc,cAFJA,CAAAA,CAAAA,EAAAA,CAAAA,EAAA,EAAA,CAAA,CAQAC,CAAAA,CAAAA,CAAAA,CAAAA,GAEVA,CAAAA,CAAA,YAAA,CAAe,cAAA,CAFLA,CAAAA,CAAAA,EAAAA,CAAAA,EAAA,EAAA,CAAA,CAQAC,OAEVA,CAAAA,CAAA,SAAA,CAAY,WAAA,CAFFA,CAAAA,CAAAA,EAAAA,CAAAA,EAAA,EAAA,EAiJL,SAASC,EAAAA,CAAyB/B,CAAAA,CAAoD,CAC3F,OAAOA,CAAAA,EAAS,OAAOA,CAAAA,EAAU,QAAA,EAAY,oBAAA,GAAwBA,CACvE,CAgDO,SAASgC,EAAAA,CAAgChC,CAAAA,CAA0E,CACxH,IAAMiC,CAAAA,CAAmE,EAAC,CAG1E,OAAAjC,EAAM,kBAAA,CAAmB,gBAAA,CAAiB,OAAA,CAAQkC,CAAAA,EAAU,CAC1D,MAAA,CAAO,OAAA,CAAQA,CAAAA,CAAO,SAAS,EAAE,OAAA,CAAQ,CAAC,CAACC,CAAAA,CAAYC,CAAQ,CAAA,GAAM,CACnEH,CAAAA,CAAa,KAAK,CAChB,UAAA,CAAAE,CAAAA,CACA,YAAA,CAAcC,CAAAA,CAAS,IAAA,CACvB,KAAA,CAAO,QAAA,CAASA,EAAS,OAAA,CAAS,EAAE,CAAA,CACpC,YAAA,CAAcA,CAAAA,CAAS,SAAA,EAAW,OAAA,CAClC,QAAA,CAAUF,EAAO,SACnB,CAAC,EACH,CAAC,EACH,CAAC,CAAA,CAEM,CACL,QAAA,CAAUlC,EAAM,MAAA,CAAO,EAAA,CACvB,WAAA,CAAaA,CAAAA,CAAM,SAAA,CAAU,EAAA,CAC7B,mBAAA,CAAqBA,CAAAA,CAAM,UAC3B,WAAA,CAAaA,CAAAA,CAAM,kBAAA,CAAmB,gBAAA,CAAiB,MAAA,CACvD,YAAA,CAAAiC,CACF,CACF,CAeO,SAASI,EAAAA,CAAwBrC,CAAAA,CAAmE,CACzG,IAAMsC,CAAAA,CAAe,IAAI,GAAA,CAEzB,OAAAtC,CAAAA,CAAM,kBAAA,CAAmB,gBAAA,CAAiB,OAAA,CAAQkC,GAAU,CAC1D,MAAA,CAAO,MAAA,CAAOA,CAAAA,CAAO,SAAS,CAAA,CAAE,OAAA,CAAQE,CAAAA,EAAY,CAClD,IAAMG,CAAAA,CAAQ,QAAA,CAASH,CAAAA,CAAS,QAAS,EAAE,CAAA,CACrCI,CAAAA,CAAiBF,CAAAA,CAAa,GAAA,CAAIF,CAAAA,CAAS,IAAI,CAAA,EAAK,EAAC,CAC3DE,CAAAA,CAAa,GAAA,CAAIF,CAAAA,CAAS,IAAA,CAAM,CAAC,GAAGI,CAAAA,CAAgBD,CAAK,CAAC,EAC5D,CAAC,EACH,CAAC,CAAA,CAEMD,CACT,CAgBO,SAASG,EAAAA,CAAoBzC,CAAAA,CAAgD,CAClF,IAAM0C,CAAAA,CAAyB,EAAC,CAEhC,OAAA1C,EAAM,kBAAA,CAAmB,gBAAA,CAAiB,OAAA,CAAQkC,CAAAA,EAAU,CAC1D,MAAA,CAAO,MAAA,CAAOA,CAAAA,CAAO,SAAS,CAAA,CAAE,OAAA,CAAQE,CAAAA,EAAY,CAC9CA,CAAAA,CAAS,SAAA,EAAW,OAAA,EACtBM,CAAAA,CAAa,KAAKN,CAAAA,CAAS,SAAA,CAAU,OAAO,EAEhD,CAAC,EACH,CAAC,CAAA,CAEMM,CACT,CAKO,IAAMC,CAAAA,CAA+B,CAE1C,wBAAA,CAA0B,GAAA,CAG1B,YAAA,CAAc,CACX,IAAA,CAAoB,CAAE,GAAA,CAAK,CAAA,CAAG,GAAA,CAAK,CAAE,CAAA,CACrC,GAAA,CAAmB,CAAE,GAAA,CAAK,EAAG,GAAA,CAAK,EAAG,CAAA,CACrC,GAAA,CAAmB,CAAE,GAAA,CAAK,CAAA,CAAG,GAAA,CAAK,CAAE,CACvC,CAAA,CAGA,eAAA,CAAiB,CAEf,SAAU,CAAA,CAEV,QAAA,CAAU,CAAA,CAEV,YAAA,CAAc,CAChB,CAAA,CAGA,WAAA,CAAa,CAEX,UAAA,CAAY,EAAA,CAEZ,aAAA,CAAe,iBACjB,CAAA,CAGA,gBAAiB,CAEf,UAAA,CAAY,CAAA,CAEZ,sBAAA,CAAwB,CAC1B,CAAA,CAGA,UAAA,CAAY,oBACd,EAeO,SAASC,EAAAA,CAAqBC,CAAAA,CAA4BN,CAAAA,CAAwB,CACvF,IAAMO,CAAAA,CAAQH,CAAAA,CAA6B,aAAaE,CAAY,CAAA,CACpE,OAAO,MAAA,CAAO,UAAUN,CAAK,CAAA,EAAKA,CAAAA,EAASO,CAAAA,CAAM,KAAOP,CAAAA,EAASO,CAAAA,CAAM,GACzE,CAcO,SAASC,EAAAA,CAAkBZ,CAAAA,CAA6B,CAC7D,OAAOA,CAAAA,CAAW,MAAA,EAAUQ,CAAAA,CAA6B,WAAA,CAAY,UAAA,EAC9DA,CAAAA,CAA6B,WAAA,CAAY,aAAA,CAAc,KAAKR,CAAU,CAC/E,CAcO,SAASa,EAAAA,CAAoBN,CAAAA,CAA+B,CACjE,OAAOA,EAAa,MAAA,EAAUC,CAAAA,CAA6B,wBAC7D,CCzZO,IAAKM,CAAAA,CAAAA,CAAAA,CAAAA,GACVA,CAAAA,CAAA,KAAA,CAAQ,QACRA,CAAAA,CAAA,OAAA,CAAU,SAAA,CACVA,CAAAA,CAAA,OAAA,CAAU,SAAA,CACVA,CAAAA,CAAA,UAAA,CAAa,aACbA,CAAAA,CAAA,MAAA,CAAS,QAAA,CACTA,CAAAA,CAAA,KAAA,CAAQ,OAAA,CACRA,CAAAA,CAAA,UAAA,CAAa,aACbA,CAAAA,CAAA,KAAA,CAAQ,OAAA,CACRA,CAAAA,CAAA,aAAA,CAAgB,eAAA,CAChBA,CAAAA,CAAA,QAAA,CAAW,WACXA,CAAAA,CAAA,IAAA,CAAO,MAAA,CACPA,CAAAA,CAAA,QAAU,SAAA,CACVA,CAAAA,CAAA,SAAA,CAAY,WAAA,CACZA,EAAA,IAAA,CAAO,MAAA,CACPA,CAAAA,CAAA,IAAA,CAAO,MAAA,CACPA,CAAAA,CAAA,OAAA,CAAU,SAAA,CACVA,EAAA,cAAA,CAAiB,gBAAA,CACjBA,CAAAA,CAAA,KAAA,CAAQ,OAAA,CACRA,CAAAA,CAAA,WAAA,CAAc,aAAA,CACdA,EAAA,IAAA,CAAO,MAAA,CACPA,CAAAA,CAAA,OAAA,CAAU,SAAA,CACVA,CAAAA,CAAA,QAAA,CAAW,UAAA,CACXA,EAAA,MAAA,CAAS,QAAA,CACTA,CAAAA,CAAA,QAAA,CAAW,WACXA,CAAAA,CAAA,mBAAA,CAAsB,qBAAA,CACtBA,CAAAA,CAAA,MAAQ,OAAA,CACRA,CAAAA,CAAA,MAAA,CAAS,QAAA,CACTA,CAAAA,CAAA,KAAA,CAAQ,OAAA,CACRA,CAAAA,CAAA,eAAiB,gBAAA,CACjBA,CAAAA,CAAA,GAAA,CAAM,KAAA,CACNA,CAAAA,CAAA,KAAA,CAAQ,OAAA,CA/BEA,CAAAA,CAAAA,EAAAA,CAAAA,EAAA,IAqCAC,CAAAA,CAAAA,CAAAA,CAAAA,GACVA,CAAAA,CAAA,GAAA,CAAM,KAAA,CACNA,CAAAA,CAAA,KAAA,CAAQ,OAAA,CACRA,CAAAA,CAAA,KAAO,MAAA,CACPA,CAAAA,CAAA,MAAA,CAAS,QAAA,CACTA,EAAA,MAAA,CAAS,QAAA,CACTA,CAAAA,CAAA,MAAA,CAAS,SACTA,CAAAA,CAAA,IAAA,CAAO,MAAA,CACPA,CAAAA,CAAA,IAAA,CAAO,MAAA,CACPA,CAAAA,CAAA,MAAA,CAAS,SACTA,CAAAA,CAAA,OAAA,CAAU,SAAA,CACVA,CAAAA,CAAA,MAAA,CAAS,QAAA,CACTA,CAAAA,CAAA,MAAA,CAAS,SAZCA,CAAAA,CAAAA,EAAAA,CAAAA,EAAA,EAAA,EA2ML,SAASC,EAAAA,CAAYnD,CAAAA,CAAuC,CACjE,OAAOA,CAAAA,EAAS,OAAOA,CAAAA,EAAU,QAAA,EAAYA,CAAAA,CAAM,KAAA,GAAU,MAC/D,CAQO,SAASoD,EAAAA,CAAclH,EAAgC,CAC5D,OAAOA,CAAAA,CAAM,IAAA,GAAS,KAAA,EAAsBA,CAAAA,CAAM,IAAA,GAAS,MAC7D,CAQO,SAASmH,EAAAA,CAAUnH,CAAAA,CAAgC,CACxD,OAAOA,CAAAA,CAAM,IAAA,GAAS,SACxB,CAQO,SAASoH,EAAAA,CAAQpH,CAAAA,CAAgC,CACtD,OAAOA,CAAAA,CAAM,IAAA,GAAS,OAAA,EAAsBA,EAAM,IAAA,GAAS,aAC7D,CAQO,SAASqH,GAAQrH,CAAAA,CAAgC,CACtD,OAAOA,CAAAA,CAAM,OAAS,OACxB,CAQO,SAASsH,EAAAA,CAAWtH,CAAAA,CAAgC,CACzD,OAAOA,CAAAA,CAAM,OAAS,UACxB,CAQO,SAASuH,EAAAA,CAAWvH,CAAAA,CAAsE,CAC/F,OAAO,OAAOA,EAAM,OAAA,EAAY,QAAA,EAAYA,CAAAA,CAAM,OAAA,CAAQ,MAAA,CAAS,CACrE,CAuEO,SAASwH,GACd5E,CAAAA,CACA6E,CAAAA,CACA3D,CAAAA,CACuB,CACvB,GAAM,CAAE,KAAA,CAAA9D,CAAM,EAAI8D,CAAAA,CAElB,OAAO,CACL,MAAA,CAAAlB,CAAAA,CACA,SAAA,CAAA6E,CAAAA,CACA,SAAA,CAAW,IAAI,IAAA,CAAKA,CAAS,CAAA,CAC7B,MAAA,CAAQzH,CAAAA,CAAM,IAAA,CACd,MAAA,CAAQA,CAAAA,CAAM,QACd,SAAA,CAAWA,CAAAA,CAAM,UAAA,CACjB,IAAA,CAAMA,CAAAA,CAAM,IAAA,CACZ,IAAA,CAAMA,CAAAA,CAAM,KACZ,OAAA,CAASA,CAAAA,CAAM,OAAA,CACf,aAAA,CAAekH,GAAclH,CAAK,CAAA,CAClC,SAAA,CAAWmH,EAAAA,CAAUnH,CAAK,CAAA,CAC1B,OAAA,CAASoH,EAAAA,CAAQpH,CAAK,CAAA,CACtB,OAAA,CAASqH,EAAAA,CAAQrH,CAAK,EACtB,UAAA,CAAYsH,EAAAA,CAAWtH,CAAK,CAC9B,CACF,CAcO,SAAS0H,EAAAA,CAAc1H,EAA6D,CACzF,IAAM2H,CAAAA,CAA+C,EAAC,CAEtD,OAAI3H,CAAAA,CAAM,KAAA,EACR2H,EAAO,IAAA,CAAK,CAAE,GAAA,CAAK3H,CAAAA,CAAM,KAAA,CAAO,EAAA,CAAIA,CAAAA,CAAM,QAAS,CAAC,CAAA,CAGlDA,CAAAA,CAAM,MAAA,EAAU,KAAA,CAAM,OAAA,CAAQA,CAAAA,CAAM,MAAM,CAAA,EAC5C2H,EAAO,IAAA,CAAK,GAAG3H,CAAAA,CAAM,MAAA,CAAO,GAAA,CAAI,CAACR,CAAAA,CAAKmC,CAAAA,IAAW,CAC/C,GAAA,CAAAnC,CAAAA,CACA,EAAA,CAAIQ,CAAAA,CAAM,SAAA,GAAY2B,CAAK,CAC7B,CAAA,CAAE,CAAC,CAAA,CAGEgG,CACT,CAKO,IAAMC,GAAiB,CAE5B,UAAA,CAAY,MAAA,CAGZ,gCAAA,CAAkC,GACpC,ECvbO,IAAKC,CAAAA,CAAAA,CAAAA,CAAAA,GAEVA,CAAAA,CAAA,UAAA,CAAa,YAAA,CAGbA,CAAAA,CAAA,KAAA,CAAQ,QAGRA,CAAAA,CAAA,KAAA,CAAQ,OAAA,CAREA,CAAAA,CAAAA,EAAAA,CAAAA,EAAA,EAAA,EAqGL,SAASC,EAAAA,CAAahE,CAAAA,CAAwC,CACnE,OAAOA,CAAAA,EAAS,OAAOA,CAAAA,EAAU,QAAA,EAAYA,CAAAA,CAAM,KAAA,GAAU,QAC/D,CAQO,SAASiE,CAAAA,CAAa/H,CAAAA,CAAiC,CAC5D,OAAOA,CAAAA,CAAM,MAAA,CAAO,YAAA,GAAiB,YACvC,CAQO,SAASgI,CAAAA,CAAQhI,CAAAA,CAAiC,CACvD,OAAOA,CAAAA,CAAM,MAAA,CAAO,YAAA,GAAiB,OACvC,CAQO,SAASiI,CAAAA,CAASjI,CAAAA,CAAiC,CACxD,OAAOA,CAAAA,CAAM,MAAA,CAAO,eAAiB,OACvC,CAuDO,SAASkI,EAAAA,CACdtF,CAAAA,CACA6E,CAAAA,CACA3D,CAAAA,CACwB,CACxB,GAAM,CAAE,KAAA,CAAA9D,CAAM,CAAA,CAAI8D,EAElB,OAAO,CACL,MAAA,CAAAlB,CAAAA,CACA,UAAA6E,CAAAA,CACA,SAAA,CAAW,IAAI,IAAA,CAAKA,CAAS,CAAA,CAC7B,OAAA,CAASzH,CAAAA,CAAM,GACf,MAAA,CAAQA,CAAAA,CAAM,MAAA,CAAO,YAAA,CACrB,YAAA,CAAc+H,CAAAA,CAAa/H,CAAK,CAAA,CAChC,QAASgI,CAAAA,CAAQhI,CAAK,CAAA,CACtB,QAAA,CAAUiI,CAAAA,CAASjI,CAAK,CAC1B,CACF,CAgBO,SAASmI,EAAAA,CAAqBC,CAAAA,CAAqCC,CAAAA,CAAgC,CACxG,OAAOD,CAAAA,GAAe,YAAA,EAA0BC,IAAa,OAC/D,CAgBO,SAASC,EAAAA,CAAiBF,CAAAA,CAAqCC,CAAAA,CAAgC,CACpG,OAAOD,IAAe,YAAA,EAA0BC,CAAAA,GAAa,OAC/D,CAKO,IAAME,EAAAA,CAAkB,CAE7B,UAAA,CAAY,SAGZ,QAAA,CAAU,MAAA,CAAO,MAAA,CAAOV,CAAW,CACrC,ECxPO,IAAKW,CAAAA,CAAAA,CAAAA,CAAAA,GAEVA,EAAA,IAAA,CAAO,MAAA,CAGPA,CAAAA,CAAA,YAAA,CAAe,eAGfA,CAAAA,CAAA,UAAA,CAAa,YAAA,CAGbA,CAAAA,CAAA,mBAAqB,oBAAA,CAGrBA,CAAAA,CAAA,iBAAA,CAAoB,mBAAA,CAGpBA,CAAAA,CAAA,cAAA,CAAiB,gBAAA,CAGjBA,CAAAA,CAAA,sBAAwB,uBAAA,CAGxBA,CAAAA,CAAA,WAAA,CAAc,aAAA,CAGdA,CAAAA,CAAA,GAAA,CAAM,KAAA,CA1BIA,CAAAA,CAAAA,EAAAA,CAAAA,EAAA,IA8FL,SAASC,EAAAA,CAAiB3E,CAAAA,CAA4C,CAC3E,OAAOA,CAAAA,EAAS,OAAOA,CAAAA,EAAU,UAAYA,CAAAA,CAAM,KAAA,GAAU,aAC/D,CAQO,SAAS4E,CAAAA,CAAO1I,CAAAA,CAAqC,CAC1D,OAAOA,EAAM,MAAA,GAAW,MAC1B,CAQO,SAAS2I,CAAAA,CAAY3I,CAAAA,CAAqC,CAC/D,OACEA,EAAM,MAAA,GAAW,uBAAA,EACjBA,CAAAA,CAAM,MAAA,GAAW,gBAErB,CAQO,SAAS+H,CAAAA,CAAa/H,EAAqC,CAChE,OAAOA,CAAAA,CAAM,MAAA,GAAW,YAC1B,CAQO,SAAS4I,CAAAA,CAAS5I,EAAqC,CAC5D,OACEA,CAAAA,CAAM,MAAA,GAAW,gBACjBA,CAAAA,CAAM,MAAA,GAAW,oBAAA,EACjBA,CAAAA,CAAM,SAAW,mBAErB,CAQO,SAAS6I,EAAAA,CAAW7I,CAAAA,CAAqC,CAC9D,OAAOA,CAAAA,CAAM,SAAW,KAC1B,CA6DO,SAAS8I,EAAAA,CACdlG,CAAAA,CACA6E,CAAAA,CACA3D,CAAAA,CAC4B,CAC5B,GAAM,CAAE,KAAA,CAAA9D,CAAM,CAAA,CAAI8D,CAAAA,CAElB,OAAO,CACL,MAAA,CAAAlB,EACA,SAAA,CAAA6E,CAAAA,CACA,SAAA,CAAW,IAAI,IAAA,CAAKA,CAAS,CAAA,CAC7B,OAAA,CAASzH,EAAM,EAAA,CACf,MAAA,CAAQA,CAAAA,CAAM,MAAA,CACd,MAAA,CAAQ0I,CAAAA,CAAO1I,CAAK,CAAA,CACpB,YAAa2I,CAAAA,CAAY3I,CAAK,CAAA,CAC9B,YAAA,CAAc+H,CAAAA,CAAa/H,CAAK,CAAA,CAChC,QAAA,CAAU4I,EAAS5I,CAAK,CAAA,CACxB,UAAA,CAAY6I,EAAAA,CAAW7I,CAAK,CAC9B,CACF,CAgBO,SAAS+I,EAAAA,CAAYX,CAAAA,CAAyCC,CAAAA,CAAoC,CACvG,OAAOD,CAAAA,GAAe,MAAA,EAAwBC,CAAAA,GAAa,MAC7D,CAgBO,SAASW,EAAAA,CAAaZ,CAAAA,CAAyCC,CAAAA,CAAoC,CACxG,OACED,CAAAA,GAAe,MAAA,GACdC,IAAa,cAAA,EACbA,CAAAA,GAAa,oBAAA,EACbA,CAAAA,GAAa,mBAAA,CAElB,CAKO,IAAMY,EAAAA,CAAuB,CAElC,UAAA,CAAY,aAAA,CAGZ,QAAA,CAAU,MAAA,CAAO,MAAA,CAAOT,CAAe,CACzC,MC3RYU,EAAAA,CAAAA,CAAAA,CAAAA,GACVA,CAAAA,CAAA,KAAA,CAAQ,OAAA,CACRA,EAAA,IAAA,CAAO,MAAA,CACPA,CAAAA,CAAA,KAAA,CAAQ,QACRA,CAAAA,CAAA,KAAA,CAAQ,OAAA,CACRA,CAAAA,CAAA,QAAA,CAAW,UAAA,CACXA,CAAAA,CAAA,IAAA,CAAO,OACPA,CAAAA,CAAA,OAAA,CAAU,SAAA,CAPAA,CAAAA,CAAAA,EAAAA,EAAAA,EAAA,EAAA,CAAA,CAaAC,EAAAA,CAAAA,CAAAA,CAAAA,GACVA,CAAAA,CAAA,WAAA,CAAc,cACdA,CAAAA,CAAA,OAAA,CAAU,SAAA,CACVA,CAAAA,CAAA,GAAA,CAAM,KAAA,CAHIA,CAAAA,CAAAA,EAAAA,EAAAA,EAAA,EAAA,CAAA,CASAC,QACVA,CAAAA,CAAA,cAAA,CAAiB,gBAAA,CACjBA,CAAAA,CAAA,aAAe,cAAA,CACfA,CAAAA,CAAA,GAAA,CAAM,KAAA,CACNA,EAAA,SAAA,CAAY,WAAA,CACZA,CAAAA,CAAA,oBAAA,CAAuB,sBAAA,CALbA,CAAAA,CAAAA,EAAAA,EAAAA,EAAA,EAAA,EA2TL,SAASC,GAAevF,CAAAA,CAA0C,CACvE,OAAOA,CAAAA,EAAS,OAAOA,CAAAA,EAAU,QAAA,EAAY,SAAA,GAAaA,CAC5D,CAQO,SAASwF,EAAAA,CAActK,CAAAA,CAAyD,CACrF,OAAO,OAAOA,CAAAA,CAAQ,MAAS,QAAA,EAAYA,CAAAA,CAAQ,IAAA,CAAK,MAAA,CAAS,CACnE,CAQO,SAASuK,CAAAA,CAAevK,EAA6E,CAC1G,OAAO,KAAA,CAAM,OAAA,CAAQA,CAAAA,CAAQ,WAAW,CAAA,EAAKA,CAAAA,CAAQ,YAAY,MAAA,CAAS,CAC5E,CAQO,SAASwK,EAAAA,CAAcxK,CAAAA,CAAoE,CAChG,OAAOA,EAAQ,WAAA,GAAgB,MACjC,CAQO,SAASyK,EAAAA,CAAezK,CAAAA,CAA8D,CAC3F,OAAOA,EAAQ,QAAA,GAAa,MAC9B,CAQO,SAAS0K,GAAY1K,CAAAA,CAAsE,CAChG,OAAOA,CAAAA,CAAQ,WAAa,MAC9B,CASO,SAAS2K,EAAAA,CACdC,CAAAA,CACAC,CAAAA,CAC+C,CAC/C,OAAOD,EAAW,IAAA,GAASC,CAC7B,CAmDO,SAASC,EAAAA,CAAsBhG,CAAAA,CAAsD,CAC1F,GAAM,CAAE,OAAA,CAAA9E,CAAQ,CAAA,CAAI8E,CAAAA,CAGpB,OAAO,CACL,GAHkBD,CAAAA,CAAmBC,CAAK,CAAA,CAI1C,SAAA,CAAW9E,CAAAA,CAAQ,GAAA,CACnB,KAAMA,CAAAA,CAAQ,IAAA,CACd,cAAA,CAAgBuK,CAAAA,CAAevK,CAAO,CAAA,CACtC,YAAA,CAAcwK,EAAAA,CAAcxK,CAAO,CAAA,CACnC,OAAA,CAASyK,EAAAA,CAAezK,CAAO,EAC/B,WAAA,CAAa0K,EAAAA,CAAY1K,CAAO,CAAA,CAChC,iBAAA,CAAmBA,CAAAA,CAAQ,WAAA,EAAa,OAAA,CACxC,mBAAoBA,CAAAA,CAAQ,QAAA,EAAU,GACxC,CACF,CAeO,SAAS+K,EAAAA,CACd/K,CAAAA,CACA6K,EACwC,CACxC,OAAKN,CAAAA,CAAevK,CAAO,EAIpBA,CAAAA,CAAQ,WAAA,CAAY,MAAA,CAAQ4K,CAAAA,EACjCD,GAAiBC,CAAAA,CAAYC,CAAI,CACnC,CAAA,CALS,EAMX,CAcO,SAASG,GAAkBhL,CAAAA,CAA4B,CAC5D,OAAKuK,CAAAA,CAAevK,CAAO,CAAA,CAIpBA,CAAAA,CAAQ,WAAA,CAAY,IAAI4K,CAAAA,EAAcA,CAAAA,CAAW,OAAA,CAAQ,GAAG,CAAA,CAH1D,EAIX,KAKaK,EAAAA,CAAoB,CAE/B,eAAA,CAAiB,GAAA,CAGjB,8BAAA,CAAgC,GAAA,CAGhC,uBAAA,CAAyB,GAAA,CAGzB,WAAY,SACd,CAAA,CAKaC,EAAAA,CAAwB,CAClC,KAAA,CAAuB,CACtB,YAAA,CACA,WAAA,CACA,YACA,YACF,CAAA,CACC,KAAA,CAAuB,CACtB,WAAA,CACA,WAAA,CACA,iBAAA,CACA,YACF,EACC,KAAA,CAAuB,CACtB,YAAA,CACA,WAAA,CACA,WAAA,CACA,WACF,CAAA,CACC,IAAA,CAAsB,CACrB,iBAAA,CACA,oBAAA,CACA,yEAAA,CACA,YACF,CACF,ECreO,SAASC,CAAAA,CAAoBrG,CAAAA,CAA6D,CAC/F,OAAI,CAACA,CAAAA,EAAS,OAAOA,CAAAA,EAAU,QAAA,CACtB,IAAA,CAIL,MAAA,GAAUA,GAAS,MAAA,CAAO,MAAA,CAAOR,CAAgB,CAAA,CAAE,QAAA,CAASQ,CAAAA,CAAM,IAAI,CAAA,CACjEA,EAAM,IAAA,CAIX,SAAA,GAAaA,CAAAA,CAAAA,SAAAA,CAGb,cAAA,GAAkBA,CAAAA,CAAAA,cAAAA,CAGlB,UAAA,GAAcA,CAAAA,CAAAA,UAAAA,CAGd,MAAA,GAAUA,SAGV,oBAAA,GAAwBA,CAAAA,CAAAA,oBAAAA,CAGxB,UAAA,GAAcA,CAAAA,CAAAA,UAAAA,CAIX,IACT,CAqBO,SAASsG,EAAAA,CAA4B9H,CAAAA,CAAoD,CAC9F,IAAM2B,CAAAA,CAAa,IAAI,GAAA,CAEvB,GAAI3B,CAAAA,CAAQ,MAAA,GAAW,MAAA,EAAU,MAAM,OAAA,CAAQA,CAAAA,CAAQ,KAAK,CAAA,CAAA,CAC1D,IAAA,IAAWqB,CAAAA,IAASrB,CAAAA,CAAQ,KAAA,CAC1B,GAAI,KAAA,CAAM,OAAA,CAAQqB,CAAAA,CAAM,SAAS,CAAA,CAC/B,IAAA,IAAWG,CAAAA,IAASH,CAAAA,CAAM,UAAW,CACnC,IAAMkG,CAAAA,CAAOM,CAAAA,CAAoBrG,CAAK,CAAA,CAClC+F,CAAAA,EACF5F,CAAAA,CAAW,GAAA,CAAI4F,CAAI,EAEvB,CAAA,CAKN,OAAO,KAAA,CAAM,IAAA,CAAK5F,CAAU,CAC9B,CAkBO,SAASoG,EAAAA,CAAqB/H,CAAAA,CAAyD,CAC5F,OAAOmB,EAAAA,CAAcnB,CAAO,CAC9B,CASA,SAASgI,EAAAA,CAAiBxG,CAAAA,CAA0C,CAClE,IAAM+F,CAAAA,CAAOM,CAAAA,CAAoBrG,CAAK,CAAA,CACtC,OAAK+F,CAAAA,CAGC,MAAA,GAAU/F,CAAAA,CAITA,CAAAA,CAHE,CAAE,GAAGA,CAAAA,CAAO,IAAA,CAAA+F,CAAK,CAAA,CAJR,IAQpB,CAiCA,eAAsBU,EAAAA,CACpBjI,CAAAA,CACAkI,CAAAA,CACe,CACf,IAAM9G,CAAAA,CAAS2G,EAAAA,CAAqB/H,CAAO,CAAA,CAE3C,IAAA,IAAWmI,CAAAA,IAAY/G,CAAAA,CAAQ,CAE7B,IAAMI,CAAAA,CAAQwG,EAAAA,CAAiBG,CAAQ,CAAA,CACvC,GAAI,CAAC3G,CAAAA,CAAO,CACN0G,EAAS,SAAA,EACX,MAAMA,CAAAA,CAAS,SAAA,CAAUC,CAAQ,CAAA,CAEnC,QACF,CAGA,OAAQ3G,EAAM,IAAA,EACZ,KAAA,SAAA,CACM0G,CAAAA,CAAS,SAAA,EACX,MAAMA,CAAAA,CAAS,SAAA,CAAU1G,CAAK,CAAA,CAEhC,MAEF,KAAA,cAAA,CACM0G,CAAAA,CAAS,aAAA,EACX,MAAMA,CAAAA,CAAS,aAAA,CAAc1G,CAAK,CAAA,CAEpC,MAEF,KAAA,UAAA,CACM0G,CAAAA,CAAS,iBAAA,EACX,MAAMA,CAAAA,CAAS,iBAAA,CAAkB1G,CAAK,CAAA,CAExC,MAEF,KAAA,MAAA,CACM0G,CAAAA,CAAS,eACX,MAAMA,CAAAA,CAAS,aAAA,CAAc1G,CAAK,EAEpC,MAEF,KAAA,oBAAA,CACM0G,CAAAA,CAAS,mBAAA,EACX,MAAMA,CAAAA,CAAS,mBAAA,CAAoB1G,CAAK,EAE1C,MAEF,KAAA,UAAA,CACM0G,CAAAA,CAAS,mBAAA,EACX,MAAMA,CAAAA,CAAS,mBAAA,CAAoB1G,CAAK,EAE1C,MAEF,QAEE,IAAM4G,CAAAA,CAAyB5G,CAAAA,CAC3B0G,CAAAA,CAAS,SAAA,EACX,MAAMA,EAAS,SAAA,CAAUE,CAAe,CAAA,CAE1C,KACJ,CACF,CACF,CAmEO,SAASC,EAAAA,CACd9H,EACA+H,CAAAA,CACe,CACf,OACE/H,CAAAA,CAAO,UAAU,CAAA,GAAM,WAAA,EACvBA,CAAAA,CAAO,kBAAkB,CAAA,GAAM+H,CAAAA,CAExB/H,CAAAA,CAAO,eAAe,CAAA,CAExB,IACT,CAgCA,eAAsBgI,GACpBC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CAC6C,CAC7C,GAAI,CAACD,CAAAA,CACH,OAAO,CACL,OAAA,CAAS,KAAA,CACT,KAAA,CAAO,oCACT,CAAA,CAGF,GAAI,CAACA,CAAAA,CAAU,WAAW,SAAS,CAAA,CACjC,OAAO,CACL,OAAA,CAAS,KAAA,CACT,KAAA,CAAO,mDACT,EAGF,GAAI,CAACC,CAAAA,CACH,OAAO,CACL,OAAA,CAAS,KAAA,CACT,KAAA,CAAO,mDACT,CAAA,CAGF,GAAI,CAEF,GAAI,OAAO,MAAA,CAAW,GAAA,CACpB,OAAO,CACL,OAAA,CAAS,CAAA,CAAA,CACT,KAAA,CAAO,kEACT,EAIF,IAAMC,CAAAA,CAAS,MAAM,OAAO,QAAQ,CAAA,CAG9BC,CAAAA,CAAeH,CAAAA,CAAU,SAAA,CAAU,CAAC,CAAA,CAGpCI,CAAAA,CAAoBF,CAAAA,CACvB,WAAW,QAAA,CAAUD,CAAS,CAAA,CAC9B,MAAA,CAAOF,CAAO,CAAA,CACd,MAAA,CAAO,KAAK,EAGTM,CAAAA,CAAiB,MAAA,CAAO,IAAA,CAAKF,CAAAA,CAAc,KAAK,CAAA,CAChDG,CAAAA,CAAiB,MAAA,CAAO,KAAKF,CAAAA,CAAmB,KAAK,CAAA,CAE3D,GAAIC,EAAe,MAAA,GAAWC,CAAAA,CAAe,MAAA,CAC3C,OAAO,CACL,OAAA,CAAS,CAAA,CAAA,CACT,KAAA,CAAO,2BACT,CAAA,CAGF,IAAMC,CAAAA,CAAUL,CAAAA,CAAO,gBAAgBG,CAAAA,CAAgBC,CAAc,CAAA,CAErE,OAAO,CACL,OAAA,CAAAC,CAAAA,CACA,KAAA,CAAOA,EAAU,KAAA,CAAA,CAAY,+BAC/B,CAEF,CAAA,MAAS1M,CAAAA,CAAO,CACd,OAAO,CACL,QAAS,KAAA,CACT,KAAA,CAAO,CAAA,8BAAA,EAAiCA,CAAAA,YAAiB,MAAQA,CAAAA,CAAM,OAAA,CAAU,eAAe,CAAA,CAClG,CACF,CACF","file":"index.js","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 } 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): Promise<SendMessageResponse> {\n return this.httpClient.request<SendMessageResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MESSAGES,\n body: {\n recipient: { id: recipientId },\n messaging_type: 'RESPONSE',\n sender_action: action,\n },\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 // 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_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 /** \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\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 /** \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 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 | 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 | 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 ('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 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_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 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}"]}
1
+ {"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","apiOptions","AttachmentsAPI","body","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","messageId","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.js","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 } 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): Promise<SendMessageResponse> {\n return this.httpClient.request<SendMessageResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MESSAGES,\n body: {\n recipient: { id: recipientId },\n messaging_type: 'RESPONSE',\n sender_action: action,\n },\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 // 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 /** \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}"]}