├── .vscode └── settings.json ├── helpers ├── utils.ts ├── context.ts └── session.ts ├── deno.jsonc ├── handlers ├── start.ts ├── help.ts ├── stats.ts ├── mod.ts ├── print.ts ├── updates.ts └── navigation.ts ├── deps.ts ├── mod.ts ├── LICENSE ├── bot.ts ├── README.md └── deno.lock /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enable": true, 3 | "deno.lint": true, 4 | "deno.unstable": false 5 | } 6 | -------------------------------------------------------------------------------- /helpers/utils.ts: -------------------------------------------------------------------------------- 1 | export function escapeHtml(str: string) { 2 | return str 3 | .replace(/&/g, "&") 4 | .replace(//g, ">"); 6 | } 7 | -------------------------------------------------------------------------------- /helpers/context.ts: -------------------------------------------------------------------------------- 1 | import { SessionData } from "./session.ts"; 2 | import { BaseContext, SessionFlavor } from "../deps.ts"; 3 | 4 | export type Context = 5 | & BaseContext 6 | & SessionFlavor; 7 | -------------------------------------------------------------------------------- /deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "fmt": { 3 | "useTabs": false, 4 | "lineWidth": 80, 5 | "indentWidth": 4, 6 | "semiColons": true, 7 | "singleQuote": false 8 | }, 9 | "unstable": [ 10 | "kv" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /helpers/session.ts: -------------------------------------------------------------------------------- 1 | import { DenoKVAdapter } from "../deps.ts"; 2 | 3 | export interface SessionData { 4 | json_showed: number; 5 | } 6 | 7 | export function initial(): SessionData { 8 | return { json_showed: 0 }; 9 | } 10 | 11 | export const kv = await Deno.openKv(); 12 | 13 | export const storage = new DenoKVAdapter(kv, ["users"]); 14 | -------------------------------------------------------------------------------- /handlers/start.ts: -------------------------------------------------------------------------------- 1 | import { Composer } from "../deps.ts"; 2 | import { Context } from "../helpers/context.ts"; 3 | 4 | export const start = new Composer(); 5 | 6 | start.command("start", async (ctx) => { 7 | await ctx.reply( 8 | "👋🏼 Hiya! I can show you the JSON data of any message. By @dcdunkan from @dcbots.", 9 | ); 10 | }); 11 | -------------------------------------------------------------------------------- /handlers/help.ts: -------------------------------------------------------------------------------- 1 | import { Composer } from "../deps.ts"; 2 | import { Context } from "../helpers/context.ts"; 3 | 4 | export const help = new Composer(); 5 | 6 | help.command("help", async (ctx) => { 7 | await ctx.reply(`Send or forward me a message :) 8 | 9 | See the README in the GitHub repository: github.com/dcdunkan/show-json-bot`); 10 | }); 11 | -------------------------------------------------------------------------------- /handlers/stats.ts: -------------------------------------------------------------------------------- 1 | import { Composer } from "../deps.ts"; 2 | import { Context } from "../helpers/context.ts"; 3 | 4 | export const stats = new Composer(); 5 | 6 | stats.command("stats", async (ctx) => { 7 | const jsonShowed = new Intl 8 | .NumberFormat("en-US", { useGrouping: true }) 9 | .format(ctx.session.json_showed); 10 | 11 | await ctx.reply(`I have showed you ${jsonShowed} JSON data so far!`); 12 | }); 13 | -------------------------------------------------------------------------------- /handlers/mod.ts: -------------------------------------------------------------------------------- 1 | import { Composer } from "../deps.ts"; 2 | import { Context } from "../helpers/context.ts"; 3 | 4 | import { updates } from "./updates.ts"; 5 | import { start } from "./start.ts"; 6 | import { print } from "./print.ts"; 7 | import { navigation } from "./navigation.ts"; 8 | import { stats } from "./stats.ts"; 9 | import { help } from "./help.ts"; 10 | 11 | export const handlers = new Composer(); 12 | 13 | handlers 14 | .use(updates) 15 | .use(start) 16 | .use(print) 17 | .use(navigation) 18 | .use(stats) 19 | .use(help); 20 | -------------------------------------------------------------------------------- /handlers/print.ts: -------------------------------------------------------------------------------- 1 | import { Composer, InlineKeyboardButton } from "../deps.ts"; 2 | import { Context } from "../helpers/context.ts"; 3 | 4 | export const print = new Composer(); 5 | 6 | print.callbackQuery(/print-(.+)-(.+)/, async (ctx) => { 7 | await ctx.answerCallbackQuery(); 8 | 9 | const keyboard = ctx.callbackQuery.message?.reply_markup?.inline_keyboard; 10 | if (!keyboard) return; 11 | 12 | for (const row of keyboard) { 13 | for (const btn of row as InlineKeyboardButton.CallbackButton[]) { 14 | if (btn.callback_data === ctx.callbackQuery.data) { 15 | await ctx.reply(`${btn.text}`); 16 | break; 17 | } 18 | } 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /deps.ts: -------------------------------------------------------------------------------- 1 | export { 2 | Bot, 3 | Composer, 4 | Context as BaseContext, 5 | GrammyError, 6 | HttpError, 7 | InlineKeyboard, 8 | InputFile, 9 | session, 10 | type SessionFlavor, 11 | webhookCallback, 12 | } from "https://deno.land/x/grammy@v1.31.3/mod.ts"; 13 | export { 14 | DenoKVAdapter, 15 | } from "https://raw.githubusercontent.com/grammyjs/storages/5eda80d5f0dc4232c1affdda6aada6cc0ca3160d/packages/denokv/src/mod.ts"; 16 | 17 | export type { 18 | InlineKeyboardButton, 19 | } from "https://deno.land/x/grammy@v1.31.3/types.ts"; 20 | 21 | import type { Message } from "https://deno.land/x/grammy@v1.31.3/types.ts"; 22 | 23 | type ReplyMessage = NonNullable; 24 | 25 | export type { Message, ReplyMessage }; 26 | -------------------------------------------------------------------------------- /mod.ts: -------------------------------------------------------------------------------- 1 | import { bot } from "./bot.ts"; 2 | import { webhookCallback } from "./deps.ts"; 3 | 4 | if (Deno.env.get("DEBUG") != null) { 5 | bot.start({ 6 | drop_pending_updates: true, 7 | onStart: (info) => console.log(info.username, "started."), 8 | }); 9 | } else { 10 | const SECRET_PATHNAME = "/" + bot.token; 11 | const handleUpdate = webhookCallback(bot, "std/http"); 12 | await bot.init(); 13 | Deno.serve({ 14 | onError: (error) => { 15 | console.error(error); 16 | return new Response("Internal Server Error", { status: 500 }); 17 | }, 18 | }, async (req) => { 19 | const { pathname } = new URL(req.url); 20 | if (req.method == "POST" && pathname === SECRET_PATHNAME) { 21 | return await handleUpdate(req); 22 | } 23 | return Response.redirect(`https://t.me/${bot.botInfo.username}`); 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-2024 dcdunkan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bot.ts: -------------------------------------------------------------------------------- 1 | import { Bot, GrammyError, HttpError, session } from "./deps.ts"; 2 | import { Context } from "./helpers/context.ts"; 3 | import { initial, storage } from "./helpers/session.ts"; 4 | import { handlers } from "./handlers/mod.ts"; 5 | 6 | const BOT_TOKEN = Deno.env.get("BOT_TOKEN"); 7 | if (BOT_TOKEN == null) { 8 | throw new Error("Missing environment variable: BOT_TOKEN"); 9 | } 10 | 11 | export const bot = new Bot(BOT_TOKEN); 12 | 13 | bot.use(session({ initial, storage })); 14 | 15 | bot.api.config.use((prev, method, payload) => 16 | prev(method, { 17 | ...payload, 18 | parse_mode: "HTML", 19 | disable_web_page_preview: true, 20 | }) 21 | ); 22 | 23 | bot.use(handlers); 24 | 25 | bot.catch(({ ctx, error }) => { 26 | console.error(`Error while handling update ${ctx.update.update_id}:`); 27 | if (error instanceof GrammyError) { 28 | console.error("Error in request:", error.description); 29 | } else if (error instanceof HttpError) { 30 | console.error("Could not contact Telegram:"); 31 | } else { 32 | console.error("Unknown error:"); 33 | } 34 | console.log(error); 35 | }); 36 | -------------------------------------------------------------------------------- /handlers/updates.ts: -------------------------------------------------------------------------------- 1 | import { Context } from "../helpers/context.ts"; 2 | import { Composer, InlineKeyboard } from "../deps.ts"; 3 | import { escapeHtml } from "../helpers/utils.ts"; 4 | 5 | export const updates = new Composer(); 6 | 7 | updates.use(async (ctx, next) => { 8 | if (ctx.chat?.type !== "private") return; 9 | if (ctx.callbackQuery) return await next(); 10 | if (!ctx.message && !ctx.editedMessage) return; 11 | 12 | const data = JSON.stringify(ctx.update, undefined, 2); 13 | const escaped = escapeHtml(data); 14 | const total_messages = Math.ceil(escaped.length / 4096); 15 | 16 | for (let i = 1; i <= total_messages; i++) { 17 | await ctx.reply( 18 | `
${
19 |                 escapeHtml(data.substring((i - 1) * 4096, i * 4096))
20 |             }
`, 21 | { 22 | reply_parameters: { 23 | allow_sending_without_reply: true, 24 | message_id: ctx.msgId || 0, 25 | }, 26 | link_preview_options: { 27 | is_disabled: true, 28 | }, 29 | }, 30 | ); 31 | } 32 | 33 | const keyboard = new InlineKeyboard(); 34 | const pairs = Object.entries(ctx.update); 35 | 36 | for (const pair of pairs) { 37 | // => update_id, (message | edited_message) 38 | if (typeof pair[1] === "object") { 39 | keyboard 40 | .text(pair[0], `print-key-${pair[0]}`) 41 | .text("Object 📂", `go-${pair[0]}-1`); 42 | } else { 43 | keyboard 44 | .text(pair[0], `print-key-${pair[0]}`) 45 | .text(pair[1], `print-value-${pair[0]}`); 46 | } 47 | keyboard.row(); 48 | } 49 | 50 | await ctx.reply(`update_id: ${ctx.update.update_id}\nupdate`, { 51 | reply_markup: keyboard, 52 | reply_parameters: { 53 | allow_sending_without_reply: true, 54 | message_id: ctx.msgId || 0, 55 | }, 56 | link_preview_options: { 57 | is_disabled: true, 58 | }, 59 | }); 60 | 61 | ctx.session.json_showed++; 62 | 63 | await next(); 64 | }); 65 | -------------------------------------------------------------------------------- /handlers/navigation.ts: -------------------------------------------------------------------------------- 1 | // Please, DO NOT touch this thing, -- it somehow works, you know! 2 | import { Context } from "../helpers/context.ts"; 3 | import { Composer, InlineKeyboard, Message, ReplyMessage } from "../deps.ts"; 4 | 5 | export const navigation = new Composer(); 6 | 7 | navigation.callbackQuery(/go-(.+)-(.+)/, async (ctx) => { 8 | if (!ctx.match || !ctx.callbackQuery.message?.text) { 9 | return await ctx.answerCallbackQuery("Invalid query"); 10 | } 11 | 12 | await ctx.answerCallbackQuery(); 13 | const destinationKey = ctx.match[1] as keyof ReplyMessage; 14 | const destinationIndex = parseInt(ctx.match[2]); 15 | const message = ctx.callbackQuery.message.text.split("\n"); 16 | const update_id = message[0].split(": ")[1]; 17 | 18 | // [0: "update", 1: "message", 2: "chat", ...] 19 | const directions = message[1].split(" / ") as Array< 20 | keyof ReplyMessage | "message" 21 | >; 22 | 23 | let toGoBack = directions[directions.length - 1]; 24 | if (destinationIndex === directions.length - 2) { 25 | directions.splice(directions.length - 2, 2); 26 | toGoBack = directions[directions.length - 1]; 27 | } 28 | 29 | const keyboard = new InlineKeyboard(); 30 | if (destinationIndex > 1) { 31 | keyboard 32 | .text("⤴️", `go-${toGoBack}-${destinationIndex - 1}`) 33 | .text("‏‏‎ ‎", "do-nothing") 34 | .row(); 35 | } 36 | 37 | directions.push(destinationKey); 38 | if (!toGoBack) return await ctx.answerCallbackQuery("Can't go back :("); 39 | 40 | let path = ctx.callbackQuery.message.reply_to_message as ReplyMessage & { 41 | message: Message; 42 | } & undefined; 43 | 44 | for (let i = 2; i < directions.length; i++) path = path[directions[i]]; 45 | 46 | for (const pair of Object.entries(path)) { 47 | keyboard.text(pair[0], `print-key-${pair[0]}`); 48 | typeof pair[1] == "object" 49 | ? keyboard.text( 50 | "Object 📂", 51 | `go-${pair[0]}-${destinationIndex + 1}`, 52 | ) 53 | : keyboard.text(`${pair[1]}`, `print-value-${pair[0]}`); 54 | keyboard.row(); 55 | } 56 | 57 | await ctx.editMessageText( 58 | `update_id: ${update_id} 59 | ${directions.join(" / ")}`, 60 | { reply_markup: keyboard }, 61 | ); 62 | }); 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Show JSON Bot

2 | 3 | ### Try the running bot here: [Show JSON Bot](https://telegram.me/jsoonbot) 4 | 5 | A simple Telegram Bot to show JSON data of Telegram messages. The JSON data is 6 | the updates that Telegram sent to the bot. The bot also provides an UI to 7 | navigate through the JSON object. The workflow is highly inspired by 8 | [JSONShowBot](https://telegram.me/JSONShowBot) which is **NOT** working as of 9 | May 2, 2022 (Still a nope in Nov, 2024). 10 | 11 | Re-written in [TypeScript](https://typescriptlang.org/) and now it runs on 12 | [Deno](https://deno.land/). 13 | 14 | - [Built Using](#built-using) 15 | - [Setup](#setup) › [Running Locally](#running-locally) 16 | - [Setup](#setup) › [Deno Deploy](#deno-deploy) 17 | - [Setup](#setup) › [Environment Variables](#environment-variables) 18 | 19 | This is a re-write. See the old version 20 | [here](https://github.com/dcdunkan/show-json-bot/tree/node). 21 | 22 | ## Built Using 23 | 24 | Thanks to these tools and libraries. 25 | 26 | 1. [grammY](https://grammy.dev) - The Telegram Bot Framework. 27 | 2. [Deno KV](https://deno.com/kv) - KV Database. 28 | 29 | ## Setup 30 | 31 | ### Running Locally 32 | 33 | Make sure you have installed [Deno CLI](https://deno.land/). 34 | 35 | - Clone the repository. 36 | ```bash 37 | git clone https://github.com/dcdunkan/show-json-bot.git 38 | ``` 39 | - Change directory (`cd`) to the cloned repository. 40 | - Run the bot using the command below. 41 | ```bash 42 | DEBUG=1 BOT_TOKEN="" deno -E=BOT_TOKEN,DEBUG -N=api.telegram.org -I mod.ts 43 | ``` 44 | 45 | See the list of [environment variables](#environment-variables). 46 | 47 | **Required permissions** 48 | 49 | - `net` - To communicate with Telegram servers and receive updates. 50 | - `env` - To access environment variables. 51 | 52 | If everything is done correct, you should see "(Username) started" in your 53 | console. 54 | 55 | ### Deno Deploy 56 | 57 | The working bot, [@jsoonbot](https://telegram.me/jsoonbot) is currently deployed 58 | on **[Deno Deploy](https://deno.com/deploy)**. 59 | 60 | After deploying you will get a link to your application, in the format 61 | `https://.deno.dev/`. 62 | 63 | Open a browser and go to the link down below. 64 | 65 | - Replace the `` with your `BOT_TOKEN`. 66 | - Replace `` with the link to your application. 67 | 68 | `https://api.telegram.org/bot/setWebhook?url=/` 69 | 70 | This will set the bot's webhook to the deployed application, so that Telegram 71 | will sent further updates to there. 72 | 73 | ### Environment Variables 74 | 75 | | Variable | Required? | Description | 76 | | ----------- | --------- | ------------------------------------------------------------------------------ | 77 | | `DEBUG` | No. | If not set, the bot would run in the webhook mode. Set to enable long polling. | 78 | | `BOT_TOKEN` | **Yes.** | The API token of the Bot. Chat with https://t.me/BotFather to get one. | 79 | 80 | ## License 81 | 82 | This application is licensed under the MIT License. See the LICENSE file for 83 | more information on copying and distributing this piece of software. 84 | 85 | ## Contributing 86 | 87 | Feel free to contribute! And if you are having issues or if you want suggest 88 | something, please open an issue here: 89 | [dcdunkan/show-json-bot/issues](https://github.com/dcdunkan/show-json-bot/issues). 90 | Or, open a [PQ](https://telegram.me/grammyjs/34358)! 91 | 92 | --- 93 | 94 |

95 | Made with ❤️ and ☕
96 | 97 | channel ~ 98 | public instance bot 99 | 100 |

101 | -------------------------------------------------------------------------------- /deno.lock: -------------------------------------------------------------------------------- 1 | { 2 | "version": "4", 3 | "specifiers": { 4 | "jsr:@kitsonk/kv-toolbox@*": "0.22.0", 5 | "jsr:@std/assert@1": "1.0.6", 6 | "jsr:@std/bytes@1": "1.0.2", 7 | "jsr:@std/collections@*": "1.0.9", 8 | "jsr:@std/crypto@1": "1.0.3", 9 | "jsr:@std/encoding@1": "1.0.5", 10 | "jsr:@std/media-types@1": "1.1.0" 11 | }, 12 | "jsr": { 13 | "@kitsonk/kv-toolbox@0.22.0": { 14 | "integrity": "7cb715760b3397c3c34c94666e1964ba6c62661fe8ceda9dc575a63925c9e731", 15 | "dependencies": [ 16 | "jsr:@std/assert", 17 | "jsr:@std/bytes", 18 | "jsr:@std/crypto", 19 | "jsr:@std/encoding", 20 | "jsr:@std/media-types" 21 | ] 22 | }, 23 | "@std/assert@1.0.6": { 24 | "integrity": "1904c05806a25d94fe791d6d883b685c9e2dcd60e4f9fc30f4fc5cf010c72207" 25 | }, 26 | "@std/bytes@1.0.2": { 27 | "integrity": "fbdee322bbd8c599a6af186a1603b3355e59a5fb1baa139f8f4c3c9a1b3e3d57" 28 | }, 29 | "@std/collections@1.0.9": { 30 | "integrity": "4f58104ead08a04a2199374247f07befe50ba01d9cca8cbb23ab9a0419921e71" 31 | }, 32 | "@std/crypto@1.0.3": { 33 | "integrity": "a2a32f51ddef632d299e3879cd027c630dcd4d1d9a5285d6e6788072f4e51e7f" 34 | }, 35 | "@std/encoding@1.0.5": { 36 | "integrity": "ecf363d4fc25bd85bd915ff6733a7e79b67e0e7806334af15f4645c569fefc04" 37 | }, 38 | "@std/media-types@1.1.0": { 39 | "integrity": "c9d093f0c05c3512932b330e3cc1fe1d627b301db33a4c2c2185c02471d6eaa4" 40 | } 41 | }, 42 | "remote": { 43 | "https://cdn.skypack.dev/-/debug@v4.3.4-o4liVvMlOnQWbLSYZMXw/dist=es2019,mode=imports/optimized/debug.js": "671100993996e39b501301a87000607916d4d2d9f8fc8e9c5200ae5ba64a1389", 44 | "https://cdn.skypack.dev/-/ms@v2.1.2-giBDZ1IA5lmQ3ZXaa87V/dist=es2019,mode=imports/optimized/ms.js": "fd88e2d51900437011f1ad232f3393ce97db1b87a7844b3c58dd6d65562c1276", 45 | "https://cdn.skypack.dev/debug@4.3.4": "7b1d010cc930f71b940ba5941da055bc181115229e29de7214bdb4425c68ea76", 46 | "https://deno.land/std@0.211.0/path/_common/assert_path.ts": "2ca275f36ac1788b2acb60fb2b79cb06027198bc2ba6fb7e163efaedde98c297", 47 | "https://deno.land/std@0.211.0/path/_common/basename.ts": "569744855bc8445f3a56087fd2aed56bdad39da971a8d92b138c9913aecc5fa2", 48 | "https://deno.land/std@0.211.0/path/_common/constants.ts": "dc5f8057159f4b48cd304eb3027e42f1148cf4df1fb4240774d3492b5d12ac0c", 49 | "https://deno.land/std@0.211.0/path/_common/strip_trailing_separators.ts": "7024a93447efcdcfeaa9339a98fa63ef9d53de363f1fbe9858970f1bba02655a", 50 | "https://deno.land/std@0.211.0/path/_os.ts": "8fb9b90fb6b753bd8c77cfd8a33c2ff6c5f5bc185f50de8ca4ac6a05710b2c15", 51 | "https://deno.land/std@0.211.0/path/basename.ts": "5d341aadb7ada266e2280561692c165771d071c98746fcb66da928870cd47668", 52 | "https://deno.land/std@0.211.0/path/posix/_util.ts": "1e3937da30f080bfc99fe45d7ed23c47dd8585c5e473b2d771380d3a6937cf9d", 53 | "https://deno.land/std@0.211.0/path/posix/basename.ts": "39ee27a29f1f35935d3603ccf01d53f3d6e0c5d4d0f84421e65bd1afeff42843", 54 | "https://deno.land/std@0.211.0/path/windows/_util.ts": "d5f47363e5293fced22c984550d5e70e98e266cc3f31769e1710511803d04808", 55 | "https://deno.land/std@0.211.0/path/windows/basename.ts": "e2dbf31d1d6385bfab1ce38c333aa290b6d7ae9e0ecb8234a654e583cf22f8fe", 56 | "https://deno.land/x/grammy@v1.31.3/bot.ts": "477241b42959a7721292259b958da0601a3f50bb6cc07a642c8f74ccc3226a6c", 57 | "https://deno.land/x/grammy@v1.31.3/composer.ts": "dab5a40d8a6fdc734bfb218f8b2e4ef846c05b833219ddd3fdee3f145bb2660b", 58 | "https://deno.land/x/grammy@v1.31.3/context.ts": "983ddaeb299c762f9a3fa642f8b7206883673cc63b93f89431adf9f8e2131d23", 59 | "https://deno.land/x/grammy@v1.31.3/convenience/constants.ts": "1560129784be52f49aa0bea8716f09ed00dac367fef195be6a2c09bdfc43fb99", 60 | "https://deno.land/x/grammy@v1.31.3/convenience/frameworks.ts": "bc83a7b68cbbd2e7d3df08ccedb605b4f5ac8870f61d17dea23964c1d82a5ee6", 61 | "https://deno.land/x/grammy@v1.31.3/convenience/inline_query.ts": "409d1940c7670708064efa495003bcbfdf6763a756b2e6303c464489fd3394ff", 62 | "https://deno.land/x/grammy@v1.31.3/convenience/input_media.ts": "7af72a5fdb1af0417e31b1327003f536ddfdf64e06ab8bc7f5da6b574de38658", 63 | "https://deno.land/x/grammy@v1.31.3/convenience/keyboard.ts": "dcfdc05f51758855d31dc80637798e0ca1d7f9b85038a6e9e600522e7cdac490", 64 | "https://deno.land/x/grammy@v1.31.3/convenience/session.ts": "f0ce5742f7938aae146946c8b84d29540d20f592193ebfc217cb79e6e1af33fe", 65 | "https://deno.land/x/grammy@v1.31.3/convenience/webhook.ts": "722f6da8de7578ecfcd263ca07ec3b81f09e7f243fdf2a887ac0e6cab509e116", 66 | "https://deno.land/x/grammy@v1.31.3/core/api.ts": "5e5ed88b2c0c3a9cade89bf7a4e479e598e8310fb7a90d50ad57c090f3845a9a", 67 | "https://deno.land/x/grammy@v1.31.3/core/client.ts": "d4dfeab249537cda49f9c72904a4929f26819bded57e16559e0150db44f4fd93", 68 | "https://deno.land/x/grammy@v1.31.3/core/error.ts": "5245f18f273da6be364f525090c24d2e9a282c180904f674f66946f2b2556247", 69 | "https://deno.land/x/grammy@v1.31.3/core/payload.ts": "420e17c3c2830b5576ea187cfce77578fe09f1204b25c25ea2f220ca7c86e73b", 70 | "https://deno.land/x/grammy@v1.31.3/filter.ts": "dd30fa957e37a0857e471157bc5a21a13b8f5c3d145b512679aefb3ff5174670", 71 | "https://deno.land/x/grammy@v1.31.3/mod.ts": "7723e08709ff7fd01df3e463503e14e4fd1a581669380eed70351e1121e8a833", 72 | "https://deno.land/x/grammy@v1.31.3/platform.deno.ts": "68272a7e1d9a2d74d8a45342526485dbc0531dee812f675d7f8a4e7fc8393028", 73 | "https://deno.land/x/grammy@v1.31.3/types.deno.ts": "4d1d3f770b5ae7bbd86096b32f69b52c8312191ded9be2d92cc57a53f075e36f", 74 | "https://deno.land/x/grammy@v1.31.3/types.ts": "729415590dfa188dbe924dea614dff4e976babdbabb28a307b869fc25777cdf0", 75 | "https://deno.land/x/grammy_types@v3.15.0/api.ts": "ae04d6628e3d25ae805bc07a19475065044fc44cde0a40877405bc3544d03a5f", 76 | "https://deno.land/x/grammy_types@v3.15.0/inline.ts": "ef999d5131968bdc49c0b74d2b0ff94fca310edfa06b02fe1ae1ac2949156934", 77 | "https://deno.land/x/grammy_types@v3.15.0/langs.ts": "5f5fd09c58ba3ae942dd7cea2696f95587d2032c1829bba4bca81762b7ef73b6", 78 | "https://deno.land/x/grammy_types@v3.15.0/manage.ts": "2bf2395311dcfdbb97d3227048eb877cac92d2a247563bb0e4f2e45acd4f99b1", 79 | "https://deno.land/x/grammy_types@v3.15.0/markup.ts": "b989e0712f9731c59e6cb308371b1722d823dd55de3d6bcaf3e4ed645a42e1f9", 80 | "https://deno.land/x/grammy_types@v3.15.0/message.ts": "c0d049ce1ba418fba06a8ce34d0eb7b68b019f508009051c5fc49386c4730905", 81 | "https://deno.land/x/grammy_types@v3.15.0/methods.ts": "fea3c1818e777161c6e55d9d9c27f5512939647fa21471c0f7284ab33c18272b", 82 | "https://deno.land/x/grammy_types@v3.15.0/mod.ts": "7ecea1d3f7085d64419b78183039c78d70d655aeaa8b07f118ffbfb823f5b0b7", 83 | "https://deno.land/x/grammy_types@v3.15.0/passport.ts": "19820e7d6c279521f8bc8912d6a378239f73d4ab525453808994b5f44ef95215", 84 | "https://deno.land/x/grammy_types@v3.15.0/payment.ts": "c899cd6528ddcf464e3318c9761abe77b1f0590076e38d25c8aa6c563636e18f", 85 | "https://deno.land/x/grammy_types@v3.15.0/settings.ts": "f8ff810da6f1007ed24cd504809bf46820229c395ff9bfc3e5c8ceaef5b2aae1", 86 | "https://deno.land/x/grammy_types@v3.15.0/update.ts": "71cc0d5ec860149b71415ba03282b1d7edd0466b36e2789521a3b3a3d7796493", 87 | "https://raw.githubusercontent.com/grammyjs/storages/5eda80d5f0dc4232c1affdda6aada6cc0ca3160d/packages/denokv/src/adapter.ts": "4db9e2289ded90ee86002baf0341043086431d55111d1f1e2c464323b9be7738", 88 | "https://raw.githubusercontent.com/grammyjs/storages/5eda80d5f0dc4232c1affdda6aada6cc0ca3160d/packages/denokv/src/deps.ts": "13bb68745f9737e6f06164a2bb674e4655fb3554e2461cf75a1787c947422346", 89 | "https://raw.githubusercontent.com/grammyjs/storages/5eda80d5f0dc4232c1affdda6aada6cc0ca3160d/packages/denokv/src/mod.ts": "e1dac7718b7f09e478bcd73b1efab26956f8328b9b39e9d922088bd7e2cc44d7" 90 | } 91 | } 92 | --------------------------------------------------------------------------------