├── .yarnrc ├── assets ├── Y-fit.png ├── stop.svg ├── file.svg ├── webview.css └── webview.js ├── media ├── updates-2.png └── filter-query.png ├── .gitignore ├── src ├── webview_components │ ├── main.js │ └── App.svelte ├── updates_explorer │ ├── events.ts │ ├── provider.ts │ ├── bot_listener.ts │ └── mod.ts ├── filter_explorer │ ├── mod.ts │ ├── generated │ │ ├── metadata.ts │ │ └── filter_queries.ts │ ├── provider.ts │ ├── doc.ts │ └── prepare.ts ├── scripts │ └── compile_svelte.mjs ├── snippets │ ├── javascript.code-snippets │ └── typescript.code-snippets └── extension.ts ├── .vscodeignore ├── CHANGELOG.md ├── .vscode ├── extensions.json ├── settings.json ├── tasks.json └── launch.json ├── tsconfig.json ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── .eslintrc.json ├── LICENSE ├── README.md └── package.json /.yarnrc: -------------------------------------------------------------------------------- 1 | --ignore-engines true -------------------------------------------------------------------------------- /assets/Y-fit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grammyjs/vscode/HEAD/assets/Y-fit.png -------------------------------------------------------------------------------- /media/updates-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grammyjs/vscode/HEAD/media/updates-2.png -------------------------------------------------------------------------------- /media/filter-query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grammyjs/vscode/HEAD/media/filter-query.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /out/ 2 | /dist/ 3 | 4 | /node_modules/ 5 | /.yarn/ 6 | /.vscode-test/ 7 | 8 | *.vsix 9 | data.json 10 | -------------------------------------------------------------------------------- /src/webview_components/main.js: -------------------------------------------------------------------------------- 1 | import App from "./App.svelte"; 2 | 3 | const app = new App({ 4 | target: document.getElementById("app"), 5 | }); 6 | 7 | export default app; 8 | -------------------------------------------------------------------------------- /assets/stop.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/updates_explorer/events.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | 3 | export const botStoppedEvent = new vscode.EventEmitter(); 4 | 5 | export const treeLabelSelectionEvent = new vscode.EventEmitter(); 6 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/** 4 | node_modules/** 5 | src/** 6 | .gitignore 7 | .yarnrc 8 | webpack.config.js 9 | vsc-extension-quickstart.md 10 | **/tsconfig.json 11 | **/.eslintrc.json 12 | **/*.map 13 | **/*.ts 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "grammyjs" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | ## [Unreleased] 8 | 9 | - Initial release -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint", 6 | "connor4312.esbuild-problem-matchers", 7 | "svelte.svelte-vscode" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /src/filter_explorer/mod.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | 3 | import { FilterQueryWebviewProvider } from "./provider"; 4 | 5 | export async function initFilterQueryBrowser(context: vscode.ExtensionContext) { 6 | vscode.window.registerWebviewViewProvider( 7 | "filter-query", 8 | new FilterQueryWebviewProvider(context) 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2020", 5 | "lib": ["ES2020"], 6 | "sourceMap": true, 7 | "rootDir": "src", 8 | "strict": true, 9 | "esModuleInterop": true 10 | // "noImplicitReturns": true, 11 | // "noFallthroughCasesInSwitch": true, 12 | // "noUnusedParameters": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /assets/file.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/webview.css: -------------------------------------------------------------------------------- 1 | main.svelte-gt661f{margin-top:6px}input.svelte-gt661f{padding:3px 5px;margin:3px;font-size:13px;line-height:20px;border-radius:2px;border:none;background-color:var(--vscode-input-background);color:var(--vscode-input-foreground);outline:none;width:100%;box-shadow:inset 0 0 0 1px var(--vscode-editorWidget-border);flex:1}details.svelte-gt661f{border-radius:3px;margin-bottom:8px;text-align:start}summary.svelte-gt661f{cursor:pointer;color:var(--vscode-panel-foreground);font-weight:700} 2 | -------------------------------------------------------------------------------- /src/filter_explorer/generated/metadata.ts: -------------------------------------------------------------------------------- 1 | 2 | export const UPDATE_KEYS = ["message","edited_message","channel_post","edited_channel_post","inline_query","chosen_inline_result","callback_query","shipping_query","pre_checkout_query","poll","poll_answer","my_chat_member","chat_member","chat_join_request"]; 3 | 4 | export const L1_SHORTCUTS = {"":["message","channel_post"],"msg":["message","channel_post"],"edit":["edited_message","edited_channel_post"]}; 5 | 6 | export const L2_SHORTCUTS = {"":["entities","caption_entities"],"media":["photo","video"],"file":["photo","animation","audio","document","video","video_note","voice","sticker"]}; 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false, // set this to true to hide the "out" folder with the compiled JS files 5 | "dist": false // set this to true to hide the "dist" folder with the compiled JS files 6 | }, 7 | "search.exclude": { 8 | "out": true, // set this to false to include "out" folder in search results 9 | "dist": true // set this to false to include "dist" folder in search results 10 | }, 11 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 12 | "typescript.tsc.autoDetect": "off", 13 | "deno.enable": false 14 | } -------------------------------------------------------------------------------- /src/scripts/compile_svelte.mjs: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | 3 | import { watch } from "chokidar"; 4 | import * as esbuild from "esbuild"; 5 | import sveltePlugin from "esbuild-svelte"; 6 | 7 | const mainFile = path.join("src", "webview_components", "main.js"); 8 | const svelteFile = path.join("src", "webview_components", "App.svelte"); 9 | 10 | watch(svelteFile).on("change", (file) => { 11 | console.log(`${file} changed, rebuilding...`); 12 | build(); 13 | }); 14 | 15 | function build() { 16 | esbuild.build({ 17 | entryPoints: [mainFile], 18 | bundle: true, 19 | outfile: "assets/webview.js", 20 | plugins: [sveltePlugin()], 21 | minify: true, 22 | logLevel: "info", 23 | }); 24 | } 25 | 26 | build(); 27 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": ["@typescript-eslint", "import"], 9 | "rules": { 10 | "@typescript-eslint/naming-convention": "warn", 11 | "@typescript-eslint/semi": "warn", 12 | "curly": "warn", 13 | "eqeqeq": "warn", 14 | "no-throw-literal": "warn", 15 | "semi": "off", 16 | "import/order": [ 17 | "error", 18 | { 19 | "groups": [ 20 | "builtin", 21 | "external", 22 | "internal", 23 | ["parent", "sibling", "index"] 24 | ], 25 | "newlines-between": "always" 26 | } 27 | ] 28 | }, 29 | "ignorePatterns": ["out", "dist", "**/*.d.ts", "assets"] 30 | } 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Generate Filter Queries", 8 | "type": "npm", 9 | "script": "generate-filter-queries", 10 | "isBackground": false, 11 | "presentation": { 12 | "reveal": "always", 13 | "group": "watchers" 14 | }, 15 | "group": { 16 | "kind": "build", 17 | "isDefault": false 18 | } 19 | }, 20 | { 21 | "label": "Start the extension", 22 | "type": "npm", 23 | "script": "esbuild-watch", 24 | "isBackground": true, 25 | "problemMatcher": "$esbuild-watch", 26 | "presentation": { 27 | "reveal": "always", 28 | "group": "watchers" 29 | }, 30 | "dependsOn": "Generate Filter Queries", 31 | "dependsOrder": "sequence", 32 | "group": { 33 | "kind": "build", 34 | "isDefault": true 35 | } 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ], 15 | "outFiles": [ 16 | "${workspaceFolder}/dist/**/*.js" 17 | ], 18 | "preLaunchTask": "${defaultBuildTask}" 19 | }, 20 | { 21 | "name": "Extension Tests", 22 | "type": "extensionHost", 23 | "request": "launch", 24 | "args": [ 25 | "--extensionDevelopmentPath=${workspaceFolder}", 26 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 27 | ], 28 | "outFiles": [ 29 | "${workspaceFolder}/out/**/*.js", 30 | "${workspaceFolder}/dist/**/*.js" 31 | ], 32 | "preLaunchTask": "tasks: watch-tests" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023-2024 grammyjs 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 | -------------------------------------------------------------------------------- /src/filter_explorer/provider.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | 3 | import * as vscode from "vscode"; 4 | 5 | export class FilterQueryWebviewProvider implements vscode.WebviewViewProvider { 6 | private extensionContext: vscode.ExtensionContext; 7 | 8 | constructor(context: vscode.ExtensionContext) { 9 | this.extensionContext = context; 10 | } 11 | resolveWebviewView( 12 | webviewView: vscode.WebviewView, 13 | context: vscode.WebviewViewResolveContext, 14 | token: vscode.CancellationToken 15 | ): void | Thenable { 16 | const getPathToFile = (fileName: string) => { 17 | return webviewView.webview.asWebviewUri( 18 | vscode.Uri.file( 19 | path.resolve(this.extensionContext.extensionPath, "assets", fileName) 20 | ) 21 | ); 22 | }; 23 | 24 | webviewView.webview.options = { enableScripts: true }; 25 | webviewView.webview.html = `\n\n \n \n \n \n\n \n
\n \n \n\n`; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/snippets/javascript.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "Hello world bot": { 3 | "prefix": "gy", 4 | "body": [ 5 | "const { Bot } = require(\"grammy\");", 6 | "", 7 | "// Create an instance of the `Bot` class and pass your bot token to it.", 8 | "const bot = new Bot('$token'); // <-- put your bot token between the \"\"", 9 | "", 10 | "// You can now register listeners on your bot object `bot`.", 11 | "// grammY will call the listeners when users send messages to your bot.", 12 | "", 13 | "// Handle the /start command.", 14 | "bot.command(\"start\", (ctx) => ctx.reply(\"Welcome! Up and running.\"));", 15 | "// Handle other messages.", 16 | "bot.on(\"message\", (ctx) => ctx.reply(\"Got another message!\"));", 17 | "", 18 | "// Now that you specified how to handle messages, you can start your bot.", 19 | "// This will connect to the Telegram servers and wait for messages.", 20 | "", 21 | "// Start the bot.", 22 | "bot.start();" 23 | ], 24 | "description": "Basic bot that replies with Hello world on `/start`" 25 | }, 26 | "Command handler function": { 27 | "prefix": "cmd", 28 | "body": [ 29 | "bot.command('${1:command}', (ctx) => {", 30 | " ctx.reply('Hello, world!');", 31 | "});" 32 | ], 33 | "description": "Handler function for bot commands" 34 | }, 35 | "Filter query handler": { 36 | "prefix": "on", 37 | "body": [ 38 | "bot.on('${1:filterQuery}', (ctx) => {", 39 | " // do something here", 40 | "});" 41 | ], 42 | "description": "Handler function for filter queries" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/snippets/typescript.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "Hello world bot": { 3 | "prefix": "gy", 4 | "body": [ 5 | "import { Bot } from \"grammy\";", 6 | "", 7 | "// Create an instance of the `Bot` class and pass your bot token to it.", 8 | "const bot = new Bot('$token'); // <-- put your bot token between the \"\"", 9 | "", 10 | "// You can now register listeners on your bot object `bot`.", 11 | "// grammY will call the listeners when users send messages to your bot.", 12 | "", 13 | "// Handle the /start command.", 14 | "bot.command(\"start\", (ctx) => ctx.reply(\"Welcome! Up and running.\"));", 15 | "// Handle other messages.", 16 | "bot.on(\"message\", (ctx) => ctx.reply(\"Got another message!\"));", 17 | "", 18 | "// Now that you specified how to handle messages, you can start your bot.", 19 | "// This will connect to the Telegram servers and wait for messages.", 20 | "", 21 | "// Start the bot.", 22 | "bot.start();" 23 | ], 24 | "description": "Starter bot that replies with Hello world on `/start`" 25 | }, 26 | "Command handler function": { 27 | "prefix": "cmd", 28 | "body": [ 29 | "bot.command('${1:command}', (ctx) => {", 30 | "", 31 | " ctx.reply('Hello, world!');", 32 | "});", 33 | "" 34 | ], 35 | "description": "Handler function for bot commands" 36 | }, 37 | "Filter query handler": { 38 | "prefix": "on", 39 | "body": [ 40 | "bot.on('${1:filterQuery}', (ctx) => {", 41 | " // do something here", 42 | "", 43 | "});" 44 | ], 45 | "description": "Handler function for filter query" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/webview_components/App.svelte: -------------------------------------------------------------------------------- 1 | 24 | 25 |
26 | 27 | {#if results.length === 0} 28 |

No results found

29 | {:else} 30 | {#each results as { query, description }} 31 |
32 | {query} 33 |

{description}

34 |
35 | {/each} 36 | {/if} 37 |
38 | 39 | 70 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | 3 | import { generate } from "./filter_explorer/doc"; 4 | import { initFilterQueryBrowser } from "./filter_explorer/mod"; 5 | import { botStoppedEvent } from "./updates_explorer/events"; 6 | import { initUpdatesExplorer } from "./updates_explorer/mod"; 7 | 8 | export async function activate(context: vscode.ExtensionContext) { 9 | const startCommand = vscode.commands.registerCommand( 10 | "updates-explorer.start", 11 | async () => { 12 | const token = await vscode.window.showInputBox({ 13 | title: "Enter your Bot token", 14 | }); 15 | if (token) { 16 | await initUpdatesExplorer(token, context); 17 | } else { 18 | vscode.window.showErrorMessage("Token was not provided"); 19 | } 20 | } 21 | ); 22 | const stopCommand = vscode.commands.registerCommand( 23 | "updates-explorer.stop", 24 | async () => { 25 | botStoppedEvent.fire(true); 26 | } 27 | ); 28 | await initFilterQueryBrowser(context); 29 | 30 | const filterQueryArray = generate(); 31 | 32 | const filterQueryHoverProvider = vscode.languages.registerHoverProvider( 33 | ["typescript", "javascript"], 34 | { 35 | provideHover(document, position) { 36 | const wordRange = document.getWordRangeAtPosition(position); 37 | const word = document.getText(wordRange); 38 | const foundFilterQuery = filterQueryArray.find( 39 | ({ query }) => word === query 40 | ); 41 | const hoverResult = foundFilterQuery 42 | ? { contents: [foundFilterQuery.description] } 43 | : null; 44 | 45 | return hoverResult; 46 | }, 47 | } 48 | ); 49 | 50 | context.subscriptions.push( 51 | startCommand, 52 | stopCommand, 53 | filterQueryHoverProvider 54 | ); 55 | } 56 | 57 | // this method is called when your extension is deactivated 58 | export async function deactivate() {} 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # grammY VS Code 2 | 3 | Enhance your experience when developing with grammY. 4 | 5 | - [Features](#features) 6 | - [Snippets](#snippets) 7 | - [Updates Explorer](#updates-explorer) 8 | - [Filter Explorer](#filter-explorer) 9 | - [Contributing](#contributing) 10 | - [Development](#development) 11 | 12 | ## Features 13 | 14 | ### Snippets 15 | 16 | The extension features some of the most used code snippets for the grammy 17 | library to save users time and effort in developing telegram bots. 18 | 19 | ### Updates Explorer 20 | 21 | We all need to go and check for the full update json tree sometimes, right!!! 22 | `Typescript` users have types but still we sometimes need to have a look on what 23 | we are working with. 24 | 25 | The extension features `a real-time` updates explorer in the sidebar and it will 26 | show all the updates that your bot will receive. 27 | 28 |
29 | Updates Explorer 30 |
31 | 32 | ### Filter Explorer 33 | 34 | One of the many cool features of `grammy` is it's 35 | [Filter Queries](https://grammy.dev/guide/filter-queries.html) and there are 36 | lots of them (like 800+ of em) and you may want to know a bit more about what 37 | exactly do they filter and how to access them. 38 | 39 | And the the explorer does exactly that you get a complete list of all the 40 | `Filter Queries` with their description right in your editor. 41 | 42 |
43 | Filter Query 44 |
45 | 46 | ## Contributing 47 | 48 | You’re welcome to contribute by reporting issues and making pull requests of any 49 | size. Don’t forget that we’re following 50 | [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). 51 | 52 | ## Development 53 | 54 | 1. Clone the repository and open it with VS Code. 55 | 56 | ```sh 57 | git clone https://github.com/grammyjs/vscode.git 58 | ``` 59 | 60 | 2. Install the dependencies. 61 | 62 | ```sh 63 | yarn install 64 | ``` 65 | 66 | 3. Press `F5` or the whatever key you have configured to start the development 67 | tasks. 68 | -------------------------------------------------------------------------------- /src/updates_explorer/provider.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Event, 3 | EventEmitter, 4 | ProviderResult, 5 | ThemeIcon, 6 | TreeDataProvider, 7 | TreeItem, 8 | } from "vscode"; 9 | 10 | // Define a class that implements the VS Code TreeDataProvider interface 11 | export class UpdatesExplorerTreeDataProvider 12 | implements TreeDataProvider 13 | { 14 | private data: string[]; 15 | 16 | // Define an event emitter for when the tree data has changed 17 | private treeDataChanged: EventEmitter = new EventEmitter< 18 | string | undefined 19 | >(); 20 | 21 | // Define an onDidChangeTreeData property that returns the event emitter's event property 22 | readonly onDidChangeTreeData?: 23 | | Event 24 | | undefined = this.treeDataChanged.event; 25 | 26 | constructor(data: string[]) { 27 | this.data = data; 28 | } 29 | 30 | // Define a method that takes an element (a string in this case) 31 | //and returns a TreeItem object with the label set to the element and an icon set to the JSON icon 32 | getTreeItem(element: string): TreeItem | Thenable { 33 | return { 34 | label: element, 35 | iconPath: new ThemeIcon("json"), 36 | }; 37 | } 38 | 39 | // Define a method that takes an optional element parameter, 40 | //which is unused in this case. If element is undefined, 41 | //it returns a promise that resolves to the data array; otherwise, it returns an empty array. 42 | getChildren(element?: string | undefined): ProviderResult { 43 | if (element === undefined) { 44 | return Promise.resolve(this.data); 45 | } else { 46 | return Promise.resolve([]); 47 | } 48 | } 49 | 50 | // Define a method that takes an updated tree view data, 51 | // which can either be a string or an array of strings, and adds it to the data property. 52 | //It then emits the treeDataChanged event to signal that the tree data has changed. 53 | 54 | addNewEntry(updatedTreeViewData: string[] | string) { 55 | if (Array.isArray(updatedTreeViewData)) { 56 | this.data.push(...updatedTreeViewData); 57 | } else { 58 | this.data.push(updatedTreeViewData); 59 | } 60 | 61 | this.treeDataChanged.fire(undefined); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/updates_explorer/bot_listener.ts: -------------------------------------------------------------------------------- 1 | import { Bot } from "grammy"; 2 | import type { Message, Update } from "grammy/types"; 3 | 4 | type BotState = "listening" | "intializing" | "stopping" | "error" | "idle"; 5 | 6 | export class BotListener { 7 | public token: string; 8 | 9 | public error: Error | undefined; 10 | 11 | private jsonData: (Message & Update.NonChannel) | undefined; 12 | 13 | private state: BotState = "idle"; 14 | 15 | constructor(botToken: string) { 16 | this.token = botToken; 17 | } 18 | 19 | public async startListeningToUpdates( 20 | onDataReceived: (data: Message & Update.NonChannel) => void 21 | ) { 22 | try { 23 | const bot = this.getBotInstance(); 24 | 25 | bot.use(async (ctx) => { 26 | const hasDownload = ctx.has(":file"); 27 | const url = hasDownload 28 | ? await ctx.getFile().then((file) => ({ 29 | url: `https://api.telegram.org/file/bot${this.token}/${file.file_path}`, 30 | })) 31 | : {}; 32 | const decoratedUpdate = { 33 | ...ctx.update, 34 | type: 35 | Object.keys(ctx.update).filter((key) => key !== "update_id")[0] ?? 36 | "unknown", 37 | timestamp: new Date(), 38 | hasDownload, 39 | ...url, 40 | }; 41 | // console.log(decoratedUpdate.message); 42 | this.jsonData = decoratedUpdate.message; 43 | if (this.jsonData !== undefined) { 44 | onDataReceived(this.jsonData); 45 | } 46 | }); 47 | 48 | this.state = "intializing"; 49 | await bot.api.getMe(); 50 | await bot.init(); 51 | await bot.start({ 52 | // eslint-disable-next-line @typescript-eslint/naming-convention 53 | allowed_updates: [ 54 | "message", 55 | "edited_message", 56 | "channel_post", 57 | "edited_channel_post", 58 | "inline_query", 59 | "chosen_inline_result", 60 | "callback_query", 61 | "shipping_query", 62 | "pre_checkout_query", 63 | "poll", 64 | "poll_answer", 65 | "my_chat_member", 66 | "chat_member", 67 | "chat_join_request", 68 | ], 69 | onStart: async () => { 70 | this.state = "listening"; 71 | }, 72 | }); 73 | } catch (err) { 74 | this.state = "error"; 75 | this.error = err as Error; 76 | } 77 | } 78 | 79 | public async stopListeningToUpdates() { 80 | this.state = "stopping"; 81 | await this.getBotInstance().stop(); 82 | this.state = "idle"; 83 | } 84 | 85 | private getBotInstance() { 86 | return new Bot(this.token); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/filter_explorer/doc.ts: -------------------------------------------------------------------------------- 1 | import FILTER_QUERIES from "./generated/filter_queries"; 2 | import { L1_SHORTCUTS, L2_SHORTCUTS, UPDATE_KEYS } from "./generated/metadata"; 3 | 4 | function camelCase(str: string, separator: string) { 5 | return ( 6 | str[0] + 7 | str 8 | .split(separator) 9 | .map((w) => w[0].toUpperCase() + w.substring(1)) 10 | .join("") 11 | .substring(1) 12 | ); 13 | } 14 | 15 | const CONTEXT_SHORTCUTS: Record = UPDATE_KEYS.reduce( 16 | (prev, current) => { 17 | return { ...prev, [current]: camelCase(current, "_") }; 18 | }, 19 | {} 20 | ); 21 | 22 | function buildName(element: string[]) { 23 | return element.map((key, index) => `${index === 0 ? "" : " / "}${key}`); 24 | } 25 | 26 | const PREFIX_DOCS = { 27 | // eslint-disable-next-line @typescript-eslint/naming-convention 28 | chat_member: 29 | "You need to specify this update in allowed_updates to receive them.", 30 | }; 31 | 32 | export function generate() { 33 | const queryDocs: { query: string; description: string }[] = []; 34 | 35 | for (const query of FILTER_QUERIES) { 36 | const [l1, l2, L3] = query.split(":"); 37 | const L1 = L1_SHORTCUTS[l1 as keyof typeof L1_SHORTCUTS] ?? [l1]; 38 | const L2 = L2_SHORTCUTS[l2 as keyof typeof L2_SHORTCUTS] ?? [l2]; 39 | 40 | const prefix = PREFIX_DOCS?.[query as keyof typeof PREFIX_DOCS]; 41 | 42 | const L1T = buildName(L1); 43 | const L2T = buildName(L2); 44 | 45 | let description: string = ""; 46 | 47 | if (L1[0] && !L2[0] && !L3) { 48 | description = [ 49 | `Query for filtering "${L1T}" update.`, 50 | `Here's how you can access the information about the update:`, 51 | L1.map((k1) => `\`\`\`ctx.${CONTEXT_SHORTCUTS[k1]}\`\`\``).join("\n\n"), 52 | ].join("\n\n"); 53 | } else if (L1[0] && L2[0] && !L3) { 54 | description = [ 55 | `Query for filtering "${L1T}" update with the field "${L2T}".`, 56 | "Here is how you can access the properties of the field:", 57 | L1.map((k1) => 58 | L2.map( 59 | (k2) => `\`\`\`ctx.${CONTEXT_SHORTCUTS[k1]}.${k2};\`\`\`` 60 | ).join("\n\n") 61 | ).join("\n\n"), 62 | ].join("\n\n"); 63 | } else if (L1[0] && L2[0] && L3) { 64 | const isEntity = L2.includes("entities"); 65 | const info0 = isEntity 66 | ? `containing at least one entity of the type "${L3}"` 67 | : `with "${L3}" property`; 68 | 69 | const accessInfo = L2.join().includes("entities") 70 | ? `ctx.entities("${L3}");` 71 | : L1.map((k1) => 72 | L2.map((k2) => { 73 | return `\`\`\`ctx.${CONTEXT_SHORTCUTS[k1]}.${k2}.${L3}\`\`\``; 74 | }).join("\n\n") 75 | ).join("\n\n"); 76 | 77 | description = [ 78 | `Query for filtering "${L1T}" update with the field "${L2T}" ${info0}.`, 79 | `Here is how you can access the ${ 80 | isEntity ? `entities of "${L3}" type` : `"${L3}" property` 81 | }:`, 82 | accessInfo, 83 | ].join("\n\n"); 84 | } else { 85 | throw new Error(`There is some issue with the "${query}" filter query.`); 86 | } 87 | 88 | queryDocs.push({ 89 | query, 90 | description: prefix ? `${prefix}\n${description}` : description, 91 | }); 92 | } 93 | 94 | return queryDocs; 95 | } 96 | -------------------------------------------------------------------------------- /src/updates_explorer/mod.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "fs/promises"; 2 | import * as path from "path"; 3 | 4 | import type { Message, Update } from "grammy/types"; 5 | import * as vscode from "vscode"; 6 | 7 | import { BotListener } from "./bot_listener"; 8 | import { botStoppedEvent, treeLabelSelectionEvent } from "./events"; 9 | import { UpdatesExplorerTreeDataProvider } from "./provider"; 10 | 11 | export async function initUpdatesExplorer( 12 | token: string, 13 | context: vscode.ExtensionContext 14 | ) { 15 | const tempFilePath = path.join(context.extensionPath, "data.json"); 16 | await fs.writeFile(tempFilePath, "", { encoding: "utf-8" }); 17 | 18 | const tempDocument = await vscode.workspace.openTextDocument( 19 | vscode.Uri.file(tempFilePath) 20 | ); 21 | const shownDocument = await vscode.window.showTextDocument(tempDocument, { 22 | viewColumn: vscode.ViewColumn.Beside, 23 | }); 24 | 25 | const treeDataProvider = new UpdatesExplorerTreeDataProvider([" "]); 26 | const treeView = vscode.window.createTreeView("updates-explorer", { 27 | treeDataProvider, 28 | }); 29 | 30 | let jsonData: Record = {}; 31 | 32 | const listener = new BotListener(token); 33 | 34 | listener.startListeningToUpdates((data) => { 35 | const now = new Date().toLocaleString(undefined, { 36 | year: "numeric", 37 | month: "long", 38 | day: "numeric", 39 | hour: "numeric", 40 | minute: "numeric", 41 | second: "numeric", 42 | hour12: false, 43 | }); 44 | 45 | jsonData[now] = data; 46 | treeDataProvider.addNewEntry(now); 47 | 48 | shownDocument.edit(async (editBuilder) => { 49 | const document = shownDocument.document; 50 | await editAndWriteUpdatedJsonDataInFile( 51 | document, 52 | editBuilder, 53 | JSON.stringify(jsonData[now], null, 2) 54 | ); 55 | }); 56 | }); 57 | 58 | const changeEventListener = treeView.onDidChangeSelection((e) => { 59 | const selectedElement = e.selection[0]; 60 | treeLabelSelectionEvent.fire(selectedElement); 61 | }); 62 | 63 | const labelChangeListener = treeLabelSelectionEvent.event((label) => { 64 | shownDocument.edit(async (editBuilder) => { 65 | await editAndWriteUpdatedJsonDataInFile( 66 | shownDocument.document, 67 | editBuilder, 68 | JSON.stringify(jsonData[label], null, 2) 69 | ); 70 | }); 71 | }); 72 | 73 | const botStoppedListener = botStoppedEvent.event(async (event) => { 74 | if (event) { 75 | await listener.stopListeningToUpdates(); 76 | treeView.dispose(); 77 | await closeFileIfOpen(vscode.Uri.file(tempFilePath)); 78 | vscode.window.showErrorMessage("Bot stopped"); 79 | } 80 | }); 81 | context.subscriptions.push( 82 | changeEventListener, 83 | labelChangeListener, 84 | botStoppedListener 85 | ); 86 | } 87 | 88 | const editAndWriteUpdatedJsonDataInFile = async ( 89 | document: vscode.TextDocument, 90 | editBuilder: vscode.TextEditorEdit, 91 | data: string 92 | ) => { 93 | const lastLine = document.lineAt(document.lineCount - 1); 94 | 95 | const range = new vscode.Range( 96 | 0, 97 | 0, 98 | lastLine.lineNumber, 99 | lastLine.range.end.character 100 | ); 101 | editBuilder.replace(range, data); 102 | await document.save(); 103 | }; 104 | 105 | const closeFileIfOpen = async (file: vscode.Uri) => { 106 | const tabs: vscode.Tab[] = vscode.window.tabGroups.all 107 | .map((tg) => tg.tabs) 108 | .flat(); 109 | const index = tabs.findIndex( 110 | (tab) => 111 | tab.input instanceof vscode.TabInputText && 112 | tab.input.uri.path === file.path 113 | ); 114 | if (index !== -1) { 115 | await vscode.window.tabGroups.close(tabs[index]); 116 | } 117 | }; 118 | -------------------------------------------------------------------------------- /src/filter_explorer/prepare.ts: -------------------------------------------------------------------------------- 1 | import { opendir, writeFile } from "fs/promises"; 2 | 3 | import axios from "axios"; 4 | import { 5 | Project, 6 | PropertyAssignment, 7 | SourceFile, 8 | StringLiteral, 9 | SyntaxKind, 10 | } from "ts-morph"; 11 | 12 | function getPropertiesOfObject(source: SourceFile, key: string) { 13 | return source 14 | .getVariableDeclarationOrThrow(key) 15 | .getInitializerIfKindOrThrow(SyntaxKind.AsExpression) 16 | .getExpressionIfKindOrThrow(SyntaxKind.ObjectLiteralExpression) 17 | .getProperties() as PropertyAssignment[]; 18 | } 19 | 20 | function getObject(source: SourceFile, key: string) { 21 | return getPropertiesOfObject(source, key).reduce((properties, property) => { 22 | const propertyNameKind = property.getNameNode().getKind(); 23 | const propertyName = 24 | propertyNameKind === SyntaxKind.Identifier 25 | ? property.getName() 26 | : property 27 | .getNameNode() 28 | .asKindOrThrow(SyntaxKind.StringLiteral) 29 | .getLiteralText(); 30 | const value = property 31 | .getInitializerIfKindOrThrow(SyntaxKind.ArrayLiteralExpression) 32 | .getElements() 33 | .map((element: any) => { 34 | return (element as StringLiteral).getLiteralText(); 35 | }); 36 | return { ...properties, [propertyName]: value }; 37 | }, {}); 38 | } 39 | 40 | type Shortcuts = Record; 41 | 42 | async function isEmptyDir(path: string) { 43 | try { 44 | const directory = await opendir(path); 45 | const entry = await directory.read(); 46 | await directory.close(); 47 | 48 | return entry === null; 49 | } catch (error) { 50 | return false; 51 | } 52 | } 53 | 54 | async function generateTypeFilesFromRemoteSource() { 55 | if (await isEmptyDir("./generated")) { 56 | console.log("Files already exist"); 57 | return; 58 | } else { 59 | try { 60 | // redirects to latest version of grammY = up to date filter queries. 61 | const response = await axios.get("https://deno.land/x/grammy/filter.ts"); 62 | 63 | const filterFileContent = await response.data; 64 | const project = new Project(); 65 | // NOTE: ts_morph doesn't resolve the imports in the filter.ts file because, currently 66 | // FilterQuery and other local variables are independent of those relative imports. 67 | // This logic needs to be changed if this isn't the situation in the future. 68 | const source = project.createSourceFile(".filter.ts", filterFileContent); 69 | 70 | const UPDATE_KEYS = getPropertiesOfObject(source, "UPDATE_KEYS").map( 71 | (property) => property.getName() 72 | ) as string[]; 73 | const L1_SHORTCUTS = getObject(source, "L1_SHORTCUTS") as Shortcuts; 74 | const L2_SHORTCUTS = getObject(source, "L2_SHORTCUTS") as Shortcuts; 75 | const FILTER_QUERIES = source 76 | .getTypeAliasOrThrow("FilterQuery") 77 | .getType() 78 | .getUnionTypes() 79 | .map((u: { getLiteralValue: () => any }) => 80 | u.getLiteralValue() 81 | ) as string[]; 82 | 83 | const modFile = `export default ${JSON.stringify(FILTER_QUERIES)};`; 84 | const filterFile = ` 85 | export const UPDATE_KEYS = ${JSON.stringify(UPDATE_KEYS)};\n 86 | export const L1_SHORTCUTS = ${JSON.stringify(L1_SHORTCUTS)};\n 87 | export const L2_SHORTCUTS = ${JSON.stringify(L2_SHORTCUTS)};\n`; 88 | 89 | await writeFile( 90 | "./src/filter_explorer/generated/filter_queries.ts", 91 | modFile 92 | ); 93 | await writeFile( 94 | "./src/filter_explorer/generated/metadata.ts", 95 | filterFile 96 | ); 97 | } catch (error) { 98 | console.log(error); 99 | throw new Error("Request failed"); 100 | } 101 | } 102 | } 103 | generateTypeFilesFromRemoteSource().then(); 104 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grammyjs", 3 | "displayName": "grammY", 4 | "publisher": "grammyjs", 5 | "description": "Tooling for grammY bot development", 6 | "preview": true, 7 | "icon": "assets/Y-fit.png", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/grammyjs/vscode" 11 | }, 12 | "version": "1.0.0", 13 | "engines": { 14 | "vscode": "^1.77.0" 15 | }, 16 | "categories": [ 17 | "Snippets", 18 | "Other" 19 | ], 20 | "keywords": [ 21 | "telegram", 22 | "bot", 23 | "grammy" 24 | ], 25 | "activationEvents": [ 26 | "onLanguage:javascript", 27 | "onLanguage:typescript" 28 | ], 29 | "main": "./dist/extension.js", 30 | "contributes": { 31 | "viewsContainers": { 32 | "activitybar": [ 33 | { 34 | "id": "grammyjs-tools", 35 | "title": "grammy", 36 | "icon": "assets/Y-fit.png" 37 | } 38 | ] 39 | }, 40 | "views": { 41 | "grammyjs-tools": [ 42 | { 43 | "type": "tree", 44 | "id": "updates-explorer", 45 | "name": "Updates Explorer", 46 | "contextualTitle": "Updates Explorer" 47 | }, 48 | { 49 | "type": "webview", 50 | "id": "filter-query", 51 | "name": "Filter Explorer", 52 | "contextualTitle": "Filter Explorer" 53 | } 54 | ] 55 | }, 56 | "viewsWelcome": [ 57 | { 58 | "view": "updates-explorer", 59 | "contents": "Visualize Telegram updates as they happen.\n[Start](command:updates-explorer.start)" 60 | }, 61 | { 62 | "view": "filter-explorer", 63 | "contents": "Filter queries documentation" 64 | } 65 | ], 66 | "commands": [ 67 | { 68 | "command": "updates-explorer.start", 69 | "title": "Start" 70 | }, 71 | { 72 | "command": "updates-explorer.stop", 73 | "title": "Stop", 74 | "icon": "assets/stop.svg" 75 | } 76 | ], 77 | "menus": { 78 | "view/title": [ 79 | { 80 | "command": "updates-explorer.stop", 81 | "when": "view == updates-explorer", 82 | "group": "navigation" 83 | } 84 | ] 85 | }, 86 | "snippets": [ 87 | { 88 | "language": "javascript", 89 | "path": "./src/snippets/javascript.code-snippets" 90 | }, 91 | { 92 | "language": "typescript", 93 | "path": "./src/snippets/typescript.code-snippets" 94 | } 95 | ] 96 | }, 97 | "scripts": { 98 | "vscode:prepublish": "yarn run esbuild-base --minify", 99 | "esbuild-base": "esbuild ./src/extension.ts --bundle --outfile=dist/extension.js --external:vscode --format=cjs --platform=node", 100 | "esbuild": "yarn run esbuild-base --sourcemap", 101 | "esbuild-watch": "yarn run esbuild-base --sourcemap --watch", 102 | "compile-web": "node src/scripts/compile_svelte.mjs", 103 | "generate-filter-queries": "ts-node src/filter_explorer/prepare.ts" 104 | }, 105 | "devDependencies": { 106 | "@types/glob": "^7.2.0", 107 | "@types/mocha": "^9.1.1", 108 | "@types/node": "16.x", 109 | "@types/temp": "^0.9.1", 110 | "@types/vscode": "^1.77.0", 111 | "@typescript-eslint/eslint-plugin": "^5.30.0", 112 | "@typescript-eslint/parser": "^5.30.0", 113 | "@vscode/test-electron": "^2.1.5", 114 | "axios": "^1.4.0", 115 | "chokidar": "^3.5.3", 116 | "esbuild": "^0.17.16", 117 | "esbuild-svelte": "^0.7.3", 118 | "eslint": "^8.18.0", 119 | "eslint-plugin-import": "^2.27.5", 120 | "glob": "^8.0.3", 121 | "mocha": "^10.0.0", 122 | "svelte": "^3.58.0", 123 | "ts-morph": "^18.0.0", 124 | "ts-node": "^10.9.1", 125 | "typescript": "^4.7.4" 126 | }, 127 | "dependencies": { 128 | "fuse.js": "^6.6.2", 129 | "grammy": "^1.16.0" 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/filter_explorer/generated/filter_queries.ts: -------------------------------------------------------------------------------- 1 | export default ["message","edited_message","channel_post","edited_channel_post","inline_query","chosen_inline_result","callback_query","shipping_query","pre_checkout_query","poll","poll_answer","my_chat_member","chat_member","chat_join_request","message:poll","message:new_chat_members","message:left_chat_member","message:group_chat_created","message:supergroup_chat_created","message:migrate_to_chat_id","message:migrate_from_chat_id","message:successful_payment","message:user_shared","message:chat_shared","message:connected_website","message:write_access_allowed","message:passport_data","message:forum_topic_created","message:forum_topic_edited","message:forum_topic_closed","message:forum_topic_reopened","message:general_forum_topic_hidden","message:general_forum_topic_unhidden","message:sticker","message:video_note","message:voice","message:contact","message:dice","message:venue","message:new_chat_title","message:new_chat_photo","message:delete_chat_photo","message:message_auto_delete_timer_changed","message:pinned_message","message:invoice","message:proximity_alert_triggered","message:video_chat_scheduled","message:video_chat_started","message:video_chat_ended","message:video_chat_participants_invited","message:web_app_data","message:forward_date","message:is_topic_message","message:is_automatic_forward","message:text","message:animation","message:audio","message:document","message:photo","message:video","message:game","message:location","message:entities","message:caption_entities","message:has_media_spoiler","message:caption","edited_message:poll","edited_message:new_chat_members","edited_message:left_chat_member","edited_message:group_chat_created","edited_message:supergroup_chat_created","edited_message:migrate_to_chat_id","edited_message:migrate_from_chat_id","edited_message:successful_payment","edited_message:user_shared","edited_message:chat_shared","edited_message:connected_website","edited_message:write_access_allowed","edited_message:passport_data","edited_message:forum_topic_created","edited_message:forum_topic_edited","edited_message:forum_topic_closed","edited_message:forum_topic_reopened","edited_message:general_forum_topic_hidden","edited_message:general_forum_topic_unhidden","edited_message:sticker","edited_message:video_note","edited_message:voice","edited_message:contact","edited_message:dice","edited_message:venue","edited_message:new_chat_title","edited_message:new_chat_photo","edited_message:delete_chat_photo","edited_message:message_auto_delete_timer_changed","edited_message:pinned_message","edited_message:invoice","edited_message:proximity_alert_triggered","edited_message:video_chat_scheduled","edited_message:video_chat_started","edited_message:video_chat_ended","edited_message:video_chat_participants_invited","edited_message:web_app_data","edited_message:forward_date","edited_message:is_topic_message","edited_message:is_automatic_forward","edited_message:text","edited_message:animation","edited_message:audio","edited_message:document","edited_message:photo","edited_message:video","edited_message:game","edited_message:location","edited_message:entities","edited_message:caption_entities","edited_message:has_media_spoiler","edited_message:caption","channel_post:poll","channel_post:sticker","channel_post:video_note","channel_post:voice","channel_post:contact","channel_post:dice","channel_post:venue","channel_post:new_chat_title","channel_post:new_chat_photo","channel_post:delete_chat_photo","channel_post:message_auto_delete_timer_changed","channel_post:pinned_message","channel_post:invoice","channel_post:proximity_alert_triggered","channel_post:video_chat_scheduled","channel_post:video_chat_started","channel_post:video_chat_ended","channel_post:video_chat_participants_invited","channel_post:web_app_data","channel_post:forward_date","channel_post:is_topic_message","channel_post:is_automatic_forward","channel_post:text","channel_post:animation","channel_post:audio","channel_post:document","channel_post:photo","channel_post:video","channel_post:game","channel_post:location","channel_post:entities","channel_post:caption_entities","channel_post:has_media_spoiler","channel_post:caption","channel_post:channel_chat_created","edited_channel_post:poll","edited_channel_post:sticker","edited_channel_post:video_note","edited_channel_post:voice","edited_channel_post:contact","edited_channel_post:dice","edited_channel_post:venue","edited_channel_post:new_chat_title","edited_channel_post:new_chat_photo","edited_channel_post:delete_chat_photo","edited_channel_post:message_auto_delete_timer_changed","edited_channel_post:pinned_message","edited_channel_post:invoice","edited_channel_post:proximity_alert_triggered","edited_channel_post:video_chat_scheduled","edited_channel_post:video_chat_started","edited_channel_post:video_chat_ended","edited_channel_post:video_chat_participants_invited","edited_channel_post:web_app_data","edited_channel_post:forward_date","edited_channel_post:is_topic_message","edited_channel_post:is_automatic_forward","edited_channel_post:text","edited_channel_post:animation","edited_channel_post:audio","edited_channel_post:document","edited_channel_post:photo","edited_channel_post:video","edited_channel_post:game","edited_channel_post:location","edited_channel_post:entities","edited_channel_post:caption_entities","edited_channel_post:has_media_spoiler","edited_channel_post:caption","edited_channel_post:channel_chat_created","callback_query:data","callback_query:game_short_name","my_chat_member:from","chat_member:from","message:new_chat_members:me","message:new_chat_members:is_bot","message:new_chat_members:is_premium","message:new_chat_members:added_to_attachment_menu","message:left_chat_member:me","message:left_chat_member:is_bot","message:left_chat_member:is_premium","message:left_chat_member:added_to_attachment_menu","message:forum_topic_edited:name","message:forum_topic_edited:icon_custom_emoji_id","message:sticker:is_video","message:sticker:is_animated","message:sticker:premium_animation","message:entities:mention","message:entities:hashtag","message:entities:cashtag","message:entities:bot_command","message:entities:url","message:entities:email","message:entities:phone_number","message:entities:bold","message:entities:italic","message:entities:underline","message:entities:strikethrough","message:entities:spoiler","message:entities:code","message:entities:pre","message:entities:text_link","message:entities:text_mention","message:entities:custom_emoji","message:caption_entities:mention","message:caption_entities:hashtag","message:caption_entities:cashtag","message:caption_entities:bot_command","message:caption_entities:url","message:caption_entities:email","message:caption_entities:phone_number","message:caption_entities:bold","message:caption_entities:italic","message:caption_entities:underline","message:caption_entities:strikethrough","message:caption_entities:spoiler","message:caption_entities:code","message:caption_entities:pre","message:caption_entities:text_link","message:caption_entities:text_mention","message:caption_entities:custom_emoji","edited_message:new_chat_members:me","edited_message:new_chat_members:is_bot","edited_message:new_chat_members:is_premium","edited_message:new_chat_members:added_to_attachment_menu","edited_message:left_chat_member:me","edited_message:left_chat_member:is_bot","edited_message:left_chat_member:is_premium","edited_message:left_chat_member:added_to_attachment_menu","edited_message:forum_topic_edited:name","edited_message:forum_topic_edited:icon_custom_emoji_id","edited_message:sticker:is_video","edited_message:sticker:is_animated","edited_message:sticker:premium_animation","edited_message:entities:mention","edited_message:entities:hashtag","edited_message:entities:cashtag","edited_message:entities:bot_command","edited_message:entities:url","edited_message:entities:email","edited_message:entities:phone_number","edited_message:entities:bold","edited_message:entities:italic","edited_message:entities:underline","edited_message:entities:strikethrough","edited_message:entities:spoiler","edited_message:entities:code","edited_message:entities:pre","edited_message:entities:text_link","edited_message:entities:text_mention","edited_message:entities:custom_emoji","edited_message:caption_entities:mention","edited_message:caption_entities:hashtag","edited_message:caption_entities:cashtag","edited_message:caption_entities:bot_command","edited_message:caption_entities:url","edited_message:caption_entities:email","edited_message:caption_entities:phone_number","edited_message:caption_entities:bold","edited_message:caption_entities:italic","edited_message:caption_entities:underline","edited_message:caption_entities:strikethrough","edited_message:caption_entities:spoiler","edited_message:caption_entities:code","edited_message:caption_entities:pre","edited_message:caption_entities:text_link","edited_message:caption_entities:text_mention","edited_message:caption_entities:custom_emoji","channel_post:sticker:is_video","channel_post:sticker:is_animated","channel_post:sticker:premium_animation","channel_post:entities:mention","channel_post:entities:hashtag","channel_post:entities:cashtag","channel_post:entities:bot_command","channel_post:entities:url","channel_post:entities:email","channel_post:entities:phone_number","channel_post:entities:bold","channel_post:entities:italic","channel_post:entities:underline","channel_post:entities:strikethrough","channel_post:entities:spoiler","channel_post:entities:code","channel_post:entities:pre","channel_post:entities:text_link","channel_post:entities:text_mention","channel_post:entities:custom_emoji","channel_post:caption_entities:mention","channel_post:caption_entities:hashtag","channel_post:caption_entities:cashtag","channel_post:caption_entities:bot_command","channel_post:caption_entities:url","channel_post:caption_entities:email","channel_post:caption_entities:phone_number","channel_post:caption_entities:bold","channel_post:caption_entities:italic","channel_post:caption_entities:underline","channel_post:caption_entities:strikethrough","channel_post:caption_entities:spoiler","channel_post:caption_entities:code","channel_post:caption_entities:pre","channel_post:caption_entities:text_link","channel_post:caption_entities:text_mention","channel_post:caption_entities:custom_emoji","edited_channel_post:sticker:is_video","edited_channel_post:sticker:is_animated","edited_channel_post:sticker:premium_animation","edited_channel_post:entities:mention","edited_channel_post:entities:hashtag","edited_channel_post:entities:cashtag","edited_channel_post:entities:bot_command","edited_channel_post:entities:url","edited_channel_post:entities:email","edited_channel_post:entities:phone_number","edited_channel_post:entities:bold","edited_channel_post:entities:italic","edited_channel_post:entities:underline","edited_channel_post:entities:strikethrough","edited_channel_post:entities:spoiler","edited_channel_post:entities:code","edited_channel_post:entities:pre","edited_channel_post:entities:text_link","edited_channel_post:entities:text_mention","edited_channel_post:entities:custom_emoji","edited_channel_post:caption_entities:mention","edited_channel_post:caption_entities:hashtag","edited_channel_post:caption_entities:cashtag","edited_channel_post:caption_entities:bot_command","edited_channel_post:caption_entities:url","edited_channel_post:caption_entities:email","edited_channel_post:caption_entities:phone_number","edited_channel_post:caption_entities:bold","edited_channel_post:caption_entities:italic","edited_channel_post:caption_entities:underline","edited_channel_post:caption_entities:strikethrough","edited_channel_post:caption_entities:spoiler","edited_channel_post:caption_entities:code","edited_channel_post:caption_entities:pre","edited_channel_post:caption_entities:text_link","edited_channel_post:caption_entities:text_mention","edited_channel_post:caption_entities:custom_emoji","my_chat_member:from:me","my_chat_member:from:is_bot","my_chat_member:from:is_premium","my_chat_member:from:added_to_attachment_menu","chat_member:from:me","chat_member:from:is_bot","chat_member:from:is_premium","chat_member:from:added_to_attachment_menu","msg","edit",":poll","msg:poll",":new_chat_members","msg:new_chat_members",":left_chat_member","msg:left_chat_member",":group_chat_created","msg:group_chat_created",":supergroup_chat_created","msg:supergroup_chat_created",":migrate_to_chat_id","msg:migrate_to_chat_id",":migrate_from_chat_id","msg:migrate_from_chat_id",":successful_payment","msg:successful_payment",":user_shared","msg:user_shared",":chat_shared","msg:chat_shared",":connected_website","msg:connected_website",":write_access_allowed","msg:write_access_allowed",":passport_data","msg:passport_data",":forum_topic_created","msg:forum_topic_created",":forum_topic_edited","msg:forum_topic_edited",":forum_topic_closed","msg:forum_topic_closed",":forum_topic_reopened","msg:forum_topic_reopened",":general_forum_topic_hidden","msg:general_forum_topic_hidden",":general_forum_topic_unhidden","msg:general_forum_topic_unhidden","message:file",":sticker",":file","msg:sticker","msg:file",":video_note","msg:video_note",":voice","msg:voice",":contact","msg:contact",":dice","msg:dice",":venue","msg:venue",":new_chat_title","msg:new_chat_title",":new_chat_photo","msg:new_chat_photo",":delete_chat_photo","msg:delete_chat_photo",":message_auto_delete_timer_changed","msg:message_auto_delete_timer_changed",":pinned_message","msg:pinned_message",":invoice","msg:invoice",":proximity_alert_triggered","msg:proximity_alert_triggered",":video_chat_scheduled","msg:video_chat_scheduled",":video_chat_started","msg:video_chat_started",":video_chat_ended","msg:video_chat_ended",":video_chat_participants_invited","msg:video_chat_participants_invited",":web_app_data","msg:web_app_data",":forward_date","msg:forward_date",":is_topic_message","msg:is_topic_message",":is_automatic_forward","msg:is_automatic_forward",":text","msg:text",":animation","msg:animation",":audio","msg:audio",":document","msg:document","message:media",":photo",":media","msg:photo","msg:media",":video","msg:video",":game","msg:game",":location","msg:location",":entities","msg:entities",":caption_entities","msg:caption_entities",":has_media_spoiler","msg:has_media_spoiler",":caption","msg:caption","edit:poll","edit:new_chat_members","edit:left_chat_member","edit:group_chat_created","edit:supergroup_chat_created","edit:migrate_to_chat_id","edit:migrate_from_chat_id","edit:successful_payment","edit:user_shared","edit:chat_shared","edit:connected_website","edit:write_access_allowed","edit:passport_data","edit:forum_topic_created","edit:forum_topic_edited","edit:forum_topic_closed","edit:forum_topic_reopened","edit:general_forum_topic_hidden","edit:general_forum_topic_unhidden","edited_message:file","edit:sticker","edit:file","edit:video_note","edit:voice","edit:contact","edit:dice","edit:venue","edit:new_chat_title","edit:new_chat_photo","edit:delete_chat_photo","edit:message_auto_delete_timer_changed","edit:pinned_message","edit:invoice","edit:proximity_alert_triggered","edit:video_chat_scheduled","edit:video_chat_started","edit:video_chat_ended","edit:video_chat_participants_invited","edit:web_app_data","edit:forward_date","edit:is_topic_message","edit:is_automatic_forward","edit:text","edit:animation","edit:audio","edit:document","edited_message:media","edit:photo","edit:media","edit:video","edit:game","edit:location","edit:entities","edit:caption_entities","edit:has_media_spoiler","edit:caption","channel_post:file","channel_post:media",":channel_chat_created","msg:channel_chat_created","edited_channel_post:file","edited_channel_post:media","edit:channel_chat_created",":new_chat_members:me","msg:new_chat_members:me",":new_chat_members:is_bot","msg:new_chat_members:is_bot",":new_chat_members:is_premium","msg:new_chat_members:is_premium",":new_chat_members:added_to_attachment_menu","msg:new_chat_members:added_to_attachment_menu",":left_chat_member:me","msg:left_chat_member:me",":left_chat_member:is_bot","msg:left_chat_member:is_bot",":left_chat_member:is_premium","msg:left_chat_member:is_premium",":left_chat_member:added_to_attachment_menu","msg:left_chat_member:added_to_attachment_menu",":forum_topic_edited:name","msg:forum_topic_edited:name",":forum_topic_edited:icon_custom_emoji_id","msg:forum_topic_edited:icon_custom_emoji_id","message:file:is_video",":sticker:is_video",":file:is_video","msg:sticker:is_video","msg:file:is_video","message:file:is_animated",":sticker:is_animated",":file:is_animated","msg:sticker:is_animated","msg:file:is_animated","message:file:premium_animation",":sticker:premium_animation",":file:premium_animation","msg:sticker:premium_animation","msg:file:premium_animation","message::mention",":entities:mention","::mention","msg:entities:mention","msg::mention","message::hashtag",":entities:hashtag","::hashtag","msg:entities:hashtag","msg::hashtag","message::cashtag",":entities:cashtag","::cashtag","msg:entities:cashtag","msg::cashtag","message::bot_command",":entities:bot_command","::bot_command","msg:entities:bot_command","msg::bot_command","message::url",":entities:url","::url","msg:entities:url","msg::url","message::email",":entities:email","::email","msg:entities:email","msg::email","message::phone_number",":entities:phone_number","::phone_number","msg:entities:phone_number","msg::phone_number","message::bold",":entities:bold","::bold","msg:entities:bold","msg::bold","message::italic",":entities:italic","::italic","msg:entities:italic","msg::italic","message::underline",":entities:underline","::underline","msg:entities:underline","msg::underline","message::strikethrough",":entities:strikethrough","::strikethrough","msg:entities:strikethrough","msg::strikethrough","message::spoiler",":entities:spoiler","::spoiler","msg:entities:spoiler","msg::spoiler","message::code",":entities:code","::code","msg:entities:code","msg::code","message::pre",":entities:pre","::pre","msg:entities:pre","msg::pre","message::text_link",":entities:text_link","::text_link","msg:entities:text_link","msg::text_link","message::text_mention",":entities:text_mention","::text_mention","msg:entities:text_mention","msg::text_mention","message::custom_emoji",":entities:custom_emoji","::custom_emoji","msg:entities:custom_emoji","msg::custom_emoji",":caption_entities:mention","msg:caption_entities:mention",":caption_entities:hashtag","msg:caption_entities:hashtag",":caption_entities:cashtag","msg:caption_entities:cashtag",":caption_entities:bot_command","msg:caption_entities:bot_command",":caption_entities:url","msg:caption_entities:url",":caption_entities:email","msg:caption_entities:email",":caption_entities:phone_number","msg:caption_entities:phone_number",":caption_entities:bold","msg:caption_entities:bold",":caption_entities:italic","msg:caption_entities:italic",":caption_entities:underline","msg:caption_entities:underline",":caption_entities:strikethrough","msg:caption_entities:strikethrough",":caption_entities:spoiler","msg:caption_entities:spoiler",":caption_entities:code","msg:caption_entities:code",":caption_entities:pre","msg:caption_entities:pre",":caption_entities:text_link","msg:caption_entities:text_link",":caption_entities:text_mention","msg:caption_entities:text_mention",":caption_entities:custom_emoji","msg:caption_entities:custom_emoji","edit:new_chat_members:me","edit:new_chat_members:is_bot","edit:new_chat_members:is_premium","edit:new_chat_members:added_to_attachment_menu","edit:left_chat_member:me","edit:left_chat_member:is_bot","edit:left_chat_member:is_premium","edit:left_chat_member:added_to_attachment_menu","edit:forum_topic_edited:name","edit:forum_topic_edited:icon_custom_emoji_id","edited_message:file:is_video","edit:sticker:is_video","edit:file:is_video","edited_message:file:is_animated","edit:sticker:is_animated","edit:file:is_animated","edited_message:file:premium_animation","edit:sticker:premium_animation","edit:file:premium_animation","edited_message::mention","edit:entities:mention","edit::mention","edited_message::hashtag","edit:entities:hashtag","edit::hashtag","edited_message::cashtag","edit:entities:cashtag","edit::cashtag","edited_message::bot_command","edit:entities:bot_command","edit::bot_command","edited_message::url","edit:entities:url","edit::url","edited_message::email","edit:entities:email","edit::email","edited_message::phone_number","edit:entities:phone_number","edit::phone_number","edited_message::bold","edit:entities:bold","edit::bold","edited_message::italic","edit:entities:italic","edit::italic","edited_message::underline","edit:entities:underline","edit::underline","edited_message::strikethrough","edit:entities:strikethrough","edit::strikethrough","edited_message::spoiler","edit:entities:spoiler","edit::spoiler","edited_message::code","edit:entities:code","edit::code","edited_message::pre","edit:entities:pre","edit::pre","edited_message::text_link","edit:entities:text_link","edit::text_link","edited_message::text_mention","edit:entities:text_mention","edit::text_mention","edited_message::custom_emoji","edit:entities:custom_emoji","edit::custom_emoji","edit:caption_entities:mention","edit:caption_entities:hashtag","edit:caption_entities:cashtag","edit:caption_entities:bot_command","edit:caption_entities:url","edit:caption_entities:email","edit:caption_entities:phone_number","edit:caption_entities:bold","edit:caption_entities:italic","edit:caption_entities:underline","edit:caption_entities:strikethrough","edit:caption_entities:spoiler","edit:caption_entities:code","edit:caption_entities:pre","edit:caption_entities:text_link","edit:caption_entities:text_mention","edit:caption_entities:custom_emoji","channel_post:file:is_video","channel_post:file:is_animated","channel_post:file:premium_animation","channel_post::mention","channel_post::hashtag","channel_post::cashtag","channel_post::bot_command","channel_post::url","channel_post::email","channel_post::phone_number","channel_post::bold","channel_post::italic","channel_post::underline","channel_post::strikethrough","channel_post::spoiler","channel_post::code","channel_post::pre","channel_post::text_link","channel_post::text_mention","channel_post::custom_emoji","edited_channel_post:file:is_video","edited_channel_post:file:is_animated","edited_channel_post:file:premium_animation","edited_channel_post::mention","edited_channel_post::hashtag","edited_channel_post::cashtag","edited_channel_post::bot_command","edited_channel_post::url","edited_channel_post::email","edited_channel_post::phone_number","edited_channel_post::bold","edited_channel_post::italic","edited_channel_post::underline","edited_channel_post::strikethrough","edited_channel_post::spoiler","edited_channel_post::code","edited_channel_post::pre","edited_channel_post::text_link","edited_channel_post::text_mention","edited_channel_post::custom_emoji"]; -------------------------------------------------------------------------------- /assets/webview.js: -------------------------------------------------------------------------------- 1 | "use strict";(()=>{function k(){}function ce(t){return t()}function Me(){return Object.create(null)}function H(t){t.forEach(ce)}function Y(t){return typeof t=="function"}function je(t,e){return t!=t?e==e:t!==e||t&&typeof t=="object"||typeof t=="function"}function Te(t){return Object.keys(t).length===0}var Ce=!1;function rt(){Ce=!0}function _t(){Ce=!1}function $(t,e){t.appendChild(e)}function B(t,e,n){t.insertBefore(e,n||null)}function P(t){t.parentNode&&t.parentNode.removeChild(t)}function Le(t,e){for(let n=0;nt.removeEventListener(e,n,i)}function T(t,e,n){n==null?t.removeAttribute(e):t.getAttribute(e)!==n&&t.setAttribute(e,n)}function lt(t){return Array.from(t.childNodes)}function ae(t,e){e=""+e,t.data!==e&&(t.data=e)}function Ne(t,e,n,i){n===null?t.style.removeProperty(e):t.style.setProperty(e,n,i?"important":"")}var re;function q(t){re=t}var N=[];var Ae=[],D=[],Oe=[],dt=Promise.resolve(),se=!1;function ut(){se||(se=!0,dt.then(De))}function oe(t){D.push(t)}var ie=new Set,R=0;function De(){if(R!==0)return;let t=re;do{try{for(;Rt.indexOf(i)===-1?e.push(i):n.push(i)),n.forEach(i=>i()),D=e}var pt=new Set;function ft(t,e){t&&t.i&&(pt.delete(t),t.i(e))}var rn=typeof window<"u"?window:typeof globalThis<"u"?globalThis:global;var gt=["allowfullscreen","allowpaymentrequest","async","autofocus","autoplay","checked","controls","default","defer","disabled","formnovalidate","hidden","inert","ismap","loop","multiple","muted","nomodule","novalidate","open","playsinline","readonly","required","reversed","selected"],_n=new Set([...gt]);function bt(t,e,n,i){let{fragment:s,after_update:c}=t.$$;s&&s.m(e,n),i||oe(()=>{let o=t.$$.on_mount.map(ce).filter(Y);t.$$.on_destroy?t.$$.on_destroy.push(...o):H(o),t.$$.on_mount=[]}),c.forEach(oe)}function Pe(t,e){let n=t.$$;n.fragment!==null&&(mt(n.after_update),H(n.on_destroy),n.fragment&&n.fragment.d(e),n.on_destroy=n.fragment=null,n.ctx=[])}function yt(t,e){t.$$.dirty[0]===-1&&(N.push(t),ut(),t.$$.dirty.fill(0)),t.$$.dirty[e/31|0]|=1<{let p=m.length?m[0]:h;return a.ctx&&s(a.ctx[d],a.ctx[d]=p)&&(!a.skip_bound&&a.bound[d]&&a.bound[d](p),l&&yt(t,d)),h}):[],a.update(),l=!0,H(a.before_update),a.fragment=i?i(a.ctx):!1,e.target){if(e.hydrate){rt();let d=lt(e.target);a.fragment&&a.fragment.l(d),d.forEach(P)}else a.fragment&&a.fragment.c();e.intro&&ft(t.$$.fragment),bt(t,e.target,e.anchor,e.customElement),_t(),De()}q(_)}var wt;typeof HTMLElement=="function"&&(wt=class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}connectedCallback(){let{on_mount:t}=this.$$;this.$$.on_disconnect=t.map(ce).filter(Y);for(let e in this.$$.slotted)this.appendChild(this.$$.slotted[e])}attributeChangedCallback(t,e,n){this[t]=n}disconnectedCallback(){H(this.$$.on_disconnect)}$destroy(){Pe(this,1),this.$destroy=k}$on(t,e){if(!Y(e))return k;let n=this.$$.callbacks[t]||(this.$$.callbacks[t]=[]);return n.push(e),()=>{let i=n.indexOf(e);i!==-1&&n.splice(i,1)}}$set(t){this.$$set&&!Te(t)&&(this.$$.skip_bound=!0,this.$$set(t),this.$$.skip_bound=!1)}});var G=class{$destroy(){Pe(this,1),this.$destroy=k}$on(e,n){if(!Y(n))return k;let i=this.$$.callbacks[e]||(this.$$.callbacks[e]=[]);return i.push(n),()=>{let s=i.indexOf(n);s!==-1&&i.splice(s,1)}}$set(e){this.$$set&&!Te(e)&&(this.$$.skip_bound=!0,this.$$set(e),this.$$.skip_bound=!1)}};function E(t){return Array.isArray?Array.isArray(t):Ge(t)==="[object Array]"}var vt=1/0;function xt(t){if(typeof t=="string")return t;let e=t+"";return e=="0"&&1/t==-vt?"-0":e}function kt(t){return t==null?"":xt(t)}function w(t){return typeof t=="string"}function ze(t){return typeof t=="number"}function $t(t){return t===!0||t===!1||Et(t)&&Ge(t)=="[object Boolean]"}function Ye(t){return typeof t=="object"}function Et(t){return Ye(t)&&t!==null}function g(t){return t!=null}function _e(t){return!t.trim().length}function Ge(t){return t==null?t===void 0?"[object Undefined]":"[object Null]":Object.prototype.toString.call(t)}var Ft="Incorrect 'index' type",St=t=>`Invalid value for key ${t}`,Mt=t=>`Pattern length exceeds max of ${t}.`,At=t=>`Missing ${t} property in key`,Ot=t=>`Property 'weight' in key '${t}' must be a positive integer`,He=Object.prototype.hasOwnProperty,le=class{constructor(e){this._keys=[],this._keyMap={};let n=0;e.forEach(i=>{let s=Xe(i);n+=s.weight,this._keys.push(s),this._keyMap[s.id]=s,n+=s.weight}),this._keys.forEach(i=>{i.weight/=n})}get(e){return this._keyMap[e]}keys(){return this._keys}toJSON(){return JSON.stringify(this._keys)}};function Xe(t){let e=null,n=null,i=null,s=1,c=null;if(w(t)||E(t))i=t,e=Be(t),n=de(t);else{if(!He.call(t,"name"))throw new Error(At("name"));let o=t.name;if(i=o,He.call(t,"weight")&&(s=t.weight,s<=0))throw new Error(Ot(o));e=Be(o),n=de(o),c=t.getFn}return{path:e,id:n,weight:s,src:i,getFn:c}}function Be(t){return E(t)?t:t.split(".")}function de(t){return E(t)?t.join("."):t}function jt(t,e){let n=[],i=!1,s=(c,o,r)=>{if(g(c))if(!o[r])n.push(c);else{let _=o[r],a=c[_];if(!g(a))return;if(r===o.length-1&&(w(a)||ze(a)||$t(a)))n.push(kt(a));else if(E(a)){i=!0;for(let l=0,d=a.length;lt.score===e.score?t.idx{this._keysMap[n.id]=i})}create(){this.isCreated||!this.docs.length||(this.isCreated=!0,w(this.docs[0])?this.docs.forEach((e,n)=>{this._addString(e,n)}):this.docs.forEach((e,n)=>{this._addObject(e,n)}),this.norm.clear())}add(e){let n=this.size();w(e)?this._addString(e,n):this._addObject(e,n)}removeAt(e){this.records.splice(e,1);for(let n=e,i=this.size();n{let o=s.getFn?s.getFn(e):this.getFn(e,s.path);if(g(o)){if(E(o)){let r=[],_=[{nestedArrIndex:-1,value:o}];for(;_.length;){let{nestedArrIndex:a,value:l}=_.pop();if(g(l))if(w(l)&&!_e(l)){let d={v:l,i:a,n:this.norm.get(l)};r.push(d)}else E(l)&&l.forEach((d,h)=>{_.push({nestedArrIndex:h,value:d})})}i.$[c]=r}else if(w(o)&&!_e(o)){let r={v:o,n:this.norm.get(o)};i.$[c]=r}}}),this.records.push(i)}toJSON(){return{keys:this.keys,records:this.records}}};function Qe(t,e,{getFn:n=u.getFn,fieldNormWeight:i=u.fieldNormWeight}={}){let s=new W({getFn:n,fieldNormWeight:i});return s.setKeys(t.map(Xe)),s.setSources(e),s.create(),s}function Dt(t,{getFn:e=u.getFn,fieldNormWeight:n=u.fieldNormWeight}={}){let{keys:i,records:s}=t,c=new W({getFn:e,fieldNormWeight:n});return c.setKeys(i),c.setIndexRecords(s),c}function Q(t,{errors:e=0,currentLocation:n=0,expectedLocation:i=0,distance:s=u.distance,ignoreLocation:c=u.ignoreLocation}={}){let o=e/t.length;if(c)return o;let r=Math.abs(i-n);return s?o+r/s:r?1:o}function Pt(t=[],e=u.minMatchCharLength){let n=[],i=-1,s=-1,c=0;for(let o=t.length;c=e&&n.push([i,s]),i=-1)}return t[c-1]&&c-i>=e&&n.push([i,c-1]),n}var C=32;function qt(t,e,n,{location:i=u.location,distance:s=u.distance,threshold:c=u.threshold,findAllMatches:o=u.findAllMatches,minMatchCharLength:r=u.minMatchCharLength,includeMatches:_=u.includeMatches,ignoreLocation:a=u.ignoreLocation}={}){if(e.length>C)throw new Error(Mt(C));let l=e.length,d=t.length,h=Math.max(0,Math.min(i,d)),m=c,p=h,f=r>1||_,A=f?Array(d):[],x;for(;(x=t.indexOf(e,p))>-1;){let b=Q(e,{currentLocation:x,expectedLocation:h,distance:s,ignoreLocation:a});if(m=Math.min(b,m),p=x+l,f){let S=0;for(;S=Fe;y-=1){let z=y-1,Se=n[t.charAt(z)];if(f&&(A[z]=+!!Se),I[y]=(I[y+1]<<1|1)&Se,b&&(I[y]|=(L[y+1]|L[y])<<1|1|L[y+1]),I[y]&at&&(O=Q(e,{errors:b,currentLocation:z,expectedLocation:h,distance:s,ignoreLocation:a}),O<=m)){if(m=O,p=z,p<=h)break;Fe=Math.max(1,2*h-p)}}if(Q(e,{errors:b+1,currentLocation:h,expectedLocation:h,distance:s,ignoreLocation:a})>m)break;L=I}let te={isMatch:p>=0,score:Math.max(.001,O)};if(f){let b=Pt(A,r);b.length?_&&(te.indices=b):te.isMatch=!1}return te}function Ht(t){let e={};for(let n=0,i=t.length;n{this.chunks.push({pattern:h,alphabet:Ht(h),startIndex:m})},d=this.pattern.length;if(d>C){let h=0,m=d%C,p=d-m;for(;h{let{isMatch:x,score:L,indices:O}=qt(e,p,f,{location:s+A,distance:c,threshold:o,findAllMatches:r,minMatchCharLength:_,includeMatches:i,ignoreLocation:a});x&&(h=!0),d+=L,x&&O&&(l=[...l,...O])});let m={isMatch:h,score:h?d/this.chunks.length:1};return h&&i&&(m.indices=l),m}},v=class{constructor(e){this.pattern=e}static isMultiMatch(e){return Ue(e,this.multiRegex)}static isSingleMatch(e){return Ue(e,this.singleRegex)}search(){}};function Ue(t,e){let n=t.match(e);return n?n[1]:null}var ue=class extends v{constructor(e){super(e)}static get type(){return"exact"}static get multiRegex(){return/^="(.*)"$/}static get singleRegex(){return/^=(.*)$/}search(e){let n=e===this.pattern;return{isMatch:n,score:n?0:1,indices:[0,this.pattern.length-1]}}},he=class extends v{constructor(e){super(e)}static get type(){return"inverse-exact"}static get multiRegex(){return/^!"(.*)"$/}static get singleRegex(){return/^!(.*)$/}search(e){let i=e.indexOf(this.pattern)===-1;return{isMatch:i,score:i?0:1,indices:[0,e.length-1]}}},me=class extends v{constructor(e){super(e)}static get type(){return"prefix-exact"}static get multiRegex(){return/^\^"(.*)"$/}static get singleRegex(){return/^\^(.*)$/}search(e){let n=e.startsWith(this.pattern);return{isMatch:n,score:n?0:1,indices:[0,this.pattern.length-1]}}},pe=class extends v{constructor(e){super(e)}static get type(){return"inverse-prefix-exact"}static get multiRegex(){return/^!\^"(.*)"$/}static get singleRegex(){return/^!\^(.*)$/}search(e){let n=!e.startsWith(this.pattern);return{isMatch:n,score:n?0:1,indices:[0,e.length-1]}}},fe=class extends v{constructor(e){super(e)}static get type(){return"suffix-exact"}static get multiRegex(){return/^"(.*)"\$$/}static get singleRegex(){return/^(.*)\$$/}search(e){let n=e.endsWith(this.pattern);return{isMatch:n,score:n?0:1,indices:[e.length-this.pattern.length,e.length-1]}}},ge=class extends v{constructor(e){super(e)}static get type(){return"inverse-suffix-exact"}static get multiRegex(){return/^!"(.*)"\$$/}static get singleRegex(){return/^!(.*)\$$/}search(e){let n=!e.endsWith(this.pattern);return{isMatch:n,score:n?0:1,indices:[0,e.length-1]}}},J=class extends v{constructor(e,{location:n=u.location,threshold:i=u.threshold,distance:s=u.distance,includeMatches:c=u.includeMatches,findAllMatches:o=u.findAllMatches,minMatchCharLength:r=u.minMatchCharLength,isCaseSensitive:_=u.isCaseSensitive,ignoreLocation:a=u.ignoreLocation}={}){super(e),this._bitapSearch=new V(e,{location:n,threshold:i,distance:s,includeMatches:c,findAllMatches:o,minMatchCharLength:r,isCaseSensitive:_,ignoreLocation:a})}static get type(){return"fuzzy"}static get multiRegex(){return/^"(.*)"$/}static get singleRegex(){return/^(.*)$/}search(e){return this._bitapSearch.searchIn(e)}},Z=class extends v{constructor(e){super(e)}static get type(){return"include"}static get multiRegex(){return/^'"(.*)"$/}static get singleRegex(){return/^'(.*)$/}search(e){let n=0,i,s=[],c=this.pattern.length;for(;(i=e.indexOf(this.pattern,n))>-1;)n=i+c,s.push([i,n-1]);let o=!!s.length;return{isMatch:o,score:o?0:1,indices:s}}},be=[ue,Z,me,pe,ge,fe,he,J],We=be.length,Bt=/ +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/,Ut="|";function Wt(t,e={}){return t.split(Ut).map(n=>{let i=n.trim().split(Bt).filter(c=>c&&!!c.trim()),s=[];for(let c=0,o=i.length;c!!(t[ee.AND]||t[ee.OR]),Yt=t=>!!t[xe.PATH],Gt=t=>!E(t)&&Ye(t)&&!ke(t),Ke=t=>({[ee.AND]:Object.keys(t).map(e=>({[e]:t[e]}))});function Ve(t,e,{auto:n=!0}={}){let i=s=>{let c=Object.keys(s),o=Yt(s);if(!o&&c.length>1&&!ke(s))return i(Ke(s));if(Gt(s)){let _=o?s[xe.PATH]:c[0],a=o?s[xe.PATTERN]:s[_];if(!w(a))throw new Error(St(_));let l={keyId:de(_),pattern:a};return n&&(l.searcher=ve(a,e)),l}let r={children:[],operator:c[0]};return c.forEach(_=>{let a=s[_];E(a)&&a.forEach(l=>{r.children.push(i(l))})}),r};return ke(t)||(t=Ke(t)),i(t)}function Xt(t,{ignoreFieldNorm:e=u.ignoreFieldNorm}){t.forEach(n=>{let i=1;n.matches.forEach(({key:s,norm:c,score:o})=>{let r=s?s.weight:null;i*=Math.pow(o===0&&r?Number.EPSILON:o,(r||1)*(e?1:c))}),n.score=i})}function Qt(t,e){let n=t.matches;e.matches=[],g(n)&&n.forEach(i=>{if(!g(i.indices)||!i.indices.length)return;let{indices:s,value:c}=i,o={indices:s,value:c};i.key&&(o.key=i.key.src),i.idx>-1&&(o.refIndex=i.idx),e.matches.push(o)})}function Vt(t,e){e.score=t.score}function Jt(t,e,{includeMatches:n=u.includeMatches,includeScore:i=u.includeScore}={}){let s=[];return n&&s.push(Qt),i&&s.push(Vt),t.map(c=>{let{idx:o}=c,r={item:e[o],refIndex:o};return s.length&&s.forEach(_=>{_(c,r)}),r})}var F=class{constructor(e,n={},i){this.options={...u,...n},this.options.useExtendedSearch,this._keyStore=new le(this.options.keys),this.setCollection(e,i)}setCollection(e,n){if(this._docs=e,n&&!(n instanceof W))throw new Error(Ft);this._myIndex=n||Qe(this.options.keys,this._docs,{getFn:this.options.getFn,fieldNormWeight:this.options.fieldNormWeight})}add(e){g(e)&&(this._docs.push(e),this._myIndex.add(e))}remove(e=()=>!1){let n=[];for(let i=0,s=this._docs.length;i-1&&(_=_.slice(0,n)),Jt(_,this._docs,{includeMatches:i,includeScore:s})}_searchStringList(e){let n=ve(e,this.options),{records:i}=this._myIndex,s=[];return i.forEach(({v:c,i:o,n:r})=>{if(!g(c))return;let{isMatch:_,score:a,indices:l}=n.searchIn(c);_&&s.push({item:c,idx:o,matches:[{score:a,value:c,norm:r,indices:l}]})}),s}_searchLogical(e){let n=Ve(e,this.options),i=(r,_,a)=>{if(!r.children){let{keyId:d,searcher:h}=r,m=this._findMatches({key:this._keyStore.get(d),value:this._myIndex.getValueForItemAtKeyId(_,d),searcher:h});return m&&m.length?[{idx:a,item:_,matches:m}]:[]}let l=[];for(let d=0,h=r.children.length;d{if(g(r)){let a=i(n,r,_);a.length&&(c[_]||(c[_]={idx:_,item:r,matches:[]},o.push(c[_])),a.forEach(({matches:l})=>{c[_].matches.push(...l)}))}}),o}_searchObjectList(e){let n=ve(e,this.options),{keys:i,records:s}=this._myIndex,c=[];return s.forEach(({$:o,i:r})=>{if(!g(o))return;let _=[];i.forEach((a,l)=>{_.push(...this._findMatches({key:a,value:o[l],searcher:n}))}),_.length&&c.push({idx:r,item:o,matches:_})}),c}_findMatches({key:e,value:n,searcher:i}){if(!g(n))return[];let s=[];if(E(n))n.forEach(({v:c,i:o,n:r})=>{if(!g(c))return;let{isMatch:_,score:a,indices:l}=i.searchIn(c);_&&s.push({score:a,key:e,value:c,idx:o,norm:r,indices:l})});else{let{v:c,n:o}=n,{isMatch:r,score:_,indices:a}=i.searchIn(c);r&&s.push({score:_,key:e,value:c,norm:o,indices:a})}return s}};F.version="6.6.2";F.createIndex=Qe;F.parseIndex=Dt;F.config=u;F.parseQuery=Ve;zt(ye);var Je=["message","edited_message","channel_post","edited_channel_post","inline_query","chosen_inline_result","callback_query","shipping_query","pre_checkout_query","poll","poll_answer","my_chat_member","chat_member","chat_join_request","message:poll","message:new_chat_members","message:left_chat_member","message:group_chat_created","message:supergroup_chat_created","message:migrate_to_chat_id","message:migrate_from_chat_id","message:successful_payment","message:user_shared","message:chat_shared","message:connected_website","message:write_access_allowed","message:passport_data","message:forum_topic_created","message:forum_topic_edited","message:forum_topic_closed","message:forum_topic_reopened","message:general_forum_topic_hidden","message:general_forum_topic_unhidden","message:sticker","message:video_note","message:voice","message:contact","message:dice","message:venue","message:new_chat_title","message:new_chat_photo","message:delete_chat_photo","message:message_auto_delete_timer_changed","message:pinned_message","message:invoice","message:proximity_alert_triggered","message:video_chat_scheduled","message:video_chat_started","message:video_chat_ended","message:video_chat_participants_invited","message:web_app_data","message:forward_date","message:is_topic_message","message:is_automatic_forward","message:text","message:animation","message:audio","message:document","message:photo","message:video","message:game","message:location","message:entities","message:caption_entities","message:has_media_spoiler","message:caption","edited_message:poll","edited_message:new_chat_members","edited_message:left_chat_member","edited_message:group_chat_created","edited_message:supergroup_chat_created","edited_message:migrate_to_chat_id","edited_message:migrate_from_chat_id","edited_message:successful_payment","edited_message:user_shared","edited_message:chat_shared","edited_message:connected_website","edited_message:write_access_allowed","edited_message:passport_data","edited_message:forum_topic_created","edited_message:forum_topic_edited","edited_message:forum_topic_closed","edited_message:forum_topic_reopened","edited_message:general_forum_topic_hidden","edited_message:general_forum_topic_unhidden","edited_message:sticker","edited_message:video_note","edited_message:voice","edited_message:contact","edited_message:dice","edited_message:venue","edited_message:new_chat_title","edited_message:new_chat_photo","edited_message:delete_chat_photo","edited_message:message_auto_delete_timer_changed","edited_message:pinned_message","edited_message:invoice","edited_message:proximity_alert_triggered","edited_message:video_chat_scheduled","edited_message:video_chat_started","edited_message:video_chat_ended","edited_message:video_chat_participants_invited","edited_message:web_app_data","edited_message:forward_date","edited_message:is_topic_message","edited_message:is_automatic_forward","edited_message:text","edited_message:animation","edited_message:audio","edited_message:document","edited_message:photo","edited_message:video","edited_message:game","edited_message:location","edited_message:entities","edited_message:caption_entities","edited_message:has_media_spoiler","edited_message:caption","channel_post:poll","channel_post:sticker","channel_post:video_note","channel_post:voice","channel_post:contact","channel_post:dice","channel_post:venue","channel_post:new_chat_title","channel_post:new_chat_photo","channel_post:delete_chat_photo","channel_post:message_auto_delete_timer_changed","channel_post:pinned_message","channel_post:invoice","channel_post:proximity_alert_triggered","channel_post:video_chat_scheduled","channel_post:video_chat_started","channel_post:video_chat_ended","channel_post:video_chat_participants_invited","channel_post:web_app_data","channel_post:forward_date","channel_post:is_topic_message","channel_post:is_automatic_forward","channel_post:text","channel_post:animation","channel_post:audio","channel_post:document","channel_post:photo","channel_post:video","channel_post:game","channel_post:location","channel_post:entities","channel_post:caption_entities","channel_post:has_media_spoiler","channel_post:caption","channel_post:channel_chat_created","edited_channel_post:poll","edited_channel_post:sticker","edited_channel_post:video_note","edited_channel_post:voice","edited_channel_post:contact","edited_channel_post:dice","edited_channel_post:venue","edited_channel_post:new_chat_title","edited_channel_post:new_chat_photo","edited_channel_post:delete_chat_photo","edited_channel_post:message_auto_delete_timer_changed","edited_channel_post:pinned_message","edited_channel_post:invoice","edited_channel_post:proximity_alert_triggered","edited_channel_post:video_chat_scheduled","edited_channel_post:video_chat_started","edited_channel_post:video_chat_ended","edited_channel_post:video_chat_participants_invited","edited_channel_post:web_app_data","edited_channel_post:forward_date","edited_channel_post:is_topic_message","edited_channel_post:is_automatic_forward","edited_channel_post:text","edited_channel_post:animation","edited_channel_post:audio","edited_channel_post:document","edited_channel_post:photo","edited_channel_post:video","edited_channel_post:game","edited_channel_post:location","edited_channel_post:entities","edited_channel_post:caption_entities","edited_channel_post:has_media_spoiler","edited_channel_post:caption","edited_channel_post:channel_chat_created","callback_query:data","callback_query:game_short_name","my_chat_member:from","chat_member:from","message:new_chat_members:me","message:new_chat_members:is_bot","message:new_chat_members:is_premium","message:new_chat_members:added_to_attachment_menu","message:left_chat_member:me","message:left_chat_member:is_bot","message:left_chat_member:is_premium","message:left_chat_member:added_to_attachment_menu","message:forum_topic_edited:name","message:forum_topic_edited:icon_custom_emoji_id","message:sticker:is_video","message:sticker:is_animated","message:sticker:premium_animation","message:entities:mention","message:entities:hashtag","message:entities:cashtag","message:entities:bot_command","message:entities:url","message:entities:email","message:entities:phone_number","message:entities:bold","message:entities:italic","message:entities:underline","message:entities:strikethrough","message:entities:spoiler","message:entities:code","message:entities:pre","message:entities:text_link","message:entities:text_mention","message:entities:custom_emoji","message:caption_entities:mention","message:caption_entities:hashtag","message:caption_entities:cashtag","message:caption_entities:bot_command","message:caption_entities:url","message:caption_entities:email","message:caption_entities:phone_number","message:caption_entities:bold","message:caption_entities:italic","message:caption_entities:underline","message:caption_entities:strikethrough","message:caption_entities:spoiler","message:caption_entities:code","message:caption_entities:pre","message:caption_entities:text_link","message:caption_entities:text_mention","message:caption_entities:custom_emoji","edited_message:new_chat_members:me","edited_message:new_chat_members:is_bot","edited_message:new_chat_members:is_premium","edited_message:new_chat_members:added_to_attachment_menu","edited_message:left_chat_member:me","edited_message:left_chat_member:is_bot","edited_message:left_chat_member:is_premium","edited_message:left_chat_member:added_to_attachment_menu","edited_message:forum_topic_edited:name","edited_message:forum_topic_edited:icon_custom_emoji_id","edited_message:sticker:is_video","edited_message:sticker:is_animated","edited_message:sticker:premium_animation","edited_message:entities:mention","edited_message:entities:hashtag","edited_message:entities:cashtag","edited_message:entities:bot_command","edited_message:entities:url","edited_message:entities:email","edited_message:entities:phone_number","edited_message:entities:bold","edited_message:entities:italic","edited_message:entities:underline","edited_message:entities:strikethrough","edited_message:entities:spoiler","edited_message:entities:code","edited_message:entities:pre","edited_message:entities:text_link","edited_message:entities:text_mention","edited_message:entities:custom_emoji","edited_message:caption_entities:mention","edited_message:caption_entities:hashtag","edited_message:caption_entities:cashtag","edited_message:caption_entities:bot_command","edited_message:caption_entities:url","edited_message:caption_entities:email","edited_message:caption_entities:phone_number","edited_message:caption_entities:bold","edited_message:caption_entities:italic","edited_message:caption_entities:underline","edited_message:caption_entities:strikethrough","edited_message:caption_entities:spoiler","edited_message:caption_entities:code","edited_message:caption_entities:pre","edited_message:caption_entities:text_link","edited_message:caption_entities:text_mention","edited_message:caption_entities:custom_emoji","channel_post:sticker:is_video","channel_post:sticker:is_animated","channel_post:sticker:premium_animation","channel_post:entities:mention","channel_post:entities:hashtag","channel_post:entities:cashtag","channel_post:entities:bot_command","channel_post:entities:url","channel_post:entities:email","channel_post:entities:phone_number","channel_post:entities:bold","channel_post:entities:italic","channel_post:entities:underline","channel_post:entities:strikethrough","channel_post:entities:spoiler","channel_post:entities:code","channel_post:entities:pre","channel_post:entities:text_link","channel_post:entities:text_mention","channel_post:entities:custom_emoji","channel_post:caption_entities:mention","channel_post:caption_entities:hashtag","channel_post:caption_entities:cashtag","channel_post:caption_entities:bot_command","channel_post:caption_entities:url","channel_post:caption_entities:email","channel_post:caption_entities:phone_number","channel_post:caption_entities:bold","channel_post:caption_entities:italic","channel_post:caption_entities:underline","channel_post:caption_entities:strikethrough","channel_post:caption_entities:spoiler","channel_post:caption_entities:code","channel_post:caption_entities:pre","channel_post:caption_entities:text_link","channel_post:caption_entities:text_mention","channel_post:caption_entities:custom_emoji","edited_channel_post:sticker:is_video","edited_channel_post:sticker:is_animated","edited_channel_post:sticker:premium_animation","edited_channel_post:entities:mention","edited_channel_post:entities:hashtag","edited_channel_post:entities:cashtag","edited_channel_post:entities:bot_command","edited_channel_post:entities:url","edited_channel_post:entities:email","edited_channel_post:entities:phone_number","edited_channel_post:entities:bold","edited_channel_post:entities:italic","edited_channel_post:entities:underline","edited_channel_post:entities:strikethrough","edited_channel_post:entities:spoiler","edited_channel_post:entities:code","edited_channel_post:entities:pre","edited_channel_post:entities:text_link","edited_channel_post:entities:text_mention","edited_channel_post:entities:custom_emoji","edited_channel_post:caption_entities:mention","edited_channel_post:caption_entities:hashtag","edited_channel_post:caption_entities:cashtag","edited_channel_post:caption_entities:bot_command","edited_channel_post:caption_entities:url","edited_channel_post:caption_entities:email","edited_channel_post:caption_entities:phone_number","edited_channel_post:caption_entities:bold","edited_channel_post:caption_entities:italic","edited_channel_post:caption_entities:underline","edited_channel_post:caption_entities:strikethrough","edited_channel_post:caption_entities:spoiler","edited_channel_post:caption_entities:code","edited_channel_post:caption_entities:pre","edited_channel_post:caption_entities:text_link","edited_channel_post:caption_entities:text_mention","edited_channel_post:caption_entities:custom_emoji","my_chat_member:from:me","my_chat_member:from:is_bot","my_chat_member:from:is_premium","my_chat_member:from:added_to_attachment_menu","chat_member:from:me","chat_member:from:is_bot","chat_member:from:is_premium","chat_member:from:added_to_attachment_menu","msg","edit",":poll","msg:poll",":new_chat_members","msg:new_chat_members",":left_chat_member","msg:left_chat_member",":group_chat_created","msg:group_chat_created",":supergroup_chat_created","msg:supergroup_chat_created",":migrate_to_chat_id","msg:migrate_to_chat_id",":migrate_from_chat_id","msg:migrate_from_chat_id",":successful_payment","msg:successful_payment",":user_shared","msg:user_shared",":chat_shared","msg:chat_shared",":connected_website","msg:connected_website",":write_access_allowed","msg:write_access_allowed",":passport_data","msg:passport_data",":forum_topic_created","msg:forum_topic_created",":forum_topic_edited","msg:forum_topic_edited",":forum_topic_closed","msg:forum_topic_closed",":forum_topic_reopened","msg:forum_topic_reopened",":general_forum_topic_hidden","msg:general_forum_topic_hidden",":general_forum_topic_unhidden","msg:general_forum_topic_unhidden","message:file",":sticker",":file","msg:sticker","msg:file",":video_note","msg:video_note",":voice","msg:voice",":contact","msg:contact",":dice","msg:dice",":venue","msg:venue",":new_chat_title","msg:new_chat_title",":new_chat_photo","msg:new_chat_photo",":delete_chat_photo","msg:delete_chat_photo",":message_auto_delete_timer_changed","msg:message_auto_delete_timer_changed",":pinned_message","msg:pinned_message",":invoice","msg:invoice",":proximity_alert_triggered","msg:proximity_alert_triggered",":video_chat_scheduled","msg:video_chat_scheduled",":video_chat_started","msg:video_chat_started",":video_chat_ended","msg:video_chat_ended",":video_chat_participants_invited","msg:video_chat_participants_invited",":web_app_data","msg:web_app_data",":forward_date","msg:forward_date",":is_topic_message","msg:is_topic_message",":is_automatic_forward","msg:is_automatic_forward",":text","msg:text",":animation","msg:animation",":audio","msg:audio",":document","msg:document","message:media",":photo",":media","msg:photo","msg:media",":video","msg:video",":game","msg:game",":location","msg:location",":entities","msg:entities",":caption_entities","msg:caption_entities",":has_media_spoiler","msg:has_media_spoiler",":caption","msg:caption","edit:poll","edit:new_chat_members","edit:left_chat_member","edit:group_chat_created","edit:supergroup_chat_created","edit:migrate_to_chat_id","edit:migrate_from_chat_id","edit:successful_payment","edit:user_shared","edit:chat_shared","edit:connected_website","edit:write_access_allowed","edit:passport_data","edit:forum_topic_created","edit:forum_topic_edited","edit:forum_topic_closed","edit:forum_topic_reopened","edit:general_forum_topic_hidden","edit:general_forum_topic_unhidden","edited_message:file","edit:sticker","edit:file","edit:video_note","edit:voice","edit:contact","edit:dice","edit:venue","edit:new_chat_title","edit:new_chat_photo","edit:delete_chat_photo","edit:message_auto_delete_timer_changed","edit:pinned_message","edit:invoice","edit:proximity_alert_triggered","edit:video_chat_scheduled","edit:video_chat_started","edit:video_chat_ended","edit:video_chat_participants_invited","edit:web_app_data","edit:forward_date","edit:is_topic_message","edit:is_automatic_forward","edit:text","edit:animation","edit:audio","edit:document","edited_message:media","edit:photo","edit:media","edit:video","edit:game","edit:location","edit:entities","edit:caption_entities","edit:has_media_spoiler","edit:caption","channel_post:file","channel_post:media",":channel_chat_created","msg:channel_chat_created","edited_channel_post:file","edited_channel_post:media","edit:channel_chat_created",":new_chat_members:me","msg:new_chat_members:me",":new_chat_members:is_bot","msg:new_chat_members:is_bot",":new_chat_members:is_premium","msg:new_chat_members:is_premium",":new_chat_members:added_to_attachment_menu","msg:new_chat_members:added_to_attachment_menu",":left_chat_member:me","msg:left_chat_member:me",":left_chat_member:is_bot","msg:left_chat_member:is_bot",":left_chat_member:is_premium","msg:left_chat_member:is_premium",":left_chat_member:added_to_attachment_menu","msg:left_chat_member:added_to_attachment_menu",":forum_topic_edited:name","msg:forum_topic_edited:name",":forum_topic_edited:icon_custom_emoji_id","msg:forum_topic_edited:icon_custom_emoji_id","message:file:is_video",":sticker:is_video",":file:is_video","msg:sticker:is_video","msg:file:is_video","message:file:is_animated",":sticker:is_animated",":file:is_animated","msg:sticker:is_animated","msg:file:is_animated","message:file:premium_animation",":sticker:premium_animation",":file:premium_animation","msg:sticker:premium_animation","msg:file:premium_animation","message::mention",":entities:mention","::mention","msg:entities:mention","msg::mention","message::hashtag",":entities:hashtag","::hashtag","msg:entities:hashtag","msg::hashtag","message::cashtag",":entities:cashtag","::cashtag","msg:entities:cashtag","msg::cashtag","message::bot_command",":entities:bot_command","::bot_command","msg:entities:bot_command","msg::bot_command","message::url",":entities:url","::url","msg:entities:url","msg::url","message::email",":entities:email","::email","msg:entities:email","msg::email","message::phone_number",":entities:phone_number","::phone_number","msg:entities:phone_number","msg::phone_number","message::bold",":entities:bold","::bold","msg:entities:bold","msg::bold","message::italic",":entities:italic","::italic","msg:entities:italic","msg::italic","message::underline",":entities:underline","::underline","msg:entities:underline","msg::underline","message::strikethrough",":entities:strikethrough","::strikethrough","msg:entities:strikethrough","msg::strikethrough","message::spoiler",":entities:spoiler","::spoiler","msg:entities:spoiler","msg::spoiler","message::code",":entities:code","::code","msg:entities:code","msg::code","message::pre",":entities:pre","::pre","msg:entities:pre","msg::pre","message::text_link",":entities:text_link","::text_link","msg:entities:text_link","msg::text_link","message::text_mention",":entities:text_mention","::text_mention","msg:entities:text_mention","msg::text_mention","message::custom_emoji",":entities:custom_emoji","::custom_emoji","msg:entities:custom_emoji","msg::custom_emoji",":caption_entities:mention","msg:caption_entities:mention",":caption_entities:hashtag","msg:caption_entities:hashtag",":caption_entities:cashtag","msg:caption_entities:cashtag",":caption_entities:bot_command","msg:caption_entities:bot_command",":caption_entities:url","msg:caption_entities:url",":caption_entities:email","msg:caption_entities:email",":caption_entities:phone_number","msg:caption_entities:phone_number",":caption_entities:bold","msg:caption_entities:bold",":caption_entities:italic","msg:caption_entities:italic",":caption_entities:underline","msg:caption_entities:underline",":caption_entities:strikethrough","msg:caption_entities:strikethrough",":caption_entities:spoiler","msg:caption_entities:spoiler",":caption_entities:code","msg:caption_entities:code",":caption_entities:pre","msg:caption_entities:pre",":caption_entities:text_link","msg:caption_entities:text_link",":caption_entities:text_mention","msg:caption_entities:text_mention",":caption_entities:custom_emoji","msg:caption_entities:custom_emoji","edit:new_chat_members:me","edit:new_chat_members:is_bot","edit:new_chat_members:is_premium","edit:new_chat_members:added_to_attachment_menu","edit:left_chat_member:me","edit:left_chat_member:is_bot","edit:left_chat_member:is_premium","edit:left_chat_member:added_to_attachment_menu","edit:forum_topic_edited:name","edit:forum_topic_edited:icon_custom_emoji_id","edited_message:file:is_video","edit:sticker:is_video","edit:file:is_video","edited_message:file:is_animated","edit:sticker:is_animated","edit:file:is_animated","edited_message:file:premium_animation","edit:sticker:premium_animation","edit:file:premium_animation","edited_message::mention","edit:entities:mention","edit::mention","edited_message::hashtag","edit:entities:hashtag","edit::hashtag","edited_message::cashtag","edit:entities:cashtag","edit::cashtag","edited_message::bot_command","edit:entities:bot_command","edit::bot_command","edited_message::url","edit:entities:url","edit::url","edited_message::email","edit:entities:email","edit::email","edited_message::phone_number","edit:entities:phone_number","edit::phone_number","edited_message::bold","edit:entities:bold","edit::bold","edited_message::italic","edit:entities:italic","edit::italic","edited_message::underline","edit:entities:underline","edit::underline","edited_message::strikethrough","edit:entities:strikethrough","edit::strikethrough","edited_message::spoiler","edit:entities:spoiler","edit::spoiler","edited_message::code","edit:entities:code","edit::code","edited_message::pre","edit:entities:pre","edit::pre","edited_message::text_link","edit:entities:text_link","edit::text_link","edited_message::text_mention","edit:entities:text_mention","edit::text_mention","edited_message::custom_emoji","edit:entities:custom_emoji","edit::custom_emoji","edit:caption_entities:mention","edit:caption_entities:hashtag","edit:caption_entities:cashtag","edit:caption_entities:bot_command","edit:caption_entities:url","edit:caption_entities:email","edit:caption_entities:phone_number","edit:caption_entities:bold","edit:caption_entities:italic","edit:caption_entities:underline","edit:caption_entities:strikethrough","edit:caption_entities:spoiler","edit:caption_entities:code","edit:caption_entities:pre","edit:caption_entities:text_link","edit:caption_entities:text_mention","edit:caption_entities:custom_emoji","channel_post:file:is_video","channel_post:file:is_animated","channel_post:file:premium_animation","channel_post::mention","channel_post::hashtag","channel_post::cashtag","channel_post::bot_command","channel_post::url","channel_post::email","channel_post::phone_number","channel_post::bold","channel_post::italic","channel_post::underline","channel_post::strikethrough","channel_post::spoiler","channel_post::code","channel_post::pre","channel_post::text_link","channel_post::text_mention","channel_post::custom_emoji","edited_channel_post:file:is_video","edited_channel_post:file:is_animated","edited_channel_post:file:premium_animation","edited_channel_post::mention","edited_channel_post::hashtag","edited_channel_post::cashtag","edited_channel_post::bot_command","edited_channel_post::url","edited_channel_post::email","edited_channel_post::phone_number","edited_channel_post::bold","edited_channel_post::italic","edited_channel_post::underline","edited_channel_post::strikethrough","edited_channel_post::spoiler","edited_channel_post::code","edited_channel_post::pre","edited_channel_post::text_link","edited_channel_post::text_mention","edited_channel_post::custom_emoji"];var Ze=["message","edited_message","channel_post","edited_channel_post","inline_query","chosen_inline_result","callback_query","shipping_query","pre_checkout_query","poll","poll_answer","my_chat_member","chat_member","chat_join_request"],et={"":["message","channel_post"],msg:["message","channel_post"],edit:["edited_message","edited_channel_post"]},tt={"":["entities","caption_entities"],media:["photo","video"],file:["photo","animation","audio","document","video","video_note","voice","sticker"]};function Zt(t,e){return t[0]+t.split(e).map(n=>n[0].toUpperCase()+n.substring(1)).join("").substring(1)}var $e=Ze.reduce((t,e)=>({...t,[e]:Zt(e,"_")}),{});function nt(t){return t.map((e,n)=>`${n===0?"":" / "}${e}`)}var en={chat_member:"You need to specify this update in allowed_updates to receive them."};function it(){let t=[];for(let e of Je){let[n,i,s]=e.split(":"),c=et[n]??[n],o=tt[i]??[i],r=en?.[e],_=nt(c),a=nt(o),l="";if(c[0]&&!o[0]&&!s)l=[`Query for filtering "${_}" update.`,"Here's how you can access the information about the update:",c.map(d=>`ctx.${$e[d]};`).join(` 2 | 3 | `)].join(` 4 | 5 | `);else if(c[0]&&o[0]&&!s)l=[`Query for filtering "${_}" update with the field "${a}".`,"Here is how you can access the properties of the field:",c.map(d=>o.map(h=>`ctx.${$e[d]}.${h};`).join(` 6 | 7 | `)).join(` 8 | 9 | `)].join(` 10 | 11 | `);else if(c[0]&&o[0]&&s){let d=o.includes("entities"),h=d?`containing at least one entity of the type "${s}"`:`with "${s}" property`,m=o.join().includes("entities")?`ctx.entities("${s}");`:c.map(p=>o.map(f=>`ctx.${$e[p]}.${f}.${s};`).join(` 12 | 13 | `)).join(` 14 | 15 | `);l=[`Query for filtering "${_}" update with the field "${a}" ${h}.`,`Here is how you can access the ${d?`entities of "${s}" type`:`"${s}" property`}:`,m].join(` 16 | 17 | `)}else throw new Error(`There is some issue with the "${e}" filter query.`);t.push({query:e,description:r?`${r} 18 | ${l}`:l})}return t}function st(t,e,n){let i=t.slice();return i[1]=e[n].query,i[6]=e[n].description,i}function tn(t){let e,n=t[0],i=[];for(let s=0;sa.item))}function _(a){n(1,i=a.target.value),r()}return[s,i,_]}var Ee=class extends G{constructor(e){super(),qe(this,e,on,sn,je,{})}},ct=Ee;var cn=new ct({target:document.getElementById("app")}),Fn=cn;})(); 19 | --------------------------------------------------------------------------------