@fragno-dev/telegram-fragment 0.0.1
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/LICENSE.md +16 -0
- package/README.md +87 -0
- package/dist/browser/client/react.d.ts +226 -0
- package/dist/browser/client/react.d.ts.map +1 -0
- package/dist/browser/client/react.js +166 -0
- package/dist/browser/client/react.js.map +1 -0
- package/dist/browser/client/solid.d.ts +228 -0
- package/dist/browser/client/solid.d.ts.map +1 -0
- package/dist/browser/client/solid.js +136 -0
- package/dist/browser/client/solid.js.map +1 -0
- package/dist/browser/client/svelte.d.ts +223 -0
- package/dist/browser/client/svelte.d.ts.map +1 -0
- package/dist/browser/client/svelte.js +134 -0
- package/dist/browser/client/svelte.js.map +1 -0
- package/dist/browser/client/vanilla.d.ts +252 -0
- package/dist/browser/client/vanilla.d.ts.map +1 -0
- package/dist/browser/client/vanilla.js +160 -0
- package/dist/browser/client/vanilla.js.map +1 -0
- package/dist/browser/client/vue.d.ts +226 -0
- package/dist/browser/client/vue.d.ts.map +1 -0
- package/dist/browser/client/vue.js +133 -0
- package/dist/browser/client/vue.js.map +1 -0
- package/dist/browser/client-Bk-J98pf.d.ts +679 -0
- package/dist/browser/client-Bk-J98pf.d.ts.map +1 -0
- package/dist/browser/index.d.ts +1392 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +24 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/schema-QDMf15Vn.js +2343 -0
- package/dist/browser/schema-QDMf15Vn.js.map +1 -0
- package/dist/node/command-handler-api.js +42 -0
- package/dist/node/command-handler-api.js.map +1 -0
- package/dist/node/definition.d.ts +194 -0
- package/dist/node/definition.d.ts.map +1 -0
- package/dist/node/definition.js +90 -0
- package/dist/node/definition.js.map +1 -0
- package/dist/node/index.d.ts +587 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +29 -0
- package/dist/node/index.js.map +1 -0
- package/dist/node/routes.d.ts +385 -0
- package/dist/node/routes.d.ts.map +1 -0
- package/dist/node/routes.js +392 -0
- package/dist/node/routes.js.map +1 -0
- package/dist/node/schema.d.ts +13 -0
- package/dist/node/schema.d.ts.map +1 -0
- package/dist/node/schema.js +78 -0
- package/dist/node/schema.js.map +1 -0
- package/dist/node/services.js +589 -0
- package/dist/node/services.js.map +1 -0
- package/dist/node/telegram-api.js +41 -0
- package/dist/node/telegram-api.js.map +1 -0
- package/dist/node/telegram-utils.js +61 -0
- package/dist/node/telegram-utils.js.map +1 -0
- package/dist/node/types.d.ts +245 -0
- package/dist/node/types.d.ts.map +1 -0
- package/dist/node/types.js +92 -0
- package/dist/node/types.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +96 -0
|
@@ -0,0 +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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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region src/telegram-api.ts
|
|
2
|
+
const normalizeBaseUrl = (url) => url.replace(/\/+$/, "");
|
|
3
|
+
function createTelegramApi(config) {
|
|
4
|
+
const baseUrl = normalizeBaseUrl(config.apiBaseUrl ?? "https://api.telegram.org");
|
|
5
|
+
const token = config.botToken;
|
|
6
|
+
const call = async (method, payload) => {
|
|
7
|
+
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;
|
|
20
|
+
return {
|
|
21
|
+
ok: false,
|
|
22
|
+
description: response.ok ? "Telegram API returned an unexpected response" : `Telegram API error (${response.status})`
|
|
23
|
+
};
|
|
24
|
+
} catch (error) {
|
|
25
|
+
return {
|
|
26
|
+
ok: false,
|
|
27
|
+
description: error instanceof Error ? error.message : "Telegram API request failed"
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
return {
|
|
32
|
+
call,
|
|
33
|
+
sendMessage: (payload) => call("sendMessage", payload),
|
|
34
|
+
editMessageText: (payload) => call("editMessageText", payload),
|
|
35
|
+
sendChatAction: (payload) => call("sendChatAction", payload)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
export { createTelegramApi };
|
|
41
|
+
//# sourceMappingURL=telegram-api.js.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { telegramCommandBindingsSchema } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/telegram-utils.ts
|
|
4
|
+
const DEFAULT_COMMAND_SCOPES = [
|
|
5
|
+
"private",
|
|
6
|
+
"group",
|
|
7
|
+
"supergroup",
|
|
8
|
+
"channel"
|
|
9
|
+
];
|
|
10
|
+
function parseTelegramUpdate(update) {
|
|
11
|
+
if (update.message) return {
|
|
12
|
+
updateId: update.update_id,
|
|
13
|
+
type: "message",
|
|
14
|
+
message: update.message
|
|
15
|
+
};
|
|
16
|
+
if (update.edited_message) return {
|
|
17
|
+
updateId: update.update_id,
|
|
18
|
+
type: "edited_message",
|
|
19
|
+
message: update.edited_message
|
|
20
|
+
};
|
|
21
|
+
if (update.channel_post) return {
|
|
22
|
+
updateId: update.update_id,
|
|
23
|
+
type: "channel_post",
|
|
24
|
+
message: update.channel_post
|
|
25
|
+
};
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
function buildMessageId(chatId, messageId) {
|
|
29
|
+
return `${chatId}:${messageId}`;
|
|
30
|
+
}
|
|
31
|
+
function buildChatMemberId(chatId, userId) {
|
|
32
|
+
return `${chatId}:${userId}`;
|
|
33
|
+
}
|
|
34
|
+
function parseCommand(message, botUsername) {
|
|
35
|
+
if (!message.text) return null;
|
|
36
|
+
const text = message.text;
|
|
37
|
+
let commandToken = null;
|
|
38
|
+
const entity = message.entities?.find((entry) => entry.type === "bot_command" && entry.offset === 0);
|
|
39
|
+
if (entity) commandToken = text.slice(0, entity.length);
|
|
40
|
+
if (!commandToken && text.startsWith("/")) commandToken = text.split(/\s+/)[0] ?? null;
|
|
41
|
+
if (!commandToken) return null;
|
|
42
|
+
const withoutSlash = commandToken.slice(1);
|
|
43
|
+
if (!withoutSlash) return null;
|
|
44
|
+
const [name, atBot] = withoutSlash.split("@");
|
|
45
|
+
if (atBot && botUsername && atBot.toLowerCase() !== botUsername.toLowerCase()) return null;
|
|
46
|
+
return {
|
|
47
|
+
name,
|
|
48
|
+
args: text.slice(commandToken.length).trim(),
|
|
49
|
+
raw: commandToken
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function parseCommandBindings(value) {
|
|
53
|
+
if (!value) return {};
|
|
54
|
+
const result = telegramCommandBindingsSchema.safeParse(value);
|
|
55
|
+
if (!result.success) return {};
|
|
56
|
+
return result.data;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
//#endregion
|
|
60
|
+
export { DEFAULT_COMMAND_SCOPES, buildChatMemberId, buildMessageId, parseCommand, parseCommandBindings, parseTelegramUpdate };
|
|
61
|
+
//# sourceMappingURL=telegram-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram-utils.js","names":[],"sources":["../../src/telegram-utils.ts"],"sourcesContent":["import type {\n TelegramCommandBindings,\n TelegramCommandScope,\n TelegramMessage,\n TelegramUpdate,\n TelegramUpdateType,\n} from \"./types\";\nimport { telegramCommandBindingsSchema } from \"./types\";\n\nexport const DEFAULT_COMMAND_SCOPES: TelegramCommandScope[] = [\n \"private\",\n \"group\",\n \"supergroup\",\n \"channel\",\n];\n\nexport type ParsedTelegramUpdate = {\n updateId: number;\n type: TelegramUpdateType;\n message: TelegramMessage;\n};\n\nexport function parseTelegramUpdate(update: TelegramUpdate): ParsedTelegramUpdate | null {\n if (update.message) {\n return { updateId: update.update_id, type: \"message\", message: update.message };\n }\n if (update.edited_message) {\n return { updateId: update.update_id, type: \"edited_message\", message: update.edited_message };\n }\n if (update.channel_post) {\n return { updateId: update.update_id, type: \"channel_post\", message: update.channel_post };\n }\n return null;\n}\n\nexport function buildMessageId(chatId: string, messageId: number): string {\n return `${chatId}:${messageId}`;\n}\n\nexport function buildChatMemberId(chatId: string, userId: string): string {\n return `${chatId}:${userId}`;\n}\n\nexport function parseCommand(\n message: TelegramMessage,\n botUsername?: string,\n): { name: string; args: string; raw: string } | null {\n if (!message.text) {\n return null;\n }\n\n const text = message.text;\n let commandToken: string | null = null;\n\n const entity = message.entities?.find(\n (entry) => entry.type === \"bot_command\" && entry.offset === 0,\n );\n if (entity) {\n commandToken = text.slice(0, entity.length);\n }\n\n if (!commandToken && text.startsWith(\"/\")) {\n commandToken = text.split(/\\s+/)[0] ?? null;\n }\n\n if (!commandToken) {\n return null;\n }\n\n const withoutSlash = commandToken.slice(1);\n if (!withoutSlash) {\n return null;\n }\n\n const [name, atBot] = withoutSlash.split(\"@\");\n if (atBot && botUsername && atBot.toLowerCase() !== botUsername.toLowerCase()) {\n return null;\n }\n\n const args = text.slice(commandToken.length).trim();\n\n return {\n name,\n args,\n raw: commandToken,\n };\n}\n\nexport function parseCommandBindings(value: unknown): TelegramCommandBindings {\n if (!value) {\n return {};\n }\n const result = telegramCommandBindingsSchema.safeParse(value);\n if (!result.success) {\n return {};\n }\n return result.data;\n}\n"],"mappings":";;;AASA,MAAa,yBAAiD;CAC5D;CACA;CACA;CACA;CACD;AAQD,SAAgB,oBAAoB,QAAqD;AACvF,KAAI,OAAO,QACT,QAAO;EAAE,UAAU,OAAO;EAAW,MAAM;EAAW,SAAS,OAAO;EAAS;AAEjF,KAAI,OAAO,eACT,QAAO;EAAE,UAAU,OAAO;EAAW,MAAM;EAAkB,SAAS,OAAO;EAAgB;AAE/F,KAAI,OAAO,aACT,QAAO;EAAE,UAAU,OAAO;EAAW,MAAM;EAAgB,SAAS,OAAO;EAAc;AAE3F,QAAO;;AAGT,SAAgB,eAAe,QAAgB,WAA2B;AACxE,QAAO,GAAG,OAAO,GAAG;;AAGtB,SAAgB,kBAAkB,QAAgB,QAAwB;AACxE,QAAO,GAAG,OAAO,GAAG;;AAGtB,SAAgB,aACd,SACA,aACoD;AACpD,KAAI,CAAC,QAAQ,KACX,QAAO;CAGT,MAAM,OAAO,QAAQ;CACrB,IAAI,eAA8B;CAElC,MAAM,SAAS,QAAQ,UAAU,MAC9B,UAAU,MAAM,SAAS,iBAAiB,MAAM,WAAW,EAC7D;AACD,KAAI,OACF,gBAAe,KAAK,MAAM,GAAG,OAAO,OAAO;AAG7C,KAAI,CAAC,gBAAgB,KAAK,WAAW,IAAI,CACvC,gBAAe,KAAK,MAAM,MAAM,CAAC,MAAM;AAGzC,KAAI,CAAC,aACH,QAAO;CAGT,MAAM,eAAe,aAAa,MAAM,EAAE;AAC1C,KAAI,CAAC,aACH,QAAO;CAGT,MAAM,CAAC,MAAM,SAAS,aAAa,MAAM,IAAI;AAC7C,KAAI,SAAS,eAAe,MAAM,aAAa,KAAK,YAAY,aAAa,CAC3E,QAAO;AAKT,QAAO;EACL;EACA,MAJW,KAAK,MAAM,aAAa,OAAO,CAAC,MAAM;EAKjD,KAAK;EACN;;AAGH,SAAgB,qBAAqB,OAAyC;AAC5E,KAAI,CAAC,MACH,QAAO,EAAE;CAEX,MAAM,SAAS,8BAA8B,UAAU,MAAM;AAC7D,KAAI,CAAC,OAAO,QACV,QAAO,EAAE;AAEX,QAAO,OAAO"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { HookFn, HookHandlerTx } from "@fragno-dev/db";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
//#region src/types.d.ts
|
|
5
|
+
declare const telegramChatTypeSchema: z.ZodEnum<{
|
|
6
|
+
private: "private";
|
|
7
|
+
group: "group";
|
|
8
|
+
supergroup: "supergroup";
|
|
9
|
+
channel: "channel";
|
|
10
|
+
}>;
|
|
11
|
+
type TelegramChatType = z.infer<typeof telegramChatTypeSchema>;
|
|
12
|
+
type TelegramCommandScope = TelegramChatType;
|
|
13
|
+
declare const telegramMessageEntitySchema: z.ZodObject<{
|
|
14
|
+
type: z.ZodString;
|
|
15
|
+
offset: z.ZodNumber;
|
|
16
|
+
length: z.ZodNumber;
|
|
17
|
+
}, z.core.$loose>;
|
|
18
|
+
type TelegramMessageEntity = z.infer<typeof telegramMessageEntitySchema>;
|
|
19
|
+
declare const telegramUserSchema: z.ZodObject<{
|
|
20
|
+
id: z.ZodNumber;
|
|
21
|
+
is_bot: z.ZodOptional<z.ZodBoolean>;
|
|
22
|
+
first_name: z.ZodString;
|
|
23
|
+
last_name: z.ZodOptional<z.ZodString>;
|
|
24
|
+
username: z.ZodOptional<z.ZodString>;
|
|
25
|
+
language_code: z.ZodOptional<z.ZodString>;
|
|
26
|
+
}, z.core.$loose>;
|
|
27
|
+
type TelegramUser = z.infer<typeof telegramUserSchema>;
|
|
28
|
+
declare const telegramChatSchema: z.ZodObject<{
|
|
29
|
+
id: z.ZodNumber;
|
|
30
|
+
type: z.ZodEnum<{
|
|
31
|
+
private: "private";
|
|
32
|
+
group: "group";
|
|
33
|
+
supergroup: "supergroup";
|
|
34
|
+
channel: "channel";
|
|
35
|
+
}>;
|
|
36
|
+
title: z.ZodOptional<z.ZodString>;
|
|
37
|
+
username: z.ZodOptional<z.ZodString>;
|
|
38
|
+
is_forum: z.ZodOptional<z.ZodBoolean>;
|
|
39
|
+
}, z.core.$loose>;
|
|
40
|
+
type TelegramChat = z.infer<typeof telegramChatSchema>;
|
|
41
|
+
interface TelegramMessage {
|
|
42
|
+
message_id: number;
|
|
43
|
+
date: number;
|
|
44
|
+
edit_date?: number;
|
|
45
|
+
text?: string;
|
|
46
|
+
from?: TelegramUser;
|
|
47
|
+
sender_chat?: TelegramChat;
|
|
48
|
+
chat: TelegramChat;
|
|
49
|
+
reply_to_message?: TelegramMessage;
|
|
50
|
+
new_chat_members?: TelegramUser[];
|
|
51
|
+
left_chat_member?: TelegramUser;
|
|
52
|
+
entities?: TelegramMessageEntity[];
|
|
53
|
+
[key: string]: unknown;
|
|
54
|
+
}
|
|
55
|
+
declare const telegramUpdateSchema: z.ZodObject<{
|
|
56
|
+
update_id: z.ZodNumber;
|
|
57
|
+
message: z.ZodOptional<z.ZodType<TelegramMessage, unknown, z.core.$ZodTypeInternals<TelegramMessage, unknown>>>;
|
|
58
|
+
edited_message: z.ZodOptional<z.ZodType<TelegramMessage, unknown, z.core.$ZodTypeInternals<TelegramMessage, unknown>>>;
|
|
59
|
+
channel_post: z.ZodOptional<z.ZodType<TelegramMessage, unknown, z.core.$ZodTypeInternals<TelegramMessage, unknown>>>;
|
|
60
|
+
}, z.core.$loose>;
|
|
61
|
+
type TelegramUpdate = z.infer<typeof telegramUpdateSchema>;
|
|
62
|
+
type TelegramUpdateType = "message" | "edited_message" | "channel_post";
|
|
63
|
+
declare const telegramCommandBindingSchema: z.ZodObject<{
|
|
64
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
65
|
+
scopes: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
66
|
+
private: "private";
|
|
67
|
+
group: "group";
|
|
68
|
+
supergroup: "supergroup";
|
|
69
|
+
channel: "channel";
|
|
70
|
+
}>>>;
|
|
71
|
+
}, z.core.$loose>;
|
|
72
|
+
type TelegramCommandBinding = z.infer<typeof telegramCommandBindingSchema>;
|
|
73
|
+
declare const telegramCommandBindingsSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
74
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
75
|
+
scopes: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
76
|
+
private: "private";
|
|
77
|
+
group: "group";
|
|
78
|
+
supergroup: "supergroup";
|
|
79
|
+
channel: "channel";
|
|
80
|
+
}>>>;
|
|
81
|
+
}, z.core.$loose>>;
|
|
82
|
+
type TelegramCommandBindings = z.infer<typeof telegramCommandBindingsSchema>;
|
|
83
|
+
interface TelegramUserSummary {
|
|
84
|
+
id: string;
|
|
85
|
+
username: string | null;
|
|
86
|
+
firstName: string;
|
|
87
|
+
lastName: string | null;
|
|
88
|
+
isBot: boolean;
|
|
89
|
+
languageCode: string | null;
|
|
90
|
+
createdAt: Date;
|
|
91
|
+
updatedAt: Date;
|
|
92
|
+
}
|
|
93
|
+
interface TelegramChatSummary {
|
|
94
|
+
id: string;
|
|
95
|
+
type: TelegramChatType;
|
|
96
|
+
title: string | null;
|
|
97
|
+
username: string | null;
|
|
98
|
+
isForum: boolean;
|
|
99
|
+
commandBindings: TelegramCommandBindings | null;
|
|
100
|
+
createdAt: Date;
|
|
101
|
+
updatedAt: Date;
|
|
102
|
+
}
|
|
103
|
+
interface TelegramChatMemberSummary {
|
|
104
|
+
id: string;
|
|
105
|
+
chatId: string;
|
|
106
|
+
userId: string;
|
|
107
|
+
status: string;
|
|
108
|
+
joinedAt: Date | null;
|
|
109
|
+
leftAt: Date | null;
|
|
110
|
+
user: TelegramUserSummary | null;
|
|
111
|
+
createdAt: Date;
|
|
112
|
+
updatedAt: Date;
|
|
113
|
+
}
|
|
114
|
+
interface TelegramMessageSummary {
|
|
115
|
+
id: string;
|
|
116
|
+
chatId: string;
|
|
117
|
+
fromUserId: string | null;
|
|
118
|
+
senderChatId: string | null;
|
|
119
|
+
replyToMessageId: string | null;
|
|
120
|
+
messageType: TelegramUpdateType;
|
|
121
|
+
text: string | null;
|
|
122
|
+
payload: unknown | null;
|
|
123
|
+
sentAt: Date;
|
|
124
|
+
editedAt: Date | null;
|
|
125
|
+
commandName: string | null;
|
|
126
|
+
fromUser: TelegramUserSummary | null;
|
|
127
|
+
}
|
|
128
|
+
interface TelegramMessageHookPayload {
|
|
129
|
+
updateId: number;
|
|
130
|
+
updateType: TelegramUpdateType;
|
|
131
|
+
messageId: string;
|
|
132
|
+
chatId: string;
|
|
133
|
+
fromUserId: string | null;
|
|
134
|
+
text: string | null;
|
|
135
|
+
commandName: string | null;
|
|
136
|
+
sentAt: Date;
|
|
137
|
+
editedAt: Date | null;
|
|
138
|
+
}
|
|
139
|
+
interface TelegramCommandHookPayload {
|
|
140
|
+
updateId: number;
|
|
141
|
+
messageId: string;
|
|
142
|
+
chatId: string;
|
|
143
|
+
fromUserId: string | null;
|
|
144
|
+
commandName: string;
|
|
145
|
+
args: string;
|
|
146
|
+
raw: string;
|
|
147
|
+
sentAt: Date;
|
|
148
|
+
}
|
|
149
|
+
interface TelegramChatMemberHookPayload {
|
|
150
|
+
updateId: number;
|
|
151
|
+
chatId: string;
|
|
152
|
+
userId: string;
|
|
153
|
+
status: string;
|
|
154
|
+
joinedAt: Date | null;
|
|
155
|
+
leftAt: Date | null;
|
|
156
|
+
}
|
|
157
|
+
type TelegramOutgoingHookAction = "sendMessage" | "editMessageText";
|
|
158
|
+
type TelegramOutgoingHookPayload = {
|
|
159
|
+
action: TelegramOutgoingHookAction;
|
|
160
|
+
payload: Record<string, unknown>;
|
|
161
|
+
};
|
|
162
|
+
type TelegramHooks = {
|
|
163
|
+
onMessageReceived?: (payload: TelegramMessageHookPayload) => Promise<void> | void;
|
|
164
|
+
onCommandMatched?: (payload: TelegramCommandHookPayload) => Promise<void> | void;
|
|
165
|
+
onChatMemberUpdated?: (payload: TelegramChatMemberHookPayload) => Promise<void> | void;
|
|
166
|
+
};
|
|
167
|
+
type TelegramInternalHookPayload = {
|
|
168
|
+
update: TelegramUpdate;
|
|
169
|
+
};
|
|
170
|
+
type TelegramHooksMap = {
|
|
171
|
+
internalProcessUpdate: HookFn<TelegramInternalHookPayload>;
|
|
172
|
+
internalOutgoingMessage: HookFn<TelegramOutgoingHookPayload>;
|
|
173
|
+
onMessageReceived: HookFn<TelegramMessageHookPayload>;
|
|
174
|
+
onCommandMatched: HookFn<TelegramCommandHookPayload>;
|
|
175
|
+
onChatMemberUpdated: HookFn<TelegramChatMemberHookPayload>;
|
|
176
|
+
};
|
|
177
|
+
type TelegramApiResult<T> = {
|
|
178
|
+
ok: true;
|
|
179
|
+
result: T;
|
|
180
|
+
} | {
|
|
181
|
+
ok: false;
|
|
182
|
+
error_code?: number;
|
|
183
|
+
description?: string;
|
|
184
|
+
};
|
|
185
|
+
interface TelegramApi {
|
|
186
|
+
call<T>(method: string, payload: Record<string, unknown>): Promise<TelegramApiResult<T>>;
|
|
187
|
+
sendMessage(payload: Record<string, unknown>): Promise<TelegramApiResult<TelegramMessage>>;
|
|
188
|
+
editMessageText(payload: Record<string, unknown>): Promise<TelegramApiResult<TelegramMessage>>;
|
|
189
|
+
sendChatAction(payload: Record<string, unknown>): Promise<TelegramApiResult<boolean>>;
|
|
190
|
+
}
|
|
191
|
+
type TelegramQueuedResult = {
|
|
192
|
+
ok: true;
|
|
193
|
+
queued: true;
|
|
194
|
+
} | {
|
|
195
|
+
ok: false;
|
|
196
|
+
error_code?: number;
|
|
197
|
+
description?: string;
|
|
198
|
+
};
|
|
199
|
+
type TelegramCommandApiResult<T> = TelegramApiResult<T> | TelegramQueuedResult;
|
|
200
|
+
interface TelegramCommandApi {
|
|
201
|
+
call<T>(method: string, payload: Record<string, unknown>): Promise<TelegramCommandApiResult<T>>;
|
|
202
|
+
sendMessage(payload: Record<string, unknown>): Promise<TelegramQueuedResult>;
|
|
203
|
+
editMessageText(payload: Record<string, unknown>): Promise<TelegramQueuedResult>;
|
|
204
|
+
sendChatAction(payload: Record<string, unknown>): Promise<TelegramApiResult<boolean>>;
|
|
205
|
+
}
|
|
206
|
+
interface TelegramCommandContext {
|
|
207
|
+
updateId: number;
|
|
208
|
+
idempotencyKey: string;
|
|
209
|
+
update: TelegramUpdate;
|
|
210
|
+
message: TelegramMessage;
|
|
211
|
+
chat: TelegramChatSummary;
|
|
212
|
+
fromUser: TelegramUserSummary | null;
|
|
213
|
+
command: {
|
|
214
|
+
name: string;
|
|
215
|
+
args: string;
|
|
216
|
+
raw: string;
|
|
217
|
+
};
|
|
218
|
+
api: TelegramCommandApi;
|
|
219
|
+
handlerTx: HookHandlerTx;
|
|
220
|
+
}
|
|
221
|
+
type TelegramCommandHandler = (ctx: TelegramCommandContext) => Promise<void> | void;
|
|
222
|
+
interface TelegramCommandDefinition {
|
|
223
|
+
name: string;
|
|
224
|
+
description?: string;
|
|
225
|
+
scopes?: TelegramCommandScope[];
|
|
226
|
+
handler: TelegramCommandHandler;
|
|
227
|
+
}
|
|
228
|
+
type TelegramCommandRegistry = Record<string, TelegramCommandDefinition>;
|
|
229
|
+
interface TelegramFragmentConfig {
|
|
230
|
+
botToken: string;
|
|
231
|
+
webhookSecretToken: string;
|
|
232
|
+
botUsername?: string;
|
|
233
|
+
apiBaseUrl?: string;
|
|
234
|
+
commands?: TelegramCommandRegistry;
|
|
235
|
+
hooks?: TelegramHooks;
|
|
236
|
+
}
|
|
237
|
+
type TelegramConfigBuilder = {
|
|
238
|
+
command: (command: TelegramCommandDefinition) => TelegramConfigBuilder;
|
|
239
|
+
build: (overrides?: Partial<TelegramFragmentConfig>) => TelegramFragmentConfig;
|
|
240
|
+
};
|
|
241
|
+
declare function defineCommand(name: string, definition: Omit<TelegramCommandDefinition, "name">): TelegramCommandDefinition;
|
|
242
|
+
declare function createTelegram(baseConfig?: Partial<TelegramFragmentConfig>): TelegramConfigBuilder;
|
|
243
|
+
//#endregion
|
|
244
|
+
export { TelegramApi, TelegramApiResult, TelegramChatMemberHookPayload, TelegramChatMemberSummary, TelegramChatSummary, TelegramChatType, TelegramCommandApi, TelegramCommandApiResult, TelegramCommandBinding, TelegramCommandBindings, TelegramCommandContext, TelegramCommandDefinition, TelegramCommandRegistry, TelegramCommandScope, TelegramConfigBuilder, TelegramFragmentConfig, TelegramHooks, TelegramHooksMap, TelegramMessage, TelegramMessageHookPayload, TelegramMessageSummary, TelegramQueuedResult, TelegramUpdate, TelegramUpdateType, TelegramUser, TelegramUserSummary, createTelegram, defineCommand };
|
|
245
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/types.ts"],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/types.ts
|
|
4
|
+
const telegramChatTypeSchema = z.enum([
|
|
5
|
+
"private",
|
|
6
|
+
"group",
|
|
7
|
+
"supergroup",
|
|
8
|
+
"channel"
|
|
9
|
+
]);
|
|
10
|
+
const telegramMessageEntitySchema = z.object({
|
|
11
|
+
type: z.string(),
|
|
12
|
+
offset: z.number(),
|
|
13
|
+
length: z.number()
|
|
14
|
+
}).loose();
|
|
15
|
+
const telegramUserSchema = z.object({
|
|
16
|
+
id: z.number(),
|
|
17
|
+
is_bot: z.boolean().optional(),
|
|
18
|
+
first_name: z.string(),
|
|
19
|
+
last_name: z.string().optional(),
|
|
20
|
+
username: z.string().optional(),
|
|
21
|
+
language_code: z.string().optional()
|
|
22
|
+
}).loose();
|
|
23
|
+
const telegramChatSchema = z.object({
|
|
24
|
+
id: z.number(),
|
|
25
|
+
type: telegramChatTypeSchema,
|
|
26
|
+
title: z.string().optional(),
|
|
27
|
+
username: z.string().optional(),
|
|
28
|
+
is_forum: z.boolean().optional()
|
|
29
|
+
}).loose();
|
|
30
|
+
const telegramMessageSchema = z.lazy(() => z.object({
|
|
31
|
+
message_id: z.number(),
|
|
32
|
+
date: z.number(),
|
|
33
|
+
edit_date: z.number().optional(),
|
|
34
|
+
text: z.string().optional(),
|
|
35
|
+
from: telegramUserSchema.optional(),
|
|
36
|
+
sender_chat: telegramChatSchema.optional(),
|
|
37
|
+
chat: telegramChatSchema,
|
|
38
|
+
reply_to_message: telegramMessageSchema.optional(),
|
|
39
|
+
new_chat_members: z.array(telegramUserSchema).optional(),
|
|
40
|
+
left_chat_member: telegramUserSchema.optional(),
|
|
41
|
+
entities: z.array(telegramMessageEntitySchema).optional()
|
|
42
|
+
}).loose());
|
|
43
|
+
const telegramUpdateSchema = z.object({
|
|
44
|
+
update_id: z.number(),
|
|
45
|
+
message: telegramMessageSchema.optional(),
|
|
46
|
+
edited_message: telegramMessageSchema.optional(),
|
|
47
|
+
channel_post: telegramMessageSchema.optional()
|
|
48
|
+
}).loose();
|
|
49
|
+
const telegramCommandBindingSchema = z.object({
|
|
50
|
+
enabled: z.boolean().optional(),
|
|
51
|
+
scopes: z.array(telegramChatTypeSchema).optional()
|
|
52
|
+
}).loose();
|
|
53
|
+
const telegramCommandBindingsSchema = z.record(z.string(), telegramCommandBindingSchema);
|
|
54
|
+
function defineCommand(name, definition) {
|
|
55
|
+
return {
|
|
56
|
+
name,
|
|
57
|
+
...definition
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function createTelegram(baseConfig = {}) {
|
|
61
|
+
const commands = /* @__PURE__ */ new Map();
|
|
62
|
+
if (baseConfig.commands) for (const command of Object.values(baseConfig.commands)) commands.set(command.name, command);
|
|
63
|
+
const builder = {
|
|
64
|
+
command(command) {
|
|
65
|
+
commands.set(command.name, command);
|
|
66
|
+
return builder;
|
|
67
|
+
},
|
|
68
|
+
build(overrides = {}) {
|
|
69
|
+
const baseCommands = baseConfig.commands ?? {};
|
|
70
|
+
const internalCommands = Object.fromEntries(commands);
|
|
71
|
+
const overrideCommands = overrides.commands ?? {};
|
|
72
|
+
const mergedCommands = {
|
|
73
|
+
...baseCommands,
|
|
74
|
+
...internalCommands,
|
|
75
|
+
...overrideCommands
|
|
76
|
+
};
|
|
77
|
+
const resolved = {
|
|
78
|
+
...baseConfig,
|
|
79
|
+
...overrides,
|
|
80
|
+
commands: mergedCommands
|
|
81
|
+
};
|
|
82
|
+
if (!resolved.botToken) throw new Error("Telegram fragment requires botToken");
|
|
83
|
+
if (!resolved.webhookSecretToken) throw new Error("Telegram fragment requires webhookSecretToken");
|
|
84
|
+
return resolved;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
return builder;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
export { createTelegram, defineCommand, telegramChatTypeSchema, telegramCommandBindingsSchema, telegramMessageSchema, telegramUpdateSchema };
|
|
92
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../src/types.ts"],"sourcesContent":["import { z } from \"zod\";\n\nimport type { HookFn, HookHandlerTx } from \"@fragno-dev/db\";\n\nexport const telegramChatTypeSchema = z.enum([\"private\", \"group\", \"supergroup\", \"channel\"]);\nexport type TelegramChatType = z.infer<typeof telegramChatTypeSchema>;\nexport type TelegramCommandScope = TelegramChatType;\n\nexport const telegramMessageEntitySchema = z\n .object({\n type: z.string(),\n offset: z.number(),\n length: z.number(),\n })\n .loose();\nexport type TelegramMessageEntity = z.infer<typeof telegramMessageEntitySchema>;\n\nexport const telegramUserSchema = z\n .object({\n id: z.number(),\n is_bot: z.boolean().optional(),\n first_name: z.string(),\n last_name: z.string().optional(),\n username: z.string().optional(),\n language_code: z.string().optional(),\n })\n .loose();\nexport type TelegramUser = z.infer<typeof telegramUserSchema>;\n\nexport const telegramChatSchema = z\n .object({\n id: z.number(),\n type: telegramChatTypeSchema,\n title: z.string().optional(),\n username: z.string().optional(),\n is_forum: z.boolean().optional(),\n })\n .loose();\nexport type TelegramChat = z.infer<typeof telegramChatSchema>;\n\nexport interface TelegramMessage {\n message_id: number;\n date: number;\n edit_date?: number;\n text?: string;\n from?: TelegramUser;\n sender_chat?: TelegramChat;\n chat: TelegramChat;\n reply_to_message?: TelegramMessage;\n new_chat_members?: TelegramUser[];\n left_chat_member?: TelegramUser;\n entities?: TelegramMessageEntity[];\n [key: string]: unknown;\n}\n\nexport const telegramMessageSchema: z.ZodType<TelegramMessage> = z.lazy(() =>\n z\n .object({\n message_id: z.number(),\n date: z.number(),\n edit_date: z.number().optional(),\n text: z.string().optional(),\n from: telegramUserSchema.optional(),\n sender_chat: telegramChatSchema.optional(),\n chat: telegramChatSchema,\n reply_to_message: telegramMessageSchema.optional(),\n new_chat_members: z.array(telegramUserSchema).optional(),\n left_chat_member: telegramUserSchema.optional(),\n entities: z.array(telegramMessageEntitySchema).optional(),\n })\n .loose(),\n);\n\nexport const telegramUpdateSchema = z\n .object({\n update_id: z.number(),\n message: telegramMessageSchema.optional(),\n edited_message: telegramMessageSchema.optional(),\n channel_post: telegramMessageSchema.optional(),\n })\n .loose();\nexport type TelegramUpdate = z.infer<typeof telegramUpdateSchema>;\n\nexport type TelegramUpdateType = \"message\" | \"edited_message\" | \"channel_post\";\n\nexport const telegramCommandBindingSchema = z\n .object({\n enabled: z.boolean().optional(),\n scopes: z.array(telegramChatTypeSchema).optional(),\n })\n .loose();\nexport type TelegramCommandBinding = z.infer<typeof telegramCommandBindingSchema>;\n\nexport const telegramCommandBindingsSchema = z.record(z.string(), telegramCommandBindingSchema);\nexport type TelegramCommandBindings = z.infer<typeof telegramCommandBindingsSchema>;\n\nexport interface TelegramUserSummary {\n id: string;\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\nexport interface TelegramChatSummary {\n id: string;\n type: TelegramChatType;\n title: string | null;\n username: string | null;\n isForum: boolean;\n commandBindings: TelegramCommandBindings | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface TelegramChatMemberSummary {\n id: string;\n chatId: string;\n userId: string;\n status: string;\n joinedAt: Date | null;\n leftAt: Date | null;\n user: TelegramUserSummary | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface TelegramMessageSummary {\n id: string;\n chatId: string;\n fromUserId: string | null;\n senderChatId: string | null;\n replyToMessageId: string | null;\n messageType: TelegramUpdateType;\n text: string | null;\n payload: unknown | null;\n sentAt: Date;\n editedAt: Date | null;\n commandName: string | null;\n fromUser: TelegramUserSummary | null;\n}\n\nexport interface TelegramMessageHookPayload {\n updateId: number;\n updateType: TelegramUpdateType;\n messageId: string;\n chatId: string;\n fromUserId: string | null;\n text: string | null;\n commandName: string | null;\n sentAt: Date;\n editedAt: Date | null;\n}\n\nexport interface TelegramCommandHookPayload {\n updateId: number;\n messageId: string;\n chatId: string;\n fromUserId: string | null;\n commandName: string;\n args: string;\n raw: string;\n sentAt: Date;\n}\n\nexport interface TelegramChatMemberHookPayload {\n updateId: number;\n chatId: string;\n userId: string;\n status: string;\n joinedAt: Date | null;\n leftAt: Date | null;\n}\n\nexport type TelegramOutgoingHookAction = \"sendMessage\" | \"editMessageText\";\n\nexport type TelegramOutgoingHookPayload = {\n action: TelegramOutgoingHookAction;\n payload: Record<string, unknown>;\n};\n\nexport type TelegramHooks = {\n onMessageReceived?: (payload: TelegramMessageHookPayload) => Promise<void> | void;\n onCommandMatched?: (payload: TelegramCommandHookPayload) => Promise<void> | void;\n onChatMemberUpdated?: (payload: TelegramChatMemberHookPayload) => Promise<void> | void;\n};\n\nexport type TelegramInternalHookPayload = {\n update: TelegramUpdate;\n};\n\nexport type TelegramHooksMap = {\n internalProcessUpdate: HookFn<TelegramInternalHookPayload>;\n internalOutgoingMessage: HookFn<TelegramOutgoingHookPayload>;\n onMessageReceived: HookFn<TelegramMessageHookPayload>;\n onCommandMatched: HookFn<TelegramCommandHookPayload>;\n onChatMemberUpdated: HookFn<TelegramChatMemberHookPayload>;\n};\n\nexport type TelegramApiResult<T> =\n | { ok: true; result: T }\n | { ok: false; error_code?: number; description?: string };\n\nexport interface TelegramApi {\n call<T>(method: string, payload: Record<string, unknown>): Promise<TelegramApiResult<T>>;\n sendMessage(payload: Record<string, unknown>): Promise<TelegramApiResult<TelegramMessage>>;\n editMessageText(payload: Record<string, unknown>): Promise<TelegramApiResult<TelegramMessage>>;\n sendChatAction(payload: Record<string, unknown>): Promise<TelegramApiResult<boolean>>;\n}\n\nexport type TelegramQueuedResult =\n | { ok: true; queued: true }\n | { ok: false; error_code?: number; description?: string };\n\nexport type TelegramCommandApiResult<T> = TelegramApiResult<T> | TelegramQueuedResult;\n\nexport interface TelegramCommandApi {\n call<T>(method: string, payload: Record<string, unknown>): Promise<TelegramCommandApiResult<T>>;\n sendMessage(payload: Record<string, unknown>): Promise<TelegramQueuedResult>;\n editMessageText(payload: Record<string, unknown>): Promise<TelegramQueuedResult>;\n sendChatAction(payload: Record<string, unknown>): Promise<TelegramApiResult<boolean>>;\n}\n\nexport interface TelegramCommandContext {\n updateId: number;\n idempotencyKey: string;\n update: TelegramUpdate;\n message: TelegramMessage;\n chat: TelegramChatSummary;\n fromUser: TelegramUserSummary | null;\n command: {\n name: string;\n args: string;\n raw: string;\n };\n api: TelegramCommandApi;\n handlerTx: HookHandlerTx;\n}\n\nexport type TelegramCommandHandler = (ctx: TelegramCommandContext) => Promise<void> | void;\n\nexport interface TelegramCommandDefinition {\n name: string;\n description?: string;\n scopes?: TelegramCommandScope[];\n handler: TelegramCommandHandler;\n}\n\nexport type TelegramCommandRegistry = Record<string, TelegramCommandDefinition>;\n\nexport interface TelegramFragmentConfig {\n botToken: string;\n webhookSecretToken: string;\n botUsername?: string;\n apiBaseUrl?: string;\n commands?: TelegramCommandRegistry;\n hooks?: TelegramHooks;\n}\n\nexport type TelegramConfigBuilder = {\n command: (command: TelegramCommandDefinition) => TelegramConfigBuilder;\n build: (overrides?: Partial<TelegramFragmentConfig>) => TelegramFragmentConfig;\n};\n\nexport function defineCommand(\n name: string,\n definition: Omit<TelegramCommandDefinition, \"name\">,\n): TelegramCommandDefinition {\n return {\n name,\n ...definition,\n };\n}\n\nexport function createTelegram(\n baseConfig: Partial<TelegramFragmentConfig> = {},\n): TelegramConfigBuilder {\n const commands = new Map<string, TelegramCommandDefinition>();\n\n if (baseConfig.commands) {\n for (const command of Object.values(baseConfig.commands)) {\n commands.set(command.name, command);\n }\n }\n\n const builder: TelegramConfigBuilder = {\n command(command: TelegramCommandDefinition) {\n commands.set(command.name, command);\n return builder;\n },\n build(overrides: Partial<TelegramFragmentConfig> = {}) {\n const baseCommands = baseConfig.commands ?? {};\n const internalCommands = Object.fromEntries(commands);\n const overrideCommands = overrides.commands ?? {};\n const mergedCommands = {\n ...baseCommands,\n ...internalCommands,\n ...overrideCommands,\n };\n const resolved = {\n ...baseConfig,\n ...overrides,\n commands: mergedCommands,\n } as TelegramFragmentConfig;\n\n if (!resolved.botToken) {\n throw new Error(\"Telegram fragment requires botToken\");\n }\n if (!resolved.webhookSecretToken) {\n throw new Error(\"Telegram fragment requires webhookSecretToken\");\n }\n\n return resolved;\n },\n };\n\n return builder;\n}\n"],"mappings":";;;AAIA,MAAa,yBAAyB,EAAE,KAAK;CAAC;CAAW;CAAS;CAAc;CAAU,CAAC;AAI3F,MAAa,8BAA8B,EACxC,OAAO;CACN,MAAM,EAAE,QAAQ;CAChB,QAAQ,EAAE,QAAQ;CAClB,QAAQ,EAAE,QAAQ;CACnB,CAAC,CACD,OAAO;AAGV,MAAa,qBAAqB,EAC/B,OAAO;CACN,IAAI,EAAE,QAAQ;CACd,QAAQ,EAAE,SAAS,CAAC,UAAU;CAC9B,YAAY,EAAE,QAAQ;CACtB,WAAW,EAAE,QAAQ,CAAC,UAAU;CAChC,UAAU,EAAE,QAAQ,CAAC,UAAU;CAC/B,eAAe,EAAE,QAAQ,CAAC,UAAU;CACrC,CAAC,CACD,OAAO;AAGV,MAAa,qBAAqB,EAC/B,OAAO;CACN,IAAI,EAAE,QAAQ;CACd,MAAM;CACN,OAAO,EAAE,QAAQ,CAAC,UAAU;CAC5B,UAAU,EAAE,QAAQ,CAAC,UAAU;CAC/B,UAAU,EAAE,SAAS,CAAC,UAAU;CACjC,CAAC,CACD,OAAO;AAkBV,MAAa,wBAAoD,EAAE,WACjE,EACG,OAAO;CACN,YAAY,EAAE,QAAQ;CACtB,MAAM,EAAE,QAAQ;CAChB,WAAW,EAAE,QAAQ,CAAC,UAAU;CAChC,MAAM,EAAE,QAAQ,CAAC,UAAU;CAC3B,MAAM,mBAAmB,UAAU;CACnC,aAAa,mBAAmB,UAAU;CAC1C,MAAM;CACN,kBAAkB,sBAAsB,UAAU;CAClD,kBAAkB,EAAE,MAAM,mBAAmB,CAAC,UAAU;CACxD,kBAAkB,mBAAmB,UAAU;CAC/C,UAAU,EAAE,MAAM,4BAA4B,CAAC,UAAU;CAC1D,CAAC,CACD,OAAO,CACX;AAED,MAAa,uBAAuB,EACjC,OAAO;CACN,WAAW,EAAE,QAAQ;CACrB,SAAS,sBAAsB,UAAU;CACzC,gBAAgB,sBAAsB,UAAU;CAChD,cAAc,sBAAsB,UAAU;CAC/C,CAAC,CACD,OAAO;AAKV,MAAa,+BAA+B,EACzC,OAAO;CACN,SAAS,EAAE,SAAS,CAAC,UAAU;CAC/B,QAAQ,EAAE,MAAM,uBAAuB,CAAC,UAAU;CACnD,CAAC,CACD,OAAO;AAGV,MAAa,gCAAgC,EAAE,OAAO,EAAE,QAAQ,EAAE,6BAA6B;AA8K/F,SAAgB,cACd,MACA,YAC2B;AAC3B,QAAO;EACL;EACA,GAAG;EACJ;;AAGH,SAAgB,eACd,aAA8C,EAAE,EACzB;CACvB,MAAM,2BAAW,IAAI,KAAwC;AAE7D,KAAI,WAAW,SACb,MAAK,MAAM,WAAW,OAAO,OAAO,WAAW,SAAS,CACtD,UAAS,IAAI,QAAQ,MAAM,QAAQ;CAIvC,MAAM,UAAiC;EACrC,QAAQ,SAAoC;AAC1C,YAAS,IAAI,QAAQ,MAAM,QAAQ;AACnC,UAAO;;EAET,MAAM,YAA6C,EAAE,EAAE;GACrD,MAAM,eAAe,WAAW,YAAY,EAAE;GAC9C,MAAM,mBAAmB,OAAO,YAAY,SAAS;GACrD,MAAM,mBAAmB,UAAU,YAAY,EAAE;GACjD,MAAM,iBAAiB;IACrB,GAAG;IACH,GAAG;IACH,GAAG;IACJ;GACD,MAAM,WAAW;IACf,GAAG;IACH,GAAG;IACH,UAAU;IACX;AAED,OAAI,CAAC,SAAS,SACZ,OAAM,IAAI,MAAM,sCAAsC;AAExD,OAAI,CAAC,SAAS,mBACZ,OAAM,IAAI,MAAM,gDAAgD;AAGlE,UAAO;;EAEV;AAED,QAAO"}
|