@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.
- package/dist/browser/client/react.d.ts +129 -3
- package/dist/browser/client/react.d.ts.map +1 -1
- package/dist/browser/client/react.js +32 -22
- package/dist/browser/client/react.js.map +1 -1
- package/dist/browser/client/solid.d.ts +129 -3
- package/dist/browser/client/solid.d.ts.map +1 -1
- package/dist/browser/client/solid.js +2 -2
- package/dist/browser/client/solid.js.map +1 -1
- package/dist/browser/client/svelte.d.ts +129 -3
- package/dist/browser/client/svelte.d.ts.map +1 -1
- package/dist/browser/client/svelte.js +1 -1
- package/dist/browser/client/vanilla.d.ts +129 -3
- package/dist/browser/client/vanilla.d.ts.map +1 -1
- package/dist/browser/client/vanilla.js +1 -1
- package/dist/browser/client/vue.d.ts +129 -3
- package/dist/browser/client/vue.d.ts.map +1 -1
- package/dist/browser/client/vue.js +1 -1
- package/dist/browser/{client-Bk-J98pf.d.ts → client-BumUy6cu.d.ts} +87 -83
- package/dist/browser/client-BumUy6cu.d.ts.map +1 -0
- package/dist/browser/index.d.ts +697 -48
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +2 -2
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/{schema-QDMf15Vn.js → schema-IrJsGm4M.js} +264 -41
- package/dist/browser/schema-IrJsGm4M.js.map +1 -0
- package/dist/node/definition.d.ts.map +1 -1
- package/dist/node/index.d.ts +260 -13
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +2 -2
- package/dist/node/index.js.map +1 -1
- package/dist/node/routes.d.ts +130 -9
- package/dist/node/routes.d.ts.map +1 -1
- package/dist/node/routes.js +25 -15
- package/dist/node/routes.js.map +1 -1
- package/dist/node/services.js +56 -53
- package/dist/node/services.js.map +1 -1
- package/dist/node/telegram-api.js +80 -16
- package/dist/node/telegram-api.js.map +1 -1
- package/dist/node/telegram-utils.js +284 -9
- package/dist/node/telegram-utils.js.map +1 -1
- package/dist/node/types.d.ts +308 -27
- package/dist/node/types.d.ts.map +1 -1
- package/dist/node/types.js +232 -27
- package/dist/node/types.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -8
- package/dist/browser/client-Bk-J98pf.d.ts.map +0 -1
- 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
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
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:
|
|
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) =>
|
|
34
|
-
editMessageText: (payload) =>
|
|
35
|
-
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
|
|
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"}
|