diff --git a/src/interactive/payload.ts b/src/interactive/payload.ts index 316ae88257a..71c7ae0828f 100644 --- a/src/interactive/payload.ts +++ b/src/interactive/payload.ts @@ -46,17 +46,9 @@ export type MessagePresentationTone = "info" | "success" | "warning" | "danger" export type MessagePresentationButtonStyle = InteractiveButtonStyle; -export type MessagePresentationButton = { - label: string; - value?: string; - url?: string; - style?: MessagePresentationButtonStyle; -}; +export type MessagePresentationButton = InteractiveReplyButton; -export type MessagePresentationOption = { - label: string; - value: string; -}; +export type MessagePresentationOption = InteractiveReplyOption; export type MessagePresentationTextBlock = { type: "text"; @@ -124,11 +116,18 @@ function normalizePresentationTone(value: unknown): MessagePresentationTone | un : undefined; } -function normalizeInteractiveButton(raw: unknown): InteractiveReplyButton | undefined { +function toRecord(raw: unknown): Record | undefined { if (!raw || typeof raw !== "object" || Array.isArray(raw)) { return undefined; } - const record = raw as Record; + return raw as Record; +} + +function normalizeButton(raw: unknown): InteractiveReplyButton | undefined { + const record = toRecord(raw); + if (!record) { + return undefined; + } const label = normalizeOptionalString(record.label) ?? normalizeOptionalString(record.text); const value = normalizeOptionalString(record.value) ?? @@ -146,11 +145,11 @@ function normalizeInteractiveButton(raw: unknown): InteractiveReplyButton | unde }; } -function normalizeInteractiveOption(raw: unknown): InteractiveReplyOption | undefined { - if (!raw || typeof raw !== "object" || Array.isArray(raw)) { +function normalizeOption(raw: unknown): InteractiveReplyOption | undefined { + const record = toRecord(raw); + if (!record) { return undefined; } - const record = raw as Record; const label = normalizeOptionalString(record.label) ?? normalizeOptionalString(record.text); const value = normalizeOptionalString(record.value); if (!label || !value) { @@ -159,30 +158,28 @@ function normalizeInteractiveOption(raw: unknown): InteractiveReplyOption | unde return { label, value }; } +function normalizeList(value: unknown, normalizeEntry: (entry: unknown) => T | undefined): T[] { + return Array.isArray(value) + ? value.map((entry) => normalizeEntry(entry)).filter((entry): entry is T => Boolean(entry)) + : []; +} + function normalizeInteractiveBlock(raw: unknown): InteractiveReplyBlock | undefined { - if (!raw || typeof raw !== "object" || Array.isArray(raw)) { + const record = toRecord(raw); + if (!record) { return undefined; } - const record = raw as Record; const type = normalizeOptionalLowercaseString(record.type); if (type === "text") { const text = normalizeOptionalString(record.text); return text ? { type: "text", text } : undefined; } if (type === "buttons") { - const buttons = Array.isArray(record.buttons) - ? record.buttons - .map((entry) => normalizeInteractiveButton(entry)) - .filter((entry): entry is InteractiveReplyButton => Boolean(entry)) - : []; + const buttons = normalizeList(record.buttons, normalizeButton); return buttons.length > 0 ? { type: "buttons", buttons } : undefined; } if (type === "select") { - const options = Array.isArray(record.options) - ? record.options - .map((entry) => normalizeInteractiveOption(entry)) - .filter((entry): entry is InteractiveReplyOption => Boolean(entry)) - : []; + const options = normalizeList(record.options, normalizeOption); return options.length > 0 ? { type: "select", @@ -195,50 +192,19 @@ function normalizeInteractiveBlock(raw: unknown): InteractiveReplyBlock | undefi } export function normalizeInteractiveReply(raw: unknown): InteractiveReply | undefined { - if (!raw || typeof raw !== "object" || Array.isArray(raw)) { + const record = toRecord(raw); + if (!record) { return undefined; } - const record = raw as Record; - const blocks = Array.isArray(record.blocks) - ? record.blocks - .map((entry) => normalizeInteractiveBlock(entry)) - .filter((entry): entry is InteractiveReplyBlock => Boolean(entry)) - : []; + const blocks = normalizeList(record.blocks, normalizeInteractiveBlock); return blocks.length > 0 ? { blocks } : undefined; } -function normalizePresentationButton(raw: unknown): MessagePresentationButton | undefined { - if (!raw || typeof raw !== "object" || Array.isArray(raw)) { - return undefined; - } - const record = raw as Record; - const label = normalizeOptionalString(record.label) ?? normalizeOptionalString(record.text); - const value = - normalizeOptionalString(record.value) ?? - normalizeOptionalString(record.callbackData) ?? - normalizeOptionalString(record.callback_data); - const url = normalizeOptionalString(record.url); - if (!label || (!value && !url)) { - return undefined; - } - return { - label, - ...(value ? { value } : {}), - ...(url ? { url } : {}), - style: normalizeButtonStyle(record.style), - }; -} - -function normalizePresentationOption(raw: unknown): MessagePresentationOption | undefined { - const option = normalizeInteractiveOption(raw); - return option ? { label: option.label, value: option.value } : undefined; -} - function normalizePresentationBlock(raw: unknown): MessagePresentationBlock | undefined { - if (!raw || typeof raw !== "object" || Array.isArray(raw)) { + const record = toRecord(raw); + if (!record) { return undefined; } - const record = raw as Record; const type = normalizeOptionalLowercaseString(record.type); if (type === "text" || type === "context") { const text = normalizeOptionalString(record.text); @@ -248,19 +214,11 @@ function normalizePresentationBlock(raw: unknown): MessagePresentationBlock | un return { type: "divider" }; } if (type === "buttons") { - const buttons = Array.isArray(record.buttons) - ? record.buttons - .map((entry) => normalizePresentationButton(entry)) - .filter((entry): entry is MessagePresentationButton => Boolean(entry)) - : []; + const buttons = normalizeList(record.buttons, normalizeButton); return buttons.length > 0 ? { type: "buttons", buttons } : undefined; } if (type === "select") { - const options = Array.isArray(record.options) - ? record.options - .map((entry) => normalizePresentationOption(entry)) - .filter((entry): entry is MessagePresentationOption => Boolean(entry)) - : []; + const options = normalizeList(record.options, normalizeOption); return options.length > 0 ? { type: "select", @@ -273,15 +231,11 @@ function normalizePresentationBlock(raw: unknown): MessagePresentationBlock | un } export function normalizeMessagePresentation(raw: unknown): MessagePresentation | undefined { - if (!raw || typeof raw !== "object" || Array.isArray(raw)) { + const record = toRecord(raw); + if (!record) { return undefined; } - const record = raw as Record; - const blocks = Array.isArray(record.blocks) - ? record.blocks - .map((entry) => normalizePresentationBlock(entry)) - .filter((entry): entry is MessagePresentationBlock => Boolean(entry)) - : []; + const blocks = normalizeList(record.blocks, normalizePresentationBlock); const title = normalizeOptionalString(record.title); if (!title && blocks.length === 0) { return undefined;