import type { Message, ReactionType } from '../resources/messages.js'; /** * Common envelope for every webhook event. Per contract §4.1: every * delivery body is shaped `{ api_version, event_id, event_type, * created_at, trace_id?, data }`. `data` is a per-event-type payload — * the type guards below narrow it to a typed shape. */ export interface WebhookEventBase { api_version: string; event_id: string; event_type: string; created_at: string; trace_id?: string; data: Record; } export type MessageEventType = 'message.queued' | 'message.scheduled' | 'message.sent' | 'message.delivered' | 'message.failed' | 'message.received' | 'message.read' | 'message.cancelled' | 'message.fallback_triggered'; export interface MessageEvent extends WebhookEventBase { event_type: `message.${string}`; data: { message: Message; }; } export type ReactionEventType = 'reaction.added' | 'reaction.received' | 'reaction.removed'; /** Keys every `reaction.*` delivery carries, whatever its direction. */ type ReactionEventDataBase = { parent_message_id: string; reaction_id: string; reaction_type: ReactionType; reaction_emoji: string | null; removed_at?: string; }; /** * The `data` payload of a `reaction.*` delivery, per contract §4.3.2. It is * FLAT — the fields sit directly on `data`, not under a `reaction` key (a * nested `{ reaction }` shape was declared here until WHA-2193 and no * producer ever emitted it). * * Discriminated on `direction`, because the handle key differs by family and * that asymmetry is deliberate on the producer side: an inbound tapback names * the counterparty who reacted to us (`from_handle`), an outbound one names * the line that acted (`actor_handle`). Reading the wrong one is a compile * error — narrow on `direction` first. `reaction.removed` is the only event * that fires in both directions. * * Timestamps are optional because each delivery carries exactly one of them * (`received_at` inbound-add, `added_at` outbound-add, `removed_at` either * direction). Keeping them optional also lets a future `reaction.*` member * with a new timestamp key narrow without an SDK release. * * `reaction_type` is the widened set that includes `custom` (WHA-2102): a * counterparty may send an arbitrary emoji, and `reaction_emoji` then carries * it verbatim — or `null` when the bridge supplied none. For the 6 classic * tapbacks the emoji is always server-derived (WHA-2100). */ export type ReactionEventData = (ReactionEventDataBase & { direction: 'inbound'; from_handle: string; received_at?: string; }) | (ReactionEventDataBase & { direction: 'outbound'; actor_handle: string; added_at?: string; }); export interface ReactionEvent extends WebhookEventBase { event_type: `reaction.${string}`; data: ReactionEventData; } export type LineEventType = 'line.connected' | 'line.disconnected' | 'line.offline' | 'line.degraded' | 'line.apple_id_flagged' | 'line.quota_warning' | 'line.quota_exceeded' | 'line.capability_changed'; /** * `data` is intentionally typed as `Record` until the * contract pins per-event-type field shapes. Today's payloads vary by * event (e.g. `line.apple_id_flagged` carries `flag_reason`, * `line.quota_warning` carries `bucket` + `usage`), and surfacing a * union with optional fields would let TypeScript autocomplete suggest * keys that aren't present at runtime. Tighten when the contract is * amended to specify the per-event shapes. */ export interface LineEvent extends WebhookEventBase { event_type: `line.${string}`; data: Record; } export type TypingIndicatorEventType = 'typing_indicator.started' | 'typing_indicator.stopped'; /** * `data` is intentionally `Record` — the partner-facing * shape is not yet documented in the contract. See `LineEvent` for the * same rationale. */ export interface TypingIndicatorEvent extends WebhookEventBase { event_type: `typing_indicator.${string}`; data: Record; } export type TrialEventType = 'trial.linked' | 'trial.dormant' | 'trial.reactivated' | 'trial.bind_conflict' | 'trial.revoked'; /** See `LineEvent` for why `data` is loose. */ export interface TrialEvent extends WebhookEventBase { event_type: `trial.${string}`; data: Record; } export type PreOrderEventType = 'pre_order.fulfilled' | 'pre_order.cancelled' | 'pre_order.refunded'; /** * Pre-order lifecycle events fired when ops procures hardware against a * customer pre-order. `pre_order.fulfilled` carries the freshly-activated * `line_id` so partner dashboards can wire it without a follow-up GET. * `data` is left loose for the same reason as `LineEvent` until the * per-event-type shapes are pinned in the contract. */ export interface PreOrderEvent extends WebhookEventBase { event_type: `pre_order.${string}`; data: Record; } export type BindingEventType = 'binding.released'; /** * Shared-plan contact-binding lifecycle (contract §4.3.7). Fires on the * VIRTUAL line when a `(virtual line, contact handle)` leg is torn down. * `data` carries `{ line_id, contact_handle, outbound_number (nullable), * released_at, reason: 'inactivity' | 'carrier_terminated' }` — the * `outbound_number` being the physical line's number the contact knew, * since that association is exactly what the release severs. * * Left as `Record` for the same reason as `LineEvent`: * `event_type` is the template literal `binding.${string}` so the guard * keeps prefix-matching, and a concrete `data` shape here would mistype * any future `binding.*` event. There is deliberately no * `binding.created` — the first outbound to a new contact already * signals it via `message.queued`. */ export interface BindingEvent extends WebhookEventBase { event_type: `binding.${string}`; data: Record; } /** * Administrative synthetic probe — the suspended-state health check that * decides whether a disabled subscription can be resumed. Not a partner * business event, but consumers do receive it, so it gets an alias and a * guard like every other family. * * Named `Admin*` after the backend's `ADMIN_EVENTS` catalog constant * while the wire prefix is `webhook.` (and `isAdminEvent` matches that * prefix). The names deliberately differ: `WebhookEvent*` is already * taken by the union and the envelope base, so an accurate * `WebhookEventType` here would collide with both. */ export type AdminEventType = 'webhook.test'; /** See `LineEvent` for why `data` is loose. */ export interface AdminEvent extends WebhookEventBase { event_type: `webhook.${string}`; data: Record; } /** * Discriminated union over the typed event families plus `WebhookEventBase` * as the catch-all for event types not yet known to this SDK version. * Use a type guard (`isMessageEvent`, `isReactionEvent`, ...) to narrow * inside an event handler: * * ```ts * function handle(event: WebhookEvent) { * if (isMessageEvent(event)) { * console.log(event.data.message.id) // typed as Message * } * } * ``` */ export type WebhookEvent = MessageEvent | ReactionEvent | LineEvent | TypingIndicatorEvent | TrialEvent | PreOrderEvent | BindingEvent | AdminEvent | WebhookEventBase; export declare function isMessageEvent(event: WebhookEventBase): event is MessageEvent; export declare function isReactionEvent(event: WebhookEventBase): event is ReactionEvent; export declare function isLineEvent(event: WebhookEventBase): event is LineEvent; export declare function isTypingIndicatorEvent(event: WebhookEventBase): event is TypingIndicatorEvent; export declare function isTrialEvent(event: WebhookEventBase): event is TrialEvent; export declare function isPreOrderEvent(event: WebhookEventBase): event is PreOrderEvent; export declare function isBindingEvent(event: WebhookEventBase): event is BindingEvent; export declare function isAdminEvent(event: WebhookEventBase): event is AdminEvent; export {}; //# sourceMappingURL=types.d.ts.map