@fragno-dev/telegram-fragment 0.0.1 → 0.0.3

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.
Files changed (48) hide show
  1. package/dist/browser/client/react.d.ts +129 -3
  2. package/dist/browser/client/react.d.ts.map +1 -1
  3. package/dist/browser/client/react.js +32 -22
  4. package/dist/browser/client/react.js.map +1 -1
  5. package/dist/browser/client/solid.d.ts +129 -3
  6. package/dist/browser/client/solid.d.ts.map +1 -1
  7. package/dist/browser/client/solid.js +2 -2
  8. package/dist/browser/client/solid.js.map +1 -1
  9. package/dist/browser/client/svelte.d.ts +129 -3
  10. package/dist/browser/client/svelte.d.ts.map +1 -1
  11. package/dist/browser/client/svelte.js +1 -1
  12. package/dist/browser/client/vanilla.d.ts +129 -3
  13. package/dist/browser/client/vanilla.d.ts.map +1 -1
  14. package/dist/browser/client/vanilla.js +1 -1
  15. package/dist/browser/client/vue.d.ts +129 -3
  16. package/dist/browser/client/vue.d.ts.map +1 -1
  17. package/dist/browser/client/vue.js +1 -1
  18. package/dist/browser/{client-Bk-J98pf.d.ts → client-BumUy6cu.d.ts} +87 -83
  19. package/dist/browser/client-BumUy6cu.d.ts.map +1 -0
  20. package/dist/browser/index.d.ts +697 -48
  21. package/dist/browser/index.d.ts.map +1 -1
  22. package/dist/browser/index.js +2 -2
  23. package/dist/browser/index.js.map +1 -1
  24. package/dist/browser/{schema-QDMf15Vn.js → schema-IrJsGm4M.js} +264 -41
  25. package/dist/browser/schema-IrJsGm4M.js.map +1 -0
  26. package/dist/node/definition.d.ts.map +1 -1
  27. package/dist/node/index.d.ts +260 -13
  28. package/dist/node/index.d.ts.map +1 -1
  29. package/dist/node/index.js +2 -2
  30. package/dist/node/index.js.map +1 -1
  31. package/dist/node/routes.d.ts +130 -9
  32. package/dist/node/routes.d.ts.map +1 -1
  33. package/dist/node/routes.js +25 -15
  34. package/dist/node/routes.js.map +1 -1
  35. package/dist/node/services.js +56 -53
  36. package/dist/node/services.js.map +1 -1
  37. package/dist/node/telegram-api.js +80 -16
  38. package/dist/node/telegram-api.js.map +1 -1
  39. package/dist/node/telegram-utils.js +284 -9
  40. package/dist/node/telegram-utils.js.map +1 -1
  41. package/dist/node/types.d.ts +308 -27
  42. package/dist/node/types.d.ts.map +1 -1
  43. package/dist/node/types.js +232 -27
  44. package/dist/node/types.js.map +1 -1
  45. package/dist/tsconfig.tsbuildinfo +1 -1
  46. package/package.json +13 -8
  47. package/dist/browser/client-Bk-J98pf.d.ts.map +0 -1
  48. package/dist/browser/schema-QDMf15Vn.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"services.js","names":[],"sources":["../../src/services.ts"],"sourcesContent":["import { FragnoId, FragnoReference } from \"@fragno-dev/db/schema\";\nimport type { TypedUnitOfWork } from \"@fragno-dev/db/unit-of-work\";\n\nimport { type Cursor, type DatabaseServiceContext } from \"@fragno-dev/db\";\n\nimport { telegramSchema } from \"./schema\";\nimport {\n DEFAULT_COMMAND_SCOPES,\n buildChatMemberId,\n buildMessageId,\n parseCommand,\n parseCommandBindings,\n parseTelegramUpdate,\n} from \"./telegram-utils\";\nimport {\n telegramMessageSchema,\n type TelegramMessage,\n type TelegramChatMemberHookPayload,\n type TelegramChatMemberSummary,\n type TelegramChatSummary,\n type TelegramCommandScope,\n type TelegramFragmentConfig,\n type TelegramHooksMap,\n type TelegramMessageHookPayload,\n type TelegramMessageSummary,\n type TelegramUpdate,\n type TelegramUpdateType,\n type TelegramUserSummary,\n} from \"./types\";\n\nconst missingId = \"__missing__\";\n\ntype RecordId = string | FragnoId;\ntype RecordRef = string | FragnoId | FragnoReference;\n\ntype TelegramUserRecord = {\n id: RecordId;\n username: string | null;\n firstName: string;\n lastName: string | null;\n isBot: boolean;\n languageCode: string | null;\n createdAt: Date;\n updatedAt: Date;\n};\n\ntype TelegramChatRecord = {\n id: RecordId;\n type: string;\n title: string | null;\n username: string | null;\n isForum: boolean;\n commandBindings: unknown | null;\n createdAt: Date;\n updatedAt: Date;\n};\n\ntype TelegramChatMemberRecord = {\n id: RecordId;\n chatId: RecordRef;\n userId: RecordRef;\n status: string;\n joinedAt: Date | null;\n leftAt: Date | null;\n createdAt: Date;\n updatedAt: Date;\n chatMemberUser?: TelegramUserRecord | null;\n};\n\ntype TelegramMessageRecord = {\n id: RecordId;\n chatId: RecordRef;\n fromUserId: RecordRef | null;\n senderChatId: RecordRef | null;\n replyToMessageId: RecordRef | null;\n messageType: string;\n text: string | null;\n payload: unknown | null;\n sentAt: Date;\n editedAt: Date | null;\n commandName: string | null;\n messageAuthor?: TelegramUserRecord | null;\n};\n\nconst parseCompositeId = (value: RecordId) => {\n const raw = String(value.valueOf());\n const [first, second] = raw.split(\":\");\n\n return {\n first: first ?? raw,\n second: second ?? null,\n };\n};\n\nconst parseChatMemberCompositeId = (value: RecordId) => {\n const { first, second } = parseCompositeId(value);\n\n return {\n chatId: first,\n userId: second ?? \"\",\n };\n};\n\nconst parseMessageCompositeId = (value: RecordId) => {\n const { first, second } = parseCompositeId(value);\n\n return {\n chatId: first,\n messageId: second ?? \"\",\n };\n};\n\nconst parseTelegramMessagePayload = (payload: unknown) => {\n const result = telegramMessageSchema.safeParse(payload);\n return result.success ? result.data : null;\n};\n\nconst toUserSummary = (user: TelegramUserRecord): TelegramUserSummary => ({\n id: String(user.id.valueOf()),\n username: user.username,\n firstName: user.firstName,\n lastName: user.lastName,\n isBot: user.isBot,\n languageCode: user.languageCode,\n createdAt: user.createdAt,\n updatedAt: user.updatedAt,\n});\n\nconst toChatSummary = (chat: TelegramChatRecord): TelegramChatSummary => ({\n id: String(chat.id.valueOf()),\n type: chat.type as TelegramChatSummary[\"type\"],\n title: chat.title,\n username: chat.username,\n isForum: chat.isForum,\n commandBindings: chat.commandBindings ? parseCommandBindings(chat.commandBindings) : null,\n createdAt: chat.createdAt,\n updatedAt: chat.updatedAt,\n});\n\nconst toChatMemberSummary = (member: TelegramChatMemberRecord): TelegramChatMemberSummary => {\n const composite = parseChatMemberCompositeId(member.id);\n const userId = member.chatMemberUser\n ? String(member.chatMemberUser.id.valueOf())\n : composite.userId;\n\n return {\n id: String(member.id.valueOf()),\n chatId: composite.chatId,\n userId,\n status: member.status,\n joinedAt: member.joinedAt,\n leftAt: member.leftAt,\n user: member.chatMemberUser ? toUserSummary(member.chatMemberUser) : null,\n createdAt: member.createdAt,\n updatedAt: member.updatedAt,\n };\n};\n\nconst toMessageSummary = (message: TelegramMessageRecord): TelegramMessageSummary => {\n const composite = parseMessageCompositeId(message.id);\n const payload = parseTelegramMessagePayload(message.payload);\n const chatId = payload?.chat ? String(payload.chat.id) : composite.chatId;\n const fromUserId = payload?.from\n ? String(payload.from.id)\n : message.messageAuthor\n ? String(message.messageAuthor.id.valueOf())\n : null;\n const senderChatId = payload?.sender_chat ? String(payload.sender_chat.id) : null;\n const replyToMessageId = payload?.reply_to_message\n ? buildMessageId(chatId, payload.reply_to_message.message_id)\n : null;\n\n return {\n id: String(message.id.valueOf()),\n chatId,\n fromUserId,\n senderChatId,\n replyToMessageId,\n messageType: message.messageType as TelegramMessageSummary[\"messageType\"],\n text: message.text,\n payload: message.payload,\n sentAt: message.sentAt,\n editedAt: message.editedAt,\n commandName: message.commandName,\n fromUser: message.messageAuthor ? toUserSummary(message.messageAuthor) : null,\n };\n};\n\nexport type ProcessIncomingUpdateResult =\n | { kind: \"ignored\"; updateId: number }\n | {\n kind: \"message\";\n updateId: number;\n updateType: TelegramMessageSummary[\"messageType\"];\n chat: TelegramChatSummary;\n message: TelegramMessageSummary;\n fromUser: TelegramUserSummary | null;\n command: {\n name: string;\n args: string;\n raw: string;\n scopes: TelegramCommandScope[];\n } | null;\n };\n\ntype ProcessIncomingUpdateRetrieveResult = [\n TelegramChatRecord[],\n TelegramUserRecord[],\n TelegramChatMemberRecord[],\n TelegramMessageRecord | null,\n];\n\ntype TelegramBaseUow = TypedUnitOfWork<typeof telegramSchema, [], unknown, TelegramHooksMap>;\ntype TelegramProcessUow = TypedUnitOfWork<\n typeof telegramSchema,\n ProcessIncomingUpdateRetrieveResult,\n unknown,\n TelegramHooksMap\n>;\n\ntype UpsertOutgoingMessageRetrieveResult = [\n TelegramChatRecord[],\n TelegramUserRecord[],\n TelegramMessageRecord | null,\n];\n\ntype TelegramOutgoingUow = TypedUnitOfWork<\n typeof telegramSchema,\n UpsertOutgoingMessageRetrieveResult,\n unknown,\n TelegramHooksMap\n>;\n\nexport type ProcessIncomingUpdateOps =\n | { kind: \"ignored\"; updateId: number }\n | {\n kind: \"message\";\n updateId: number;\n retrieve: (uow: TelegramBaseUow) => TelegramProcessUow;\n mutate: (input: {\n uow: TelegramBaseUow;\n retrieveResult: ProcessIncomingUpdateRetrieveResult;\n }) => ProcessIncomingUpdateResult;\n };\n\nexport const createProcessIncomingUpdateOps = (config: TelegramFragmentConfig) => {\n const commands = config.commands ?? {};\n const botUsername = config.botUsername;\n\n const resolveCommandScopes = (\n commandName: string,\n chatType: TelegramChatSummary[\"type\"],\n bindings: ReturnType<typeof parseCommandBindings>,\n ) => {\n const definition = commands[commandName];\n if (!definition) {\n return null;\n }\n\n const binding = bindings[commandName];\n const enabled = binding ? binding.enabled !== false : true;\n const scopes = binding?.scopes ?? definition.scopes ?? DEFAULT_COMMAND_SCOPES;\n\n if (!enabled || !scopes.includes(chatType)) {\n return null;\n }\n\n return {\n scopes,\n };\n };\n\n return (update: TelegramUpdate): ProcessIncomingUpdateOps => {\n const parsed = parseTelegramUpdate(update);\n if (!parsed) {\n return {\n kind: \"ignored\",\n updateId: update.update_id,\n };\n }\n\n const { message, type, updateId } = parsed;\n const chatId = String(message.chat.id);\n const messageId = buildMessageId(chatId, message.message_id);\n const sentAt = new Date(message.date * 1000);\n const editedAt = message.edit_date ? new Date(message.edit_date * 1000) : null;\n const fromUser = message.from ?? null;\n const fromUserId = fromUser ? String(fromUser.id) : null;\n const senderChat = message.sender_chat ?? null;\n const senderChatId = senderChat ? String(senderChat.id) : null;\n const replyToMessageId = message.reply_to_message\n ? buildMessageId(chatId, message.reply_to_message.message_id)\n : null;\n\n const commandMatch = parseCommand(message, botUsername);\n const commandName = commandMatch?.name ?? null;\n\n const membershipMap = new Map<\n string,\n { status: string; joinedAt: Date | null; leftAt: Date | null; notify: boolean }\n >();\n\n const newMembers = message.new_chat_members ?? [];\n for (const member of newMembers) {\n membershipMap.set(String(member.id), {\n status: \"member\",\n joinedAt: sentAt,\n leftAt: null,\n notify: true,\n });\n }\n\n if (message.left_chat_member) {\n membershipMap.set(String(message.left_chat_member.id), {\n status: \"left\",\n joinedAt: null,\n leftAt: sentAt,\n notify: true,\n });\n }\n\n if (fromUserId && message.chat.type !== \"channel\" && !membershipMap.has(fromUserId)) {\n membershipMap.set(fromUserId, {\n status: \"member\",\n joinedAt: sentAt,\n leftAt: null,\n notify: false,\n });\n }\n\n const chatIds = Array.from(\n new Set([chatId, senderChatId ? String(senderChatId) : null].filter(Boolean) as string[]),\n );\n\n const userIds = Array.from(\n new Set(\n [\n fromUserId,\n ...newMembers.map((member) => String(member.id)),\n message.left_chat_member ? String(message.left_chat_member.id) : null,\n ].filter(Boolean) as string[],\n ),\n );\n\n const memberIds = Array.from(\n new Set(Array.from(membershipMap.keys()).map((userId) => buildChatMemberId(chatId, userId))),\n );\n\n const chatsForUpsert: Array<typeof message.chat> = [];\n const seenChatIds = new Set<string>();\n for (const chat of [message.chat, senderChat]) {\n if (!chat) {\n continue;\n }\n const id = String(chat.id);\n if (seenChatIds.has(id)) {\n continue;\n }\n seenChatIds.add(id);\n chatsForUpsert.push(chat);\n }\n\n const usersForUpsert: Array<NonNullable<typeof fromUser>> = [];\n const seenUserIds = new Set<string>();\n for (const user of [fromUser, ...newMembers, message.left_chat_member]) {\n if (!user) {\n continue;\n }\n const id = String(user.id);\n if (seenUserIds.has(id)) {\n continue;\n }\n seenUserIds.add(id);\n usersForUpsert.push(user as NonNullable<typeof fromUser>);\n }\n\n return {\n kind: \"message\",\n updateId,\n retrieve: (uow) =>\n uow\n .find(\"chat\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"in\", chatIds.length ? chatIds : [missingId])),\n )\n .find(\"user\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"in\", userIds.length ? userIds : [missingId])),\n )\n .find(\"chatMember\", (b) =>\n b.whereIndex(\"primary\", (eb) =>\n eb(\"id\", \"in\", memberIds.length ? memberIds : [missingId]),\n ),\n )\n .findFirst(\"message\", (b) => b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", messageId))),\n mutate: ({\n uow,\n retrieveResult: [existingChats, existingUsers, existingMembers, existingMessage],\n }) => {\n const now = new Date();\n\n const chatById = new Map(existingChats.map((chat) => [chat.id.valueOf(), chat] as const));\n const userById = new Map(existingUsers.map((user) => [user.id.valueOf(), user] as const));\n const memberById = new Map(\n existingMembers.map((member) => [member.id.valueOf(), member] as const),\n );\n\n const chatSummaries = new Map<string, TelegramChatSummary>();\n for (const chat of chatsForUpsert) {\n const id = String(chat.id);\n const existing = chatById.get(id);\n if (!existing) {\n uow.create(\"chat\", {\n id,\n type: chat.type,\n title: chat.title ?? null,\n username: chat.username ?? null,\n isForum: chat.is_forum ?? false,\n commandBindings: null,\n createdAt: now,\n updatedAt: now,\n });\n\n chatSummaries.set(id, {\n id,\n type: chat.type,\n title: chat.title ?? null,\n username: chat.username ?? null,\n isForum: chat.is_forum ?? false,\n commandBindings: null,\n createdAt: now,\n updatedAt: now,\n });\n } else {\n uow.update(\"chat\", existing.id, (b) =>\n b\n .set({\n type: chat.type,\n title: chat.title ?? null,\n username: chat.username ?? null,\n isForum: chat.is_forum ?? false,\n updatedAt: now,\n })\n .check(),\n );\n\n chatSummaries.set(id, {\n ...toChatSummary(existing),\n type: chat.type,\n title: chat.title ?? null,\n username: chat.username ?? null,\n isForum: chat.is_forum ?? false,\n updatedAt: now,\n });\n }\n }\n\n const userSummaries = new Map<string, TelegramUserSummary>();\n for (const user of usersForUpsert) {\n const id = String(user.id);\n const existing = userById.get(id);\n if (!existing) {\n uow.create(\"user\", {\n id,\n username: user.username ?? null,\n firstName: user.first_name,\n lastName: user.last_name ?? null,\n isBot: user.is_bot ?? false,\n languageCode: user.language_code ?? null,\n createdAt: now,\n updatedAt: now,\n });\n\n userSummaries.set(id, {\n id,\n username: user.username ?? null,\n firstName: user.first_name,\n lastName: user.last_name ?? null,\n isBot: user.is_bot ?? false,\n languageCode: user.language_code ?? null,\n createdAt: now,\n updatedAt: now,\n });\n } else {\n uow.update(\"user\", existing.id, (b) =>\n b\n .set({\n username: user.username ?? null,\n firstName: user.first_name,\n lastName: user.last_name ?? null,\n isBot: user.is_bot ?? false,\n languageCode: user.language_code ?? null,\n updatedAt: now,\n })\n .check(),\n );\n\n userSummaries.set(id, {\n ...toUserSummary(existing),\n username: user.username ?? null,\n firstName: user.first_name,\n lastName: user.last_name ?? null,\n isBot: user.is_bot ?? false,\n languageCode: user.language_code ?? null,\n updatedAt: now,\n });\n }\n }\n\n const memberPayloads: TelegramChatMemberHookPayload[] = [];\n for (const [userId, membership] of membershipMap.entries()) {\n const memberId = buildChatMemberId(chatId, userId);\n const existing = memberById.get(memberId);\n\n if (!existing) {\n uow.create(\"chatMember\", {\n id: memberId,\n chatId,\n userId,\n status: membership.status,\n joinedAt: membership.joinedAt,\n leftAt: membership.leftAt,\n createdAt: now,\n updatedAt: now,\n });\n\n if (membership.notify) {\n memberPayloads.push({\n updateId,\n chatId,\n userId,\n status: membership.status,\n joinedAt: membership.joinedAt,\n leftAt: membership.leftAt,\n });\n }\n continue;\n }\n\n const hasExplicitJoin =\n membership.status === \"member\" && membership.joinedAt !== null && membership.notify;\n const nextJoinedAt = hasExplicitJoin ? membership.joinedAt : existing.joinedAt;\n const nextLeftAt =\n membership.status === \"left\"\n ? (membership.leftAt ?? existing.leftAt ?? now)\n : membership.status === \"member\"\n ? null\n : existing.leftAt;\n\n const changed =\n existing.status !== membership.status ||\n existing.joinedAt?.getTime() !== nextJoinedAt?.getTime() ||\n existing.leftAt?.getTime() !== nextLeftAt?.getTime();\n\n if (changed) {\n uow.update(\"chatMember\", existing.id, (b) =>\n b\n .set({\n status: membership.status,\n joinedAt: nextJoinedAt,\n leftAt: nextLeftAt,\n updatedAt: now,\n })\n .check(),\n );\n\n if (membership.notify) {\n memberPayloads.push({\n updateId,\n chatId,\n userId,\n status: membership.status,\n joinedAt: nextJoinedAt,\n leftAt: nextLeftAt,\n });\n }\n }\n }\n\n let shouldTriggerMessage = false;\n let messageSummary: TelegramMessageSummary;\n if (!existingMessage) {\n uow.create(\"message\", {\n id: messageId,\n chatId,\n fromUserId,\n senderChatId,\n replyToMessageId,\n messageType: type,\n text: message.text ?? null,\n payload: message,\n sentAt,\n editedAt,\n commandName,\n });\n\n shouldTriggerMessage = true;\n messageSummary = {\n id: messageId,\n chatId,\n fromUserId,\n senderChatId,\n replyToMessageId,\n messageType: type,\n text: message.text ?? null,\n payload: message,\n sentAt,\n editedAt,\n commandName,\n fromUser: fromUserId ? (userSummaries.get(fromUserId) ?? null) : null,\n };\n } else {\n const isEdit = type === \"edited_message\";\n const duplicateEdit =\n isEdit &&\n existingMessage.editedAt?.getTime() === editedAt?.getTime() &&\n existingMessage.text === (message.text ?? null);\n\n if (isEdit && !duplicateEdit) {\n uow.update(\"message\", existingMessage.id, (b) =>\n b\n .set({\n messageType: type,\n text: message.text ?? null,\n payload: message,\n editedAt,\n commandName,\n })\n .check(),\n );\n shouldTriggerMessage = true;\n }\n\n messageSummary = {\n id: String(existingMessage.id.valueOf()),\n chatId: String(existingMessage.chatId.valueOf()),\n fromUserId: existingMessage.fromUserId\n ? String(existingMessage.fromUserId.valueOf())\n : null,\n senderChatId: existingMessage.senderChatId\n ? String(existingMessage.senderChatId.valueOf())\n : null,\n replyToMessageId: existingMessage.replyToMessageId\n ? String(existingMessage.replyToMessageId.valueOf())\n : null,\n messageType: type,\n text: message.text ?? existingMessage.text,\n payload: message,\n sentAt: existingMessage.sentAt,\n editedAt: editedAt ?? existingMessage.editedAt,\n commandName,\n fromUser: fromUserId ? (userSummaries.get(fromUserId) ?? null) : null,\n };\n }\n\n const chatSummary =\n chatSummaries.get(chatId) ??\n (chatById.get(chatId)\n ? toChatSummary(chatById.get(chatId)!)\n : {\n id: chatId,\n type: message.chat.type,\n title: message.chat.title ?? null,\n username: message.chat.username ?? null,\n isForum: message.chat.is_forum ?? false,\n commandBindings: null,\n createdAt: now,\n updatedAt: now,\n });\n\n const commandBindings = chatSummary.commandBindings ?? {};\n\n let commandResult: {\n name: string;\n args: string;\n raw: string;\n scopes: TelegramCommandScope[];\n } | null = null;\n\n if (commandMatch && type !== \"edited_message\") {\n const resolved = resolveCommandScopes(\n commandMatch.name,\n chatSummary.type,\n commandBindings,\n );\n if (resolved) {\n commandResult = {\n name: commandMatch.name,\n args: commandMatch.args,\n raw: commandMatch.raw,\n scopes: resolved.scopes,\n };\n\n if (shouldTriggerMessage) {\n uow.triggerHook(\"onCommandMatched\", {\n updateId,\n messageId: messageSummary.id,\n chatId,\n fromUserId,\n commandName: commandMatch.name,\n args: commandMatch.args,\n raw: commandMatch.raw,\n sentAt,\n });\n }\n }\n }\n\n if (shouldTriggerMessage) {\n const payload: TelegramMessageHookPayload = {\n updateId,\n updateType: type,\n messageId: messageSummary.id,\n chatId,\n fromUserId,\n text: message.text ?? null,\n commandName,\n sentAt: messageSummary.sentAt,\n editedAt: messageSummary.editedAt,\n };\n\n uow.triggerHook(\"onMessageReceived\", payload);\n }\n\n for (const payload of memberPayloads) {\n uow.triggerHook(\"onChatMemberUpdated\", payload);\n }\n\n return {\n kind: \"message\",\n updateId,\n updateType: type,\n chat: chatSummary,\n message: messageSummary,\n fromUser: fromUserId ? (userSummaries.get(fromUserId) ?? null) : null,\n command: commandResult,\n } satisfies ProcessIncomingUpdateResult;\n },\n };\n };\n};\n\nexport type UpsertOutgoingMessageOps = {\n retrieve: (uow: TelegramBaseUow) => TelegramOutgoingUow;\n mutate: (input: {\n uow: TelegramBaseUow;\n retrieveResult: UpsertOutgoingMessageRetrieveResult;\n }) => void;\n};\n\nexport const createUpsertOutgoingMessageOps = (input: {\n message: TelegramMessage;\n messageType: TelegramUpdateType;\n}): UpsertOutgoingMessageOps => {\n const { message, messageType } = input;\n const chatId = String(message.chat.id);\n const senderChatId = message.sender_chat ? String(message.sender_chat.id) : null;\n const fromUser = message.from ?? null;\n const fromUserId = fromUser ? String(fromUser.id) : null;\n const messageId = buildMessageId(chatId, message.message_id);\n const replyToMessageId = message.reply_to_message\n ? buildMessageId(chatId, message.reply_to_message.message_id)\n : null;\n const sentAt = new Date(message.date * 1000);\n const editedAt = message.edit_date ? new Date(message.edit_date * 1000) : null;\n\n const chatIds = Array.from(new Set([chatId, senderChatId].filter(Boolean) as string[]));\n\n return {\n retrieve: (uow) =>\n uow\n .find(\"chat\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"in\", chatIds.length ? chatIds : [missingId])),\n )\n .find(\"user\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"in\", fromUserId ? [fromUserId] : [missingId])),\n )\n .findFirst(\"message\", (b) => b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", messageId))),\n mutate: ({ uow, retrieveResult: [existingChats, existingUsers, existingMessage] }) => {\n const now = new Date();\n const chatById = new Map(existingChats.map((chat) => [chat.id.valueOf(), chat] as const));\n const userById = new Map(existingUsers.map((user) => [user.id.valueOf(), user] as const));\n\n const chatsForUpsert = [message.chat, message.sender_chat].filter(Boolean) as Array<\n typeof message.chat\n >;\n for (const chat of chatsForUpsert) {\n const id = String(chat.id);\n const existing = chatById.get(id);\n if (!existing) {\n uow.create(\"chat\", {\n id,\n type: chat.type,\n title: chat.title ?? null,\n username: chat.username ?? null,\n isForum: chat.is_forum ?? false,\n commandBindings: null,\n createdAt: now,\n updatedAt: now,\n });\n } else {\n uow.update(\"chat\", existing.id, (b) =>\n b\n .set({\n type: chat.type,\n title: chat.title ?? null,\n username: chat.username ?? null,\n isForum: chat.is_forum ?? false,\n updatedAt: now,\n })\n .check(),\n );\n }\n }\n\n if (fromUser) {\n const id = String(fromUser.id);\n const existing = userById.get(id);\n if (!existing) {\n uow.create(\"user\", {\n id,\n username: fromUser.username ?? null,\n firstName: fromUser.first_name,\n lastName: fromUser.last_name ?? null,\n isBot: fromUser.is_bot ?? false,\n languageCode: fromUser.language_code ?? null,\n createdAt: now,\n updatedAt: now,\n });\n } else {\n uow.update(\"user\", existing.id, (b) =>\n b\n .set({\n username: fromUser.username ?? null,\n firstName: fromUser.first_name,\n lastName: fromUser.last_name ?? null,\n isBot: fromUser.is_bot ?? false,\n languageCode: fromUser.language_code ?? null,\n updatedAt: now,\n })\n .check(),\n );\n }\n }\n\n const messagePayload = {\n chatId,\n fromUserId,\n senderChatId,\n replyToMessageId,\n messageType,\n text: message.text ?? null,\n payload: message,\n sentAt,\n editedAt,\n commandName: null,\n };\n\n if (!existingMessage) {\n uow.create(\"message\", {\n id: messageId,\n ...messagePayload,\n });\n } else {\n uow.update(\"message\", existingMessage.id, (b) => b.set(messagePayload).check());\n }\n },\n };\n};\n\nexport const createTelegramServices = (config: TelegramFragmentConfig) => {\n const buildProcessIncomingUpdateOps = createProcessIncomingUpdateOps(config);\n type ServiceContext = DatabaseServiceContext<TelegramHooksMap>;\n\n return {\n processIncomingUpdate: function (this: ServiceContext, update: TelegramUpdate) {\n const ops = buildProcessIncomingUpdateOps(update);\n if (ops.kind === \"ignored\") {\n return this.serviceTx(telegramSchema)\n .mutate(() => ops satisfies ProcessIncomingUpdateResult)\n .build();\n }\n\n return this.serviceTx(telegramSchema)\n .retrieve(ops.retrieve)\n .mutate(({ uow, retrieveResult }) => ops.mutate({ uow, retrieveResult }))\n .build();\n },\n\n bindCommand: function (\n this: ServiceContext,\n input: {\n chatId: string;\n commandName: string;\n enabled: boolean;\n scopes?: TelegramCommandScope[];\n },\n ) {\n return this.serviceTx(telegramSchema)\n .retrieve((uow) =>\n uow.findFirst(\"chat\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", input.chatId)),\n ),\n )\n .mutate(({ uow, retrieveResult: [chat] }) => {\n if (!chat) {\n return { ok: false as const, reason: \"chat_not_found\" as const };\n }\n\n const bindings = parseCommandBindings(chat.commandBindings);\n const nextBindings = {\n ...bindings,\n [input.commandName]: {\n enabled: input.enabled,\n scopes: input.scopes,\n },\n };\n\n uow.update(\"chat\", chat.id, (b) =>\n b\n .set({\n commandBindings: nextBindings,\n updatedAt: new Date(),\n })\n .check(),\n );\n\n return {\n ok: true as const,\n binding: {\n chatId: input.chatId,\n commandName: input.commandName,\n enabled: input.enabled,\n scopes: input.scopes,\n },\n };\n })\n .build();\n },\n\n listChats: function (this: ServiceContext, type?: TelegramChatSummary[\"type\"]) {\n return this.serviceTx(telegramSchema)\n .retrieve((uow) => {\n if (type) {\n return uow.find(\"chat\", (b) =>\n b.whereIndex(\"idx_chat_type\", (eb) => eb(\"type\", \"=\", type)),\n );\n }\n return uow.find(\"chat\", (b) => b.whereIndex(\"primary\"));\n })\n .transformRetrieve(([chats]) => chats.map(toChatSummary))\n .build();\n },\n\n getChat: function (this: ServiceContext, chatId: string) {\n return this.serviceTx(telegramSchema)\n .retrieve((uow) =>\n uow.findFirst(\"chat\", (b) => b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", chatId))),\n )\n .transformRetrieve(([chat]) => (chat ? toChatSummary(chat) : null))\n .build();\n },\n\n getChatWithMembers: function (this: ServiceContext, chatId: string) {\n return this.serviceTx(telegramSchema)\n .retrieve((uow) =>\n uow\n .findFirst(\"chat\", (b) => b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", chatId)))\n .find(\"chatMember\", (b) =>\n b\n .whereIndex(\"idx_chat_member_chat\", (eb) => eb(\"chatId\", \"=\", chatId))\n .join((j) => j.chatMemberUser()),\n ),\n )\n .transformRetrieve(([chat, members]) => ({\n chat: chat ? toChatSummary(chat) : null,\n members: members.map(toChatMemberSummary),\n }))\n .build();\n },\n\n listMessages: function (\n this: ServiceContext,\n input: {\n chatId: string;\n pageSize: number;\n order: \"asc\" | \"desc\";\n cursor?: Cursor;\n },\n ) {\n return this.serviceTx(telegramSchema)\n .retrieve((uow) =>\n uow.findWithCursor(\"message\", (b) => {\n const query = b\n .whereIndex(\"idx_message_chat_sent\", (eb) => eb(\"chatId\", \"=\", input.chatId))\n .orderByIndex(\"idx_message_chat_sent\", input.order)\n .pageSize(input.pageSize)\n .join((j) => j.messageAuthor());\n\n return input.cursor ? query.after(input.cursor) : query;\n }),\n )\n .transformRetrieve(([messages]) => ({\n messages: messages.items.map(toMessageSummary),\n cursor: messages.cursor,\n hasNextPage: messages.hasNextPage,\n }))\n .build();\n },\n\n upsertOutgoingMessage: function (\n this: ServiceContext,\n input: {\n message: TelegramMessage;\n messageType: TelegramUpdateType;\n },\n ) {\n const ops = createUpsertOutgoingMessageOps(input);\n return this.serviceTx(telegramSchema)\n .retrieve(ops.retrieve)\n .mutate(({ uow, retrieveResult }) => ops.mutate({ uow, retrieveResult }))\n .build();\n },\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"services.js","names":[],"sources":["../../src/services.ts"],"sourcesContent":["import { FragnoId, FragnoReference } from \"@fragno-dev/db/schema\";\nimport type { TypedUnitOfWork } from \"@fragno-dev/db/unit-of-work\";\n\nimport { type Cursor, type DatabaseServiceContext } from \"@fragno-dev/db\";\n\nimport { telegramSchema } from \"./schema\";\nimport {\n DEFAULT_COMMAND_SCOPES,\n buildChatMemberId,\n buildMessageId,\n extractTelegramAttachments,\n parseCommand,\n parseCommandBindings,\n parseTelegramUpdate,\n safeNormalizeTelegramMessage,\n} from \"./telegram-utils\";\nimport {\n type TelegramMessage,\n type TelegramChatMemberHookPayload,\n type TelegramChatMemberSummary,\n type TelegramChatSummary,\n type TelegramCommandScope,\n type TelegramFragmentConfig,\n type TelegramHooksMap,\n type TelegramMessageHookPayload,\n type TelegramMessageSummary,\n type TelegramUpdate,\n type TelegramUpdateType,\n type TelegramUserSummary,\n} from \"./types\";\n\nconst missingId = \"__missing__\";\n\ntype RecordId = string | FragnoId;\ntype RecordRef = string | FragnoId | FragnoReference;\n\ntype TelegramUserRecord = {\n id: RecordId;\n username: string | null;\n firstName: string;\n lastName: string | null;\n isBot: boolean;\n languageCode: string | null;\n createdAt: Date;\n updatedAt: Date;\n};\n\ntype TelegramChatRecord = {\n id: RecordId;\n type: string;\n title: string | null;\n username: string | null;\n isForum: boolean;\n commandBindings: unknown | null;\n createdAt: Date;\n updatedAt: Date;\n};\n\ntype TelegramChatMemberRecord = {\n id: RecordId;\n chatId: RecordRef;\n userId: RecordRef;\n status: string;\n joinedAt: Date | null;\n leftAt: Date | null;\n createdAt: Date;\n updatedAt: Date;\n chatMemberUser?: TelegramUserRecord | null;\n};\n\ntype TelegramMessageRecord = {\n id: RecordId;\n chatId: RecordRef;\n fromUserId: RecordRef | null;\n senderChatId: RecordRef | null;\n replyToMessageId: RecordRef | null;\n messageType: string;\n text: string | null;\n payload: unknown | null;\n sentAt: Date;\n editedAt: Date | null;\n commandName: string | null;\n messageAuthor?: TelegramUserRecord | null;\n};\n\nconst parseCompositeId = (value: RecordId) => {\n const raw = String(value.valueOf());\n const [first, second] = raw.split(\":\");\n\n return {\n first: first ?? raw,\n second: second ?? null,\n };\n};\n\nconst parseChatMemberCompositeId = (value: RecordId) => {\n const { first, second } = parseCompositeId(value);\n\n return {\n chatId: first,\n userId: second ?? \"\",\n };\n};\n\nconst parseMessageCompositeId = (value: RecordId) => {\n const { first, second } = parseCompositeId(value);\n\n return {\n chatId: first,\n messageId: second ?? \"\",\n };\n};\n\nconst parseTelegramMessagePayload = (payload: unknown) => safeNormalizeTelegramMessage(payload);\n\nconst toUserSummary = (user: TelegramUserRecord): TelegramUserSummary => ({\n id: String(user.id.valueOf()),\n username: user.username,\n firstName: user.firstName,\n lastName: user.lastName,\n isBot: user.isBot,\n languageCode: user.languageCode,\n createdAt: user.createdAt,\n updatedAt: user.updatedAt,\n});\n\nconst toChatSummary = (chat: TelegramChatRecord): TelegramChatSummary => ({\n id: String(chat.id.valueOf()),\n type: chat.type as TelegramChatSummary[\"type\"],\n title: chat.title,\n username: chat.username,\n isForum: chat.isForum,\n commandBindings: chat.commandBindings ? parseCommandBindings(chat.commandBindings) : null,\n createdAt: chat.createdAt,\n updatedAt: chat.updatedAt,\n});\n\nconst toChatMemberSummary = (member: TelegramChatMemberRecord): TelegramChatMemberSummary => {\n const composite = parseChatMemberCompositeId(member.id);\n const userId = member.chatMemberUser\n ? String(member.chatMemberUser.id.valueOf())\n : composite.userId;\n\n return {\n id: String(member.id.valueOf()),\n chatId: composite.chatId,\n userId,\n status: member.status,\n joinedAt: member.joinedAt,\n leftAt: member.leftAt,\n user: member.chatMemberUser ? toUserSummary(member.chatMemberUser) : null,\n createdAt: member.createdAt,\n updatedAt: member.updatedAt,\n };\n};\n\nconst toMessageSummary = (message: TelegramMessageRecord): TelegramMessageSummary => {\n const composite = parseMessageCompositeId(message.id);\n const payload = parseTelegramMessagePayload(message.payload);\n const chatId = payload?.chat ? String(payload.chat.id) : composite.chatId;\n const fromUserId = payload?.from\n ? String(payload.from.id)\n : message.messageAuthor\n ? String(message.messageAuthor.id.valueOf())\n : null;\n const senderChatId = payload?.senderChat ? String(payload.senderChat.id) : null;\n const replyToMessageId = payload?.replyToMessage\n ? buildMessageId(chatId, payload.replyToMessage.messageId)\n : null;\n const attachments = payload ? extractTelegramAttachments(payload) : [];\n\n return {\n id: String(message.id.valueOf()),\n chatId,\n fromUserId,\n senderChatId,\n replyToMessageId,\n messageType: message.messageType as TelegramMessageSummary[\"messageType\"],\n text: message.text,\n attachments,\n payload: message.payload,\n sentAt: message.sentAt,\n editedAt: message.editedAt,\n commandName: message.commandName,\n fromUser: message.messageAuthor ? toUserSummary(message.messageAuthor) : null,\n };\n};\n\nexport type ProcessIncomingUpdateResult =\n | { kind: \"ignored\"; updateId: number }\n | {\n kind: \"message\";\n updateId: number;\n updateType: TelegramMessageSummary[\"messageType\"];\n chat: TelegramChatSummary;\n message: TelegramMessageSummary;\n fromUser: TelegramUserSummary | null;\n command: {\n name: string;\n args: string;\n raw: string;\n scopes: TelegramCommandScope[];\n } | null;\n };\n\ntype ProcessIncomingUpdateRetrieveResult = [\n TelegramChatRecord[],\n TelegramUserRecord[],\n TelegramChatMemberRecord[],\n TelegramMessageRecord | null,\n];\n\ntype TelegramBaseUow = TypedUnitOfWork<typeof telegramSchema, [], unknown, TelegramHooksMap>;\ntype TelegramProcessUow = TypedUnitOfWork<\n typeof telegramSchema,\n ProcessIncomingUpdateRetrieveResult,\n unknown,\n TelegramHooksMap\n>;\n\ntype UpsertOutgoingMessageRetrieveResult = [\n TelegramChatRecord[],\n TelegramUserRecord[],\n TelegramMessageRecord | null,\n];\n\ntype TelegramOutgoingUow = TypedUnitOfWork<\n typeof telegramSchema,\n UpsertOutgoingMessageRetrieveResult,\n unknown,\n TelegramHooksMap\n>;\n\nexport type ProcessIncomingUpdateOps =\n | { kind: \"ignored\"; updateId: number }\n | {\n kind: \"message\";\n updateId: number;\n retrieve: (uow: TelegramBaseUow) => TelegramProcessUow;\n mutate: (input: {\n uow: TelegramBaseUow;\n retrieveResult: ProcessIncomingUpdateRetrieveResult;\n }) => ProcessIncomingUpdateResult;\n };\n\nexport const createProcessIncomingUpdateOps = (config: TelegramFragmentConfig) => {\n const commands = config.commands ?? {};\n const botUsername = config.botUsername;\n\n const resolveCommandScopes = (\n commandName: string,\n chatType: TelegramChatSummary[\"type\"],\n bindings: ReturnType<typeof parseCommandBindings>,\n ) => {\n const definition = commands[commandName];\n if (!definition) {\n return null;\n }\n\n const binding = bindings[commandName];\n const enabled = binding ? binding.enabled !== false : true;\n const scopes = binding?.scopes ?? definition.scopes ?? DEFAULT_COMMAND_SCOPES;\n\n if (!enabled || !scopes.includes(chatType)) {\n return null;\n }\n\n return {\n scopes,\n };\n };\n\n return (update: TelegramUpdate): ProcessIncomingUpdateOps => {\n const parsed = parseTelegramUpdate(update);\n if (!parsed) {\n return {\n kind: \"ignored\",\n updateId: update.updateId,\n };\n }\n\n const { message, type, updateId } = parsed;\n const chatId = String(message.chat.id);\n const messageId = buildMessageId(chatId, message.messageId);\n const sentAt = new Date(message.date * 1000);\n const editedAt = message.editDate ? new Date(message.editDate * 1000) : null;\n const fromUser = message.from ?? null;\n const fromUserId = fromUser ? String(fromUser.id) : null;\n const senderChat = message.senderChat ?? null;\n const senderChatId = senderChat ? String(senderChat.id) : null;\n const replyToMessageId = message.replyToMessage\n ? buildMessageId(chatId, message.replyToMessage.messageId)\n : null;\n\n const commandMatch = parseCommand(message, botUsername);\n const commandName = commandMatch?.name ?? null;\n const attachments = extractTelegramAttachments(message);\n\n const membershipMap = new Map<\n string,\n { status: string; joinedAt: Date | null; leftAt: Date | null; notify: boolean }\n >();\n\n const newMembers = message.newChatMembers ?? [];\n for (const member of newMembers) {\n membershipMap.set(String(member.id), {\n status: \"member\",\n joinedAt: sentAt,\n leftAt: null,\n notify: true,\n });\n }\n\n if (message.leftChatMember) {\n membershipMap.set(String(message.leftChatMember.id), {\n status: \"left\",\n joinedAt: null,\n leftAt: sentAt,\n notify: true,\n });\n }\n\n if (fromUserId && message.chat.type !== \"channel\" && !membershipMap.has(fromUserId)) {\n membershipMap.set(fromUserId, {\n status: \"member\",\n joinedAt: sentAt,\n leftAt: null,\n notify: false,\n });\n }\n\n const chatIds = Array.from(\n new Set([chatId, senderChatId ? String(senderChatId) : null].filter(Boolean) as string[]),\n );\n\n const userIds = Array.from(\n new Set(\n [\n fromUserId,\n ...newMembers.map((member) => String(member.id)),\n message.leftChatMember ? String(message.leftChatMember.id) : null,\n ].filter(Boolean) as string[],\n ),\n );\n\n const memberIds = Array.from(\n new Set(Array.from(membershipMap.keys()).map((userId) => buildChatMemberId(chatId, userId))),\n );\n\n const chatsForUpsert: Array<typeof message.chat> = [];\n const seenChatIds = new Set<string>();\n for (const chat of [message.chat, senderChat]) {\n if (!chat) {\n continue;\n }\n const id = String(chat.id);\n if (seenChatIds.has(id)) {\n continue;\n }\n seenChatIds.add(id);\n chatsForUpsert.push(chat);\n }\n\n const usersForUpsert: Array<NonNullable<typeof fromUser>> = [];\n const seenUserIds = new Set<string>();\n for (const user of [fromUser, ...newMembers, message.leftChatMember]) {\n if (!user) {\n continue;\n }\n const id = String(user.id);\n if (seenUserIds.has(id)) {\n continue;\n }\n seenUserIds.add(id);\n usersForUpsert.push(user as NonNullable<typeof fromUser>);\n }\n\n return {\n kind: \"message\",\n updateId,\n retrieve: (uow) =>\n uow\n .find(\"chat\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"in\", chatIds.length ? chatIds : [missingId])),\n )\n .find(\"user\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"in\", userIds.length ? userIds : [missingId])),\n )\n .find(\"chatMember\", (b) =>\n b.whereIndex(\"primary\", (eb) =>\n eb(\"id\", \"in\", memberIds.length ? memberIds : [missingId]),\n ),\n )\n .findFirst(\"message\", (b) => b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", messageId))),\n mutate: ({\n uow,\n retrieveResult: [existingChats, existingUsers, existingMembers, existingMessage],\n }) => {\n const now = new Date();\n\n const chatById = new Map(existingChats.map((chat) => [chat.id.valueOf(), chat] as const));\n const userById = new Map(existingUsers.map((user) => [user.id.valueOf(), user] as const));\n const memberById = new Map(\n existingMembers.map((member) => [member.id.valueOf(), member] as const),\n );\n\n const chatSummaries = new Map<string, TelegramChatSummary>();\n for (const chat of chatsForUpsert) {\n const id = String(chat.id);\n const existing = chatById.get(id);\n if (!existing) {\n uow.create(\"chat\", {\n id,\n type: chat.type,\n title: chat.title ?? null,\n username: chat.username ?? null,\n isForum: chat.isForum ?? false,\n commandBindings: null,\n createdAt: now,\n updatedAt: now,\n });\n\n chatSummaries.set(id, {\n id,\n type: chat.type,\n title: chat.title ?? null,\n username: chat.username ?? null,\n isForum: chat.isForum ?? false,\n commandBindings: null,\n createdAt: now,\n updatedAt: now,\n });\n } else {\n uow.update(\"chat\", existing.id, (b) =>\n b\n .set({\n type: chat.type,\n title: chat.title ?? null,\n username: chat.username ?? null,\n isForum: chat.isForum ?? false,\n updatedAt: now,\n })\n .check(),\n );\n\n chatSummaries.set(id, {\n ...toChatSummary(existing),\n type: chat.type,\n title: chat.title ?? null,\n username: chat.username ?? null,\n isForum: chat.isForum ?? false,\n updatedAt: now,\n });\n }\n }\n\n const userSummaries = new Map<string, TelegramUserSummary>();\n for (const user of usersForUpsert) {\n const id = String(user.id);\n const existing = userById.get(id);\n if (!existing) {\n uow.create(\"user\", {\n id,\n username: user.username ?? null,\n firstName: user.firstName,\n lastName: user.lastName ?? null,\n isBot: user.isBot ?? false,\n languageCode: user.languageCode ?? null,\n createdAt: now,\n updatedAt: now,\n });\n\n userSummaries.set(id, {\n id,\n username: user.username ?? null,\n firstName: user.firstName,\n lastName: user.lastName ?? null,\n isBot: user.isBot ?? false,\n languageCode: user.languageCode ?? null,\n createdAt: now,\n updatedAt: now,\n });\n } else {\n uow.update(\"user\", existing.id, (b) =>\n b\n .set({\n username: user.username ?? null,\n firstName: user.firstName,\n lastName: user.lastName ?? null,\n isBot: user.isBot ?? false,\n languageCode: user.languageCode ?? null,\n updatedAt: now,\n })\n .check(),\n );\n\n userSummaries.set(id, {\n ...toUserSummary(existing),\n username: user.username ?? null,\n firstName: user.firstName,\n lastName: user.lastName ?? null,\n isBot: user.isBot ?? false,\n languageCode: user.languageCode ?? null,\n updatedAt: now,\n });\n }\n }\n\n const memberPayloads: TelegramChatMemberHookPayload[] = [];\n for (const [userId, membership] of membershipMap.entries()) {\n const memberId = buildChatMemberId(chatId, userId);\n const existing = memberById.get(memberId);\n\n if (!existing) {\n uow.create(\"chatMember\", {\n id: memberId,\n chatId,\n userId,\n status: membership.status,\n joinedAt: membership.joinedAt,\n leftAt: membership.leftAt,\n createdAt: now,\n updatedAt: now,\n });\n\n if (membership.notify) {\n memberPayloads.push({\n updateId,\n chatId,\n userId,\n status: membership.status,\n joinedAt: membership.joinedAt,\n leftAt: membership.leftAt,\n });\n }\n continue;\n }\n\n const hasExplicitJoin =\n membership.status === \"member\" && membership.joinedAt !== null && membership.notify;\n const nextJoinedAt = hasExplicitJoin ? membership.joinedAt : existing.joinedAt;\n const nextLeftAt =\n membership.status === \"left\"\n ? (membership.leftAt ?? existing.leftAt ?? now)\n : membership.status === \"member\"\n ? null\n : existing.leftAt;\n\n const changed =\n existing.status !== membership.status ||\n existing.joinedAt?.getTime() !== nextJoinedAt?.getTime() ||\n existing.leftAt?.getTime() !== nextLeftAt?.getTime();\n\n if (changed) {\n uow.update(\"chatMember\", existing.id, (b) =>\n b\n .set({\n status: membership.status,\n joinedAt: nextJoinedAt,\n leftAt: nextLeftAt,\n updatedAt: now,\n })\n .check(),\n );\n\n if (membership.notify) {\n memberPayloads.push({\n updateId,\n chatId,\n userId,\n status: membership.status,\n joinedAt: nextJoinedAt,\n leftAt: nextLeftAt,\n });\n }\n }\n }\n\n let shouldTriggerMessage = false;\n let messageSummary: TelegramMessageSummary;\n if (!existingMessage) {\n uow.create(\"message\", {\n id: messageId,\n chatId,\n fromUserId,\n senderChatId,\n replyToMessageId,\n messageType: type,\n text: message.text ?? null,\n payload: message,\n sentAt,\n editedAt,\n commandName,\n });\n\n shouldTriggerMessage = true;\n messageSummary = {\n id: messageId,\n chatId,\n fromUserId,\n senderChatId,\n replyToMessageId,\n messageType: type,\n text: message.text ?? null,\n attachments,\n payload: message,\n sentAt,\n editedAt,\n commandName,\n fromUser: fromUserId ? (userSummaries.get(fromUserId) ?? null) : null,\n };\n } else {\n const isEdit = type === \"edited_message\";\n const duplicateEdit =\n isEdit &&\n existingMessage.editedAt?.getTime() === editedAt?.getTime() &&\n existingMessage.text === (message.text ?? null);\n\n if (isEdit && !duplicateEdit) {\n uow.update(\"message\", existingMessage.id, (b) =>\n b\n .set({\n messageType: type,\n text: message.text ?? null,\n payload: message,\n editedAt,\n commandName,\n })\n .check(),\n );\n shouldTriggerMessage = true;\n }\n\n messageSummary = {\n id: String(existingMessage.id.valueOf()),\n chatId: String(existingMessage.chatId.valueOf()),\n fromUserId: existingMessage.fromUserId\n ? String(existingMessage.fromUserId.valueOf())\n : null,\n senderChatId: existingMessage.senderChatId\n ? String(existingMessage.senderChatId.valueOf())\n : null,\n replyToMessageId: existingMessage.replyToMessageId\n ? String(existingMessage.replyToMessageId.valueOf())\n : null,\n messageType: type,\n text: message.text ?? existingMessage.text,\n attachments,\n payload: message,\n sentAt: existingMessage.sentAt,\n editedAt: editedAt ?? existingMessage.editedAt,\n commandName,\n fromUser: fromUserId ? (userSummaries.get(fromUserId) ?? null) : null,\n };\n }\n\n const chatSummary =\n chatSummaries.get(chatId) ??\n (chatById.get(chatId)\n ? toChatSummary(chatById.get(chatId)!)\n : {\n id: chatId,\n type: message.chat.type,\n title: message.chat.title ?? null,\n username: message.chat.username ?? null,\n isForum: message.chat.isForum ?? false,\n commandBindings: null,\n createdAt: now,\n updatedAt: now,\n });\n\n const commandBindings = chatSummary.commandBindings ?? {};\n\n let commandResult: {\n name: string;\n args: string;\n raw: string;\n scopes: TelegramCommandScope[];\n } | null = null;\n\n if (commandMatch && type !== \"edited_message\") {\n const resolved = resolveCommandScopes(\n commandMatch.name,\n chatSummary.type,\n commandBindings,\n );\n if (resolved) {\n commandResult = {\n name: commandMatch.name,\n args: commandMatch.args,\n raw: commandMatch.raw,\n scopes: resolved.scopes,\n };\n\n if (shouldTriggerMessage) {\n uow.triggerHook(\"onCommandMatched\", {\n updateId,\n messageId: messageSummary.id,\n chatId,\n fromUserId,\n commandName: commandMatch.name,\n args: commandMatch.args,\n raw: commandMatch.raw,\n sentAt,\n });\n }\n }\n }\n\n if (shouldTriggerMessage) {\n const payload: TelegramMessageHookPayload = {\n updateId,\n updateType: type,\n messageId: messageSummary.id,\n chatId,\n fromUserId,\n text: message.text ?? null,\n attachments,\n commandName,\n sentAt: messageSummary.sentAt,\n editedAt: messageSummary.editedAt,\n };\n\n uow.triggerHook(\"onMessageReceived\", payload);\n }\n\n for (const payload of memberPayloads) {\n uow.triggerHook(\"onChatMemberUpdated\", payload);\n }\n\n return {\n kind: \"message\",\n updateId,\n updateType: type,\n chat: chatSummary,\n message: messageSummary,\n fromUser: fromUserId ? (userSummaries.get(fromUserId) ?? null) : null,\n command: commandResult,\n } satisfies ProcessIncomingUpdateResult;\n },\n };\n };\n};\n\nexport type UpsertOutgoingMessageOps = {\n retrieve: (uow: TelegramBaseUow) => TelegramOutgoingUow;\n mutate: (input: {\n uow: TelegramBaseUow;\n retrieveResult: UpsertOutgoingMessageRetrieveResult;\n }) => void;\n};\n\nexport const createUpsertOutgoingMessageOps = (input: {\n message: TelegramMessage;\n messageType: TelegramUpdateType;\n}): UpsertOutgoingMessageOps => {\n const { message, messageType } = input;\n const chatId = String(message.chat.id);\n const senderChatId = message.senderChat ? String(message.senderChat.id) : null;\n const fromUser = message.from ?? null;\n const fromUserId = fromUser ? String(fromUser.id) : null;\n const messageId = buildMessageId(chatId, message.messageId);\n const replyToMessageId = message.replyToMessage\n ? buildMessageId(chatId, message.replyToMessage.messageId)\n : null;\n const sentAt = new Date(message.date * 1000);\n const editedAt = message.editDate ? new Date(message.editDate * 1000) : null;\n\n const chatIds = Array.from(new Set([chatId, senderChatId].filter(Boolean) as string[]));\n\n return {\n retrieve: (uow) =>\n uow\n .find(\"chat\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"in\", chatIds.length ? chatIds : [missingId])),\n )\n .find(\"user\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"in\", fromUserId ? [fromUserId] : [missingId])),\n )\n .findFirst(\"message\", (b) => b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", messageId))),\n mutate: ({ uow, retrieveResult: [existingChats, existingUsers, existingMessage] }) => {\n const now = new Date();\n const chatById = new Map(existingChats.map((chat) => [chat.id.valueOf(), chat] as const));\n const userById = new Map(existingUsers.map((user) => [user.id.valueOf(), user] as const));\n\n const chatsForUpsert = [message.chat, message.senderChat].filter(Boolean) as Array<\n typeof message.chat\n >;\n for (const chat of chatsForUpsert) {\n const id = String(chat.id);\n const existing = chatById.get(id);\n if (!existing) {\n uow.create(\"chat\", {\n id,\n type: chat.type,\n title: chat.title ?? null,\n username: chat.username ?? null,\n isForum: chat.isForum ?? false,\n commandBindings: null,\n createdAt: now,\n updatedAt: now,\n });\n } else {\n uow.update(\"chat\", existing.id, (b) =>\n b\n .set({\n type: chat.type,\n title: chat.title ?? null,\n username: chat.username ?? null,\n isForum: chat.isForum ?? false,\n updatedAt: now,\n })\n .check(),\n );\n }\n }\n\n if (fromUser) {\n const id = String(fromUser.id);\n const existing = userById.get(id);\n if (!existing) {\n uow.create(\"user\", {\n id,\n username: fromUser.username ?? null,\n firstName: fromUser.firstName,\n lastName: fromUser.lastName ?? null,\n isBot: fromUser.isBot ?? false,\n languageCode: fromUser.languageCode ?? null,\n createdAt: now,\n updatedAt: now,\n });\n } else {\n uow.update(\"user\", existing.id, (b) =>\n b\n .set({\n username: fromUser.username ?? null,\n firstName: fromUser.firstName,\n lastName: fromUser.lastName ?? null,\n isBot: fromUser.isBot ?? false,\n languageCode: fromUser.languageCode ?? null,\n updatedAt: now,\n })\n .check(),\n );\n }\n }\n\n const messagePayload = {\n chatId,\n fromUserId,\n senderChatId,\n replyToMessageId,\n messageType,\n text: message.text ?? null,\n payload: message,\n sentAt,\n editedAt,\n commandName: null,\n };\n\n if (!existingMessage) {\n uow.create(\"message\", {\n id: messageId,\n ...messagePayload,\n });\n } else {\n uow.update(\"message\", existingMessage.id, (b) => b.set(messagePayload).check());\n }\n },\n };\n};\n\nexport const createTelegramServices = (config: TelegramFragmentConfig) => {\n const buildProcessIncomingUpdateOps = createProcessIncomingUpdateOps(config);\n type ServiceContext = DatabaseServiceContext<TelegramHooksMap>;\n\n return {\n processIncomingUpdate: function (this: ServiceContext, update: TelegramUpdate) {\n const ops = buildProcessIncomingUpdateOps(update);\n if (ops.kind === \"ignored\") {\n return this.serviceTx(telegramSchema)\n .mutate(() => ops satisfies ProcessIncomingUpdateResult)\n .build();\n }\n\n return this.serviceTx(telegramSchema)\n .retrieve(ops.retrieve)\n .mutate(({ uow, retrieveResult }) => ops.mutate({ uow, retrieveResult }))\n .build();\n },\n\n bindCommand: function (\n this: ServiceContext,\n input: {\n chatId: string;\n commandName: string;\n enabled: boolean;\n scopes?: TelegramCommandScope[];\n },\n ) {\n return this.serviceTx(telegramSchema)\n .retrieve((uow) =>\n uow.findFirst(\"chat\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", input.chatId)),\n ),\n )\n .mutate(({ uow, retrieveResult: [chat] }) => {\n if (!chat) {\n return { ok: false as const, reason: \"chat_not_found\" as const };\n }\n\n const bindings = parseCommandBindings(chat.commandBindings);\n const nextBindings = {\n ...bindings,\n [input.commandName]: {\n enabled: input.enabled,\n scopes: input.scopes,\n },\n };\n\n uow.update(\"chat\", chat.id, (b) =>\n b\n .set({\n commandBindings: nextBindings,\n updatedAt: new Date(),\n })\n .check(),\n );\n\n return {\n ok: true as const,\n binding: {\n chatId: input.chatId,\n commandName: input.commandName,\n enabled: input.enabled,\n scopes: input.scopes,\n },\n };\n })\n .build();\n },\n\n listChats: function (this: ServiceContext, type?: TelegramChatSummary[\"type\"]) {\n return this.serviceTx(telegramSchema)\n .retrieve((uow) => {\n if (type) {\n return uow.find(\"chat\", (b) =>\n b.whereIndex(\"idx_chat_type\", (eb) => eb(\"type\", \"=\", type)),\n );\n }\n return uow.find(\"chat\", (b) => b.whereIndex(\"primary\"));\n })\n .transformRetrieve(([chats]) => chats.map(toChatSummary))\n .build();\n },\n\n getChat: function (this: ServiceContext, chatId: string) {\n return this.serviceTx(telegramSchema)\n .retrieve((uow) =>\n uow.findFirst(\"chat\", (b) => b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", chatId))),\n )\n .transformRetrieve(([chat]) => (chat ? toChatSummary(chat) : null))\n .build();\n },\n\n getChatWithMembers: function (this: ServiceContext, chatId: string) {\n return this.serviceTx(telegramSchema)\n .retrieve((uow) =>\n uow\n .findFirst(\"chat\", (b) => b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", chatId)))\n .find(\"chatMember\", (b) =>\n b\n .whereIndex(\"idx_chat_member_chat\", (eb) => eb(\"chatId\", \"=\", chatId))\n .join((j) => j.chatMemberUser()),\n ),\n )\n .transformRetrieve(([chat, members]) => ({\n chat: chat ? toChatSummary(chat) : null,\n members: members.map(toChatMemberSummary),\n }))\n .build();\n },\n\n listMessages: function (\n this: ServiceContext,\n input: {\n chatId: string;\n pageSize: number;\n order: \"asc\" | \"desc\";\n cursor?: Cursor;\n },\n ) {\n return this.serviceTx(telegramSchema)\n .retrieve((uow) =>\n uow.findWithCursor(\"message\", (b) => {\n const query = b\n .whereIndex(\"idx_message_chat_sent\", (eb) => eb(\"chatId\", \"=\", input.chatId))\n .orderByIndex(\"idx_message_chat_sent\", input.order)\n .pageSize(input.pageSize)\n .join((j) => j.messageAuthor());\n\n return input.cursor ? query.after(input.cursor) : query;\n }),\n )\n .transformRetrieve(([messages]) => ({\n messages: messages.items.map(toMessageSummary),\n cursor: messages.cursor,\n hasNextPage: messages.hasNextPage,\n }))\n .build();\n },\n\n upsertOutgoingMessage: function (\n this: ServiceContext,\n input: {\n message: TelegramMessage;\n messageType: TelegramUpdateType;\n },\n ) {\n const ops = createUpsertOutgoingMessageOps(input);\n return this.serviceTx(telegramSchema)\n .retrieve(ops.retrieve)\n .mutate(({ uow, retrieveResult }) => ops.mutate({ uow, retrieveResult }))\n .build();\n },\n };\n};\n"],"mappings":"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"}
@@ -1,25 +1,86 @@
1
+ import { normalizeTelegramMessage } from "./telegram-utils.js";
2
+
1
3
  //#region src/telegram-api.ts
2
4
  const normalizeBaseUrl = (url) => url.replace(/\/+$/, "");
5
+ const filterUndefined = (payload) => Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== void 0));
6
+ const normalizeSendMessagePayload = (payload) => {
7
+ const message = payload;
8
+ return filterUndefined({
9
+ chat_id: message.chat_id ?? message.chatId,
10
+ text: message.text,
11
+ parse_mode: message.parse_mode ?? message.parseMode,
12
+ disable_web_page_preview: message.disable_web_page_preview ?? message.disableWebPagePreview,
13
+ reply_to_message_id: message.reply_to_message_id ?? message.replyToMessageId
14
+ });
15
+ };
16
+ const normalizeEditMessageTextPayload = (payload) => {
17
+ const message = payload;
18
+ return filterUndefined({
19
+ chat_id: message.chat_id ?? message.chatId,
20
+ message_id: message.message_id ?? message.messageId,
21
+ text: message.text,
22
+ parse_mode: message.parse_mode ?? message.parseMode,
23
+ disable_web_page_preview: message.disable_web_page_preview ?? message.disableWebPagePreview
24
+ });
25
+ };
26
+ const normalizeSendChatActionPayload = (payload) => {
27
+ const action = payload;
28
+ return filterUndefined({
29
+ chat_id: action.chat_id ?? action.chatId,
30
+ action: action.action
31
+ });
32
+ };
33
+ const normalizeTelegramApiResult = (data, normalizeResult) => {
34
+ if (!data || typeof data !== "object") return null;
35
+ const envelope = data;
36
+ if (envelope.ok === true) return {
37
+ ok: true,
38
+ result: normalizeResult(envelope.result)
39
+ };
40
+ if (envelope.ok === false) return {
41
+ ok: false,
42
+ errorCode: typeof envelope.errorCode === "number" ? envelope.errorCode : typeof envelope.error_code === "number" ? envelope.error_code : void 0,
43
+ description: typeof envelope.description === "string" ? envelope.description : void 0
44
+ };
45
+ return null;
46
+ };
3
47
  function createTelegramApi(config) {
4
48
  const baseUrl = normalizeBaseUrl(config.apiBaseUrl ?? "https://api.telegram.org");
5
49
  const token = config.botToken;
50
+ const callRaw = async (method, payload) => {
51
+ const response = await fetch(`${baseUrl}/bot${token}/${method}`, {
52
+ method: "POST",
53
+ headers: { "content-type": "application/json" },
54
+ body: JSON.stringify(payload)
55
+ });
56
+ try {
57
+ return await response.json();
58
+ } catch {
59
+ return null;
60
+ }
61
+ };
6
62
  const call = async (method, payload) => {
7
63
  try {
8
- const response = await fetch(`${baseUrl}/bot${token}/${method}`, {
9
- method: "POST",
10
- headers: { "content-type": "application/json" },
11
- body: JSON.stringify(payload)
12
- });
13
- let data = null;
14
- try {
15
- data = await response.json();
16
- } catch {
17
- data = null;
18
- }
19
- if (data && typeof data === "object" && "ok" in data) return data;
64
+ const result = normalizeTelegramApiResult(await callRaw(method, payload), (value) => value);
65
+ if (result) return result;
66
+ return {
67
+ ok: false,
68
+ description: "Telegram API returned an unexpected response"
69
+ };
70
+ } catch (error) {
71
+ return {
72
+ ok: false,
73
+ description: error instanceof Error ? error.message : "Telegram API request failed"
74
+ };
75
+ }
76
+ };
77
+ const callWithNormalization = async (method, payload, normalizeResult) => {
78
+ try {
79
+ const result = normalizeTelegramApiResult(await callRaw(method, payload), normalizeResult);
80
+ if (result) return result;
20
81
  return {
21
82
  ok: false,
22
- description: response.ok ? "Telegram API returned an unexpected response" : `Telegram API error (${response.status})`
83
+ description: `Telegram API returned an invalid ${method} result`
23
84
  };
24
85
  } catch (error) {
25
86
  return {
@@ -30,9 +91,12 @@ function createTelegramApi(config) {
30
91
  };
31
92
  return {
32
93
  call,
33
- sendMessage: (payload) => call("sendMessage", payload),
34
- editMessageText: (payload) => call("editMessageText", payload),
35
- sendChatAction: (payload) => call("sendChatAction", payload)
94
+ sendMessage: (payload) => callWithNormalization("sendMessage", normalizeSendMessagePayload(payload), normalizeTelegramMessage),
95
+ editMessageText: (payload) => callWithNormalization("editMessageText", normalizeEditMessageTextPayload(payload), normalizeTelegramMessage),
96
+ sendChatAction: (payload) => callWithNormalization("sendChatAction", normalizeSendChatActionPayload(payload), (value) => {
97
+ if (typeof value !== "boolean") throw new Error("Invalid Telegram boolean result");
98
+ return value;
99
+ })
36
100
  };
37
101
  }
38
102
 
@@ -1 +1 @@
1
- {"version":3,"file":"telegram-api.js","names":[],"sources":["../../src/telegram-api.ts"],"sourcesContent":["import type { TelegramApi, TelegramApiResult, TelegramFragmentConfig } from \"./types\";\n\nconst normalizeBaseUrl = (url: string) => url.replace(/\\/+$/, \"\");\n\nexport function createTelegramApi(\n config: Pick<TelegramFragmentConfig, \"botToken\" | \"apiBaseUrl\">,\n): TelegramApi {\n const baseUrl = normalizeBaseUrl(config.apiBaseUrl ?? \"https://api.telegram.org\");\n const token = config.botToken;\n\n const call = async <T>(\n method: string,\n payload: Record<string, unknown>,\n ): Promise<TelegramApiResult<T>> => {\n try {\n const response = await fetch(`${baseUrl}/bot${token}/${method}`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n let data: TelegramApiResult<T> | null = null;\n try {\n data = (await response.json()) as TelegramApiResult<T>;\n } catch {\n data = null;\n }\n\n if (data && typeof data === \"object\" && \"ok\" in data) {\n return data;\n }\n\n return {\n ok: false,\n description: response.ok\n ? \"Telegram API returned an unexpected response\"\n : `Telegram API error (${response.status})`,\n };\n } catch (error) {\n return {\n ok: false,\n description: error instanceof Error ? error.message : \"Telegram API request failed\",\n };\n }\n };\n\n return {\n call,\n sendMessage: (payload) => call(\"sendMessage\", payload),\n editMessageText: (payload) => call(\"editMessageText\", payload),\n sendChatAction: (payload) => call(\"sendChatAction\", payload),\n };\n}\n"],"mappings":";AAEA,MAAM,oBAAoB,QAAgB,IAAI,QAAQ,QAAQ,GAAG;AAEjE,SAAgB,kBACd,QACa;CACb,MAAM,UAAU,iBAAiB,OAAO,cAAc,2BAA2B;CACjF,MAAM,QAAQ,OAAO;CAErB,MAAM,OAAO,OACX,QACA,YACkC;AAClC,MAAI;GACF,MAAM,WAAW,MAAM,MAAM,GAAG,QAAQ,MAAM,MAAM,GAAG,UAAU;IAC/D,QAAQ;IACR,SAAS,EACP,gBAAgB,oBACjB;IACD,MAAM,KAAK,UAAU,QAAQ;IAC9B,CAAC;GAEF,IAAI,OAAoC;AACxC,OAAI;AACF,WAAQ,MAAM,SAAS,MAAM;WACvB;AACN,WAAO;;AAGT,OAAI,QAAQ,OAAO,SAAS,YAAY,QAAQ,KAC9C,QAAO;AAGT,UAAO;IACL,IAAI;IACJ,aAAa,SAAS,KAClB,iDACA,uBAAuB,SAAS,OAAO;IAC5C;WACM,OAAO;AACd,UAAO;IACL,IAAI;IACJ,aAAa,iBAAiB,QAAQ,MAAM,UAAU;IACvD;;;AAIL,QAAO;EACL;EACA,cAAc,YAAY,KAAK,eAAe,QAAQ;EACtD,kBAAkB,YAAY,KAAK,mBAAmB,QAAQ;EAC9D,iBAAiB,YAAY,KAAK,kBAAkB,QAAQ;EAC7D"}
1
+ {"version":3,"file":"telegram-api.js","names":[],"sources":["../../src/telegram-api.ts"],"sourcesContent":["import { normalizeTelegramMessage } from \"./telegram-utils\";\nimport type { TelegramApi, TelegramApiResult, TelegramFragmentConfig } from \"./types\";\n\nconst normalizeBaseUrl = (url: string) => url.replace(/\\/+$/, \"\");\n\nconst filterUndefined = (payload: Record<string, unknown>) =>\n Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== undefined));\n\ntype TelegramApiEnvelope = {\n ok?: unknown;\n result?: unknown;\n error_code?: unknown;\n errorCode?: unknown;\n description?: unknown;\n};\n\ntype SendMessagePayload = {\n chatId?: unknown;\n chat_id?: unknown;\n text?: unknown;\n parseMode?: unknown;\n parse_mode?: unknown;\n disableWebPagePreview?: unknown;\n disable_web_page_preview?: unknown;\n replyToMessageId?: unknown;\n reply_to_message_id?: unknown;\n};\n\ntype EditMessageTextPayload = SendMessagePayload & {\n messageId?: unknown;\n message_id?: unknown;\n};\n\ntype SendChatActionPayload = {\n chatId?: unknown;\n chat_id?: unknown;\n action?: unknown;\n};\n\nconst normalizeSendMessagePayload = (payload: Record<string, unknown>) => {\n const message = payload as SendMessagePayload;\n return filterUndefined({\n chat_id: message.chat_id ?? message.chatId,\n text: message.text,\n parse_mode: message.parse_mode ?? message.parseMode,\n disable_web_page_preview: message.disable_web_page_preview ?? message.disableWebPagePreview,\n reply_to_message_id: message.reply_to_message_id ?? message.replyToMessageId,\n });\n};\n\nconst normalizeEditMessageTextPayload = (payload: Record<string, unknown>) => {\n const message = payload as EditMessageTextPayload;\n return filterUndefined({\n chat_id: message.chat_id ?? message.chatId,\n message_id: message.message_id ?? message.messageId,\n text: message.text,\n parse_mode: message.parse_mode ?? message.parseMode,\n disable_web_page_preview: message.disable_web_page_preview ?? message.disableWebPagePreview,\n });\n};\n\nconst normalizeSendChatActionPayload = (payload: Record<string, unknown>) => {\n const action = payload as SendChatActionPayload;\n return filterUndefined({\n chat_id: action.chat_id ?? action.chatId,\n action: action.action,\n });\n};\n\nconst normalizeTelegramApiResult = <T>(\n data: unknown,\n normalizeResult: (value: unknown) => T,\n): TelegramApiResult<T> | null => {\n if (!data || typeof data !== \"object\") {\n return null;\n }\n\n const envelope = data as TelegramApiEnvelope;\n if (envelope.ok === true) {\n return {\n ok: true,\n result: normalizeResult(envelope.result),\n };\n }\n\n if (envelope.ok === false) {\n return {\n ok: false,\n errorCode:\n typeof envelope.errorCode === \"number\"\n ? envelope.errorCode\n : typeof envelope.error_code === \"number\"\n ? envelope.error_code\n : undefined,\n description: typeof envelope.description === \"string\" ? envelope.description : undefined,\n };\n }\n\n return null;\n};\n\nexport function createTelegramApi(\n config: Pick<TelegramFragmentConfig, \"botToken\" | \"apiBaseUrl\">,\n): TelegramApi {\n const baseUrl = normalizeBaseUrl(config.apiBaseUrl ?? \"https://api.telegram.org\");\n const token = config.botToken;\n\n const callRaw = async (method: string, payload: Record<string, unknown>): Promise<unknown> => {\n const response = await fetch(`${baseUrl}/bot${token}/${method}`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n try {\n return await response.json();\n } catch {\n return null;\n }\n };\n\n const call = async <T>(\n method: string,\n payload: Record<string, unknown>,\n ): Promise<TelegramApiResult<T>> => {\n try {\n const data = await callRaw(method, payload);\n const result = normalizeTelegramApiResult(data, (value) => value as T);\n if (result) {\n return result;\n }\n\n return {\n ok: false,\n description: \"Telegram API returned an unexpected response\",\n };\n } catch (error) {\n return {\n ok: false,\n description: error instanceof Error ? error.message : \"Telegram API request failed\",\n };\n }\n };\n\n const callWithNormalization = async <T>(\n method: string,\n payload: Record<string, unknown>,\n normalizeResult: (value: unknown) => T,\n ): Promise<TelegramApiResult<T>> => {\n try {\n const data = await callRaw(method, payload);\n const result = normalizeTelegramApiResult(data, normalizeResult);\n if (result) {\n return result;\n }\n\n return {\n ok: false,\n description: `Telegram API returned an invalid ${method} result`,\n };\n } catch (error) {\n return {\n ok: false,\n description: error instanceof Error ? error.message : \"Telegram API request failed\",\n };\n }\n };\n\n return {\n call,\n sendMessage: (payload) =>\n callWithNormalization(\n \"sendMessage\",\n normalizeSendMessagePayload(payload),\n normalizeTelegramMessage,\n ),\n editMessageText: (payload) =>\n callWithNormalization(\n \"editMessageText\",\n normalizeEditMessageTextPayload(payload),\n normalizeTelegramMessage,\n ),\n sendChatAction: (payload) =>\n callWithNormalization(\"sendChatAction\", normalizeSendChatActionPayload(payload), (value) => {\n if (typeof value !== \"boolean\") {\n throw new Error(\"Invalid Telegram boolean result\");\n }\n return value;\n }),\n };\n}\n"],"mappings":";;;AAGA,MAAM,oBAAoB,QAAgB,IAAI,QAAQ,QAAQ,GAAG;AAEjE,MAAM,mBAAmB,YACvB,OAAO,YAAY,OAAO,QAAQ,QAAQ,CAAC,QAAQ,GAAG,WAAW,UAAU,OAAU,CAAC;AAiCxF,MAAM,+BAA+B,YAAqC;CACxE,MAAM,UAAU;AAChB,QAAO,gBAAgB;EACrB,SAAS,QAAQ,WAAW,QAAQ;EACpC,MAAM,QAAQ;EACd,YAAY,QAAQ,cAAc,QAAQ;EAC1C,0BAA0B,QAAQ,4BAA4B,QAAQ;EACtE,qBAAqB,QAAQ,uBAAuB,QAAQ;EAC7D,CAAC;;AAGJ,MAAM,mCAAmC,YAAqC;CAC5E,MAAM,UAAU;AAChB,QAAO,gBAAgB;EACrB,SAAS,QAAQ,WAAW,QAAQ;EACpC,YAAY,QAAQ,cAAc,QAAQ;EAC1C,MAAM,QAAQ;EACd,YAAY,QAAQ,cAAc,QAAQ;EAC1C,0BAA0B,QAAQ,4BAA4B,QAAQ;EACvE,CAAC;;AAGJ,MAAM,kCAAkC,YAAqC;CAC3E,MAAM,SAAS;AACf,QAAO,gBAAgB;EACrB,SAAS,OAAO,WAAW,OAAO;EAClC,QAAQ,OAAO;EAChB,CAAC;;AAGJ,MAAM,8BACJ,MACA,oBACgC;AAChC,KAAI,CAAC,QAAQ,OAAO,SAAS,SAC3B,QAAO;CAGT,MAAM,WAAW;AACjB,KAAI,SAAS,OAAO,KAClB,QAAO;EACL,IAAI;EACJ,QAAQ,gBAAgB,SAAS,OAAO;EACzC;AAGH,KAAI,SAAS,OAAO,MAClB,QAAO;EACL,IAAI;EACJ,WACE,OAAO,SAAS,cAAc,WAC1B,SAAS,YACT,OAAO,SAAS,eAAe,WAC7B,SAAS,aACT;EACR,aAAa,OAAO,SAAS,gBAAgB,WAAW,SAAS,cAAc;EAChF;AAGH,QAAO;;AAGT,SAAgB,kBACd,QACa;CACb,MAAM,UAAU,iBAAiB,OAAO,cAAc,2BAA2B;CACjF,MAAM,QAAQ,OAAO;CAErB,MAAM,UAAU,OAAO,QAAgB,YAAuD;EAC5F,MAAM,WAAW,MAAM,MAAM,GAAG,QAAQ,MAAM,MAAM,GAAG,UAAU;GAC/D,QAAQ;GACR,SAAS,EACP,gBAAgB,oBACjB;GACD,MAAM,KAAK,UAAU,QAAQ;GAC9B,CAAC;AAEF,MAAI;AACF,UAAO,MAAM,SAAS,MAAM;UACtB;AACN,UAAO;;;CAIX,MAAM,OAAO,OACX,QACA,YACkC;AAClC,MAAI;GAEF,MAAM,SAAS,2BADF,MAAM,QAAQ,QAAQ,QAAQ,GACM,UAAU,MAAW;AACtE,OAAI,OACF,QAAO;AAGT,UAAO;IACL,IAAI;IACJ,aAAa;IACd;WACM,OAAO;AACd,UAAO;IACL,IAAI;IACJ,aAAa,iBAAiB,QAAQ,MAAM,UAAU;IACvD;;;CAIL,MAAM,wBAAwB,OAC5B,QACA,SACA,oBACkC;AAClC,MAAI;GAEF,MAAM,SAAS,2BADF,MAAM,QAAQ,QAAQ,QAAQ,EACK,gBAAgB;AAChE,OAAI,OACF,QAAO;AAGT,UAAO;IACL,IAAI;IACJ,aAAa,oCAAoC,OAAO;IACzD;WACM,OAAO;AACd,UAAO;IACL,IAAI;IACJ,aAAa,iBAAiB,QAAQ,MAAM,UAAU;IACvD;;;AAIL,QAAO;EACL;EACA,cAAc,YACZ,sBACE,eACA,4BAA4B,QAAQ,EACpC,yBACD;EACH,kBAAkB,YAChB,sBACE,mBACA,gCAAgC,QAAQ,EACxC,yBACD;EACH,iBAAiB,YACf,sBAAsB,kBAAkB,+BAA+B,QAAQ,GAAG,UAAU;AAC1F,OAAI,OAAO,UAAU,UACnB,OAAM,IAAI,MAAM,kCAAkC;AAEpD,UAAO;IACP;EACL"}