├── .eslintrc.json ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── -puregram-callback-data.md │ ├── -puregram-hear.md │ ├── -puregram-markup.md │ ├── -puregram-scenes.md │ ├── -puregram-session.md │ ├── -puregram-utils.md │ ├── feature_request.md │ └── puregram.md └── workflows │ └── codeql-analysis.yml ├── .gitignore ├── .husky └── post-commit ├── LEGAL.md ├── LICENSE ├── README.md ├── commitlint.config.js ├── docs ├── examples │ ├── editing.js │ ├── hear.js │ ├── hello-world.js │ ├── keyboards │ │ ├── force-reply.js │ │ ├── inline-keyboard-builder.js │ │ ├── inline-keyboard.js │ │ ├── keyboard-builder.js │ │ ├── keyboard.js │ │ └── remove-keyboard.js │ ├── markdown │ │ ├── html.js │ │ ├── markdown-v2.js │ │ └── markdown.js │ ├── media-source │ │ ├── advanced.js │ │ ├── simple.js │ │ └── why.md │ ├── media.js │ ├── payments.js │ ├── prompt.js │ ├── scenes.js │ ├── session.js │ ├── typescript │ │ ├── hello-world.ts │ │ └── type-predicates.ts │ ├── utils.js │ └── webhook │ │ ├── express.js │ │ ├── fastify.js │ │ ├── http-https.js │ │ ├── koa.js │ │ └── secret-token.js └── supported-events.md ├── package.json ├── packages ├── callback-data │ ├── README.md │ ├── package.json │ ├── src │ │ ├── builder.ts │ │ ├── filters.ts │ │ ├── index.ts │ │ └── types.ts │ └── tsconfig.json ├── hear │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── hear-manager.ts │ │ ├── helpers.ts │ │ ├── index.ts │ │ └── types.ts │ └── tsconfig.json ├── markup │ ├── README.md │ ├── package.json │ ├── src │ │ ├── format.ts │ │ ├── index.ts │ │ └── markup.ts │ └── tsconfig.json ├── media-cacher │ ├── README.md │ ├── package.json │ ├── src │ │ ├── cacher.ts │ │ ├── index.ts │ │ ├── storages │ │ │ ├── index.ts │ │ │ ├── memory.ts │ │ │ └── storage.ts │ │ ├── types.ts │ │ └── utils.ts │ └── tsconfig.json ├── prompt │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── prompt-answer.ts │ │ ├── prompt-manager.ts │ │ ├── prompt-question.ts │ │ ├── types.ts │ │ └── utils.ts │ └── tsconfig.json ├── puregram │ ├── LEGAL.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── common │ │ │ ├── attachments │ │ │ │ ├── animation.ts │ │ │ │ ├── attachment.ts │ │ │ │ ├── audio.ts │ │ │ │ ├── contact.ts │ │ │ │ ├── document.ts │ │ │ │ ├── file-attachment.ts │ │ │ │ ├── index.ts │ │ │ │ ├── location.ts │ │ │ │ ├── photo.ts │ │ │ │ ├── poll.ts │ │ │ │ ├── sticker.ts │ │ │ │ ├── story.ts │ │ │ │ ├── venue.ts │ │ │ │ ├── video-note.ts │ │ │ │ ├── video.ts │ │ │ │ └── voice.ts │ │ │ ├── index.ts │ │ │ ├── inline-query │ │ │ │ ├── index.ts │ │ │ │ ├── message-content.ts │ │ │ │ └── result.ts │ │ │ ├── input-media │ │ │ │ ├── index.ts │ │ │ │ ├── input-media.ts │ │ │ │ └── types.ts │ │ │ ├── keyboards │ │ │ │ ├── force-reply.ts │ │ │ │ ├── index.ts │ │ │ │ ├── inline-keyboard-builder.ts │ │ │ │ ├── inline-keyboard.ts │ │ │ │ ├── keyboard-builder.ts │ │ │ │ ├── keyboard.ts │ │ │ │ └── remove.ts │ │ │ ├── media-group.ts │ │ │ ├── media-source │ │ │ │ ├── index.ts │ │ │ │ ├── media-source.ts │ │ │ │ └── types.ts │ │ │ ├── message-entities.ts │ │ │ ├── parse-mode │ │ │ │ ├── html.ts │ │ │ │ ├── index.ts │ │ │ │ ├── markdown-v2.ts │ │ │ │ └── markdown.ts │ │ │ ├── reaction.ts │ │ │ ├── structures │ │ │ │ ├── bot-command.ts │ │ │ │ ├── bot-description.ts │ │ │ │ ├── bot-short-description.ts │ │ │ │ ├── callback-game.ts │ │ │ │ ├── callback-query.ts │ │ │ │ ├── chat-administrator-rights.ts │ │ │ │ ├── chat-boost-added.ts │ │ │ │ ├── chat-boost-removed.ts │ │ │ │ ├── chat-boost-source │ │ │ │ │ ├── chat-boost-source.ts │ │ │ │ │ ├── gift-code.ts │ │ │ │ │ ├── giveaway.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── premium.ts │ │ │ │ ├── chat-boost-updated.ts │ │ │ │ ├── chat-boost.ts │ │ │ │ ├── chat-invite-link.ts │ │ │ │ ├── chat-join-request.ts │ │ │ │ ├── chat-location.ts │ │ │ │ ├── chat-member-updated.ts │ │ │ │ ├── chat-member.ts │ │ │ │ ├── chat-permissions.ts │ │ │ │ ├── chat-photo.ts │ │ │ │ ├── chat-shared.ts │ │ │ │ ├── chat.ts │ │ │ │ ├── chosen-inline-result.ts │ │ │ │ ├── composer.ts │ │ │ │ ├── contact.ts │ │ │ │ ├── dice.ts │ │ │ │ ├── encrypted-credentials.ts │ │ │ │ ├── encrypted-passport-element.ts │ │ │ │ ├── external-reply-info.ts │ │ │ │ ├── file.ts │ │ │ │ ├── forum-topic-closed.ts │ │ │ │ ├── forum-topic-created.ts │ │ │ │ ├── forum-topic-edited.ts │ │ │ │ ├── forum-topic-reopened.ts │ │ │ │ ├── forwarded-message.ts │ │ │ │ ├── game.ts │ │ │ │ ├── general-forum-topic-hidden.ts │ │ │ │ ├── general-forum-topic-unhidden.ts │ │ │ │ ├── giveaway-completed.ts │ │ │ │ ├── giveaway-created.ts │ │ │ │ ├── giveaway-winners.ts │ │ │ │ ├── giveaway.ts │ │ │ │ ├── inaccessible-message.ts │ │ │ │ ├── index.ts │ │ │ │ ├── inline-keyboard-button.ts │ │ │ │ ├── inline-keyboard-markup.ts │ │ │ │ ├── inline-query.ts │ │ │ │ ├── invoice.ts │ │ │ │ ├── link-preview-options.ts │ │ │ │ ├── location.ts │ │ │ │ ├── login-url.ts │ │ │ │ ├── mask-position.ts │ │ │ │ ├── menu-button.ts │ │ │ │ ├── message-auto-delete-timer-changed.ts │ │ │ │ ├── message-entity.ts │ │ │ │ ├── message-id.ts │ │ │ │ ├── message-origin │ │ │ │ │ ├── channel.ts │ │ │ │ │ ├── chat.ts │ │ │ │ │ ├── hidden-user.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── message-origin.ts │ │ │ │ │ └── user.ts │ │ │ │ ├── message-reaction-count-updated.ts │ │ │ │ ├── message-reaction-updated.ts │ │ │ │ ├── message.ts │ │ │ │ ├── order-info.ts │ │ │ │ ├── passport-data.ts │ │ │ │ ├── passport-file.ts │ │ │ │ ├── photo-size.ts │ │ │ │ ├── poll-answer.ts │ │ │ │ ├── poll-option.ts │ │ │ │ ├── poll.ts │ │ │ │ ├── pre-checkout-query.ts │ │ │ │ ├── proximity-alert-triggered.ts │ │ │ │ ├── reaction-count.ts │ │ │ │ ├── reaction-type │ │ │ │ │ ├── custom-emoji.ts │ │ │ │ │ ├── emoji.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── paid.ts │ │ │ │ │ └── reaction-type.ts │ │ │ │ ├── sent-web-app-message.ts │ │ │ │ ├── shipping-address.ts │ │ │ │ ├── shipping-query.ts │ │ │ │ ├── sticker-set.ts │ │ │ │ ├── story.ts │ │ │ │ ├── successful-payment.ts │ │ │ │ ├── text-quote.ts │ │ │ │ ├── update.ts │ │ │ │ ├── user-profile-photos.ts │ │ │ │ ├── user.ts │ │ │ │ ├── users-shared.ts │ │ │ │ ├── venue.ts │ │ │ │ ├── video-chat-ended.ts │ │ │ │ ├── video-chat-participants-invited.ts │ │ │ │ ├── video-chat-scheduled.ts │ │ │ │ ├── video-chat-started.ts │ │ │ │ ├── web-app-data.ts │ │ │ │ ├── web-app-info.ts │ │ │ │ └── write-access-allowed.ts │ │ │ └── updates-filter.ts │ │ ├── contexts │ │ │ ├── callback-query.ts │ │ │ ├── chat-boost-added.ts │ │ │ ├── chat-boost.ts │ │ │ ├── chat-join-request.ts │ │ │ ├── chat-member.ts │ │ │ ├── chat-shared.ts │ │ │ ├── chosen-inline-result.ts │ │ │ ├── context.ts │ │ │ ├── delete-chat-photo.ts │ │ │ ├── forum-topic-closed.ts │ │ │ ├── forum-topic-created.ts │ │ │ ├── forum-topic-edited.ts │ │ │ ├── forum-topic-reopened.ts │ │ │ ├── general-forum-topic-hidden.ts │ │ │ ├── general-forum-topic-unhidden.ts │ │ │ ├── giveaway-completed.ts │ │ │ ├── giveaway-created.ts │ │ │ ├── giveaway-winners.ts │ │ │ ├── group-chat-created.ts │ │ │ ├── index.ts │ │ │ ├── inline-query.ts │ │ │ ├── invoice.ts │ │ │ ├── left-chat-member.ts │ │ │ ├── location.ts │ │ │ ├── message-auto-delete-timer-changed.ts │ │ │ ├── message-reaction-count.ts │ │ │ ├── message-reaction.ts │ │ │ ├── message.ts │ │ │ ├── migrate-from-chat-id.ts │ │ │ ├── migrate-to-chat-id.ts │ │ │ ├── mixins │ │ │ │ ├── chat-action.ts │ │ │ │ ├── chat-control.ts │ │ │ │ ├── chat-invite-control.ts │ │ │ │ ├── chat-member-control.ts │ │ │ │ ├── chat-sender-control.ts │ │ │ │ ├── clone.ts │ │ │ │ ├── download.ts │ │ │ │ ├── forum.ts │ │ │ │ ├── index.ts │ │ │ │ ├── node.ts │ │ │ │ ├── pins.ts │ │ │ │ ├── send.ts │ │ │ │ └── target.ts │ │ │ ├── new-chat-members.ts │ │ │ ├── new-chat-photo.ts │ │ │ ├── new-chat-title.ts │ │ │ ├── passport-data.ts │ │ │ ├── pinned-message.ts │ │ │ ├── poll-answer.ts │ │ │ ├── poll.ts │ │ │ ├── pre-checkout-query.ts │ │ │ ├── proximity-alert-triggered.ts │ │ │ ├── removed-chat-boost.ts │ │ │ ├── shipping-query.ts │ │ │ ├── successful-payment.ts │ │ │ ├── unsupported.ts │ │ │ ├── users-shared.ts │ │ │ ├── video-chat-ended.ts │ │ │ ├── video-chat-participants-invited.ts │ │ │ ├── video-chat-scheduled.ts │ │ │ ├── video-chat-started.ts │ │ │ ├── web-app-data.ts │ │ │ └── write-access-allowed.ts │ │ ├── errors │ │ │ ├── api.ts │ │ │ ├── index.ts │ │ │ └── telegram.ts │ │ ├── generated │ │ │ ├── api-methods.ts │ │ │ ├── index.ts │ │ │ ├── methods.ts │ │ │ └── telegram-interfaces.ts │ │ ├── index.ts │ │ ├── telegram.ts │ │ ├── types │ │ │ ├── enums.ts │ │ │ ├── hooks.ts │ │ │ ├── interfaces.ts │ │ │ ├── mappings.ts │ │ │ ├── send-media.ts │ │ │ └── types.ts │ │ ├── updates.ts │ │ └── utils │ │ │ ├── constants.ts │ │ │ └── helpers.ts │ └── tsconfig.json ├── scenes │ ├── README.md │ ├── package.json │ ├── src │ │ ├── cache-repository.ts │ │ ├── contexts │ │ │ ├── index.ts │ │ │ ├── scene.ts │ │ │ ├── scene.types.ts │ │ │ ├── step.ts │ │ │ └── step.types.ts │ │ ├── index.ts │ │ ├── scene-manager.ts │ │ ├── scene-manager.types.ts │ │ ├── scenes │ │ │ ├── index.ts │ │ │ ├── scene.ts │ │ │ ├── step.ts │ │ │ └── step.types.ts │ │ └── types.ts │ └── tsconfig.json ├── session │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── session.ts │ │ ├── storages │ │ │ ├── index.ts │ │ │ ├── memory.ts │ │ │ └── storage.ts │ │ └── types.ts │ └── tsconfig.json └── utils │ ├── README.md │ ├── package.json │ ├── src │ ├── index.ts │ └── utils │ │ ├── get-casino-values.ts │ │ ├── index.ts │ │ └── web-app.ts │ └── tsconfig.json ├── scripts ├── doc-methods.ts ├── generate-common-structures │ ├── code-generator.ts │ ├── constants.ts │ ├── field.ts │ ├── index.ts │ ├── interface.ts │ ├── test.ts │ ├── type.ts │ ├── utils.ts │ ├── variables.ts │ └── visitor.ts ├── generate-constants │ └── index.ts ├── generate-index │ └── index.ts ├── generate-interfaces │ ├── index.ts │ └── types.ts ├── generate-references │ └── index.ts ├── generate-types │ └── index.ts └── generate-updates │ └── index.ts ├── tsconfig.json └── yarn.lock /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es2021": true, 4 | "node": true 5 | }, 6 | "extends": [ 7 | "standard", 8 | "plugin:@typescript-eslint/recommended" 9 | ], 10 | "parser": "@typescript-eslint/parser", 11 | "parserOptions": { 12 | "ecmaVersion": "latest", 13 | "sourceType": "module", 14 | "tsconfigRoot": "./", 15 | "project": [ 16 | "./tsconfig.json", 17 | "./packages/*/tsconfig.json" 18 | ] 19 | }, 20 | "plugins": [ 21 | "@typescript-eslint" 22 | ], 23 | "rules": { 24 | "@typescript-eslint/no-explicit-any": "off", 25 | "@typescript-eslint/ban-types": "off", 26 | "@typescript-eslint/no-empty-interface": "off", 27 | "@typescript-eslint/no-empty-function": "off", 28 | "no-lone-blocks": "off", 29 | "no-useless-constructor": "off", 30 | "camelcase": "off", 31 | "getter-return": "off", 32 | "no-dupe-class-members": "off", 33 | "no-redeclare": "off" 34 | } 35 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/-puregram-callback-data.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "@puregram/callback-data" 3 | about: 'report an issue with the ''@puregram/callback-data'' package' 4 | title: '' 5 | labels: "@puregram/callback-data" 6 | assignees: nitreojs 7 | --- 8 | 9 | ## the bug 10 | a clear and concise description of what the bug is. 11 | 12 | ## steps to reproduce 13 | steps to reproduce the behavior: 14 | 1. 15 | 2. 16 | 3. 17 | 4. 18 | 19 | ## expected behavior 20 | a clear and concise description of what you expected to happen 21 | 22 | ## screenshots 23 | if applicable, add screenshots to help explain your problem 24 | 25 | ## environment 26 | | package | version | 27 | | :-----------------------: | :-----: | 28 | | `@puregram/callback-data` | `X.Y.Z` | 29 | | `node` | `X.Y.Z` | 30 | | `TypeScript` | `X.Y.Z` | 31 | | `yarn` or `npm` | `X.Y.Z` | 32 | 33 | ## additional context 34 | add any other context about the problem here 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/-puregram-hear.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "@puregram/hear" 3 | about: 'report an issue with the ''@puregram/hear'' package' 4 | title: '' 5 | labels: "@puregram/hear" 6 | assignees: nitreojs 7 | --- 8 | 9 | ## the bug 10 | a clear and concise description of what the bug is. 11 | 12 | ## steps to reproduce 13 | steps to reproduce the behavior: 14 | 1. 15 | 2. 16 | 3. 17 | 4. 18 | 19 | ## expected behavior 20 | a clear and concise description of what you expected to happen 21 | 22 | ## screenshots 23 | if applicable, add screenshots to help explain your problem 24 | 25 | ## environment 26 | | package | version | 27 | | :--------------: | :-----: | 28 | | `@puregram/hear` | `X.Y.Z` | 29 | | `node` | `X.Y.Z` | 30 | | `TypeScript` | `X.Y.Z` | 31 | | `yarn` or `npm` | `X.Y.Z` | 32 | 33 | ## additional context 34 | add any other context about the problem here 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/-puregram-markup.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "@puregram/markup" 3 | about: 'report an issue with the ''@puregram/markup'' package' 4 | title: '' 5 | labels: "@puregram/markup" 6 | assignees: nitreojs 7 | --- 8 | 9 | ## the bug 10 | a clear and concise description of what the bug is. 11 | 12 | ## steps to reproduce 13 | steps to reproduce the behavior: 14 | 1. 15 | 2. 16 | 3. 17 | 4. 18 | 19 | ## expected behavior 20 | a clear and concise description of what you expected to happen 21 | 22 | ## screenshots 23 | if applicable, add screenshots to help explain your problem 24 | 25 | ## environment 26 | | package | version | 27 | | :----------------: | :-----: | 28 | | `@puregram/markup` | `X.Y.Z` | 29 | | `node` | `X.Y.Z` | 30 | | `TypeScript` | `X.Y.Z` | 31 | | `yarn` or `npm` | `X.Y.Z` | 32 | 33 | ## additional context 34 | add any other context about the problem here 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/-puregram-scenes.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "@puregram/scenes" 3 | about: 'report an issue with the ''@puregram/scenes'' package' 4 | title: '' 5 | labels: "@puregram/scenes" 6 | assignees: nitreojs 7 | --- 8 | 9 | ## the bug 10 | a clear and concise description of what the bug is. 11 | 12 | ## steps to reproduce 13 | steps to reproduce the behavior: 14 | 1. 15 | 2. 16 | 3. 17 | 4. 18 | 19 | ## expected behavior 20 | a clear and concise description of what you expected to happen 21 | 22 | ## screenshots 23 | if applicable, add screenshots to help explain your problem 24 | 25 | ## environment 26 | | package | version | 27 | | :----------------: | :-----: | 28 | | `@puregram/scenes` | `X.Y.Z` | 29 | | `node` | `X.Y.Z` | 30 | | `TypeScript` | `X.Y.Z` | 31 | | `yarn` or `npm` | `X.Y.Z` | 32 | 33 | ## additional context 34 | add any other context about the problem here 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/-puregram-session.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "@puregram/session" 3 | about: 'report an issue with the ''@puregram/session'' package' 4 | title: '' 5 | labels: "@puregram/session" 6 | assignees: nitreojs 7 | --- 8 | 9 | ## the bug 10 | a clear and concise description of what the bug is. 11 | 12 | ## steps to reproduce 13 | steps to reproduce the behavior: 14 | 1. 15 | 2. 16 | 3. 17 | 4. 18 | 19 | ## expected behavior 20 | a clear and concise description of what you expected to happen 21 | 22 | ## screenshots 23 | if applicable, add screenshots to help explain your problem 24 | 25 | ## environment 26 | | package | version | 27 | | :-----------------: | :-----: | 28 | | `@puregram/session` | `X.Y.Z` | 29 | | `node` | `X.Y.Z` | 30 | | `TypeScript` | `X.Y.Z` | 31 | | `yarn` or `npm` | `X.Y.Z` | 32 | 33 | ## additional context 34 | add any other context about the problem here 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/-puregram-utils.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "@puregram/utils" 3 | about: 'report an issue with the ''@puregram/utils'' package' 4 | title: '' 5 | labels: "@puregram/utils" 6 | assignees: nitreojs 7 | --- 8 | 9 | ## the bug 10 | a clear and concise description of what the bug is. 11 | 12 | ## steps to reproduce 13 | steps to reproduce the behavior: 14 | 1. 15 | 2. 16 | 3. 17 | 4. 18 | 19 | ## expected behavior 20 | a clear and concise description of what you expected to happen 21 | 22 | ## screenshots 23 | if applicable, add screenshots to help explain your problem 24 | 25 | ## environment 26 | | package | version | 27 | | :---------------: | :-----: | 28 | | `@puregram/utils` | `X.Y.Z` | 29 | | `node` | `X.Y.Z` | 30 | | `TypeScript` | `X.Y.Z` | 31 | | `yarn` or `npm` | `X.Y.Z` | 32 | 33 | ## additional context 34 | add any other context about the problem here 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: feature request 3 | about: suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: nitreojs 7 | --- 8 | 9 | **is your feature request related to a problem? Please describe.** 10 | a clear and concise description of what the problem is. ex. i'm always frustrated when [...] 11 | 12 | **describe the solution you'd like** 13 | a clear and concise description of what you want to happen 14 | 15 | **describe alternatives you've considered** 16 | a clear and concise description of any alternative solutions or features you've considered 17 | 18 | **additional context** 19 | add any other context or screenshots about the feature request here 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/puregram.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: puregram 3 | about: report an issue with the 'puregram' package 4 | title: '' 5 | labels: puregram 6 | assignees: nitreojs 7 | 8 | --- 9 | 10 | ## the bug 11 | a clear and concise description of what the bug is 12 | 13 | ## steps to reproduce 14 | steps to reproduce the behavior: 15 | 1. 16 | 2. 17 | 3. 18 | 4. 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 | ## environment 27 | | package | version | 28 | | :-----------: | :-----: | 29 | | `puregram` | `X.Y.Z` | 30 | | `node` | `X.Y.Z` | 31 | | `TypeScript` | `X.Y.Z` | 32 | | `yarn` or `npm` | `X.Y.Z` | 33 | 34 | ## additional context 35 | add any other context about the problem here 36 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ lord ] 6 | pull_request: 7 | branches: [ lord ] 8 | 9 | jobs: 10 | analyze: 11 | name: Analyze 12 | runs-on: ubuntu-latest 13 | permissions: 14 | actions: read 15 | contents: read 16 | security-events: write 17 | 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | language: [ 'typescript' ] 22 | 23 | steps: 24 | - name: Checkout repository 25 | uses: actions/checkout@v2 26 | 27 | # Initializes the CodeQL tools for scanning 28 | - name: Initialize CodeQL 29 | uses: github/codeql-action/init@v1 30 | with: 31 | languages: ${{ matrix.language }} 32 | 33 | - name: Perform CodeQL Analysis 34 | uses: github/codeql-action/analyze@v1 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript cache 45 | *.tsbuildinfo 46 | 47 | # Optional directories 48 | .npm 49 | .idea 50 | 51 | # Optional eslint cache 52 | .eslintcache 53 | 54 | # Optional REPL history 55 | .node_repl_history 56 | 57 | # Output of 'npm pack' 58 | *.tgz 59 | 60 | # Yarn Integrity file 61 | .yarn-integrity 62 | 63 | # dotenv environment variables file 64 | .env 65 | .env.test 66 | 67 | # parcel-bundler cache (https://parceljs.org/) 68 | .cache 69 | 70 | # next.js build output 71 | .next 72 | 73 | # nuxt.js build output 74 | .nuxt 75 | 76 | # vuepress build output 77 | .vuepress/dist 78 | 79 | # Serverless directories 80 | .serverless/ 81 | 82 | # FuseBox cache 83 | .fusebox/ 84 | 85 | # DynamoDB Local files 86 | .dynamodb/ 87 | 88 | # Other 89 | packages/**/lib 90 | .vscode/ 91 | scripts/generate-interfaces/*.json 92 | .DS_Store 93 | **/yarn.lock 94 | **/package-lock.json 95 | **/test.ts 96 | -------------------------------------------------------------------------------- /.husky/post-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | yarn run test 5 | -------------------------------------------------------------------------------- /LEGAL.md: -------------------------------------------------------------------------------- 1 | packages/puregram/LEGAL.md -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2024 starkow 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | packages/puregram/README.md -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | rules: { 4 | 'scope-enum': [2, 'always', [ 5 | 'puregram', 6 | 'hear', 7 | 'prompt', 8 | 'scenes', 9 | 'session', 10 | 'utils', 11 | 'callback-data', 12 | 'markup', 13 | 14 | 'eslint', 15 | 'commitlint', 16 | 'husky', 17 | 18 | 'scripts' 19 | ]], 20 | 'scope-case': [2, 'always', 'kebab-case'] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /docs/examples/hello-world.js: -------------------------------------------------------------------------------- 1 | import { Telegram } from 'puregram' 2 | 3 | const telegram = Telegram.fromToken(process.env.TOKEN) 4 | 5 | telegram.updates.on('message', (context) => { 6 | if (context.hasText() && /hello/i.test(context.text)) { 7 | return context.send('hello, world!') 8 | } 9 | }) 10 | 11 | telegram.updates.startPolling() 12 | .then(() => console.log(`started polling @${telegram.bot.username}`)) 13 | .catch(console.error) 14 | -------------------------------------------------------------------------------- /docs/examples/keyboards/force-reply.js: -------------------------------------------------------------------------------- 1 | // https://core.telegram.org/bots/api#forcereply 2 | 3 | import { Telegram, ForceReply } from 'puregram' 4 | 5 | const telegram = Telegram.fromToken(process.env.TOKEN) 6 | 7 | telegram.updates.on('message', (context) => ( 8 | context.send('sending you a force-reply keyboard!', { reply_markup: new ForceReply() }) 9 | )) 10 | 11 | telegram.updates.startPolling() 12 | .then(() => console.log(`started polling @${telegram.bot.username}`)) 13 | .catch(console.error) 14 | -------------------------------------------------------------------------------- /docs/examples/keyboards/inline-keyboard-builder.js: -------------------------------------------------------------------------------- 1 | import { Telegram, InlineKeyboardBuilder } from 'puregram' 2 | 3 | const telegram = Telegram.fromToken(process.env.TOKEN) 4 | 5 | telegram.updates.on('message', (context) => { 6 | const keyboard = new InlineKeyboardBuilder() 7 | .textButton({ 8 | text: 'some button', 9 | payload: 'some payload' 10 | }) 11 | .row() 12 | .textButton({ 13 | text: 'two buttons', 14 | payload: { objectPayload: true } 15 | }) 16 | .textButton({ 17 | text: 'in one row', 18 | payload: 'payload is required' 19 | }) 20 | .row() 21 | .urlButton({ 22 | text: 'some url button', 23 | url: 'https://example.com' 24 | }) 25 | .row() 26 | .switchToCurrentChatButton({ 27 | text: 'switch to current chat button', 28 | query: 'foo bar baz' 29 | }) 30 | .switchToChatButton({ 31 | text: 'switch to chat button', 32 | query: 'test tost' 33 | }) 34 | 35 | return context.send('sending you an inline-keyboard using `InlineKeyboardBuilder`!', { 36 | reply_markup: keyboard, 37 | parse_mode: 'markdown' 38 | }) 39 | }) 40 | 41 | telegram.updates.startPolling() 42 | .then(() => console.log(`started polling @${telegram.bot.username}`)) 43 | .catch(console.error) 44 | -------------------------------------------------------------------------------- /docs/examples/keyboards/inline-keyboard.js: -------------------------------------------------------------------------------- 1 | import { Telegram, InlineKeyboard } from 'puregram' 2 | 3 | const telegram = Telegram.fromToken(process.env.TOKEN) 4 | 5 | telegram.updates.on('message', (context) => { 6 | const keyboard = InlineKeyboard.keyboard([ 7 | [ 8 | InlineKeyboard.textButton({ 9 | text: 'some button', 10 | payload: 'some payload' 11 | }) 12 | ], 13 | 14 | [ 15 | InlineKeyboard.textButton({ 16 | text: 'two buttons', 17 | payload: { objectPayload: true } 18 | }), 19 | 20 | InlineKeyboard.textButton({ 21 | text: 'in one row', 22 | payload: 'payload is required' 23 | }) 24 | ], 25 | 26 | [ 27 | InlineKeyboard.urlButton({ 28 | text: 'some url button', 29 | url: 'https://example.com' 30 | }) 31 | ], 32 | 33 | [ 34 | InlineKeyboard.switchToCurrentChatButton({ 35 | text: 'switch to current chat button', 36 | query: 'foo bar baz' 37 | }), 38 | 39 | InlineKeyboard.switchToChatButton({ 40 | text: 'switch to chat button', 41 | query: 'test tost' 42 | }) 43 | ] 44 | ]) 45 | 46 | return context.send('sending you an inline-keyboard using `InlineKeyboard`!', { 47 | reply_markup: keyboard, 48 | parse_mode: 'markdown' 49 | }) 50 | }) 51 | 52 | telegram.updates.startPolling() 53 | .then(() => console.log(`started polling @${telegram.bot.username}`)) 54 | .catch(console.error) 55 | -------------------------------------------------------------------------------- /docs/examples/keyboards/keyboard-builder.js: -------------------------------------------------------------------------------- 1 | import { Telegram, KeyboardBuilder } from 'puregram' 2 | 3 | const telegram = Telegram.fromToken(process.env.TOKEN) 4 | 5 | telegram.updates.on('message', (context) => { 6 | const keyboard = new KeyboardBuilder() 7 | .textButton('some button') 8 | .row() 9 | .textButton('two buttons') 10 | .textButton('in one row') 11 | .resize() // INFO: keyboard will be much smaller 12 | 13 | return context.send('sending you a keyboard, generated using `KeyboardBuilder`!', { 14 | reply_markup: keyboard, 15 | parse_mode: 'markdown' 16 | }) 17 | }) 18 | 19 | telegram.updates.startPolling() 20 | .then(() => console.log(`started polling @${telegram.bot.username}`)) 21 | .catch(console.error) 22 | -------------------------------------------------------------------------------- /docs/examples/keyboards/keyboard.js: -------------------------------------------------------------------------------- 1 | import { Telegram, Keyboard } from 'puregram' 2 | 3 | const telegram = Telegram.fromToken(process.env.TOKEN) 4 | 5 | telegram.updates.on('message', (context) => { 6 | const keyboard = Keyboard.keyboard([ 7 | [ 8 | Keyboard.textButton('some button') 9 | ], 10 | 11 | [ 12 | Keyboard.textButton('two buttons'), 13 | Keyboard.textButton('in one row') 14 | ] 15 | ]).resize() // INFO: keyboard will be much smaller 16 | 17 | return context.send('sending you a keyboard, generated using `Keyboard`!', { 18 | reply_markup: keyboard, 19 | parse_mode: 'markdown' 20 | }) 21 | }) 22 | 23 | telegram.updates.startPolling() 24 | .then(() => console.log(`started polling @${telegram.bot.username}`)) 25 | .catch(console.error) 26 | -------------------------------------------------------------------------------- /docs/examples/keyboards/remove-keyboard.js: -------------------------------------------------------------------------------- 1 | // INFO: https://core.telegram.org/bots/api#replykeyboardremove 2 | 3 | import { Telegram, RemoveKeyboard } from 'puregram' 4 | 5 | const telegram = Telegram.fromToken(process.env.TOKEN) 6 | 7 | telegram.updates.on('message', (context) => ( 8 | context.send('if there was a default keyboard under the input, it\'d be removed now!', { 9 | reply_markup: new RemoveKeyboard(), 10 | parse_mode: 'markdown' 11 | }) 12 | )) 13 | 14 | telegram.updates.startPolling() 15 | .then(() => console.log(`started polling @${telegram.bot.username}`)) 16 | .catch(console.error) 17 | -------------------------------------------------------------------------------- /docs/examples/markdown/html.js: -------------------------------------------------------------------------------- 1 | import { Telegram, HTML } from 'puregram' 2 | 3 | const telegram = Telegram.fromToken(process.env.TOKEN) 4 | 5 | telegram.updates.on('message', async (context) => { 6 | const message = `a ${HTML.bold('message')} with ${HTML.italic('html markdown')}!` 7 | const anotherMessage = 'another message with html markdown.' 8 | 9 | await Promise.all([ 10 | context.send(message, { parse_mode: 'html' }), // <-- note how we are telling telegram 11 | context.send(anotherMessage, { parse_mode: 'html' }) // that there are some html entities in the message 12 | ]) 13 | }) 14 | 15 | telegram.updates.startPolling() 16 | .then(() => console.log(`started polling @${telegram.bot.username}`)) 17 | .catch(console.error) 18 | -------------------------------------------------------------------------------- /docs/examples/markdown/markdown-v2.js: -------------------------------------------------------------------------------- 1 | import { Telegram, MarkdownV2 } from 'puregram' 2 | 3 | const telegram = Telegram.fromToken(process.env.TOKEN) 4 | 5 | // INFO: the difference between `Markdown` and `MarkdownV2` classes 6 | // INFO: is that `MarkdownV2` can handle ~strikethrough~ and __underlined__ entities... 7 | // INFO: and that's it! 8 | // INFO: but it also requires A LOT OF escaping under the hood... 9 | // INFO: are you sure you want to use it? 10 | // -> https://core.telegram.org/bots/api#markdownv2-style <- 11 | 12 | telegram.updates.on('message', async (context) => { 13 | const message = `a ${MarkdownV2.bold('message')} with some ${MarkdownV2.strikethrough('epic')} ${MarkdownV2.underline('markdown')}\\!` 14 | const anotherMessage = 'same *message* with ~epic~ __markdown__\\.' 15 | const oneMoreMessage = MarkdownV2.build` 16 | this is a ${MarkdownV2.bold('message')}! although, everything that is not ${MarkdownV2.italic('interpolated')} is escaped automatically. 17 | ` 18 | 19 | await Promise.all([ 20 | context.send(message, { parse_mode: 'markdownv2' }), // <-- note how we are telling telegram 21 | context.send(anotherMessage, { parse_mode: 'markdownv2' }), // that there are some markdownv2 entities in the message 22 | context.send(oneMoreMessage, { parse_mode: 'markdownv2' }) 23 | ]) 24 | }) 25 | 26 | telegram.updates.startPolling() 27 | .then(() => console.log(`started polling @${telegram.bot.username}`)) 28 | .catch(console.error) 29 | -------------------------------------------------------------------------------- /docs/examples/markdown/markdown.js: -------------------------------------------------------------------------------- 1 | import { Telegram, Markdown } from 'puregram' 2 | 3 | const telegram = Telegram.fromToken(process.env.TOKEN) 4 | 5 | telegram.updates.on('message', async (context) => { 6 | const message = `a ${Markdown.bold('message')} with ${Markdown.italic('markdown')}!` 7 | const anotherMessage = 'one more *message* with _markdown_, but without a class!' 8 | 9 | await Promise.all([ 10 | context.send(message, { parse_mode: 'markdown' }), // <-- note how we are telling telegram 11 | context.send(anotherMessage, { parse_mode: 'markdown' }) // that there are some markdown entities in the message 12 | ]) 13 | }) 14 | 15 | telegram.updates.startPolling() 16 | .then(() => console.log(`started polling @${telegram.bot.username}`)) 17 | .catch(console.error) 18 | -------------------------------------------------------------------------------- /docs/examples/media-source/advanced.js: -------------------------------------------------------------------------------- 1 | import { Telegram, MediaSource, InputMedia } from 'puregram' 2 | 3 | const telegram = Telegram.fromToken(process.env.TOKEN) 4 | 5 | telegram.updates.on('message', (context) => { 6 | if (context.text === '/media') { 7 | // INFO: imagine that this array is full of URLs 8 | const urls = [] 9 | 10 | const results = urls.map( 11 | (url, i) => InputMedia.photo(MediaSource.url(url, { forceUpload: true }), { 12 | caption: i === 0 ? 'caption for a media' : undefined 13 | }) 14 | ) 15 | 16 | return context.sendMediaGroup(results) 17 | } 18 | }) 19 | 20 | telegram.updates.startPolling() 21 | .then(() => console.log(`started polling @${telegram.bot.username}`)) 22 | .catch(console.error) 23 | -------------------------------------------------------------------------------- /docs/examples/media-source/simple.js: -------------------------------------------------------------------------------- 1 | import { Telegram, MediaSource } from 'puregram' 2 | 3 | const telegram = Telegram.fromToken(process.env.TOKEN) 4 | 5 | telegram.updates.on('message', (context) => { 6 | if (context.text === '/canvas') { 7 | // INFO: imagine that we are rendering a picture using canvas 8 | // INFO: ... 9 | 10 | const buffer = ctx.toBuffer() 11 | 12 | const media = MediaSource.buffer(buffer) 13 | 14 | return context.sendPhoto(media, { 15 | caption: 'here you go!' 16 | }) 17 | } 18 | 19 | if (context.text === '/rules') { 20 | const file = MediaSource.path('./rules.pdf', { filename: 'Rules' }) 21 | 22 | return context.sendDocument(file, { 23 | caption: 'we have some rules and you need to follow them.' 24 | }) 25 | } 26 | 27 | if (context.text === '/voice') { 28 | const url = MediaSource.url(getVoiceUrl(), { forceUpload: true, filename: 'moans' }) 29 | 30 | return context.sendAudio(url) 31 | } 32 | }) 33 | 34 | telegram.updates.startPolling() 35 | .then(() => console.log(`started polling @${telegram.bot.username}`)) 36 | .catch(console.error) 37 | -------------------------------------------------------------------------------- /docs/examples/prompt.js: -------------------------------------------------------------------------------- 1 | import { Telegram } from 'puregram' 2 | import { PromptManager } from '@puregram/prompt' 3 | 4 | const telegram = Telegram.fromToken(process.env.TOKEN) 5 | 6 | const manager = new PromptManager() 7 | 8 | telegram.updates.use(manager.middleware) 9 | 10 | telegram.updates.on('message', async (context) => { 11 | let answer 12 | 13 | while (!answer || !answer.context.hasAttachments('photo')) { 14 | answer = await context.prompt('*send nudes* pls', { parse_mode: 'markdown' }) 15 | } 16 | 17 | await context.send('yooooo thanks for nudes cya') 18 | }) 19 | 20 | telegram.updates.startPolling() 21 | .then(() => console.log(`started polling @${telegram.bot.username}`)) 22 | .catch(console.error) 23 | -------------------------------------------------------------------------------- /docs/examples/session.js: -------------------------------------------------------------------------------- 1 | import { Telegram } from 'puregram' 2 | import { session } from '@puregram/session' 3 | 4 | const telegram = Telegram.fromToken(process.env.TOKEN) 5 | 6 | telegram.updates.on('message', session()) // will have `session` property in `context` on every `message` update 7 | 8 | telegram.updates.on('message', (context) => { 9 | // since this is a `message` update, we can be sure that `context.session` will be present 10 | if (!('counter' in context.session)) { 11 | context.session.counter = 0 12 | } 13 | 14 | context.session.counter += 1 15 | 16 | return context.send(`counter: *${context.session.counter}*`, { parse_mode: 'Markdown' }) 17 | }) 18 | 19 | telegram.updates.startPolling() 20 | .then(() => console.log(`started polling @${telegram.bot.username}`)) 21 | .catch(console.error) 22 | -------------------------------------------------------------------------------- /docs/examples/typescript/hello-world.ts: -------------------------------------------------------------------------------- 1 | import { Telegram } from 'puregram' 2 | 3 | const telegram = Telegram.fromToken(process.env.TOKEN as string) 4 | 5 | telegram.updates.on('message', (context) => { 6 | if (context.hasText() && /hello/i.test(context.text)) { 7 | return context.send('hello, world!') 8 | } 9 | }) 10 | 11 | telegram.updates.startPolling() 12 | .then(() => console.log(`started polling @${telegram.bot.username}`)) 13 | .catch(console.error) 14 | -------------------------------------------------------------------------------- /docs/examples/typescript/type-predicates.ts: -------------------------------------------------------------------------------- 1 | import { ChatType, Telegram } from 'puregram' 2 | 3 | const telegram = Telegram.fromToken(process.env.TOKEN as string) 4 | 5 | telegram.updates.on('message', (context) => { 6 | // INFO: every is* and has* _method_ is a type predicate 7 | // INFO: that means `hasText()` method, if returns `true`, will change `context.text`'s type to [string] (it was [string | undefined]) 8 | 9 | const text = context.text 10 | // INFO: here, text is [string | undefined] 11 | // INFO: let us execute the type predicate method and see if the type changed... 12 | 13 | if (context.hasText() && /hello/i.test(context.text)) { 14 | const text = context.text 15 | // INFO: text is now [string]! 16 | 17 | return context.send('hello, world!') 18 | } 19 | 20 | // INFO: this works for every is*, has* and can* method which can somehow influence the code flow analysis 21 | 22 | if (context.hasCaption()) { 23 | const caption = context.caption 24 | // INFO: string 25 | } 26 | 27 | if (context.hasAttachment() && context.isPM()) { 28 | const attachment = context.attachment 29 | // INFO: AnimationAttachment | AudioAttachment | ContactAttachment | ... 30 | 31 | let type = context.chatType 32 | // INFO: {} & ChatType.Private (`{}` part is because of `SoftString`, don't worry about it) 33 | 34 | // ERROR: Type 'ChatType.Group' is not assignable to type 'ChatType.Private' 35 | type = ChatType.Group 36 | } 37 | }) 38 | 39 | telegram.updates.startPolling() 40 | .then(() => console.log(`started polling @${telegram.bot.username}`)) 41 | .catch(console.error) 42 | -------------------------------------------------------------------------------- /docs/examples/utils.js: -------------------------------------------------------------------------------- 1 | import { Telegram } from 'puregram' 2 | import { getCasinoValues } from '@puregram/utils' 3 | 4 | const telegram = Telegram.fromToken(process.env.TOKEN) 5 | 6 | telegram.updates.on('message', (context) => { 7 | if (context.hasDice() && context.dice.emoji === '🎰') { 8 | // INFO: for example, user has got seven, bar, grapes 9 | console.log(getCasinoValues(context.dice.value)) // ['seven', 'bar', 'grapes'] 10 | } 11 | }) 12 | 13 | telegram.updates.startPolling() 14 | .then(() => console.log(`started polling @${telegram.bot.username}`)) 15 | .catch(console.error) 16 | -------------------------------------------------------------------------------- /docs/examples/webhook/express.js: -------------------------------------------------------------------------------- 1 | import express from 'express' 2 | 3 | import { Telegram } from 'puregram' 4 | 5 | const telegram = Telegram.fromToken(process.env.TOKEN) 6 | const app = express() 7 | 8 | app.use(express.json()) // <-- IMPORTANT 9 | app.use(telegram.updates.getWebhookMiddleware()) 10 | 11 | // INFO: also, you will need to call setWebhook at least once 12 | // telegram.api.setWebhook({ url: process.env.WEBHOOK_URL }) 13 | 14 | telegram.updates.on('message', context => context.send('handled message via `express`')) 15 | 16 | // INFO: remember that Telegram supports only these ports for Webhook: 443, 80, 88, 8443 17 | // INFO: https://core.telegram.org/bots/api#setwebhook 18 | app.listen(8443, () => console.log('started')) 19 | -------------------------------------------------------------------------------- /docs/examples/webhook/fastify.js: -------------------------------------------------------------------------------- 1 | import Fastify from 'fastify' 2 | import middie from '@fastify/middie' // using @fastify/middie for middleware support 3 | 4 | import { Telegram } from 'puregram' 5 | 6 | const telegram = Telegram.fromToken(process.env.TOKEN) 7 | const fastify = Fastify() 8 | 9 | // INFO: also, you will need to call setWebhook at least once 10 | // telegram.api.setWebhook({ url: process.env.WEBHOOK_URL }) 11 | 12 | telegram.updates.on('message', context => context.send('handled message via `fastify`')) 13 | const main = async () => { 14 | await fastify.register(middie) 15 | 16 | fastify.use(telegram.updates.getWebhookMiddleware()) 17 | 18 | // INFO: remember that Telegram supports only these ports for Webhook: 443, 80, 88, 8443 19 | // INFO: https://core.telegram.org/bots/api#setwebhook 20 | fastify.listen({ port: 8443 }, () => console.log('started')) 21 | } 22 | 23 | main().catch(console.error) 24 | -------------------------------------------------------------------------------- /docs/examples/webhook/http-https.js: -------------------------------------------------------------------------------- 1 | import http from 'http' 2 | // or 3 | import https from 'https' 4 | 5 | import { Telegram } from 'puregram' 6 | 7 | const telegram = Telegram.fromToken(process.env.TOKEN) 8 | const server = http.createServer(telegram.updates.getWebhookMiddleware()) 9 | 10 | // INFO: also, you will need to call setWebhook at least once 11 | // telegram.api.setWebhook({ url: process.env.WEBHOOK_URL }) 12 | 13 | telegram.updates.on('message', context => context.send('handled message via `http[s]`')) 14 | 15 | // INFO: remember that Telegram supports only these ports for Webhook: 443, 80, 88, 8443 16 | // INFO: https://core.telegram.org/bots/api#setwebhook 17 | server.listen(8443, () => console.log('started')) 18 | -------------------------------------------------------------------------------- /docs/examples/webhook/koa.js: -------------------------------------------------------------------------------- 1 | import Koa from 'koa' 2 | import koaBody from 'koa-body' 3 | 4 | import { Telegram } from 'puregram' 5 | 6 | const telegram = Telegram.fromToken(process.env.TOKEN) 7 | const app = new Koa() 8 | 9 | app.use(koaBody()) // <-- IMPORTANT 10 | app.use(telegram.updates.getKoaMiddleware()) 11 | 12 | // INFO: also, you will need to call setWebhook at least once 13 | // telegram.api.setWebhook({ url: process.env.WEBHOOK_URL }) 14 | 15 | telegram.updates.on('message', context => context.send('handled message via `koa`')) 16 | 17 | // INFO: remember that Telegram supports only these ports for Webhook: 443, 80, 88, 8443 18 | // INFO: https://core.telegram.org/bots/api#setwebhook 19 | app.listen(8443, () => console.log('started')) 20 | -------------------------------------------------------------------------------- /docs/examples/webhook/secret-token.js: -------------------------------------------------------------------------------- 1 | // INFO: Telegram allows you to pass `secret_token` to `setWebhook` method 2 | // INFO: this way all Telegram requests will have a `X-Telegram-Bot-Api-Secret-Token` header, 3 | // by which you can tell if the request was sent by you or not 4 | 5 | import express from 'express' 6 | 7 | import { Telegram } from 'puregram' 8 | 9 | const telegram = Telegram.fromToken(process.env.TOKEN) 10 | const app = express() 11 | 12 | app.use(express.json()) // <-- IMPORTANT 13 | app.use(telegram.updates.getWebhookMiddleware('important-secret-token')) // <-- passing 'important-secret-token' as a secret token 14 | 15 | // INFO: also, you will need to call setWebhook at least once 16 | // INFO: passing our 'important-secret-token' here ONCE 17 | // telegram.api.setWebhook({ url: process.env.WEBHOOK_URL, secret_token: 'important-secret-token' }) 18 | 19 | telegram.updates.on('message', context => context.send('handled message with a `secret_token` via `express`')) 20 | 21 | // INFO: remember that Telegram supports only these ports for Webhook: 443, 80, 88, 8443 22 | // INFO: https://core.telegram.org/bots/api#setwebhook 23 | app.listen(8443, () => console.log('started')) 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "puregram-monorepo", 3 | "private": true, 4 | "workspaces": [ 5 | "packages/*" 6 | ], 7 | "devDependencies": { 8 | "@commitlint/cli": "^17.0.3", 9 | "@commitlint/config-conventional": "^17.0.3", 10 | "@types/common-tags": "^1.8.1", 11 | "@types/debug": "^4.1.7", 12 | "@types/jest": "^27.0.2", 13 | "@typescript-eslint/eslint-plugin": "^5.31.0", 14 | "@typescript-eslint/parser": "^5.31.0", 15 | "cheerio": "^1.0.0-rc.10", 16 | "common-tags": "^1.8.0", 17 | "eslint": "^8.20.0", 18 | "eslint-config-standard": "^17.0.0", 19 | "eslint-plugin-import": "^2.25.2", 20 | "eslint-plugin-n": "^15.0.0", 21 | "eslint-plugin-promise": "^6.0.0", 22 | "husky": "^8.0.1", 23 | "ts-node": "^10.9.1", 24 | "typescript": "^5.3.3", 25 | "undici": "^5.26.2" 26 | }, 27 | "scripts": { 28 | "generate": "yarn generate-constants && yarn generate-updates && yarn generate-types", 29 | "generate-references": "ts-node scripts/generate-references/", 30 | "generate-constants": "ts-node scripts/generate-constants/", 31 | "generate-interfaces": "ts-node scripts/generate-interfaces/", 32 | "generate-updates": "ts-node scripts/generate-updates/", 33 | "generate-types": "ts-node scripts/generate-types/", 34 | "generate-index": "ts-node scripts/generate-index/" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/callback-data/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@puregram/callback-data", 3 | "version": "1.2.3", 4 | "description": "basic callback data validation and serialization for puregram", 5 | "main": "./lib/index.js", 6 | "scripts": { 7 | "build": "tsc --project tsconfig.json" 8 | }, 9 | "files": [ 10 | "lib" 11 | ], 12 | "keywords": [ 13 | "puregram", 14 | "callback-data", 15 | "serialization", 16 | "validation" 17 | ], 18 | "author": "starkow", 19 | "license": "WTFPL", 20 | "types": "./lib/index.d.ts", 21 | "directories": { 22 | "lib": "lib" 23 | }, 24 | "repository": { 25 | "type": "git", 26 | "url": "https://github.com/nitreojs/puregram/tree/lord/packages/callback-data" 27 | }, 28 | "peerDependencies": { 29 | "puregram": "^2.20.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/callback-data/src/filters.ts: -------------------------------------------------------------------------------- 1 | import type { Filter, UniqueSymbol } from './types' 2 | 3 | const EXISTS_SYMBOL = Symbol('filters.exists') 4 | type ExistsSymbol = typeof EXISTS_SYMBOL 5 | 6 | export type ExistsTrueSym = UniqueSymbol 7 | export type ExistsFalseSym = UniqueSymbol 8 | 9 | export type ExistsSym = ExistsTrueSym | ExistsFalseSym 10 | 11 | export function exists(exists?: true): Filter 12 | export function exists(exists: false): Filter 13 | export function exists (exists = true): Filter { 14 | const filter = ((value: Value) => { 15 | return exists ? value !== undefined : value === undefined 16 | }) as Filter 17 | 18 | filter[EXISTS_SYMBOL] = true as const 19 | 20 | return filter 21 | } 22 | -------------------------------------------------------------------------------- /packages/callback-data/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './builder' 2 | 3 | export * as filters from './filters' 4 | 5 | export { CallbackLayer } from './types' 6 | -------------------------------------------------------------------------------- /packages/callback-data/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2019", 4 | "experimentalDecorators": true, 5 | "module": "commonjs", 6 | "declaration": true, 7 | "outDir": "./lib", 8 | "rootDir": "./src", 9 | "pretty": true, 10 | 11 | "strict": true, 12 | "noImplicitAny": true, 13 | "strictNullChecks": true, 14 | "strictFunctionTypes": true, 15 | "strictBindCallApply": true, 16 | "strictPropertyInitialization": true, 17 | "noImplicitThis": true, 18 | "alwaysStrict": true, 19 | 20 | "esModuleInterop": true, 21 | 22 | "skipLibCheck": true, 23 | "forceConsistentCasingInFileNames": true 24 | }, 25 | 26 | "include": ["./src"] 27 | } 28 | -------------------------------------------------------------------------------- /packages/hear/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 | 7 |
8 | puregram 9 |  •  10 | typescript usage 11 |  •  12 | telegram forum 13 |
14 | 15 | ## @puregram/hear 16 | 17 | _simple implementation of hearing messages system for `puregram` package_ 18 | 19 | ### introduction 20 | 21 | `@puregram/hear` listens for every message that has `text` or `caption` property in it and checks if provided conditions coincides with the `text`/`caption` property 22 | 23 | ### example 24 | 25 | ```js 26 | const { Telegram } = require('puregram') 27 | const { HearManager } = require('@puregram/hear') 28 | 29 | const telegram = Telegram.fromToken(process.env.TOKEN) 30 | 31 | const hearManager = new HearManager() 32 | 33 | telegram.updates.on('message', hearManager.middleware) 34 | 35 | hearManager.hear(/^hello$/i, context => context.send('hello world!')) 36 | 37 | telegram.updates.startPolling() 38 | ``` 39 | 40 | ### installation 41 | 42 | ```sh 43 | $ yarn add @puregram/hear 44 | $ npm i -S @puregram/hear 45 | ``` 46 | 47 | --- 48 | 49 | ## typescript usage 50 | 51 | in typescript, you kinda have to manually point `@puregram/hear` what context will be used as default by providing it in `HearManager`: 52 | 53 | ```ts 54 | import { Telegram, MessageContext } from 'puregram' 55 | import { HearManager } from '@puregram/hear' 56 | 57 | const telegram = Telegram.fromToken(process.env.TOKEN) 58 | 59 | const hearManager = new HearManager() 60 | ``` 61 | -------------------------------------------------------------------------------- /packages/hear/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@puregram/hear", 3 | "version": "2.0.2", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "middleware-io": { 8 | "version": "2.8.1", 9 | "resolved": "https://registry.npmjs.org/middleware-io/-/middleware-io-2.8.1.tgz", 10 | "integrity": "sha512-H0XftkexHKxxQsoCsItMzM7WU3S/rIFzL3T4guU8tWLKr7e5cVkdaZ+JQeeL+TB3OaHpqFi/ozYqQl69z2X6bg==" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/hear/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@puregram/hear", 3 | "version": "2.1.0-rc.1", 4 | "description": "simple implementation of hearing messages system for puregram", 5 | "main": "lib/index", 6 | "engines": { 7 | "node": ">=12.0.0" 8 | }, 9 | "scripts": { 10 | "build": "tsc --project tsconfig.json" 11 | }, 12 | "keywords": [ 13 | "puregram", 14 | "telegram", 15 | "hear" 16 | ], 17 | "files": [ 18 | "lib" 19 | ], 20 | "author": "starkow", 21 | "license": "MIT", 22 | "dependencies": { 23 | "middleware-io": "^2.8.1", 24 | "reflect-metadata": "^0.1.14" 25 | }, 26 | "types": "./lib/index.d.ts", 27 | "repository": { 28 | "type": "git", 29 | "url": "https://github.com/nitreojs/puregram/tree/lord/packages/hear" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/hear/src/helpers.ts: -------------------------------------------------------------------------------- 1 | export const splitPath = (path: string) => ( 2 | path 3 | .replace(/\[([^[\]]*)]/g, '.$1.') 4 | .split('.') 5 | .filter(Boolean) 6 | ) 7 | 8 | export const getObjectValue = (source: Record, selectors: string[]): any => { 9 | let link = source 10 | 11 | for (const selector of selectors) { 12 | if (!link[selector]) { 13 | return 14 | } 15 | 16 | link = link[selector] 17 | } 18 | 19 | return link 20 | } 21 | 22 | export const unifyCondition = (condition: unknown) => { 23 | if (typeof condition === 'function') { 24 | return condition 25 | } 26 | 27 | if (condition instanceof RegExp) { 28 | return (text: string | undefined) => text ? condition.test(text) : false 29 | } 30 | 31 | if (Array.isArray(condition)) { 32 | const arrayConditions = condition.map(unifyCondition) 33 | 34 | return (value: string | undefined) => ( 35 | Array.isArray(value) 36 | ? arrayConditions.every(cond => value.some(val => cond(val))) 37 | : arrayConditions.some(cond => cond(value)) 38 | ) 39 | } 40 | 41 | return (value: string | undefined) => value === condition 42 | } 43 | -------------------------------------------------------------------------------- /packages/hear/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | 3 | export { HearManager } from './hear-manager' 4 | -------------------------------------------------------------------------------- /packages/hear/src/types.ts: -------------------------------------------------------------------------------- 1 | export type MaybeArray = T | T[] 2 | 3 | export interface ContextMatch { 4 | $match: RegExpMatchArray | null 5 | } 6 | 7 | export type HearFunctionCondition = (value: V, context: T) => boolean 8 | 9 | export type HearCondition = HearFunctionCondition | RegExp | string | number | boolean 10 | 11 | export type HearObjectCondition> = 12 | Record>> & { 13 | [P in keyof T]?: MaybeArray> 14 | } 15 | 16 | export type HearConditions> = 17 | | MaybeArray> 18 | | MaybeArray> 19 | -------------------------------------------------------------------------------- /packages/hear/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2019", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "outDir": "lib", 7 | "pretty": true, 8 | 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "strictNullChecks": true, 12 | "strictFunctionTypes": true, 13 | "strictBindCallApply": true, 14 | "strictPropertyInitialization": true, 15 | "noImplicitThis": true, 16 | "alwaysStrict": true, 17 | 18 | "esModuleInterop": true, 19 | 20 | "skipLibCheck": true, 21 | "forceConsistentCasingInFileNames": true 22 | }, 23 | 24 | "include": ["./src"] 25 | } 26 | -------------------------------------------------------------------------------- /packages/markup/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@puregram/markup", 3 | "version": "1.3.4", 4 | "description": "simple yet powerful markup system for puregram", 5 | "main": "./lib/index.js", 6 | "scripts": { 7 | "clear-lib": "rm -rf lib/", 8 | "build": "yarn clear-lib && tsc --project tsconfig.json" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/nitreojs/puregram/tree/lord/packages/markup" 13 | }, 14 | "types": "./lib/index.d.ts", 15 | "files": [ 16 | "lib" 17 | ], 18 | "keywords": [ 19 | "puregram", 20 | "markup", 21 | "telegram", 22 | "bot-api" 23 | ], 24 | "author": "starkow", 25 | "license": "WTFPL", 26 | "bugs": { 27 | "url": "https://github.com/nitreojs/puregram/issues" 28 | }, 29 | "homepage": "https://github.com/nitreojs/puregram#readme", 30 | "dependencies": { 31 | "puregram": "^2.24.4" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/markup/src/format.ts: -------------------------------------------------------------------------------- 1 | import { MessageEntity } from 'puregram' 2 | import { Formattable } from 'puregram/types' 3 | 4 | export class Formatted implements Formattable { 5 | constructor (public text = '', public entities: MessageEntity[] = []) { } 6 | 7 | addText (text: string) { 8 | this.text += text 9 | } 10 | 11 | addEntity (entity: MessageEntity) { 12 | this.entities.push(entity) 13 | } 14 | 15 | addEntities (entities: MessageEntity[]) { 16 | this.entities.push(...entities) 17 | } 18 | 19 | format () { 20 | return this.text 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/markup/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './markup' 2 | 3 | export { Formatted } from './format' 4 | -------------------------------------------------------------------------------- /packages/markup/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2019", 4 | "experimentalDecorators": true, 5 | "module": "commonjs", 6 | "declaration": true, 7 | "outDir": "./lib", 8 | "rootDir": "./src", 9 | "pretty": true, 10 | 11 | "strict": true, 12 | "noImplicitAny": true, 13 | "strictNullChecks": true, 14 | "strictFunctionTypes": true, 15 | "strictBindCallApply": true, 16 | "strictPropertyInitialization": true, 17 | "noImplicitThis": true, 18 | "alwaysStrict": true, 19 | 20 | "esModuleInterop": true, 21 | 22 | "skipLibCheck": true, 23 | "forceConsistentCasingInFileNames": true 24 | }, 25 | 26 | "include": ["./src"] 27 | } 28 | -------------------------------------------------------------------------------- /packages/media-cacher/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@puregram/media-cacher", 3 | "version": "1.0.4", 4 | "description": "cache sent media `file_id`s with ease for puregram!", 5 | "main": "./lib/index.js", 6 | "scripts": { 7 | "build": "tsc --project tsconfig.json" 8 | }, 9 | "files": [ 10 | "lib" 11 | ], 12 | "keywords": [ 13 | "puregram", 14 | "media", 15 | "cache", 16 | "file_id" 17 | ], 18 | "author": "starkow", 19 | "license": "WTFPL", 20 | "types": "./lib/index.d.ts", 21 | "directories": { 22 | "lib": "lib" 23 | }, 24 | "repository": { 25 | "type": "git", 26 | "url": "https://github.com/nitreojs/puregram/tree/lord/packages/media-cacher" 27 | }, 28 | "bugs": { 29 | "url": "https://github.com/nitreojs/puregram/issues" 30 | }, 31 | "homepage": "https://github.com/nitreojs/puregram#readme", 32 | "dependencies": { 33 | "puregram": "^2.20.1" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/media-cacher/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './storages' 2 | export * from './cacher' 3 | -------------------------------------------------------------------------------- /packages/media-cacher/src/storages/index.ts: -------------------------------------------------------------------------------- 1 | export { SessionStorage } from './storage' 2 | 3 | export { 4 | MemoryStorage, 5 | MemoryStorageOptions, 6 | MemoryStoreLike 7 | } from './memory' 8 | -------------------------------------------------------------------------------- /packages/media-cacher/src/storages/memory.ts: -------------------------------------------------------------------------------- 1 | import { SessionStorage } from './storage' 2 | 3 | export interface MemoryStoreLike { 4 | get(key: K): V | undefined 5 | set(key: K, value: V): this | undefined 6 | has(key: K): boolean 7 | delete(key: K): boolean 8 | } 9 | 10 | export interface MemoryStorageOptions { 11 | store: MemoryStoreLike 12 | } 13 | 14 | export class MemoryStorage implements SessionStorage { 15 | private store: MemoryStorageOptions['store'] 16 | 17 | constructor ({ store = new Map() }: Partial = {}) { 18 | this.store = store 19 | } 20 | 21 | async get (key: string) { 22 | return this.store.get(key) 23 | } 24 | 25 | async set (key: string, value: any) { 26 | this.store.set(key, value) 27 | 28 | return true 29 | } 30 | 31 | async has (key: string) { 32 | return this.store.has(key) 33 | } 34 | 35 | async delete (key: string) { 36 | return this.store.delete(key) 37 | } 38 | 39 | async touch () { } 40 | } 41 | -------------------------------------------------------------------------------- /packages/media-cacher/src/storages/storage.ts: -------------------------------------------------------------------------------- 1 | export interface SessionStorage { 2 | get(key: string): Promise 3 | set(key: string, value: any): Promise 4 | has(key: string): Promise 5 | delete(key: string): Promise 6 | touch(key: string): Promise 7 | } 8 | -------------------------------------------------------------------------------- /packages/media-cacher/src/types.ts: -------------------------------------------------------------------------------- 1 | import { Context } from 'puregram' 2 | 3 | export interface ContextInterface extends Context { 4 | [key: string]: any 5 | } 6 | -------------------------------------------------------------------------------- /packages/media-cacher/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { MediaInput, MediaSourceType } from 'puregram' 2 | 3 | /** Totally safe way to identify whether `obj` is `MediaInput` or not */ 4 | // definitely not stolen from puregram 5 | export const isMediaInput = (obj: Record): obj is MediaInput => ( 6 | obj.type !== undefined && Object.values(MediaSourceType).includes(obj.type) 7 | ) 8 | -------------------------------------------------------------------------------- /packages/media-cacher/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2019", 4 | "experimentalDecorators": true, 5 | "module": "commonjs", 6 | "declaration": true, 7 | "outDir": "./lib", 8 | "rootDir": "./src", 9 | "pretty": true, 10 | 11 | "strict": true, 12 | "noImplicitAny": true, 13 | "strictNullChecks": true, 14 | "strictFunctionTypes": true, 15 | "strictBindCallApply": true, 16 | "strictPropertyInitialization": true, 17 | "noImplicitThis": true, 18 | "alwaysStrict": true, 19 | 20 | "esModuleInterop": true, 21 | 22 | "skipLibCheck": true, 23 | "forceConsistentCasingInFileNames": true 24 | }, 25 | 26 | "include": ["./src"] 27 | } 28 | -------------------------------------------------------------------------------- /packages/prompt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@puregram/prompt", 3 | "version": "1.2.0", 4 | "description": "Basic prompt system implemetation for puregram", 5 | "main": "lib/index", 6 | "engines": { 7 | "node": ">=12.0.0" 8 | }, 9 | "scripts": { 10 | "clear-lib": "rm -rf lib/", 11 | "build": "yarn clear-lib && tsc --project tsconfig.json" 12 | }, 13 | "keywords": [ 14 | "puregram", 15 | "telegram", 16 | "prompt" 17 | ], 18 | "files": [ 19 | "lib" 20 | ], 21 | "author": "nitrojs", 22 | "license": "MIT", 23 | "dependencies": { 24 | "inspectable": "^1.2.0", 25 | "middleware-io": "^2.8.0" 26 | }, 27 | "peerDependencies": { 28 | "puregram": "^2.0.0" 29 | }, 30 | "types": "./lib/index.d.ts", 31 | "repository": { 32 | "type": "git", 33 | "url": "https://github.com/nitreojs/puregram/tree/lord/packages/prompt" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/prompt/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './prompt-question' 2 | export * from './prompt-answer' 3 | export * from './prompt-manager' 4 | 5 | export { PromptContext } from './types' 6 | -------------------------------------------------------------------------------- /packages/prompt/src/prompt-answer.ts: -------------------------------------------------------------------------------- 1 | import { inspectable } from 'inspectable' 2 | import { MessageContext } from 'puregram' 3 | 4 | import * as Types from './types' 5 | import { filterPayload } from './utils' 6 | 7 | export class PromptAnswer { 8 | constructor ( 9 | public context: Types.PromptMessageContext, 10 | private params: Types.PromptAnswerParams = {} 11 | ) { } 12 | 13 | get promptedAt () { 14 | return this.params.promptedAt 15 | } 16 | 17 | get promptedWithin () { 18 | return this.params.promptedWithin 19 | } 20 | 21 | get answeredAt () { 22 | return this.params.answeredAt 23 | } 24 | 25 | get text () { 26 | return this.context instanceof MessageContext 27 | ? this.context.text 28 | : this.context.message?.text 29 | } 30 | 31 | get caption () { 32 | return this.context instanceof MessageContext 33 | ? this.context.caption 34 | : this.context.message?.caption 35 | } 36 | } 37 | 38 | inspectable(PromptAnswer, { 39 | serialize (answer) { 40 | return filterPayload({ 41 | context: answer.context, 42 | promptedAt: answer.promptedAt, 43 | promptedWithin: answer.promptedWithin, 44 | answeredAt: answer.answeredAt, 45 | text: answer.text, 46 | caption: answer.caption 47 | }) 48 | } 49 | }) 50 | -------------------------------------------------------------------------------- /packages/prompt/src/prompt-question.ts: -------------------------------------------------------------------------------- 1 | import { SendMessageParams } from 'puregram/generated' 2 | import { inspectable } from 'inspectable' 3 | 4 | import * as Types from './types' 5 | import { filterPayload } from './utils' 6 | 7 | export class PromptQuestion { 8 | constructor (private params: Types.PromptQuestionParams) { } 9 | 10 | get requestText () { 11 | return this.params.request.text 12 | } 13 | 14 | get requestParams (): Types.Optional { 15 | return this.params.request.params ?? {} 16 | } 17 | 18 | get resolve () { 19 | return this.params.resolve 20 | } 21 | 22 | get promptedAt () { 23 | return this.params.promptedAt 24 | } 25 | 26 | get validate () { 27 | return this.params.validate 28 | } 29 | 30 | get onValidationFail () { 31 | return this.params.onValidationFail 32 | } 33 | } 34 | 35 | inspectable(PromptQuestion, { 36 | serialize (question) { 37 | return filterPayload({ 38 | promptedAt: question.promptedAt, 39 | text: question.requestText, 40 | params: question.requestParams 41 | }) 42 | } 43 | }) 44 | -------------------------------------------------------------------------------- /packages/prompt/src/utils.ts: -------------------------------------------------------------------------------- 1 | export const isPlainObject = (object: object): object is Record => ( 2 | Object.prototype.toString.call(object) === '[object Object]' 3 | ) 4 | 5 | export const filterPayload = (payload: Record) => { 6 | const filteredPayload: Record = {} 7 | 8 | for (const [key, value] of Object.entries(payload)) { 9 | const notEmpty = value !== undefined && value !== null 10 | 11 | const isEmptyArray = Array.isArray(value) && value?.length === 0 12 | 13 | if (notEmpty && !isEmptyArray) { 14 | if (isPlainObject(value)) { 15 | filteredPayload[key] = filterPayload(value) 16 | } else { 17 | filteredPayload[key] = value 18 | } 19 | } 20 | } 21 | 22 | return filteredPayload 23 | } 24 | -------------------------------------------------------------------------------- /packages/prompt/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2019", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "outDir": "lib", 7 | "pretty": true, 8 | 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "strictNullChecks": true, 12 | "strictFunctionTypes": true, 13 | "strictBindCallApply": true, 14 | "strictPropertyInitialization": true, 15 | "noImplicitThis": true, 16 | "alwaysStrict": true, 17 | 18 | "esModuleInterop": true, 19 | 20 | "skipLibCheck": true, 21 | "forceConsistentCasingInFileNames": true 22 | }, 23 | 24 | "include": ["./src"] 25 | } 26 | -------------------------------------------------------------------------------- /packages/puregram/src/common/attachments/attachment.ts: -------------------------------------------------------------------------------- 1 | import { Inspectable } from 'inspectable' 2 | 3 | import type { Structure } from '../../types/interfaces' 4 | import type { AttachmentType, MaybeArray, SoftString } from '../../types/types' 5 | import type { AttachmentsMapping } from '../../types/mappings' 6 | 7 | /** Simple attachment */ 8 | @Inspectable() 9 | export class Attachment implements Structure { 10 | attachmentType?: AttachmentType 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | is (rawTypes: MaybeArray>): this is AttachmentsMapping[T] { 17 | const types = Array.isArray(rawTypes) 18 | ? rawTypes 19 | : [rawTypes] 20 | 21 | if (this.attachmentType === undefined) { 22 | return false 23 | } 24 | 25 | return types.includes(this.attachmentType) 26 | } 27 | 28 | toJSON (): Record { 29 | throw new Error('toJSON not implemented') 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/puregram/src/common/attachments/contact.ts: -------------------------------------------------------------------------------- 1 | import type { AttachmentType } from '../../types/types' 2 | import { applyMixins } from '../../utils/helpers' 3 | 4 | import { Contact } from '../structures/contact' 5 | 6 | import { Attachment } from './attachment' 7 | 8 | class ContactAttachment extends Contact { 9 | attachmentType: AttachmentType = 'contact' 10 | 11 | toJSON () { 12 | return this.payload 13 | } 14 | } 15 | 16 | interface ContactAttachment extends Attachment { } 17 | applyMixins(ContactAttachment, [Attachment]) 18 | 19 | export { ContactAttachment } 20 | -------------------------------------------------------------------------------- /packages/puregram/src/common/attachments/document.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | import type { AttachmentType } from '../../types/types' 5 | 6 | import { PhotoSize } from '../structures/photo-size' 7 | 8 | import { FileAttachment } from './file-attachment' 9 | import { memoizeGetters } from '../../utils/helpers' 10 | 11 | /** 12 | * This object represents a general file (as opposed to photos, voice messages 13 | * and audio files). 14 | */ 15 | // TODO: extended: ['fileId', 'fileUniqueId'] 16 | @Inspectable() 17 | export class DocumentAttachment extends FileAttachment { 18 | attachmentType: AttachmentType = 'document' 19 | 20 | /** Document thumbnail as defined by sender */ 21 | @Inspect({ nullable: false }) 22 | get thumbnail () { 23 | const { thumbnail } = this.payload 24 | 25 | if (!thumbnail) { 26 | return 27 | } 28 | 29 | return new PhotoSize(thumbnail) 30 | } 31 | 32 | /** Original filename as defined by sender */ 33 | @Inspect({ nullable: false }) 34 | get fileName () { 35 | return this.payload.file_name 36 | } 37 | 38 | /** MIME type of the file as defined by sender */ 39 | @Inspect({ nullable: false }) 40 | get mimeType () { 41 | return this.payload.mime_type 42 | } 43 | 44 | /** File size */ 45 | @Inspect({ nullable: false }) 46 | get fileSize () { 47 | return this.payload.file_size 48 | } 49 | 50 | toJSON () { 51 | return this.payload 52 | } 53 | } 54 | 55 | memoizeGetters(DocumentAttachment, ['thumbnail']) 56 | -------------------------------------------------------------------------------- /packages/puregram/src/common/attachments/file-attachment.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import { AttachmentType } from '../../types/types' 4 | 5 | import { Attachment } from './attachment' 6 | 7 | export interface DefaultAttachment { 8 | file_id: string 9 | 10 | file_unique_id: string 11 | } 12 | 13 | /** Attachment with `fileId` and `fileUniqueId` properties */ 14 | @Inspectable() 15 | export class FileAttachment extends Attachment { 16 | protected payload: T 17 | 18 | /** Returns attachment's type (e.g. `'audio'`, `'photo'`) */ 19 | attachmentType?: AttachmentType 20 | 21 | constructor (payload: T) { 22 | super() 23 | 24 | this.payload = payload 25 | } 26 | 27 | /** Identifier for this file, which can be used to download or reuse the file */ 28 | @Inspect() 29 | get fileId () { 30 | return this.payload.file_id 31 | } 32 | 33 | /** 34 | * Unique identifier for this file, which is supposed to be the same over 35 | * time and for different bots. Can't be used to download or reuse the file. 36 | */ 37 | @Inspect() 38 | get fileUniqueId () { 39 | return this.payload.file_unique_id 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/puregram/src/common/attachments/index.ts: -------------------------------------------------------------------------------- 1 | export * from './animation' 2 | export * from './attachment' 3 | export * from './audio' 4 | export * from './contact' 5 | export * from './document' 6 | export * from './file-attachment' 7 | export * from './location' 8 | export * from './photo' 9 | export * from './poll' 10 | export * from './sticker' 11 | export * from './story' 12 | export * from './venue' 13 | export * from './video-note' 14 | export * from './video' 15 | export * from './voice' 16 | -------------------------------------------------------------------------------- /packages/puregram/src/common/attachments/location.ts: -------------------------------------------------------------------------------- 1 | import { AttachmentType } from '../../types/types' 2 | import { applyMixins } from '../../utils/helpers' 3 | 4 | import { Location } from '../structures/location' 5 | 6 | import { Attachment } from './attachment' 7 | 8 | class LocationAttachment extends Location { 9 | attachmentType: AttachmentType = 'location' 10 | 11 | toJSON () { 12 | return this.payload 13 | } 14 | } 15 | 16 | interface LocationAttachment extends Attachment { } 17 | applyMixins(LocationAttachment, [Attachment]) 18 | 19 | export { LocationAttachment } 20 | -------------------------------------------------------------------------------- /packages/puregram/src/common/attachments/photo.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import type { AttachmentType } from '../../types/types' 4 | 5 | import type { PhotoSize } from '../structures' 6 | 7 | import { Attachment } from './attachment' 8 | 9 | /** This object represents a photo file with it's sizes */ 10 | @Inspectable() 11 | export class PhotoAttachment extends Attachment { 12 | private payload: PhotoSize[] 13 | 14 | private readonly sorted: PhotoSize[] 15 | 16 | attachmentType: AttachmentType = 'photo' 17 | 18 | constructor (payload: PhotoSize[]) { 19 | super() 20 | 21 | this.payload = payload 22 | 23 | this.sorted = [...this.payload].sort( 24 | (first, second) => (second.width * second.height) - (first.width * first.height) 25 | ) 26 | } 27 | 28 | /** Photo sizes */ 29 | get sizes () { 30 | return this.payload 31 | } 32 | 33 | /** Biggest size of the photo */ 34 | @Inspect() 35 | get bigSize () { 36 | return this.sorted[0] 37 | } 38 | 39 | /** Medium size of the photo */ 40 | @Inspect() 41 | get mediumSize () { 42 | return this.sorted[Math.floor(this.sorted.length / 2)] 43 | } 44 | 45 | /** Smallest size of the photo */ 46 | @Inspect() 47 | get smallSize () { 48 | return this.sorted[this.sorted.length - 1] 49 | } 50 | 51 | toJSON () { 52 | return [ 53 | this.smallSize.toJSON(), 54 | this.mediumSize.toJSON(), 55 | this.bigSize.toJSON() 56 | ] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /packages/puregram/src/common/attachments/poll.ts: -------------------------------------------------------------------------------- 1 | import { AttachmentType } from '../../types/types' 2 | import { applyMixins } from '../../utils/helpers' 3 | 4 | import { Poll } from '../structures/poll' 5 | 6 | import { Attachment } from './attachment' 7 | 8 | class PollAttachment extends Poll { 9 | attachmentType: AttachmentType = 'poll' 10 | 11 | toJSON () { 12 | return this.payload 13 | } 14 | } 15 | 16 | interface PollAttachment extends Attachment { } 17 | applyMixins(PollAttachment, [Attachment]) 18 | 19 | export { PollAttachment } 20 | -------------------------------------------------------------------------------- /packages/puregram/src/common/attachments/story.ts: -------------------------------------------------------------------------------- 1 | import { AttachmentType } from '../../types/types' 2 | import { applyMixins } from '../../utils/helpers' 3 | import { Story } from '../structures/story' 4 | 5 | import { Attachment } from './attachment' 6 | 7 | class StoryAttachment extends Story { 8 | attachmentType: AttachmentType = 'story' 9 | 10 | toJSON () { 11 | return this.payload 12 | } 13 | } 14 | 15 | interface StoryAttachment extends Attachment { } 16 | applyMixins(StoryAttachment, [Attachment]) 17 | 18 | export { StoryAttachment } 19 | -------------------------------------------------------------------------------- /packages/puregram/src/common/attachments/venue.ts: -------------------------------------------------------------------------------- 1 | import { AttachmentType } from '../../types/types' 2 | import { applyMixins } from '../../utils/helpers' 3 | 4 | import { Venue } from '../structures/venue' 5 | 6 | import { Attachment } from './attachment' 7 | 8 | class VenueAttachment extends Venue { 9 | attachmentType: AttachmentType = 'venue' 10 | 11 | toJSON () { 12 | return this.payload 13 | } 14 | } 15 | 16 | interface VenueAttachment extends Attachment { } 17 | applyMixins(VenueAttachment, [Attachment]) 18 | 19 | export { VenueAttachment } 20 | -------------------------------------------------------------------------------- /packages/puregram/src/common/attachments/video-note.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | import type { AttachmentType } from '../../types/types' 5 | 6 | import { PhotoSize } from '../structures/photo-size' 7 | 8 | import { FileAttachment } from './file-attachment' 9 | import { memoizeGetters } from '../../utils/helpers' 10 | 11 | /** This object represents a video message. */ 12 | // TODO: extended: ['fileId', 'fileUniqueId'] 13 | @Inspectable() 14 | export class VideoNoteAttachment extends FileAttachment { 15 | attachmentType: AttachmentType = 'video_note' 16 | 17 | /** 18 | * Video width and height (diameter of the video message) as defined by 19 | * sender 20 | */ 21 | @Inspect() 22 | get length () { 23 | return this.payload.length 24 | } 25 | 26 | /** Duration of the video in seconds as defined by sender */ 27 | @Inspect() 28 | get duration () { 29 | return this.payload.duration 30 | } 31 | 32 | /** Video thumbnail */ 33 | @Inspect({ nullable: false }) 34 | get thumbnail () { 35 | const { thumbnail } = this.payload 36 | 37 | if (!thumbnail) { 38 | return 39 | } 40 | 41 | return new PhotoSize(thumbnail) 42 | } 43 | 44 | /** File size */ 45 | @Inspect({ nullable: false }) 46 | get fileSize () { 47 | return this.payload.file_size 48 | } 49 | 50 | toJSON () { 51 | return this.payload 52 | } 53 | } 54 | 55 | memoizeGetters(VideoNoteAttachment, ['thumbnail']) 56 | -------------------------------------------------------------------------------- /packages/puregram/src/common/attachments/video.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | import type { AttachmentType } from '../../types/types' 5 | 6 | import { PhotoSize } from '../structures/photo-size' 7 | 8 | import { FileAttachment } from './file-attachment' 9 | import { memoizeGetters } from '../../utils/helpers' 10 | 11 | /** This object represents a video file. */ 12 | // TODO: extended: ['fileId', 'fileUniqueId'] 13 | @Inspectable() 14 | export class VideoAttachment extends FileAttachment { 15 | attachmentType: AttachmentType = 'video' 16 | 17 | /** Video width as defined by sender */ 18 | @Inspect() 19 | get width () { 20 | return this.payload.width 21 | } 22 | 23 | /** Video height as defined by sender */ 24 | @Inspect() 25 | get height () { 26 | return this.payload.height 27 | } 28 | 29 | /** Duration of the video in seconds as defined by sender */ 30 | @Inspect() 31 | get duration () { 32 | return this.payload.duration 33 | } 34 | 35 | /** Video thumbnail */ 36 | @Inspect({ nullable: false }) 37 | get thumbnail () { 38 | const { thumbnail } = this.payload 39 | 40 | if (!thumbnail) { 41 | return 42 | } 43 | 44 | return new PhotoSize(thumbnail) 45 | } 46 | 47 | /** Original filename as defined by sender */ 48 | @Inspect({ nullable: false }) 49 | get fileName () { 50 | return this.payload.file_name 51 | } 52 | 53 | /** Mime type of a file as defined by sender */ 54 | @Inspect({ nullable: false }) 55 | get mimeType () { 56 | return this.payload.mime_type 57 | } 58 | 59 | /** File size */ 60 | @Inspect({ nullable: false }) 61 | get fileSize () { 62 | return this.payload.file_size 63 | } 64 | 65 | toJSON () { 66 | return this.payload 67 | } 68 | } 69 | 70 | memoizeGetters(VideoAttachment, ['thumbnail']) 71 | -------------------------------------------------------------------------------- /packages/puregram/src/common/attachments/voice.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | import { AttachmentType } from '../../types/types' 5 | 6 | import { FileAttachment } from './file-attachment' 7 | 8 | /** This object represents a voice note. */ 9 | // TODO: extended: ['fileId', 'fileUniqueId'] 10 | @Inspectable() 11 | export class VoiceAttachment extends FileAttachment { 12 | attachmentType: AttachmentType = 'voice' 13 | 14 | /** Duration of the audio in seconds as defined by sender */ 15 | @Inspect() 16 | get duration () { 17 | return this.payload.duration 18 | } 19 | 20 | /** MIME type of the file as defined by sender */ 21 | @Inspect({ nullable: false }) 22 | get mimeType () { 23 | return this.payload.mime_type 24 | } 25 | 26 | /** File size */ 27 | @Inspect({ nullable: false }) 28 | get fileSize () { 29 | return this.payload.file_size 30 | } 31 | 32 | toJSON () { 33 | return this.payload 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/puregram/src/common/index.ts: -------------------------------------------------------------------------------- 1 | export * from './attachments' 2 | export * from './inline-query' 3 | export * from './input-media' 4 | export * from './keyboards' 5 | export * from './media-source' 6 | export * from './parse-mode' 7 | export * from './structures' 8 | 9 | export * from './media-group' 10 | export * from './message-entities' 11 | export * from './reaction' 12 | export * from './updates-filter' 13 | -------------------------------------------------------------------------------- /packages/puregram/src/common/inline-query/index.ts: -------------------------------------------------------------------------------- 1 | export * from './result' 2 | export * from './message-content' 3 | -------------------------------------------------------------------------------- /packages/puregram/src/common/input-media/index.ts: -------------------------------------------------------------------------------- 1 | export * from './input-media' 2 | -------------------------------------------------------------------------------- /packages/puregram/src/common/input-media/types.ts: -------------------------------------------------------------------------------- 1 | import * as Methods from '../../generated/methods' 2 | 3 | import { Optional } from '../../types/types' 4 | 5 | export type NonMediaParams = 'chat_id' | 'message_thread_id' | 'disable_notification' | 'protect_content' | 'reply_markup' | 'reply_parameters' 6 | 7 | type InputMediaParams = Exclude 8 | 9 | type Replace = Omit & { [P in V]: T[K] } 10 | 11 | export type InputMediaStickerOriginal = Optional, 'chat_id'> 12 | export type InputMediaVideoNoteOriginal = Optional, 'chat_id'> 13 | export type InputMediaVoiceOriginal = Optional, 'chat_id'> 14 | 15 | export type InputMediaSticker = Replace 16 | export type InputMediaVideoNote = Replace 17 | export type InputMediaVoice = Replace 18 | -------------------------------------------------------------------------------- /packages/puregram/src/common/keyboards/force-reply.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | /** Force reply keyboard */ 6 | @Inspectable() 7 | export class ForceReply { 8 | @Inspect({ as: 'selective', nullable: false }) 9 | private isSelective = false 10 | 11 | @Inspect({ as: 'input_field_placeholder', nullable: false }) 12 | private placeholder?: string 13 | 14 | /** Use this parameter if you want to show the keyboard to specific users only */ 15 | selective (selective = true) { 16 | this.isSelective = selective 17 | 18 | return this 19 | } 20 | 21 | /** The placeholder to be shown in the input field when the keyboard is active */ 22 | setPlaceholder (placeholder: string) { 23 | this.placeholder = placeholder 24 | 25 | return this 26 | } 27 | 28 | /** Returns JSON which is compatible with Telegram's `ForceReply` interface */ 29 | toJSON (): Interfaces.TelegramForceReply { 30 | return { 31 | force_reply: true, 32 | input_field_placeholder: this.placeholder, 33 | selective: this.isSelective 34 | } 35 | } 36 | 37 | toString () { 38 | return JSON.stringify(this) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/puregram/src/common/keyboards/index.ts: -------------------------------------------------------------------------------- 1 | export * from './force-reply' 2 | export * from './inline-keyboard-builder' 3 | export * from './inline-keyboard' 4 | export * from './keyboard-builder' 5 | export * from './keyboard' 6 | export * from './remove' 7 | -------------------------------------------------------------------------------- /packages/puregram/src/common/keyboards/remove.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | interface RemoveKeyboardJSON { 4 | remove_keyboard: true 5 | selective: boolean 6 | } 7 | 8 | /** Remove keyboard */ 9 | @Inspectable() 10 | export class RemoveKeyboard { 11 | // TODO: remove_keyboard: true 12 | @Inspect({ as: 'selective' }) 13 | private isSelective = false 14 | 15 | /** Use this parameter if you want to show the keyboard to specific users only */ 16 | selective (selective = true) { 17 | this.isSelective = selective 18 | 19 | return this 20 | } 21 | 22 | /** Returns JSON which is compatible with Telegram's `RemoveKeyboard` interface */ 23 | toJSON (): RemoveKeyboardJSON { 24 | return { 25 | remove_keyboard: true, 26 | selective: this.isSelective 27 | } 28 | } 29 | 30 | toString () { 31 | return JSON.stringify(this) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/puregram/src/common/media-source/index.ts: -------------------------------------------------------------------------------- 1 | export { MediaSource, MediaSourceTo } from './media-source' 2 | 3 | export * from './types' 4 | -------------------------------------------------------------------------------- /packages/puregram/src/common/parse-mode/index.ts: -------------------------------------------------------------------------------- 1 | export * from './html' 2 | export * from './markdown-v2' 3 | export * from './markdown' 4 | -------------------------------------------------------------------------------- /packages/puregram/src/common/parse-mode/markdown.ts: -------------------------------------------------------------------------------- 1 | import { replaceChars } from '../../utils/helpers' 2 | 3 | /** Markdown parse mode */ 4 | export class Markdown { 5 | static parseMode = 'Markdown' as const 6 | 7 | get [Symbol.toStringTag] () { 8 | return this.constructor.name 9 | } 10 | 11 | /** @deprecated use `Markdown.escape` instead */ 12 | static raw (source: string) { 13 | return Markdown.escape(source) 14 | } 15 | 16 | /** Escape all the danger characters */ 17 | static escape (source: string) { 18 | return replaceChars(source, ['*', '_', '[', ']', '`']) 19 | } 20 | 21 | /** Bold text */ 22 | static bold (source: string, escape = true) { 23 | return `*${escape ? replaceChars(source, '*') : source}*` 24 | } 25 | 26 | /** Italic text */ 27 | static italic (source: string, escape = true) { 28 | return `_${escape ? replaceChars(source, '_') : source}_` 29 | } 30 | 31 | /** URL with text */ 32 | static url (source: string, link: string, escape = true) { 33 | return `[${escape ? replaceChars(source, '[]') : source}](${link})` 34 | } 35 | 36 | /** Mention the user */ 37 | static mention (source: string, id: number | string, escape = true) { 38 | return `[${escape ? replaceChars(source, '[]') : source}](tg://user?id=${id})` 39 | } 40 | 41 | /** Preformatted code */ 42 | static code (source: string, escape = true) { 43 | return `\`${escape ? replaceChars(source, '`') : source}\`` 44 | } 45 | 46 | /** Preformatted code */ 47 | static pre (source: string, language?: string) { 48 | const quotes = '```' 49 | 50 | return `${quotes}${language || ''}\n${source}\n${quotes}` 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/puregram/src/common/reaction.ts: -------------------------------------------------------------------------------- 1 | import * as Interfaces from '../generated/telegram-interfaces' 2 | 3 | /** Class for easier reaction interaction with API */ 4 | export class Reaction { 5 | /** Creates an emoji reaction object */ 6 | static emoji (emoji: Interfaces.TelegramReactionTypeEmoji['emoji']): Interfaces.TelegramReactionTypeEmoji { 7 | return { 8 | type: 'emoji', 9 | emoji 10 | } 11 | } 12 | 13 | /** Creates a custom emoji reaction object */ 14 | static customEmoji (id: string): Interfaces.TelegramReactionTypeCustomEmoji { 15 | return { 16 | type: 'custom_emoji', 17 | custom_emoji_id: id 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/bot-command.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents a bot command */ 8 | @Inspectable() 9 | export class BotCommand implements Structure { 10 | constructor (public payload: Interfaces.TelegramBotCommand) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** Text of the command; 1-32 characters. Can contain only lowercase English letters, digits and underscores. */ 17 | @Inspect() 18 | get command () { 19 | return this.payload.command 20 | } 21 | 22 | /** Description of the command; 1-256 characters */ 23 | @Inspect() 24 | get description () { 25 | return this.payload.description 26 | } 27 | 28 | toJSON () { 29 | return this.payload 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/bot-description.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents the bot's description. */ 8 | @Inspectable() 9 | export class BotDescription implements Structure { 10 | constructor (public payload: Interfaces.TelegramBotDescription) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** The bot's description */ 17 | @Inspect() 18 | get description () { 19 | return this.payload.description 20 | } 21 | 22 | toJSON () { 23 | return this.payload 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/bot-short-description.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents the bot's short description. */ 8 | @Inspectable() 9 | export class BotShortDescription implements Structure { 10 | constructor (public payload: Interfaces.TelegramBotShortDescription) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** The bot's short description */ 17 | @Inspect() 18 | get description () { 19 | return this.payload.short_description 20 | } 21 | 22 | toJSON () { 23 | return this.payload 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/callback-game.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** A placeholder, currently holds no information. */ 8 | @Inspectable() 9 | export class CallbackGame implements Structure { 10 | constructor (public payload: Interfaces.TelegramCallbackGame) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | toJSON () { 17 | return this.payload 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/chat-boost-added.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | import * as Interfaces from '../../generated/telegram-interfaces' 3 | 4 | import { Structure } from '../../types/interfaces' 5 | 6 | /** This object represents a service message about a user boosting a chat. */ 7 | @Inspectable() 8 | export class ChatBoostAdded implements Structure { 9 | constructor (public payload: Interfaces.TelegramChatBoostAdded) { } 10 | 11 | get [Symbol.toStringTag] () { 12 | return this.constructor.name 13 | } 14 | 15 | /** Number of boosts added by the user */ 16 | @Inspect() 17 | get boostCount () { 18 | return this.payload.boost_count 19 | } 20 | 21 | toJSON (): Record { 22 | return this.payload 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/chat-boost-removed.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | import * as Interfaces from '../../generated/telegram-interfaces' 3 | 4 | import { Structure } from '../../types/interfaces' 5 | import { Chat } from './chat' 6 | import { ChatBoostSourceGiftCode, ChatBoostSourceGiveaway, ChatBoostSourcePremium } from './chat-boost-source' 7 | import { memoizeGetters } from '../../utils/helpers' 8 | 9 | /** This object represents a boost added to a chat or changed. */ 10 | @Inspectable() 11 | export class ChatBoostRemoved implements Structure { 12 | constructor (public payload: Interfaces.TelegramChatBoostRemoved) { } 13 | 14 | get [Symbol.toStringTag] () { 15 | return this.constructor.name 16 | } 17 | 18 | /** Chat which was boosted */ 19 | @Inspect() 20 | get chat () { 21 | return new Chat(this.payload.chat) 22 | } 23 | 24 | /** Unique identifier of the boost */ 25 | @Inspect() 26 | get id () { 27 | return this.payload.boost_id 28 | } 29 | 30 | /** Point in time (Unix timestamp) when the boost was removed */ 31 | @Inspect() 32 | get removeDate () { 33 | return this.payload.remove_date 34 | } 35 | 36 | /** Source of the removed boost */ 37 | @Inspect() 38 | get source () { 39 | if (this.payload.source.source === 'premium') { 40 | return new ChatBoostSourcePremium(this.payload.source) 41 | } 42 | 43 | if (this.payload.source.source === 'gift_code') { 44 | return new ChatBoostSourceGiftCode(this.payload.source) 45 | } 46 | 47 | if (this.payload.source.source === 'giveaway') { 48 | return new ChatBoostSourceGiveaway(this.payload.source) 49 | } 50 | 51 | throw new TypeError('unknown chat boost source') 52 | } 53 | 54 | toJSON (): Record { 55 | return this.payload 56 | } 57 | } 58 | 59 | memoizeGetters(ChatBoostRemoved, ['chat', 'source']) 60 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/chat-boost-source/chat-boost-source.ts: -------------------------------------------------------------------------------- 1 | import * as Interfaces from '../../../generated/telegram-interfaces' 2 | 3 | import { Structure } from '../../../types/interfaces' 4 | 5 | import type { ChatBoostSourceGiftCode } from './gift-code' 6 | import type { ChatBoostSourceGiveaway } from './giveaway' 7 | import type { ChatBoostSourcePremium } from './premium' 8 | 9 | interface ChatBoostSourceMapping { 10 | premium: ChatBoostSourcePremium 11 | gift_code: ChatBoostSourceGiftCode 12 | giveaway: ChatBoostSourceGiveaway 13 | } 14 | 15 | export class ChatBoostSource implements Structure { 16 | constructor (public payload: Interfaces.TelegramChatBoostSource) { } 17 | 18 | get [Symbol.toStringTag] () { 19 | return this.constructor.name 20 | } 21 | 22 | /** Is this chat boost source a certain one? */ 23 | is (source: T): this is ChatBoostSourceMapping[T] { 24 | return this.payload.source === source 25 | } 26 | 27 | toJSON (): Record { 28 | return this.payload 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/chat-boost-source/gift-code.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | import * as Interfaces from '../../../generated/telegram-interfaces' 3 | 4 | import { User } from '../user' 5 | 6 | import { ChatBoostSource } from './chat-boost-source' 7 | import { memoizeGetters } from '../../../utils/helpers' 8 | 9 | /** The boost was obtained by the creation of Telegram Premium gift codes to boost a chat. Each such code boosts the chat 4 times for the duration of the corresponding Telegram Premium subscription. */ 10 | @Inspectable() 11 | export class ChatBoostSourceGiftCode extends ChatBoostSource { 12 | constructor (public payload: Interfaces.TelegramChatBoostSourceGiftCode) { 13 | super(payload) 14 | } 15 | 16 | /** Source of the boost, always `gift_code` */ 17 | @Inspect() 18 | get source () { 19 | return this.payload.source 20 | } 21 | 22 | /** User for which the gift code was created */ 23 | @Inspect() 24 | get user () { 25 | return new User(this.payload.user) 26 | } 27 | } 28 | 29 | memoizeGetters(ChatBoostSourceGiftCode, ['user']) 30 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/chat-boost-source/giveaway.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | import * as Interfaces from '../../../generated/telegram-interfaces' 3 | 4 | import { User } from '../user' 5 | 6 | import { ChatBoostSource } from './chat-boost-source' 7 | import { memoizeGetters } from '../../../utils/helpers' 8 | 9 | /** The boost was obtained by the creation of a Telegram Premium giveaway. This boosts the chat 4 times for the duration of the corresponding Telegram Premium subscription. */ 10 | @Inspectable() 11 | export class ChatBoostSourceGiveaway extends ChatBoostSource { 12 | constructor (public payload: Interfaces.TelegramChatBoostSourceGiveaway) { 13 | super(payload) 14 | } 15 | 16 | /** Source of the boost, always `giveaway` */ 17 | @Inspect() 18 | get source () { 19 | return this.payload.source 20 | } 21 | 22 | get giveawayMessageId () { 23 | return this.payload.giveaway_message_id 24 | } 25 | 26 | /** User that boosted the chat */ 27 | @Inspect({ nullable: false }) 28 | get user () { 29 | const { user } = this.payload 30 | 31 | if (!user) { 32 | return 33 | } 34 | 35 | return new User(user) 36 | } 37 | 38 | /** `true`, if the giveaway was completed, but there was no user to win the prize */ 39 | @Inspect({ compute: true, nullable: false }) 40 | isUnclaimed () { 41 | return this.payload.is_unclaimed 42 | } 43 | } 44 | 45 | memoizeGetters(ChatBoostSourceGiveaway, ['user']) 46 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/chat-boost-source/index.ts: -------------------------------------------------------------------------------- 1 | export * from './gift-code' 2 | export * from './giveaway' 3 | export * from './premium' 4 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/chat-boost-source/premium.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | import * as Interfaces from '../../../generated/telegram-interfaces' 3 | 4 | import { User } from '../user' 5 | 6 | import { ChatBoostSource } from './chat-boost-source' 7 | import { memoizeGetters } from '../../../utils/helpers' 8 | 9 | /** The boost was obtained by subscribing to Telegram Premium or by gifting a Telegram Premium subscription to another user. */ 10 | @Inspectable() 11 | export class ChatBoostSourcePremium extends ChatBoostSource { 12 | constructor (public payload: Interfaces.TelegramChatBoostSourcePremium) { 13 | super(payload) 14 | } 15 | 16 | /** Source of the boost, always `premium` */ 17 | @Inspect() 18 | get source () { 19 | return this.payload.source 20 | } 21 | 22 | /** User that boosted the chat */ 23 | @Inspect() 24 | get user () { 25 | return new User(this.payload.user) 26 | } 27 | } 28 | 29 | memoizeGetters(ChatBoostSourcePremium, ['user']) 30 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/chat-boost-updated.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | import * as Interfaces from '../../generated/telegram-interfaces' 3 | 4 | import { Structure } from '../../types/interfaces' 5 | import { Chat } from './chat' 6 | import { ChatBoost } from './chat-boost' 7 | import { memoizeGetters } from '../../utils/helpers' 8 | 9 | /** This object represents a boost added to a chat or changed. */ 10 | @Inspectable() 11 | export class ChatBoostUpdated implements Structure { 12 | constructor (public payload: Interfaces.TelegramChatBoostUpdated) { } 13 | 14 | get [Symbol.toStringTag] () { 15 | return this.constructor.name 16 | } 17 | 18 | /** Chat which was boosted */ 19 | @Inspect() 20 | get chat () { 21 | return new Chat(this.payload.chat) 22 | } 23 | 24 | /** Infomation about the chat boost */ 25 | @Inspect() 26 | get boost () { 27 | return new ChatBoost(this.payload.boost) 28 | } 29 | 30 | toJSON (): Record { 31 | return this.payload 32 | } 33 | } 34 | 35 | memoizeGetters(ChatBoostUpdated, ['chat', 'boost']) 36 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/chat-boost.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | import * as Interfaces from '../../generated/telegram-interfaces' 3 | 4 | import { Structure } from '../../types/interfaces' 5 | import { ChatBoostSourceGiftCode, ChatBoostSourceGiveaway, ChatBoostSourcePremium } from './chat-boost-source' 6 | import { memoizeGetters } from '../../utils/helpers' 7 | 8 | /** This object contains information about a chat boost. */ 9 | @Inspectable() 10 | export class ChatBoost implements Structure { 11 | constructor (public payload: Interfaces.TelegramChatBoost) { } 12 | 13 | get [Symbol.toStringTag] () { 14 | return this.constructor.name 15 | } 16 | 17 | /** Unique identifier of the boost */ 18 | @Inspect() 19 | get id () { 20 | return this.payload.boost_id 21 | } 22 | 23 | /** Point in time (Unix timestamp) when the chat was boosted */ 24 | @Inspect() 25 | get addDate () { 26 | return this.payload.add_date 27 | } 28 | 29 | /** Point in time (Unix timestamp) when the boost will automatically expire, unless the booster's Telegram Premium subscription is prolonged */ 30 | @Inspect() 31 | get expirationDate () { 32 | return this.payload.expiration_date 33 | } 34 | 35 | /** Source of the added boost */ 36 | @Inspect() 37 | get source () { 38 | if (this.payload.source.source === 'premium') { 39 | return new ChatBoostSourcePremium(this.payload.source) 40 | } 41 | 42 | if (this.payload.source.source === 'gift_code') { 43 | return new ChatBoostSourceGiftCode(this.payload.source) 44 | } 45 | 46 | if (this.payload.source.source === 'giveaway') { 47 | return new ChatBoostSourceGiveaway(this.payload.source) 48 | } 49 | 50 | throw new TypeError('unknown chat boost source') 51 | } 52 | 53 | toJSON (): Record { 54 | return this.payload 55 | } 56 | } 57 | 58 | memoizeGetters(ChatBoost, ['source']) 59 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/chat-location.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | import { Location } from './location' 8 | import { memoizeGetters } from '../../utils/helpers' 9 | 10 | /** Represents a location to which a chat is connected. */ 11 | @Inspectable() 12 | export class ChatLocation implements Structure { 13 | constructor (public payload: Interfaces.TelegramChatLocation) { } 14 | 15 | get [Symbol.toStringTag] () { 16 | return this.constructor.name 17 | } 18 | 19 | /** The location to which the supergroup is connected. Can't be a live location. */ 20 | @Inspect() 21 | get location () { 22 | return new Location(this.payload.location) 23 | } 24 | 25 | /** Location address; `1-64` characters, as defined by the chat owner */ 26 | @Inspect() 27 | get address () { 28 | return this.payload.address 29 | } 30 | 31 | toJSON () { 32 | return this.payload 33 | } 34 | } 35 | 36 | memoizeGetters(ChatLocation, ['location']) 37 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/chat-photo.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents a chat photo. */ 8 | @Inspectable() 9 | export class ChatPhoto implements Structure { 10 | constructor (public payload: Interfaces.TelegramChatPhoto) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** 17 | * File identifier of small (`160x160`) chat photo. 18 | * This `file_id` can be used only for photo download and only for as long 19 | * as the photo is not changed. 20 | */ 21 | @Inspect() 22 | get smallFileId () { 23 | return this.payload.small_file_id 24 | } 25 | 26 | /** 27 | * Unique file identifier of small (`160x160`) chat photo, which is supposed 28 | * to be the same over time and for different bots. Can't be used to download 29 | * or reuse the file. 30 | */ 31 | @Inspect() 32 | get smallFileUniqueId () { 33 | return this.payload.small_file_unique_id 34 | } 35 | 36 | /** 37 | * File identifier of big (`640x640`) chat photo. This `file_id` can be used 38 | * only for photo download and only for as long as the photo is not changed. 39 | */ 40 | @Inspect() 41 | get bigFileId () { 42 | return this.payload.big_file_id 43 | } 44 | 45 | /** 46 | * Unique file identifier of big (`640x640`) chat photo, which is supposed 47 | * to be the same over time and for different bots. Can't be used to 48 | * download or reuse the file. 49 | */ 50 | @Inspect() 51 | get bigFileUniqueId () { 52 | return this.payload.big_file_unique_id 53 | } 54 | 55 | toJSON () { 56 | return this.payload 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/chat-shared.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object contains information about the chat whose identifier was shared with the bot using a KeyboardButtonRequestChat button. */ 8 | @Inspectable() 9 | export class ChatShared implements Structure { 10 | constructor (public payload: Interfaces.TelegramChatShared) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** Identifier of the request */ 17 | @Inspect() 18 | get requestId () { 19 | return this.payload.request_id 20 | } 21 | 22 | /** Identifier of the shared chat. This number may have more than 32 significant bits and some programming languages may have difficulty/silent defects in interpreting it. But it has at most 52 significant bits, so a 64-bit integer or double-precision float type are safe for storing this identifier. The bot may not have access to the chat and could be unable to use this identifier, unless the chat is already known to the bot by some other means. */ 23 | @Inspect() 24 | get chatId () { 25 | return this.payload.chat_id 26 | } 27 | 28 | toJSON () { 29 | return this.payload 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/composer.ts: -------------------------------------------------------------------------------- 1 | import { Inspectable } from 'inspectable' 2 | import { Composer as MiddlewareComposer } from 'middleware-io' 3 | 4 | import { Context } from '../../contexts/context' 5 | 6 | @Inspectable() 7 | // @ts-expect-error Composer does not like MiddlewareComposer... 8 | export class Composer extends MiddlewareComposer { 9 | /** 10 | * Create new `Composer` instance 11 | */ 12 | static builder (): Composer { 13 | return new Composer() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/contact.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents a phone contact. */ 8 | @Inspectable() 9 | export class Contact implements Structure { 10 | constructor (public payload: Interfaces.TelegramContact) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** Contact's phone number */ 17 | @Inspect() 18 | get phoneNumber () { 19 | return this.payload.phone_number 20 | } 21 | 22 | /** Contact's first name */ 23 | @Inspect() 24 | get firstName () { 25 | return this.payload.first_name 26 | } 27 | 28 | /** Contact's last name */ 29 | @Inspect({ nullable: false }) 30 | get lastName () { 31 | return this.payload.last_name 32 | } 33 | 34 | /** Contact's user identifier in Telegram */ 35 | @Inspect({ nullable: false }) 36 | get userId () { 37 | return this.payload.user_id 38 | } 39 | 40 | /** Additional data about the contact in the form of a vCard */ 41 | @Inspect({ nullable: false }) 42 | get vCard () { 43 | return this.payload.vcard 44 | } 45 | 46 | toJSON () { 47 | return this.payload 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/dice.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Methods from '../../generated/methods' 4 | import * as Interfaces from '../../generated/telegram-interfaces' 5 | 6 | import { Structure } from '../../types/interfaces' 7 | 8 | /** This object represents an animated emoji that displays a random value. */ 9 | @Inspectable() 10 | export class Dice implements Structure { 11 | constructor (public payload: Interfaces.TelegramDice) { } 12 | 13 | get [Symbol.toStringTag] () { 14 | return this.constructor.name 15 | } 16 | 17 | /** Emoji on which the dice throw animation is based */ 18 | @Inspect() 19 | get emoji () { 20 | return this.payload.emoji as NonNullable 21 | } 22 | 23 | /** 24 | * Value of the dice, 25 | * `1-6` for `🎲`, `🎯` and `🎳` base emoji, 26 | * `1-5` for `🏀` and `⚽️` base emoji, 27 | * `1-64` for `🎰` base emoji 28 | */ 29 | @Inspect() 30 | get value () { 31 | return this.payload.value 32 | } 33 | 34 | toJSON () { 35 | return this.payload 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/encrypted-credentials.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** 8 | * Contains data required for decrypting and authenticatin 9 | * `EncryptedPassportElement`. See the Telegram Passport Documentation for a 10 | * complete description of the data decryption and authentication processes. 11 | */ 12 | @Inspectable() 13 | export class EncryptedCredentials implements Structure { 14 | constructor (public payload: Interfaces.TelegramEncryptedCredentials) { } 15 | 16 | get [Symbol.toStringTag] () { 17 | return this.constructor.name 18 | } 19 | 20 | /** 21 | * Base64-encoded encrypted JSON-serialized data with unique user's payload, 22 | * data hashes and secrets required for `EncryptedPassportElement` decryption 23 | * and authentication 24 | */ 25 | @Inspect() 26 | get data () { 27 | return this.payload.data 28 | } 29 | 30 | /** Base64-encoded data hash for data authentication */ 31 | @Inspect() 32 | get hash () { 33 | return this.payload.hash 34 | } 35 | 36 | /** 37 | * Base64-encoded secret, encrypted with the bot's public RSA key, required 38 | * for data decryption 39 | */ 40 | @Inspect() 41 | get secret () { 42 | return this.payload.secret 43 | } 44 | 45 | toJSON () { 46 | return this.payload 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/file.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents a file ready to be downloaded. The file can be downloaded via the link `https://api.telegram.org/file/bot/`. It is guaranteed that the link will be valid for at least 1 hour. When the link expires, a new one can be requested by calling `getFile`. */ 8 | @Inspectable() 9 | export class File implements Structure { 10 | constructor (public payload: Interfaces.TelegramFile) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** 17 | * Identifier for this file, which can be used to download or reuse the file 18 | */ 19 | @Inspect() 20 | get fileId () { 21 | return this.payload.file_id 22 | } 23 | 24 | /** 25 | * Unique identifier for this file, which is supposed to be the same over 26 | * time and for different bots. Can't be used to download or reuse the file. 27 | */ 28 | @Inspect() 29 | get fileUniqueId () { 30 | return this.payload.file_unique_id 31 | } 32 | 33 | /** File size, if known */ 34 | @Inspect() 35 | get fileSize () { 36 | return this.payload.file_size 37 | } 38 | 39 | /** 40 | * File path. 41 | * Use `https://api.telegram.org/file/bot/` to get the 42 | * file. 43 | */ 44 | @Inspect({ nullable: false }) 45 | get filePath () { 46 | return this.payload.file_path 47 | } 48 | 49 | toJSON () { 50 | return this.payload 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/forum-topic-closed.ts: -------------------------------------------------------------------------------- 1 | import { Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents a service message about a forum topic closed in the chat. Currently holds no information. */ 8 | @Inspectable() 9 | export class ForumTopicClosed implements Structure { 10 | constructor (public payload: Interfaces.TelegramForumTopicClosed) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | toJSON () { 17 | return this.payload 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/forum-topic-created.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents a service message about a new forum topic created in the chat. */ 8 | @Inspectable() 9 | export class ForumTopicCreated implements Structure { 10 | constructor (public payload: Interfaces.TelegramForumTopicCreated) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** Name of the topic */ 17 | @Inspect() 18 | get name () { 19 | return this.payload.name 20 | } 21 | 22 | /** Color of the topic icon in RGB format */ 23 | @Inspect() 24 | get iconColor () { 25 | return this.payload.icon_color 26 | } 27 | 28 | /** Unique identifier of the custom emoji shown as the topic icon */ 29 | @Inspect({ nullable: false }) 30 | get iconCustomEmojiId () { 31 | return this.payload.icon_custom_emoji_id 32 | } 33 | 34 | toJSON () { 35 | return this.payload 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/forum-topic-edited.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents a service message about an edited forum topic. */ 8 | @Inspectable() 9 | export class ForumTopicEdited implements Structure { 10 | constructor (public payload: Interfaces.TelegramForumTopicEdited) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** New name of the topic, if it was edited */ 17 | @Inspect() 18 | get name () { 19 | return this.payload.name 20 | } 21 | 22 | /** New identifier of the custom emoji shown as the topic icon, if it was edited; an empty string if the icon was removed */ 23 | @Inspect({ nullable: false }) 24 | get iconCustomEmojiId () { 25 | return this.payload.icon_custom_emoji_id 26 | } 27 | 28 | toJSON () { 29 | return this.payload 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/forum-topic-reopened.ts: -------------------------------------------------------------------------------- 1 | import { Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents a service message about an edited forum topic. */ 8 | @Inspectable() 9 | export class ForumTopicReopened implements Structure { 10 | constructor (public payload: Interfaces.TelegramForumTopicReopened) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | toJSON () { 17 | return this.payload 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/general-forum-topic-hidden.ts: -------------------------------------------------------------------------------- 1 | import { Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents a service message about General forum topic hidden in the chat. Currently holds no information. */ 8 | @Inspectable() 9 | export class GeneralForumTopicHidden implements Structure { 10 | constructor (public payload: Interfaces.TelegramGeneralForumTopicHidden) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | toJSON () { 17 | return this.payload 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/general-forum-topic-unhidden.ts: -------------------------------------------------------------------------------- 1 | import { Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents a service message about General forum topic unhidden in the chat. Currently holds no information. */ 8 | @Inspectable() 9 | export class GeneralForumTopicUnhidden implements Structure { 10 | constructor (public payload: Interfaces.TelegramGeneralForumTopicUnhidden) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | toJSON () { 17 | return this.payload 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/giveaway-completed.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | import * as Interfaces from '../../generated/telegram-interfaces' 3 | 4 | import { Structure } from '../../types/interfaces' 5 | import { Message } from './message' 6 | import { memoizeGetters } from '../../utils/helpers' 7 | 8 | /** This object represents a service message about the completion of a giveaway without public winners. */ 9 | @Inspectable() 10 | export class GiveawayCompleted implements Structure { 11 | constructor (public payload: Interfaces.TelegramGiveawayCompleted) { } 12 | 13 | get [Symbol.toStringTag] () { 14 | return this.constructor.name 15 | } 16 | 17 | /** Number of winners in the giveaway */ 18 | @Inspect() 19 | get winnerCount () { 20 | return this.payload.winner_count 21 | } 22 | 23 | /** Number of undistributed prizes */ 24 | @Inspect({ nullable: false }) 25 | get unclaimedPrizeCount () { 26 | return this.payload.unclaimed_prize_count 27 | } 28 | 29 | /** Message with the giveaway that was completed, if it wasn't deleted */ 30 | @Inspect({ nullable: false }) 31 | get message (): Message | undefined { 32 | const { giveaway_message } = this.payload 33 | 34 | if (!giveaway_message) { 35 | return 36 | } 37 | 38 | return new Message(giveaway_message) 39 | } 40 | 41 | toJSON () { 42 | return this.payload 43 | } 44 | } 45 | 46 | memoizeGetters(GiveawayCompleted, ['message']) 47 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/giveaway-created.ts: -------------------------------------------------------------------------------- 1 | import { Inspectable } from 'inspectable' 2 | import * as Interfaces from '../../generated/telegram-interfaces' 3 | 4 | import { Structure } from '../../types/interfaces' 5 | 6 | /** This object represents a service message about the creation of a scheduled giveaway. Currently holds no information. */ 7 | @Inspectable() 8 | export class GiveawayCreated implements Structure { 9 | constructor (public payload: Interfaces.TelegramGiveawayCreated) { } 10 | 11 | get [Symbol.toStringTag] () { 12 | return this.constructor.name 13 | } 14 | 15 | toJSON () { 16 | return this.payload 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/inaccessible-message.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | import * as Interfaces from '../../generated/telegram-interfaces' 3 | 4 | import type { Structure } from '../../types/interfaces' 5 | import { Chat } from './chat' 6 | import { memoizeGetters } from '../../utils/helpers' 7 | 8 | @Inspectable() 9 | export class InaccessibleMessage implements Structure { 10 | constructor (public payload: Interfaces.TelegramInaccessibleMessage) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** Unique message identifier inside the chat */ 17 | @Inspect() 18 | get id () { 19 | return this.payload.message_id 20 | } 21 | 22 | /** Chat the message belonged to */ 23 | @Inspect() 24 | get chat () { 25 | return new Chat(this.payload.chat) 26 | } 27 | 28 | /** Always `0`. The field can be used to differentiate regular and inaccessible messages. */ 29 | @Inspect() 30 | get date () { 31 | return this.payload.date 32 | } 33 | 34 | toJSON (): Record { 35 | return this.payload 36 | } 37 | } 38 | 39 | memoizeGetters(InaccessibleMessage, ['chat']) 40 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/inline-keyboard-markup.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | import { InlineKeyboardButton } from './inline-keyboard-button' 8 | 9 | /** This object represents an inline keyboard that appears right next to the message it belongs to. */ 10 | @Inspectable() 11 | export class InlineKeyboardMarkup implements Structure { 12 | constructor (public payload: Interfaces.TelegramInlineKeyboardMarkup) { } 13 | 14 | get [Symbol.toStringTag] () { 15 | return this.constructor.name 16 | } 17 | 18 | /** Array of button rows */ 19 | @Inspect() 20 | get inlineKeyboard () { 21 | const { inline_keyboard } = this.payload 22 | 23 | return inline_keyboard.map(row => row.map(element => new InlineKeyboardButton(element))) 24 | } 25 | 26 | toJSON () { 27 | return this.payload 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/inline-query.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | import { User } from './user' 8 | import { Location } from './location' 9 | import { memoizeGetters } from '../../utils/helpers' 10 | 11 | /** 12 | * This object represents an incoming inline query. 13 | * When the user sends an empty query, your bot could return some default or 14 | * trending results. 15 | */ 16 | @Inspectable() 17 | export class InlineQuery implements Structure { 18 | constructor (public payload: Interfaces.TelegramInlineQuery) { } 19 | 20 | get [Symbol.toStringTag] () { 21 | return this.constructor.name 22 | } 23 | 24 | /** Unique identifier for this query */ 25 | @Inspect() 26 | get id () { 27 | return this.payload.id 28 | } 29 | 30 | /** Sender */ 31 | @Inspect() 32 | get from () { 33 | return new User(this.payload.from) 34 | } 35 | 36 | /** Sender location, only for bots that request user location */ 37 | @Inspect({ nullable: false }) 38 | get location () { 39 | const { location } = this.payload 40 | 41 | if (!location) { 42 | return 43 | } 44 | 45 | return new Location(location) 46 | } 47 | 48 | /** Text of the query (up to 256 characters) */ 49 | @Inspect() 50 | get query () { 51 | return this.payload.query 52 | } 53 | 54 | /** Offset of the results to be returned, can be controlled by the bot */ 55 | @Inspect() 56 | get offset () { 57 | return this.payload.offset 58 | } 59 | 60 | toJSON () { 61 | return this.payload 62 | } 63 | } 64 | 65 | memoizeGetters(InlineQuery, ['from', 'location']) 66 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/invoice.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object contains basic information about an invoice. */ 8 | @Inspectable() 9 | export class Invoice implements Structure { 10 | constructor (public payload: Interfaces.TelegramInvoice) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** Product name */ 17 | @Inspect() 18 | get title () { 19 | return this.payload.title 20 | } 21 | 22 | /** Product description */ 23 | @Inspect() 24 | get description () { 25 | return this.payload.description 26 | } 27 | 28 | /** 29 | * Unique bot deep-linking parameter that can be used to generate this 30 | * invoice 31 | */ 32 | @Inspect() 33 | get startParameter () { 34 | return this.payload.start_parameter 35 | } 36 | 37 | /** Three-letter ISO 4217 currency code */ 38 | @Inspect() 39 | get currency () { 40 | return this.payload.currency 41 | } 42 | 43 | /** 44 | * Total price in the smallest units of the currency 45 | * (integer, not float/double). For example, for a price of 46 | * `US$ 1.45` pass `amount = 145`. See the `exp` parameter in 47 | * [currencies.json](https://core.telegram.org/bots/payments/currencies.json), 48 | * it shows the number of digits past the decimal point for each currency 49 | * (2 for the majority of currencies). 50 | */ 51 | @Inspect() 52 | get totalAmount () { 53 | return this.payload.total_amount 54 | } 55 | 56 | toJSON () { 57 | return this.payload 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/link-preview-options.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | import * as Interfaces from '../../generated' 3 | 4 | import { Structure } from '../../types/interfaces' 5 | 6 | /** Describes the options used for link preview generation. */ 7 | @Inspectable() 8 | export class LinkPreviewOptions implements Structure { 9 | constructor (public payload: Interfaces.TelegramLinkPreviewOptions) { } 10 | 11 | get [Symbol.toStringTag] () { 12 | return this.constructor.name 13 | } 14 | 15 | /** `true`, if the link preview is disabled */ 16 | @Inspect({ compute: true, nullable: false }) 17 | isDisabled () { 18 | return this.payload.is_disabled 19 | } 20 | 21 | /** URL to use for the link preview. If empty, then the first URL found in the message text will be used */ 22 | @Inspect({ nullable: false }) 23 | get url () { 24 | return this.payload.url 25 | } 26 | 27 | /** `true`, if the media in the link preview is supposed to be shrunk; ignored if the URL isn't explicitly specified or media size change isn't supported for the preview */ 28 | @Inspect({ compute: true, nullable: false }) 29 | preferSmallMedia () { 30 | return this.payload.prefer_small_media 31 | } 32 | 33 | /** `true`, if the media in the link preview is supposed to be enlarged; ignored if the URL isn't explicitly specified or media size change isn't supported for the preview */ 34 | @Inspect({ compute: true, nullable: false }) 35 | preferLargeMedia () { 36 | return this.payload.prefer_large_media 37 | } 38 | 39 | /** `true`, if the link preview must be shown above the message text; otherwise, the link preview will be shown below the message text */ 40 | @Inspect({ compute: true, nullable: false }) 41 | showAboveText () { 42 | return this.payload.show_above_text 43 | } 44 | 45 | toJSON () { 46 | return this.payload 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/location.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents a point on the map. */ 8 | @Inspectable() 9 | export class Location implements Structure { 10 | constructor (public payload: Interfaces.TelegramLocation) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** Longitude as defined by sender */ 17 | @Inspect() 18 | get longitude () { 19 | return this.payload.longitude 20 | } 21 | 22 | /** Latitude as defined by sender */ 23 | @Inspect() 24 | get latitude () { 25 | return this.payload.latitude 26 | } 27 | 28 | /** The radius of uncertainty for the location, measured in meters; `0-1500` */ 29 | @Inspect() 30 | get horizontalAccuracy () { 31 | return this.payload.horizontal_accuracy 32 | } 33 | 34 | /** 35 | * Time relative to the message sending date, 36 | * during which the location can be updated, in seconds. 37 | * For active live locations only. 38 | */ 39 | @Inspect() 40 | get livePeriod () { 41 | return this.payload.live_period 42 | } 43 | 44 | /** 45 | * The direction in which user is moving, in degrees; `1-360`. 46 | * For active live locations only. 47 | */ 48 | @Inspect() 49 | get heading () { 50 | return this.payload.heading 51 | } 52 | 53 | /** 54 | * Maximum distance for proximity alerts about approaching another chat member, in meters. 55 | * For sent live locations only. 56 | */ 57 | @Inspect() 58 | get proximityAlertRadius () { 59 | return this.payload.proximity_alert_radius 60 | } 61 | 62 | toJSON () { 63 | return this.payload 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/mask-position.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** 8 | * This object describes the position on faces where a mask should be placed 9 | * by default. 10 | */ 11 | @Inspectable() 12 | export class MaskPosition implements Structure { 13 | constructor (public payload: Interfaces.TelegramMaskPosition) { } 14 | 15 | get [Symbol.toStringTag] () { 16 | return this.constructor.name 17 | } 18 | 19 | /** 20 | * The part of the face relative to which the mask should be placed. 21 | * One of `forehead`, `eyes`, `mouth`, or `chin`. 22 | */ 23 | @Inspect() 24 | get point () { 25 | return this.payload.point 26 | } 27 | 28 | /** 29 | * Shift by X-axis measured in widths of the mask scaled to the face size, 30 | * from left to right. For example, choosing `-1.0` will place mask just to 31 | * the left of the default mask position. 32 | */ 33 | @Inspect() 34 | get xShift () { 35 | return this.payload.x_shift 36 | } 37 | 38 | /** 39 | * Shift by Y-axis measured in heights of the mask scaled to the face size, 40 | * from top to bottom. For example, `1.0` will place the mask just below the 41 | * default mask position. 42 | */ 43 | @Inspect() 44 | get yShift () { 45 | return this.payload.y_shift 46 | } 47 | 48 | /** Mask scaling coefficient. For example, `2.0` means double size. */ 49 | @Inspect() 50 | get scale () { 51 | return this.payload.scale 52 | } 53 | 54 | toJSON () { 55 | return this.payload 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/menu-button.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | import { WebAppInfo } from './web-app-info' 8 | import { memoizeGetters } from '../../utils/helpers' 9 | 10 | /** This object describes the bot's menu button in a private chat. */ 11 | @Inspectable() 12 | export class MenuButton implements Structure { 13 | constructor (public payload: Interfaces.TelegramMenuButton) { } 14 | 15 | get [Symbol.toStringTag] () { 16 | return this.constructor.name 17 | } 18 | 19 | /** Type of the button */ 20 | @Inspect() 21 | get type () { 22 | return this.payload.type 23 | } 24 | 25 | /** Text on the button */ 26 | @Inspect() 27 | get text () { 28 | return this.payload.text 29 | } 30 | 31 | /** 32 | * Description of the Web App that will be launched when the user presses the button. 33 | * The Web App will be able to send an arbitrary message on behalf of the user 34 | * using the method `answerWebAppQuery`. 35 | */ 36 | @Inspect({ nullable: false }) 37 | get webApp () { 38 | const { web_app } = this.payload 39 | 40 | if (!web_app) { 41 | return 42 | } 43 | 44 | return new WebAppInfo(web_app) 45 | } 46 | 47 | toJSON () { 48 | return this.payload 49 | } 50 | } 51 | 52 | memoizeGetters(MenuButton, ['webApp']) 53 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/message-auto-delete-timer-changed.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents a service message about a change in auto-delete timer settings */ 8 | @Inspectable() 9 | export class MessageAutoDeleteTimerChanged implements Structure { 10 | constructor (public payload: Interfaces.TelegramMessageAutoDeleteTimerChanged) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** New auto-delete time for messages in the chat */ 17 | @Inspect() 18 | get messageAutoDeleteTime () { 19 | return this.payload.message_auto_delete_time 20 | } 21 | 22 | toJSON () { 23 | return this.payload 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/message-id.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents a unique message identifier. */ 8 | @Inspectable() 9 | export class MessageId implements Structure { 10 | constructor (public payload: Interfaces.TelegramMessageId) { } 11 | 12 | /** Unique message identifier */ 13 | @Inspect() 14 | get id () { 15 | return this.payload.message_id 16 | } 17 | 18 | toJSON () { 19 | return this.payload 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/message-origin/channel.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../../generated' 4 | 5 | import { Chat } from '../chat' 6 | 7 | import { MessageOrigin } from './message-origin' 8 | import { memoizeGetters } from '../../../utils/helpers' 9 | 10 | /** The message was originally sent to a channel chat. */ 11 | @Inspectable() 12 | export class MessageOriginChannel extends MessageOrigin { 13 | constructor (public payload: Interfaces.TelegramMessageOriginChannel) { 14 | super(payload) 15 | } 16 | 17 | /** Type of the message origin, always `channel` */ 18 | @Inspect() 19 | get type () { 20 | return this.payload.type 21 | } 22 | 23 | /** Date the message was sent originally in Unix time */ 24 | @Inspect() 25 | get date () { 26 | return this.payload.date 27 | } 28 | 29 | /** Channel chat to which the message was originally sent */ 30 | @Inspect() 31 | get chat () { 32 | return new Chat(this.payload.chat) 33 | } 34 | 35 | /** Unique message identifier inside the chat */ 36 | @Inspect() 37 | get messageId () { 38 | return this.payload.message_id 39 | } 40 | 41 | /** Signature of the original post author */ 42 | @Inspect() 43 | get authorSignature () { 44 | return this.payload.author_signature 45 | } 46 | } 47 | 48 | memoizeGetters(MessageOriginChannel, ['chat']) 49 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/message-origin/chat.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../../generated' 4 | 5 | import { Chat } from '../chat' 6 | 7 | import { MessageOrigin } from './message-origin' 8 | import { memoizeGetters } from '../../../utils/helpers' 9 | 10 | /** The message was originally sent on behalf of a chat to a group chat. */ 11 | @Inspectable() 12 | export class MessageOriginChat extends MessageOrigin { 13 | constructor (public payload: Interfaces.TelegramMessageOriginChat) { 14 | super(payload) 15 | } 16 | 17 | /** Type of the message origin, always `chat` */ 18 | @Inspect() 19 | get type () { 20 | return this.payload.type 21 | } 22 | 23 | /** Date the message was sent originally in Unix time */ 24 | @Inspect() 25 | get date () { 26 | return this.payload.date 27 | } 28 | 29 | /** Chat that sent the message originally */ 30 | @Inspect() 31 | get senderChat () { 32 | return new Chat(this.payload.sender_chat) 33 | } 34 | 35 | /** For messages originally sent by an anonymous chat administrator, original message author signature */ 36 | @Inspect({ nullable: false }) 37 | get authorSignature () { 38 | return this.payload.author_signature 39 | } 40 | } 41 | 42 | memoizeGetters(MessageOriginChat, ['senderChat']) 43 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/message-origin/hidden-user.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../../generated' 4 | 5 | import { MessageOrigin } from './message-origin' 6 | 7 | /** The message was originally sent by an unknown user. */ 8 | @Inspectable() 9 | export class MessageOriginHiddenUser extends MessageOrigin { 10 | constructor (public payload: Interfaces.TelegramMessageOriginHiddenUser) { 11 | super(payload) 12 | } 13 | 14 | /** Type of the message origin, always `hidden_user` */ 15 | @Inspect() 16 | get type () { 17 | return this.payload.type 18 | } 19 | 20 | /** Date the message was sent originally in Unix time */ 21 | @Inspect() 22 | get date () { 23 | return this.payload.date 24 | } 25 | 26 | /** Name of the user that sent the message originally */ 27 | @Inspect() 28 | get senderUserName () { 29 | return this.payload.sender_user_name 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/message-origin/index.ts: -------------------------------------------------------------------------------- 1 | export * from './channel' 2 | export * from './chat' 3 | export * from './hidden-user' 4 | export * from './user' 5 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/message-origin/message-origin.ts: -------------------------------------------------------------------------------- 1 | import * as Interfaces from '../../../generated' 2 | 3 | import type { MessageOriginUser } from './user' 4 | import type { MessageOriginChat } from './chat' 5 | import type { MessageOriginChannel } from './channel' 6 | import type { MessageOriginHiddenUser } from './hidden-user' 7 | 8 | import { Structure } from '../../../types/interfaces' 9 | 10 | interface MessageOriginMapping { 11 | user: MessageOriginUser 12 | chat: MessageOriginChat 13 | channel: MessageOriginChannel 14 | hidden_user: MessageOriginHiddenUser 15 | } 16 | 17 | export class MessageOrigin implements Structure { 18 | constructor (public payload: Interfaces.TelegramMessageOrigin) { } 19 | 20 | get [Symbol.toStringTag] () { 21 | return this.constructor.name 22 | } 23 | 24 | /** Is this message origin a certain one? */ 25 | is (type: T): this is MessageOriginMapping[T] { 26 | return this.payload.type === type 27 | } 28 | 29 | toJSON () { 30 | return this.payload 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/message-origin/user.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../../generated' 4 | 5 | import { User } from '../user' 6 | 7 | import { MessageOrigin } from './message-origin' 8 | import { memoizeGetters } from '../../../utils/helpers' 9 | 10 | /** The message was originally sent by a known user. */ 11 | @Inspectable() 12 | export class MessageOriginUser extends MessageOrigin { 13 | constructor (public payload: Interfaces.TelegramMessageOriginUser) { 14 | super(payload) 15 | } 16 | 17 | /** Type of the message origin, always `user` */ 18 | @Inspect() 19 | get type () { 20 | return this.payload.type 21 | } 22 | 23 | /** Date the message was sent originally in Unix time */ 24 | @Inspect() 25 | get date () { 26 | return this.payload.date 27 | } 28 | 29 | /** User that sent the message originally */ 30 | @Inspect() 31 | get senderUser () { 32 | return new User(this.payload.sender_user) 33 | } 34 | } 35 | 36 | memoizeGetters(MessageOriginUser, ['senderUser']) 37 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/order-info.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | import { ShippingAddress } from './shipping-address' 8 | import { memoizeGetters } from '../../utils/helpers' 9 | 10 | /** This object represents information about an order. */ 11 | @Inspectable() 12 | export class OrderInfo implements Structure { 13 | constructor (public payload: Interfaces.TelegramOrderInfo) { } 14 | 15 | get [Symbol.toStringTag] () { 16 | return this.constructor.name 17 | } 18 | 19 | /** User name */ 20 | @Inspect({ nullable: false }) 21 | get name () { 22 | return this.payload.name 23 | } 24 | 25 | /** User's phone number */ 26 | @Inspect({ nullable: false }) 27 | get phoneNumber () { 28 | return this.payload.phone_number 29 | } 30 | 31 | /** User email */ 32 | @Inspect({ nullable: false }) 33 | get email () { 34 | return this.payload.email 35 | } 36 | 37 | /** User shipping address */ 38 | @Inspect({ nullable: false }) 39 | get shippingAddress () { 40 | const { shipping_address } = this.payload 41 | 42 | if (!shipping_address) { 43 | return 44 | } 45 | 46 | return new ShippingAddress(shipping_address) 47 | } 48 | 49 | toJSON () { 50 | return this.payload 51 | } 52 | } 53 | 54 | memoizeGetters(OrderInfo, ['shippingAddress']) 55 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/passport-data.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | import { EncryptedPassportElement } from './encrypted-passport-element' 8 | import { EncryptedCredentials } from './encrypted-credentials' 9 | import { memoizeGetters } from '../../utils/helpers' 10 | 11 | /** 12 | * Contains information about Telegram Passport data shared with the bot by the 13 | * user. 14 | */ 15 | @Inspectable() 16 | export class PassportData implements Structure { 17 | constructor (public payload: Interfaces.TelegramPassportData) { } 18 | 19 | get [Symbol.toStringTag] () { 20 | return this.constructor.name 21 | } 22 | 23 | /** 24 | * Array with information about documents and other Telegram Passport 25 | * elements that was shared with the bot 26 | */ 27 | @Inspect({ nullable: false }) 28 | get data () { 29 | const { data } = this.payload 30 | 31 | if (!data) { 32 | return 33 | } 34 | 35 | return data.map(element => new EncryptedPassportElement(element)) 36 | } 37 | 38 | /** Encrypted credentials required to decrypt the data */ 39 | @Inspect() 40 | get credentials () { 41 | return new EncryptedCredentials(this.payload.credentials) 42 | } 43 | 44 | toJSON () { 45 | return this.payload 46 | } 47 | } 48 | 49 | memoizeGetters(PassportData, ['credentials']) 50 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/passport-file.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** 8 | * This object represents a file uploaded to Telegram Passport. 9 | * Currently all Telegram Passport files are in JPEG format when decrypted and 10 | * don't exceed 10MB. 11 | */ 12 | @Inspectable() 13 | export class PassportFile implements Structure { 14 | constructor (public payload: Interfaces.TelegramPassportFile) { } 15 | 16 | get [Symbol.toStringTag] () { 17 | return this.constructor.name 18 | } 19 | 20 | /** 21 | * Identifier for this file, which can be used to download or reuse the file 22 | */ 23 | @Inspect() 24 | get fileId () { 25 | return this.payload.file_id 26 | } 27 | 28 | /** 29 | * Unique identifier for this file, which is supposed to be the same over 30 | * time and for different bots. Can't be used to download or reuse the file. 31 | */ 32 | @Inspect() 33 | get fileUniqueId () { 34 | return this.payload.file_unique_id 35 | } 36 | 37 | /** File size */ 38 | @Inspect() 39 | get fileSize () { 40 | return this.payload.file_size 41 | } 42 | 43 | /** Unix time when the file was uploaded */ 44 | @Inspect() 45 | get fileDate () { 46 | return this.payload.file_date 47 | } 48 | 49 | toJSON () { 50 | return this.payload 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/photo-size.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents one size of a photo or a file / sticker thumbnail */ 8 | @Inspectable() 9 | export class PhotoSize implements Structure { 10 | constructor (public payload: Interfaces.TelegramPhotoSize) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** 17 | * Identifier for this file, which can be used to download or reuse the file 18 | */ 19 | @Inspect() 20 | get fileId () { 21 | return this.payload.file_id 22 | } 23 | 24 | /** 25 | * Unique identifier for this file, which is supposed to be the same over 26 | * time and for different bots. Can't be used to download or reuse the file. 27 | */ 28 | @Inspect() 29 | get fileUniqueId () { 30 | return this.payload.file_unique_id 31 | } 32 | 33 | /** Photo width */ 34 | @Inspect() 35 | get width () { 36 | return this.payload.width 37 | } 38 | 39 | /** Photo height */ 40 | @Inspect() 41 | get height () { 42 | return this.payload.height 43 | } 44 | 45 | /** File size */ 46 | @Inspect({ nullable: false }) 47 | get fileSize () { 48 | return this.payload.file_size 49 | } 50 | 51 | toJSON () { 52 | return this.payload 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/poll-option.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object contains information about one answer option in a poll. */ 8 | @Inspectable() 9 | export class PollOption implements Structure { 10 | constructor (public payload: Interfaces.TelegramPollOption) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** Option text, 1-100 characters */ 17 | @Inspect() 18 | get text () { 19 | return this.payload.text 20 | } 21 | 22 | /** Number of users that voted for this option */ 23 | @Inspect() 24 | get voterCount () { 25 | return this.payload.voter_count 26 | } 27 | 28 | toJSON () { 29 | return this.payload 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/proximity-alert-triggered.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | import { User } from './user' 8 | import { memoizeGetters } from '../../utils/helpers' 9 | 10 | /** 11 | * This object represents the content of a service message, 12 | * sent whenever a user in the chat triggers a proximity alert set by another user. 13 | */ 14 | @Inspectable() 15 | export class ProximityAlertTriggered implements Structure { 16 | constructor (public payload: Interfaces.TelegramProximityAlertTriggered) { } 17 | 18 | /** User that triggered the alert */ 19 | @Inspect() 20 | get traveler () { 21 | return new User(this.payload.traveler) 22 | } 23 | 24 | /** User that set the alert */ 25 | @Inspect() 26 | get watcher () { 27 | return new User(this.payload.watcher) 28 | } 29 | 30 | /** The distance between the users */ 31 | @Inspect() 32 | get distance () { 33 | return this.payload.distance 34 | } 35 | 36 | toJSON () { 37 | return this.payload 38 | } 39 | } 40 | 41 | memoizeGetters(ProximityAlertTriggered, ['traveler', 'watcher']) 42 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/reaction-count.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | import * as Interfaces from '../../generated/telegram-interfaces' 3 | 4 | import { Structure } from '../../types/interfaces' 5 | import { ReactionTypeCustomEmoji, ReactionTypeEmoji } from './reaction-type' 6 | import { memoizeGetters } from '../../utils/helpers' 7 | 8 | /** Represents a reaction added to a message along with the number of times it was added. */ 9 | @Inspectable() 10 | export class ReactionCount implements Structure { 11 | constructor (public payload: Interfaces.TelegramReactionCount) { } 12 | 13 | get [Symbol.toStringTag] () { 14 | return this.constructor.name 15 | } 16 | 17 | /** Type of the reaction */ 18 | @Inspect() 19 | get type () { 20 | if (this.payload.type.type === 'emoji') { 21 | return new ReactionTypeEmoji(this.payload.type) 22 | } 23 | 24 | if (this.payload.type.type === 'custom_emoji') { 25 | return new ReactionTypeCustomEmoji(this.payload.type) 26 | } 27 | 28 | throw new TypeError('unknown reaction type') 29 | } 30 | 31 | /** Number of times the reaction was added */ 32 | @Inspect() 33 | get totalCount () { 34 | return this.payload.total_count 35 | } 36 | 37 | toJSON () { 38 | return this.payload 39 | } 40 | } 41 | 42 | memoizeGetters(ReactionCount, ['type']) 43 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/reaction-type/custom-emoji.ts: -------------------------------------------------------------------------------- 1 | import * as Interfaces from '../../../generated/telegram-interfaces' 2 | 3 | import { ReactionType } from './reaction-type' 4 | 5 | export class ReactionTypeCustomEmoji extends ReactionType { 6 | constructor (public payload: Interfaces.TelegramReactionTypeCustomEmoji) { 7 | super(payload) 8 | } 9 | 10 | /** Type of the reaction, always `custom_emoji` */ 11 | get type () { 12 | return this.payload.type 13 | } 14 | 15 | /** Custom emoji identifier */ 16 | get customEmoji () { 17 | return this.payload.custom_emoji 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/reaction-type/emoji.ts: -------------------------------------------------------------------------------- 1 | import * as Interfaces from '../../../generated/telegram-interfaces' 2 | 3 | import { ReactionType } from './reaction-type' 4 | 5 | export class ReactionTypeEmoji extends ReactionType { 6 | constructor (public payload: Interfaces.TelegramReactionTypeEmoji) { 7 | super(payload) 8 | } 9 | 10 | /** Type of the reaction, always `emoji` */ 11 | get type () { 12 | return this.payload.type 13 | } 14 | 15 | /** Reaction emoji. Currently, it can be one of "👍", "👎", "❤", "🔥", "🥰", "👏", "😁", "🤔", "🤯", "😱", "🤬", "😢", "🎉", "🤩", "🤮", "💩", "🙏", "👌", "🕊", "🤡", "🥱", "🥴", "😍", "🐳", "❤‍🔥", "🌚", "🌭", "💯", "🤣", "⚡", "🍌", "🏆", "💔", "🤨", "😐", "🍓", "🍾", "💋", "🖕", "😈", "😴", "😭", "🤓", "👻", "👨‍💻", "👀", "🎃", "🙈", "😇", "😨", "🤝", "✍", "🤗", "🫡", "🎅", "🎄", "☃", "💅", "🤪", "🗿", "🆒", "💘", "🙉", "🦄", "😘", "💊", "🙊", "😎", "👾", "🤷‍♂", "🤷", "🤷‍♀", "😡" */ 16 | get emoji () { 17 | return this.payload.emoji 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/reaction-type/index.ts: -------------------------------------------------------------------------------- 1 | export * from './custom-emoji' 2 | export * from './emoji' 3 | export * from './paid' 4 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/reaction-type/paid.ts: -------------------------------------------------------------------------------- 1 | import * as Interfaces from '../../../generated/telegram-interfaces' 2 | 3 | import { ReactionType } from './reaction-type' 4 | 5 | export class ReactionTypePaid extends ReactionType { 6 | constructor (public payload: Interfaces.TelegramReactionTypePaid) { 7 | super(payload) 8 | } 9 | 10 | /** Type of the reaction, always `paid` */ 11 | get type () { 12 | return this.payload.type 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/reaction-type/reaction-type.ts: -------------------------------------------------------------------------------- 1 | import * as Interfaces from '../../../generated/telegram-interfaces' 2 | 3 | import { Structure } from '../../../types/interfaces' 4 | 5 | import type { ReactionTypeCustomEmoji } from './custom-emoji' 6 | import type { ReactionTypeEmoji } from './emoji' 7 | import type { ReactionTypePaid } from './paid' 8 | 9 | interface ReactionTypeMapping { 10 | emoji: ReactionTypeEmoji 11 | custom_emoji: ReactionTypeCustomEmoji 12 | paid: ReactionTypePaid 13 | } 14 | 15 | export class ReactionType implements Structure { 16 | constructor (public payload: Interfaces.TelegramReactionType) { } 17 | 18 | get [Symbol.toStringTag] () { 19 | return this.constructor.name 20 | } 21 | 22 | /** Is this reaction type the same as the `type`? */ 23 | is (type: T): this is ReactionTypeMapping[T] { 24 | return this.payload.type === type 25 | } 26 | 27 | toJSON () { 28 | return this.payload 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/sent-web-app-message.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** Contains information about an inline message sent by a Web App on behalf of a user. */ 8 | @Inspectable() 9 | export class SentWebAppMessage implements Structure { 10 | constructor (public payload: Interfaces.TelegramSentWebAppMessage) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** 17 | * Identifier of the sent inline message. 18 | * 19 | * Available only if there is an inline keyboard attached to the message. 20 | */ 21 | @Inspect({ nullable: false }) 22 | get inlineMessageId () { 23 | return this.payload.inline_message_id 24 | } 25 | 26 | toJSON () { 27 | return this.payload 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/shipping-address.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents a shipping address. */ 8 | @Inspectable() 9 | export class ShippingAddress implements Structure { 10 | constructor (public payload: Interfaces.TelegramShippingAddress) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** ISO 3166-1 alpha-2 country code */ 17 | @Inspect() 18 | get countryCode () { 19 | return this.payload.country_code 20 | } 21 | 22 | /** State, if applicable */ 23 | @Inspect() 24 | get state () { 25 | return this.payload.state 26 | } 27 | 28 | /** City */ 29 | @Inspect() 30 | get city () { 31 | return this.payload.city 32 | } 33 | 34 | /** First line for the address */ 35 | @Inspect() 36 | get firstStreetLine () { 37 | return this.payload.street_line1 38 | } 39 | 40 | /** Second line for the address */ 41 | @Inspect() 42 | get secondStreetLine () { 43 | return this.payload.street_line2 44 | } 45 | 46 | /** Address post code */ 47 | @Inspect() 48 | get postCode () { 49 | return this.payload.post_code 50 | } 51 | 52 | toJSON () { 53 | return this.payload 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/shipping-query.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | import { User } from './user' 8 | import { ShippingAddress } from './shipping-address' 9 | import { memoizeGetters } from '../../utils/helpers' 10 | 11 | /** This object contains information about an incoming shipping query. */ 12 | @Inspectable() 13 | export class ShippingQuery implements Structure { 14 | constructor (public payload: Interfaces.TelegramShippingQuery) { } 15 | 16 | get [Symbol.toStringTag] () { 17 | return this.constructor.name 18 | } 19 | 20 | /** Unique query identifier */ 21 | @Inspect() 22 | get id () { 23 | return this.payload.id 24 | } 25 | 26 | /** User who sent the query */ 27 | @Inspect() 28 | get from () { 29 | return new User(this.payload.from) 30 | } 31 | 32 | /** Sender ID */ 33 | @Inspect() 34 | get senderId () { 35 | return this.from.id 36 | } 37 | 38 | /** Bot specified invoice payload */ 39 | @Inspect() 40 | get invoicePayload () { 41 | return this.payload.invoice_payload 42 | } 43 | 44 | /** User specified shipping address */ 45 | @Inspect() 46 | get shippingAddress () { 47 | return new ShippingAddress(this.payload.shipping_address) 48 | } 49 | 50 | toJSON () { 51 | return this.payload 52 | } 53 | } 54 | 55 | memoizeGetters(ShippingQuery, ['from', 'shippingAddress']) 56 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/story.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | @Inspectable() 8 | export class Story implements Structure { 9 | constructor (public payload: Interfaces.TelegramStory) { } 10 | 11 | get [Symbol.toStringTag] () { 12 | return this.constructor.name 13 | } 14 | 15 | /** Unique identifier for the story in the chat */ 16 | @Inspect() 17 | get id () { 18 | return this.payload.id 19 | } 20 | 21 | /** Chat that posted the story */ 22 | @Inspect() 23 | get chat () { 24 | return this.payload.chat 25 | } 26 | 27 | toJSON () { 28 | return this.payload 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/text-quote.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | import * as Interfaces from '../../generated/telegram-interfaces' 3 | 4 | import { Structure } from '../../types/interfaces' 5 | 6 | import { MessageEntities } from '../message-entities' 7 | 8 | import { MessageEntity } from './message-entity' 9 | import { memoizeGetters } from '../../utils/helpers' 10 | 11 | /** This object contains information about the quoted part of a message that is replied to by the given message. */ 12 | @Inspectable() 13 | export class TextQuote implements Structure { 14 | constructor (public payload: Interfaces.TelegramTextQuote) { } 15 | 16 | get [Symbol.toStringTag] () { 17 | return this.constructor.name 18 | } 19 | 20 | /** Text of the quoted part of a message that is replied to by the given message */ 21 | @Inspect() 22 | get text () { 23 | return this.payload.text 24 | } 25 | 26 | /** Special entities that appear in the quote. Currently, only `bold`, `italic`, `underline`, `strikethrough`, `spoiler`, and `custom_emoji` entities are kept in quotes. */ 27 | @Inspect({ nullable: false }) 28 | get entities () { 29 | const { entities } = this.payload 30 | 31 | if (!entities) { 32 | return undefined 33 | } 34 | 35 | return new MessageEntities(...entities.map(e => new MessageEntity(e))) 36 | } 37 | 38 | /** Approximate quote position in the original message in UTF-16 code units as specified by the sender */ 39 | @Inspect() 40 | get position () { 41 | return this.payload.position 42 | } 43 | 44 | /** `true`, if the quote was chosen manually by the message sender. Otherwise, the quote was added automatically by the server. */ 45 | @Inspect({ compute: true, nullable: false }) 46 | isManual () { 47 | return this.payload.is_manual 48 | } 49 | 50 | toJSON () { 51 | return this.payload 52 | } 53 | } 54 | 55 | memoizeGetters(TextQuote, ['entities']) 56 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/user-profile-photos.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | import { PhotoSize } from './photo-size' 8 | 9 | /** This object represent a user's profile pictures. */ 10 | @Inspectable() 11 | export class UserProfilePhotos implements Structure { 12 | constructor (public payload: Interfaces.TelegramUserProfilePhotos) { } 13 | 14 | get [Symbol.toStringTag] () { 15 | return this.constructor.name 16 | } 17 | 18 | /** Total number of profile pictures the target user has */ 19 | @Inspect() 20 | get totalCount () { 21 | return this.payload.total_count 22 | } 23 | 24 | /** Requested profile pictures (in up to 4 sizes each) */ 25 | @Inspect({ nullable: false }) 26 | get photos () { 27 | const { photos } = this.payload 28 | 29 | if (!photos.length) { 30 | return 31 | } 32 | 33 | return photos.map(row => row.map(element => new PhotoSize(element))) 34 | } 35 | 36 | toJSON () { 37 | return this.payload 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/users-shared.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object contains information about the user whose identifier was shared with the bot using a `KeyboardButtonRequestUser` button. */ 8 | @Inspectable() 9 | export class UsersShared implements Structure { 10 | constructor (public payload: Interfaces.TelegramUsersShared) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** Identifier of the request */ 17 | @Inspect() 18 | get requestId () { 19 | return this.payload.request_id 20 | } 21 | 22 | /** Identifier of the shared user. This number may have more than 32 significant bits and some programming languages may have difficulty/silent defects in interpreting it. But it has at most 52 significant bits, so a 64-bit integer or double-precision float type are safe for storing this identifier. The bot may not have access to the user and could be unable to use this identifier, unless the user is already known to the bot by some other means. */ 23 | @Inspect() 24 | get userIds () { 25 | return this.payload.user_ids 26 | } 27 | 28 | toJSON () { 29 | return this.payload 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/venue.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | import { Location } from './location' 8 | import { memoizeGetters } from '../../utils/helpers' 9 | 10 | /** This object represents a venue. */ 11 | @Inspectable() 12 | export class Venue implements Structure { 13 | constructor (public payload: Interfaces.TelegramVenue) { } 14 | 15 | get [Symbol.toStringTag] () { 16 | return this.constructor.name 17 | } 18 | 19 | /** Venue location */ 20 | @Inspect() 21 | get location () { 22 | return new Location(this.payload.location) 23 | } 24 | 25 | /** Name of the venue */ 26 | @Inspect() 27 | get title () { 28 | return this.payload.title 29 | } 30 | 31 | /** Address of the venue */ 32 | @Inspect() 33 | get address () { 34 | return this.payload.address 35 | } 36 | 37 | /** Foursquare identifier of the venue */ 38 | @Inspect({ nullable: false }) 39 | get foursquareId () { 40 | return this.payload.foursquare_id 41 | } 42 | 43 | /** Foursquare type of the venue */ 44 | @Inspect({ nullable: false }) 45 | get foursquareType () { 46 | return this.payload.foursquare_type 47 | } 48 | 49 | /** Google Places identifier of the venue */ 50 | @Inspect({ nullable: false }) 51 | get googlePlaceId () { 52 | return this.payload.google_place_id 53 | } 54 | 55 | /** 56 | * Google Places type of the venue. 57 | * (See [supported types](https://developers.google.com/places/web-service/supported_types).) 58 | */ 59 | @Inspect({ nullable: false }) 60 | get googlePlaceType () { 61 | return this.payload.google_place_type 62 | } 63 | 64 | toJSON () { 65 | return this.payload 66 | } 67 | } 68 | 69 | memoizeGetters(Venue, ['location']) 70 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/video-chat-ended.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents a service message about a video chat ended in the chat. */ 8 | @Inspectable() 9 | export class VideoChatEnded implements Structure { 10 | constructor (public payload: Interfaces.TelegramVideoChatEnded) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** Video chat duration; in seconds */ 17 | @Inspect() 18 | get duration () { 19 | return this.payload.duration 20 | } 21 | 22 | toJSON () { 23 | return this.payload 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/video-chat-participants-invited.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | import { User } from './user' 8 | 9 | /** This object represents a service message about new members invited to a video chat. */ 10 | @Inspectable() 11 | export class VideoChatParticipantsInvited implements Structure { 12 | constructor (public payload: Interfaces.TelegramVideoChatParticipantsInvited) { } 13 | 14 | get [Symbol.toStringTag] () { 15 | return this.constructor.name 16 | } 17 | 18 | /** New members that were invited to the video chat */ 19 | @Inspect() 20 | get users () { 21 | return this.payload.users.map(user => new User(user)) 22 | } 23 | 24 | toJSON () { 25 | return this.payload 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/video-chat-scheduled.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** 8 | * This object represents a service message about a video chat scheduled in the chat 9 | */ 10 | @Inspectable() 11 | export class VideoChatScheduled implements Structure { 12 | constructor (public payload: Interfaces.TelegramVideoChatScheduled) { } 13 | 14 | get [Symbol.toStringTag] () { 15 | return this.constructor.name 16 | } 17 | 18 | /** Point in time (Unix timestamp) when the video chat is supposed to be started by a chat administrator */ 19 | @Inspect() 20 | get startDate () { 21 | return this.payload.start_date 22 | } 23 | 24 | toJSON () { 25 | return this.payload 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/video-chat-started.ts: -------------------------------------------------------------------------------- 1 | import { Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** 8 | * This object represents a service message about a video chat started in the chat. 9 | * Currently holds no information. 10 | */ 11 | @Inspectable() 12 | export class VideoChatStarted implements Structure { 13 | constructor (public payload: Interfaces.TelegramVideoChatStarted) { } 14 | 15 | get [Symbol.toStringTag] () { 16 | return this.constructor.name 17 | } 18 | 19 | toJSON () { 20 | return this.payload 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/web-app-data.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** Contains data sent from a Web App to the bot. */ 8 | @Inspectable() 9 | export class WebAppData implements Structure { 10 | constructor (public payload: Interfaces.TelegramWebAppData) { } 11 | 12 | /** The data. Be aware that a bad client can send arbitrary data in this field. */ 13 | @Inspect() 14 | get data () { 15 | return this.payload.data 16 | } 17 | 18 | /** 19 | * Text of the `web_app` keyboard button, from which the Web App was opened. 20 | * Be aware that a bad client can send arbitrary data in this field. 21 | */ 22 | @Inspect() 23 | get buttonText () { 24 | return this.payload.button_text 25 | } 26 | 27 | toJSON () { 28 | return this.payload 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/web-app-info.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** Contains information about a Web App. */ 8 | @Inspectable() 9 | export class WebAppInfo implements Structure { 10 | constructor (public payload: Interfaces.TelegramWebAppInfo) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** An HTTPS URL of a Web App to be opened with additional data as specified in Initializing Web Apps */ 17 | @Inspect() 18 | get url () { 19 | return this.payload.url 20 | } 21 | 22 | toJSON () { 23 | return this.payload 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/puregram/src/common/structures/write-access-allowed.ts: -------------------------------------------------------------------------------- 1 | import { Inspect, Inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../../generated/telegram-interfaces' 4 | 5 | import { Structure } from '../../types/interfaces' 6 | 7 | /** This object represents a service message about a user allowing a bot added to the attachment menu to write messages. Currently holds no information. */ 8 | @Inspectable() 9 | export class WriteAccessAllowed implements Structure { 10 | constructor (public payload: Interfaces.TelegramWriteAccessAllowed) { } 11 | 12 | get [Symbol.toStringTag] () { 13 | return this.constructor.name 14 | } 15 | 16 | /** `true`, if the access was granted after the user accepted an explicit request from a Web App sent by the method requestWriteAccess */ 17 | @Inspect({ nullable: false }) 18 | get fromRequest () { 19 | return this.payload.from_request 20 | } 21 | 22 | /** Name of the Web App which was launched from a link */ 23 | @Inspect({ nullable: false }) 24 | get webAppName () { 25 | return this.payload.web_app_name 26 | } 27 | 28 | /** `true`, if the access was granted when the bot was added to the attachment or side menu */ 29 | @Inspect({ nullable: false }) 30 | get fromAttachmentMenu () { 31 | return this.payload.web_app_name 32 | } 33 | 34 | toJSON () { 35 | return this.payload 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/puregram/src/common/updates-filter.ts: -------------------------------------------------------------------------------- 1 | import { UpdateType } from '../types/enums' 2 | 3 | import { MaybeArray, UpdateName } from '../types/types' 4 | 5 | /** 6 | * This class manages allowed update types for the Telegram Bot API. 7 | * Provides static methods to retrieve all update types or exclude specific types. 8 | * 9 | * This may be useful when you want to tell Telegram Bot API that you're going to handle `chat_member` 10 | * and other events that require to be provided in the `allowed_updates` as well as handling all other 11 | * updates 12 | * 13 | * @example 14 | * ``` 15 | * const telegram = new Telegram({ 16 | * token: process.env.TOKEN, 17 | * allowedUpdates: UpdatesFilter.all() 18 | * }) 19 | * ``` 20 | */ 21 | export class UpdatesFilter { 22 | /** All allowed update types including `chat_member` */ 23 | static all () { 24 | return Object.values(UpdateType) 25 | } 26 | 27 | /** All allowed update types excluding `types` you provided */ 28 | static except (types: MaybeArray) { 29 | const excluded = Array.isArray(types) ? types : [types] 30 | 31 | return UpdatesFilter.all().filter(t => !excluded.includes(t)) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/puregram/src/contexts/chat-boost.ts: -------------------------------------------------------------------------------- 1 | import * as Interfaces from '../generated/telegram-interfaces' 2 | 3 | import { Telegram } from '../telegram' 4 | import { Constructor } from '../types/types' 5 | import { applyMixins } from '../utils/helpers' 6 | import { ChatBoostUpdated } from '../common/structures/chat-boost-updated' 7 | 8 | import { Context } from './context' 9 | import { CloneMixin, SendMixin } from './mixins' 10 | import { inspectable } from 'inspectable' 11 | 12 | interface ChatBoostContextOptions { 13 | telegram: Telegram 14 | update: Interfaces.TelegramUpdate 15 | payload: Interfaces.TelegramChatBoostUpdated 16 | updateId: number 17 | } 18 | 19 | /** This object represents a boost added to a chat or changed. */ 20 | class ChatBoostContext extends Context { 21 | payload: Interfaces.TelegramChatBoostUpdated 22 | 23 | constructor (options: ChatBoostContextOptions) { 24 | super({ 25 | telegram: options.telegram, 26 | updateType: 'chat_boost', 27 | updateId: options.updateId, 28 | update: options.update 29 | }) 30 | 31 | this.payload = options.payload 32 | } 33 | } 34 | 35 | interface ChatBoostContext extends Constructor, ChatBoostUpdated, SendMixin, CloneMixin { } 36 | applyMixins(ChatBoostContext, [ChatBoostUpdated, SendMixin, CloneMixin]) 37 | 38 | export { ChatBoostContext } 39 | 40 | inspectable(ChatBoostContext, { 41 | serialize (context: ChatBoostContext) { 42 | const payload = { 43 | chat: context.chat, 44 | boost: context.boost 45 | } 46 | 47 | return payload 48 | } 49 | }) 50 | -------------------------------------------------------------------------------- /packages/puregram/src/contexts/context.ts: -------------------------------------------------------------------------------- 1 | import { inspectable } from 'inspectable' 2 | 3 | import * as Interfaces from '../generated/telegram-interfaces' 4 | 5 | import { Telegram } from '../telegram' 6 | import { SERVICE_MESSAGE_EVENTS } from '../utils/constants' 7 | 8 | import type { ContextsMapping } from '../types/mappings' 9 | import type { MaybeArray, SoftString, UpdateName } from '../types/types' 10 | 11 | interface ContextOptions { 12 | telegram: Telegram 13 | update?: Interfaces.TelegramUpdate 14 | updateType: UpdateName | 'unknown' 15 | updateId?: number 16 | } 17 | 18 | class Context { 19 | telegram: Telegram 20 | updateId?: number 21 | update?: Interfaces.TelegramUpdate 22 | 23 | protected updateType: UpdateName | 'unknown' 24 | 25 | constructor (options: ContextOptions) { 26 | this.telegram = options.telegram 27 | this.updateType = options.updateType 28 | this.updateId = options.updateId 29 | this.update = options.update 30 | } 31 | 32 | get [Symbol.toStringTag] () { 33 | return this.constructor.name 34 | } 35 | 36 | is (rawTypes: MaybeArray>): this is ContextsMapping[T] { 37 | const types = Array.isArray(rawTypes) 38 | ? rawTypes 39 | : [rawTypes] 40 | 41 | // TODO: it is interfering, make 'subTypes' logic maybe? 42 | if (types.includes('service_message')) { 43 | types.push(...SERVICE_MESSAGE_EVENTS) 44 | } 45 | 46 | return types.includes(this.updateType) 47 | } 48 | } 49 | 50 | inspectable(Context, { 51 | serialize (context) { 52 | return {} 53 | } 54 | }) 55 | 56 | export { Context } 57 | -------------------------------------------------------------------------------- /packages/puregram/src/contexts/index.ts: -------------------------------------------------------------------------------- 1 | export * from './callback-query' 2 | export * from './chat-boost-added' 3 | export * from './chat-boost' 4 | export * from './chat-join-request' 5 | export * from './chat-member' 6 | export * from './chat-shared' 7 | export * from './chosen-inline-result' 8 | export * from './context' 9 | export * from './delete-chat-photo' 10 | export * from './forum-topic-closed' 11 | export * from './forum-topic-created' 12 | export * from './forum-topic-edited' 13 | export * from './forum-topic-reopened' 14 | export * from './general-forum-topic-hidden' 15 | export * from './general-forum-topic-unhidden' 16 | export * from './giveaway-completed' 17 | export * from './giveaway-created' 18 | export * from './giveaway-winners' 19 | export * from './group-chat-created' 20 | export * from './inline-query' 21 | export * from './invoice' 22 | export * from './left-chat-member' 23 | export * from './location' 24 | export * from './message-auto-delete-timer-changed' 25 | export * from './message-reaction-count' 26 | export * from './message-reaction' 27 | export * from './message' 28 | export * from './migrate-from-chat-id' 29 | export * from './migrate-to-chat-id' 30 | export * from './new-chat-members' 31 | export * from './new-chat-photo' 32 | export * from './new-chat-title' 33 | export * from './passport-data' 34 | export * from './pinned-message' 35 | export * from './poll-answer' 36 | export * from './poll' 37 | export * from './pre-checkout-query' 38 | export * from './proximity-alert-triggered' 39 | export * from './removed-chat-boost' 40 | export * from './shipping-query' 41 | export * from './successful-payment' 42 | export * from './users-shared' 43 | export * from './video-chat-ended' 44 | export * from './video-chat-participants-invited' 45 | export * from './video-chat-scheduled' 46 | export * from './video-chat-started' 47 | export * from './web-app-data' 48 | export * from './write-access-allowed' 49 | 50 | export * from './unsupported' 51 | -------------------------------------------------------------------------------- /packages/puregram/src/contexts/message-reaction-count.ts: -------------------------------------------------------------------------------- 1 | import { inspectable } from 'inspectable' 2 | import { MessageReactionCountUpdated } from '../common/structures/message-reaction-count-updated' 3 | import * as Interfaces from '../generated/telegram-interfaces' 4 | 5 | import { Telegram } from '../telegram' 6 | import { Constructor } from '../types/types' 7 | import { applyMixins } from '../utils/helpers' 8 | import { Context } from './context' 9 | import { CloneMixin, NodeMixin, SendMixin } from './mixins' 10 | 11 | interface MessageReactionCountContextOptions { 12 | telegram: Telegram 13 | update: Interfaces.TelegramUpdate 14 | payload: Interfaces.TelegramMessageReactionCountUpdated 15 | updateId: number 16 | } 17 | 18 | /** This object represents reaction changes on a message with anonymous reactions. */ 19 | class MessageReactionCountContext extends Context { 20 | payload: Interfaces.TelegramMessageReactionCountUpdated 21 | 22 | constructor (options: MessageReactionCountContextOptions) { 23 | super({ 24 | telegram: options.telegram, 25 | updateType: 'message_reaction_count', 26 | updateId: options.updateId, 27 | update: options.update 28 | }) 29 | 30 | this.payload = options.payload 31 | } 32 | } 33 | 34 | interface MessageReactionCountContext extends Constructor, MessageReactionCountUpdated, SendMixin, NodeMixin, CloneMixin { } 35 | applyMixins(MessageReactionCountContext, [MessageReactionCountUpdated, SendMixin, NodeMixin, CloneMixin]) 36 | 37 | export { MessageReactionCountContext } 38 | 39 | inspectable(MessageReactionCountContext, { 40 | serialize (context: MessageReactionCountContext) { 41 | const payload = { 42 | id: context.id, 43 | chat: context.chat, 44 | date: context.date, 45 | reactions: context.reactions 46 | } 47 | 48 | return payload 49 | } 50 | }) 51 | -------------------------------------------------------------------------------- /packages/puregram/src/contexts/mixins/chat-invite-control.ts: -------------------------------------------------------------------------------- 1 | import * as Methods from '../../generated/methods' 2 | 3 | import { Optional } from '../../types/types' 4 | 5 | import { Context } from '../context' 6 | 7 | import { TargetMixin } from './target' 8 | 9 | /** This object represents a mixin that works with all `*ChatInviteLink` methods */ 10 | class ChatInviteControlMixin { 11 | /** Generates new primary invite link */ 12 | exportInviteLink (params?: Optional) { 13 | return this.telegram.api.exportChatInviteLink({ 14 | chat_id: this.chatId, 15 | ...params 16 | }) 17 | } 18 | 19 | /** Creates an additional invite link */ 20 | createInviteLink (params?: Optional) { 21 | return this.telegram.api.createChatInviteLink({ 22 | chat_id: this.chatId, 23 | ...params 24 | }) 25 | } 26 | 27 | /** Edits non-primary invite link created by the bot */ 28 | editInviteLink (link: string, params?: Optional) { 29 | return this.telegram.api.editChatInviteLink({ 30 | chat_id: this.chatId, 31 | invite_link: link, 32 | ...params 33 | }) 34 | } 35 | 36 | /** Revokes an invite link generated by a bot */ 37 | revokeInviteLink (link: string, params?: Optional) { 38 | return this.telegram.api.revokeChatInviteLink({ 39 | chat_id: this.chatId, 40 | invite_link: link, 41 | ...params 42 | }) 43 | } 44 | } 45 | 46 | interface ChatInviteControlMixin extends Context, TargetMixin { } 47 | 48 | export { ChatInviteControlMixin } 49 | -------------------------------------------------------------------------------- /packages/puregram/src/contexts/mixins/chat-member-control.ts: -------------------------------------------------------------------------------- 1 | import * as Methods from '../../generated/methods' 2 | import * as Interfaces from '../../generated/telegram-interfaces' 3 | 4 | import { Optional } from '../../types/types' 5 | 6 | import { Context } from '../context' 7 | 8 | import { NodeMixin } from './node' 9 | import { TargetMixin } from './target' 10 | 11 | /** This object represents a mixin that is able to control member's rights */ 12 | class ChatMemberControlMixin { 13 | /** Bans a user (o_O) */ 14 | banMember (params?: Optional) { 15 | return this.telegram.api.banChatMember({ 16 | chat_id: this.chatId, 17 | user_id: this.senderId!, 18 | ...params 19 | }) 20 | } 21 | 22 | /** Unbans a user (O_o) */ 23 | unbanMember (params?: Optional) { 24 | return this.telegram.api.unbanChatMember({ 25 | chat_id: this.chatId, 26 | user_id: this.senderId!, 27 | ...params 28 | }) 29 | } 30 | 31 | /** Restricts a user (O_O) */ 32 | restrictMember (permissions: Interfaces.TelegramChatPermissions, params?: Optional) { 33 | return this.telegram.api.restrictChatMember({ 34 | chat_id: this.chatId, 35 | permissions, 36 | user_id: this.senderId!, 37 | ...params 38 | }) 39 | } 40 | 41 | /** Promotes/demotes a user (o_o) */ 42 | promoteMember (params?: Optional) { 43 | return this.telegram.api.promoteChatMember({ 44 | chat_id: this.chatId, 45 | user_id: this.senderId!, 46 | ...params 47 | }) 48 | } 49 | } 50 | 51 | interface ChatMemberControlMixin extends Context, TargetMixin, NodeMixin { } 52 | 53 | export { ChatMemberControlMixin } 54 | -------------------------------------------------------------------------------- /packages/puregram/src/contexts/mixins/chat-sender-control.ts: -------------------------------------------------------------------------------- 1 | import * as Methods from '../../generated/methods' 2 | import { Optional } from '../../types/types' 3 | 4 | import { Context } from '../context' 5 | 6 | import { TargetMixin } from './target' 7 | 8 | /** This object is a mixin that does all the chat-sender stuff, right? */ 9 | class ChatSenderControlMixin { 10 | /** Bans a channel chat */ 11 | banChatSender (senderChatId: number, params?: Optional) { 12 | return this.telegram.api.banChatSenderChat({ 13 | chat_id: this.chatId, 14 | sender_chat_id: senderChatId, 15 | ...params 16 | }) 17 | } 18 | 19 | /** Unbans a channel chat */ 20 | unbanChatSender (senderChatId: number, params?: Optional) { 21 | return this.telegram.api.unbanChatSenderChat({ 22 | chat_id: this.chatId, 23 | sender_chat_id: senderChatId, 24 | ...params 25 | }) 26 | } 27 | } 28 | 29 | interface ChatSenderControlMixin extends Context, TargetMixin { } 30 | 31 | export { ChatSenderControlMixin } 32 | -------------------------------------------------------------------------------- /packages/puregram/src/contexts/mixins/clone.ts: -------------------------------------------------------------------------------- 1 | import { TelegramUpdate } from '../../generated' 2 | import { Constructor } from '../../types/types' 3 | 4 | import { Context } from '../context' 5 | 6 | interface CloneMixinMetadata

{ 7 | payload: P 8 | } 9 | 10 | /** This object represents a mixin which has `clone(options?)` method */ 11 | class CloneMixin, Options extends Record> { 12 | clone (options?: Options) { 13 | return new (this.constructor as C)({ 14 | telegram: this.telegram, 15 | payload: this.payload, 16 | updateId: this.updateId as number, 17 | update: this.update as TelegramUpdate, 18 | type: this.updateType, 19 | ...options 20 | }) 21 | } 22 | } 23 | 24 | interface CloneMixin extends Context, CloneMixinMetadata { } 25 | 26 | export { CloneMixin } 27 | -------------------------------------------------------------------------------- /packages/puregram/src/contexts/mixins/download.ts: -------------------------------------------------------------------------------- 1 | import { Attachment, MediaInputTo, MediaSourceTo, MediaSourceToBuffer, MediaSourceToPath, MediaSourceToStream } from '../../common' 2 | 3 | import { Context } from '../context' 4 | 5 | interface DownloadMixinMetadata { 6 | get attachment(): Attachment | undefined 7 | } 8 | 9 | /** This object represents a mixin that can be used to download media files */ 10 | class DownloadMixin { 11 | /** Downloads attachment */ 12 | download(to?: MediaSourceToBuffer): Promise 13 | download(to: MediaSourceToPath): Promise 14 | download(to: MediaSourceToStream): Promise 15 | 16 | download (to: MediaInputTo = MediaSourceTo.buffer()) { 17 | if (this.attachment === undefined) { 18 | return Promise.resolve(null) 19 | } 20 | 21 | return this.telegram.downloadFile(this.attachment, to) 22 | } 23 | } 24 | 25 | interface DownloadMixin extends Context, DownloadMixinMetadata { } 26 | 27 | export { DownloadMixin } 28 | -------------------------------------------------------------------------------- /packages/puregram/src/contexts/mixins/index.ts: -------------------------------------------------------------------------------- 1 | export * from './chat-control' 2 | export * from './chat-invite-control' 3 | export * from './chat-member-control' 4 | export * from './chat-sender-control' 5 | 6 | export * from './forum' 7 | export * from './pins' 8 | export * from './chat-action' 9 | 10 | export * from './clone' 11 | export * from './node' 12 | export * from './send' 13 | export * from './target' 14 | export * from './download' 15 | -------------------------------------------------------------------------------- /packages/puregram/src/contexts/mixins/pins.ts: -------------------------------------------------------------------------------- 1 | import * as Methods from '../../generated/methods' 2 | 3 | import { Optional } from '../../types/types' 4 | 5 | import { Context } from '../context' 6 | import { NodeMixin } from './node' 7 | import { TargetMixin } from './target' 8 | 9 | /** This object represents a mixin that ensures you have methods to pin/unpin messages in the chat */ 10 | class PinsMixin { 11 | /** Adds message to the list of pinned messages */ 12 | pinChatMessage (params?: Optional) { 13 | return this.telegram.api.pinChatMessage({ 14 | chat_id: this.chatId, 15 | message_id: this.id, 16 | ...params 17 | }) 18 | } 19 | 20 | /** Removes message from the list of pinned messages */ 21 | unpinChatMessage (params?: Optional) { 22 | return this.telegram.api.unpinChatMessage({ 23 | chat_id: this.chatId, 24 | message_id: this.id, 25 | ...params 26 | }) 27 | } 28 | 29 | /** Clears the list of pinned messages */ 30 | unpinAllChatMessages (params?: Optional) { 31 | return this.telegram.api.unpinAllChatMessages({ 32 | chat_id: this.chatId, 33 | ...params 34 | }) 35 | } 36 | } 37 | 38 | interface PinsMixin extends Context, TargetMixin, NodeMixin { } 39 | 40 | export { PinsMixin } 41 | -------------------------------------------------------------------------------- /packages/puregram/src/contexts/removed-chat-boost.ts: -------------------------------------------------------------------------------- 1 | import { inspectable } from 'inspectable' 2 | import { ChatBoostRemoved } from '../common/structures/chat-boost-removed' 3 | import * as Interfaces from '../generated/telegram-interfaces' 4 | 5 | import { Telegram } from '../telegram' 6 | import { Constructor } from '../types/types' 7 | import { applyMixins } from '../utils/helpers' 8 | 9 | import { Context } from './context' 10 | import { CloneMixin, SendMixin } from './mixins' 11 | 12 | interface RemovedChatBoostContextOptions { 13 | telegram: Telegram 14 | update: Interfaces.TelegramUpdate 15 | payload: Interfaces.TelegramChatBoostRemoved 16 | updateId: number 17 | } 18 | 19 | /** This object represents a boost removed from a chat. */ 20 | class RemovedChatBoostContext extends Context { 21 | payload: Interfaces.TelegramChatBoostRemoved 22 | 23 | constructor (options: RemovedChatBoostContextOptions) { 24 | super({ 25 | telegram: options.telegram, 26 | updateType: 'removed_chat_boost', 27 | updateId: options.updateId, 28 | update: options.update 29 | }) 30 | 31 | this.payload = options.payload 32 | } 33 | } 34 | 35 | interface RemovedChatBoostContext extends Constructor, ChatBoostRemoved, SendMixin, CloneMixin { } 36 | applyMixins(RemovedChatBoostContext, [ChatBoostRemoved, SendMixin, CloneMixin]) 37 | 38 | export { RemovedChatBoostContext } 39 | 40 | inspectable(RemovedChatBoostContext, { 41 | serialize (context: RemovedChatBoostContext) { 42 | const payload = { 43 | id: context.id, 44 | chat: context.chat, 45 | removeDate: context.removeDate, 46 | source: context.source 47 | } 48 | 49 | return payload 50 | } 51 | }) 52 | -------------------------------------------------------------------------------- /packages/puregram/src/contexts/unsupported.ts: -------------------------------------------------------------------------------- 1 | import * as Interfaces from '../generated/telegram-interfaces' 2 | 3 | import { Telegram } from '../telegram' 4 | import { Constructor, UpdateName } from '../types/types' 5 | import { Context } from './context' 6 | 7 | interface UnsupportedContextOptions { 8 | telegram: Telegram 9 | type: UpdateName 10 | update: Interfaces.TelegramUpdate 11 | payload: Record 12 | updateId: number 13 | } 14 | 15 | /** This class represents an unsupported context. Yeah, a context that puregram has no idea how to resolve for now. Cool. */ 16 | class UnsupportedContext extends Context { 17 | payload: Record 18 | 19 | constructor (options: UnsupportedContextOptions) { 20 | super({ 21 | telegram: options.telegram, 22 | updateType: options.type, 23 | updateId: options.updateId, 24 | update: options.update 25 | }) 26 | 27 | this.payload = options.payload 28 | } 29 | } 30 | 31 | interface UnsupportedContext extends Constructor { } 32 | 33 | export { UnsupportedContext } 34 | -------------------------------------------------------------------------------- /packages/puregram/src/errors/api.ts: -------------------------------------------------------------------------------- 1 | import { TelegramError } from './telegram' 2 | 3 | import type { ApiResponseError } from '../types/interfaces' 4 | 5 | export class APIError extends TelegramError { 6 | parameters: ApiResponseError['parameters'] 7 | 8 | constructor (params: ApiResponseError) { 9 | super({ 10 | error_code: params.error_code, 11 | description: params.description 12 | }) 13 | 14 | if (params.parameters) { 15 | this.parameters = params.parameters 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/puregram/src/errors/index.ts: -------------------------------------------------------------------------------- 1 | export * from './api' 2 | export * from './telegram' 3 | -------------------------------------------------------------------------------- /packages/puregram/src/errors/telegram.ts: -------------------------------------------------------------------------------- 1 | export interface ErrorOptions { 2 | error_code: number 3 | description: string 4 | cause?: unknown 5 | } 6 | 7 | export class TelegramError extends Error { 8 | /** Error code */ 9 | code: number 10 | /** Error stack */ 11 | stack!: string 12 | /** Error cause */ 13 | cause?: unknown 14 | 15 | constructor ({ error_code, description, cause }: ErrorOptions) { 16 | super(description) 17 | 18 | this.code = error_code 19 | this.name = this.constructor.name 20 | this.cause = cause 21 | 22 | Error.captureStackTrace(this, this.constructor) 23 | } 24 | 25 | get [Symbol.toStringTag] () { 26 | return this.constructor.name 27 | } 28 | 29 | toJSON (): Pick { 30 | const json = {} as Pick 31 | 32 | for (const key of Object.getOwnPropertyNames(this)) { 33 | json[key as keyof this] = this[key as keyof this] 34 | } 35 | 36 | return json 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/puregram/src/generated/index.ts: -------------------------------------------------------------------------------- 1 | export * from './api-methods' 2 | export * from './methods' 3 | export * from './telegram-interfaces' 4 | -------------------------------------------------------------------------------- /packages/puregram/src/index.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata' 2 | 3 | export { Middleware, NextMiddleware } from 'middleware-io' 4 | 5 | export * from './telegram' 6 | export * from './contexts' 7 | export * from './errors' 8 | export * from './common' 9 | 10 | export * from './types/enums' 11 | export * from './types/hooks' 12 | -------------------------------------------------------------------------------- /packages/puregram/src/types/hooks.ts: -------------------------------------------------------------------------------- 1 | import type { RequestInit, Response } from 'undici' 2 | 3 | import type { ApiResponseUnion } from './interfaces' 4 | import type { MaybePromise } from './types' 5 | 6 | export type RequestContext = (context: T) => MaybePromise 7 | 8 | export interface BaseContext { 9 | controller: AbortController 10 | init: RequestInit 11 | } 12 | 13 | export interface BeforeRequestContext extends BaseContext { 14 | path: string 15 | params: Record 16 | } 17 | 18 | export type OnBeforeRequestHandler = RequestContext 19 | 20 | export interface RequestInterceptHandler extends BeforeRequestContext { 21 | query: string 22 | url: string 23 | } 24 | 25 | export type OnRequestInterceptHandler = RequestContext 26 | 27 | export interface ResponseInterceptHandler extends RequestInterceptHandler { 28 | response: Response 29 | json: ApiResponseUnion 30 | } 31 | 32 | export type OnResponseInterceptHandler = RequestContext 33 | 34 | export interface AfterRequestHandler extends ResponseInterceptHandler {} 35 | 36 | export type OnAfterRequestHandler = RequestContext 37 | 38 | export interface ErrorHandler { 39 | error: Error 40 | } 41 | 42 | export type OnErrorHandler = RequestContext 43 | 44 | export interface Hooks { 45 | onBeforeRequest: OnBeforeRequestHandler[] 46 | onRequestIntercept: OnRequestInterceptHandler[] 47 | onResponseIntercept: OnResponseInterceptHandler[] 48 | onAfterRequest: OnAfterRequestHandler[] 49 | onError: OnErrorHandler[] 50 | } 51 | 52 | type Extract = T extends Array ? R : never 53 | 54 | export type HookHandler = Extract 55 | export type HookContext = BeforeRequestContext | RequestInterceptHandler | ResponseInterceptHandler | AfterRequestHandler | ErrorHandler 56 | -------------------------------------------------------------------------------- /packages/puregram/src/types/send-media.ts: -------------------------------------------------------------------------------- 1 | import * as Methods from '../generated/methods' 2 | 3 | import { Optional } from './types' 4 | 5 | type id = { type: T } & Optional 6 | 7 | export type tSendAnimation = id<'animation', Methods.SendAnimationParams> 8 | export type tSendAudio = id<'audio', Methods.SendAudioParams> 9 | export type tSendDocument = id<'document', Methods.SendDocumentParams> 10 | export type tSendPhoto = id<'photo', Methods.SendPhotoParams> 11 | export type tSendSticker = id<'sticker', Methods.SendStickerParams> 12 | export type tSendVideo = id<'video', Methods.SendVideoParams> 13 | export type tSendVideoNote = id<'video_note', Methods.SendVideoNoteParams> 14 | export type tSendVoice = id<'voice', Methods.SendVoiceParams> 15 | 16 | export type tSendMethods = 17 | | tSendAnimation 18 | | tSendAudio 19 | | tSendDocument 20 | | tSendPhoto 21 | | tSendSticker 22 | | tSendVideo 23 | | tSendVideoNote 24 | | tSendVoice 25 | -------------------------------------------------------------------------------- /packages/puregram/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2019", 4 | "experimentalDecorators": true, 5 | "module": "commonjs", 6 | "declaration": true, 7 | "outDir": "./lib", 8 | "rootDir": "./src", 9 | "pretty": true, 10 | 11 | "strict": true, 12 | "noImplicitAny": true, 13 | "strictNullChecks": true, 14 | "strictFunctionTypes": true, 15 | "strictBindCallApply": true, 16 | "strictPropertyInitialization": true, 17 | "noImplicitThis": true, 18 | "alwaysStrict": true, 19 | 20 | "esModuleInterop": true, 21 | "importHelpers": true, 22 | 23 | "skipLibCheck": true, 24 | "forceConsistentCasingInFileNames": true 25 | }, 26 | 27 | "include": ["./src"] 28 | } 29 | -------------------------------------------------------------------------------- /packages/scenes/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@puregram/scenes", 3 | "version": "2.0.1", 4 | "description": "Simple implementation of middleware-based scene management for puregram", 5 | "main": "lib/index", 6 | "engines": { 7 | "node": ">=12.0.0" 8 | }, 9 | "scripts": { 10 | "build": "tsc --project tsconfig.json" 11 | }, 12 | "keywords": [ 13 | "puregram", 14 | "telegram", 15 | "scenes" 16 | ], 17 | "files": [ 18 | "lib" 19 | ], 20 | "author": "nitrojs", 21 | "license": "MIT", 22 | "dependencies": { 23 | "@puregram/session": "^2.0.1-rc.1" 24 | }, 25 | "peerDependencies": { 26 | "puregram": "^2.0.0" 27 | }, 28 | "types": "./lib/index.d.ts", 29 | "directories": { 30 | "lib": "lib" 31 | }, 32 | "repository": { 33 | "type": "git", 34 | "url": "https://github.com/nitreojs/puregram/tree/lord/packages/scenes" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/scenes/src/cache-repository.ts: -------------------------------------------------------------------------------- 1 | type CacheRepositorySortingValues = (a: Value, b: Value) => number 2 | 3 | export class CacheRepository { 4 | private readonly collection: Map = new Map() 5 | 6 | keys: Key[] = [] 7 | values: Value[] = [] 8 | 9 | protected sortingValues?: CacheRepositorySortingValues 10 | 11 | constructor ({ sortingValues }: { 12 | sortingValues?: CacheRepositorySortingValues 13 | } = {}) { 14 | this.sortingValues = sortingValues 15 | } 16 | 17 | /** Checks has value by key */ 18 | has (key: Key) { 19 | return this.collection.has(key) 20 | } 21 | 22 | /** Sets value by key */ 23 | set (key: Key, value: Value) { 24 | this.collection.set(key, value) 25 | 26 | this.keys = [...this.collection.keys()] 27 | this.values = [...this.collection.values()] 28 | 29 | if (this.sortingValues) { 30 | this.values.sort(this.sortingValues) 31 | } 32 | } 33 | 34 | /** Returns value by key */ 35 | get (key: Key): Value | undefined { 36 | return this.collection.get(key) 37 | } 38 | 39 | /** Sets value by key else error if exits */ 40 | strictSet (key: Key, value: Value) { 41 | if (this.collection.has(key)) { 42 | throw new Error(`value by ${key} already exists`) 43 | } 44 | 45 | return this.set(key, value) 46 | } 47 | 48 | /** Returns value by key else error */ 49 | strictGet (key: Key): Value { 50 | const value = this.get(key) 51 | 52 | if (!value) { 53 | throw new Error(`value by ${key} not found`) 54 | } 55 | 56 | return value 57 | } 58 | 59 | /** Returns iterator */ 60 | [Symbol.iterator] (): IterableIterator<[Key, Value]> { 61 | return this.collection[Symbol.iterator]() 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /packages/scenes/src/contexts/index.ts: -------------------------------------------------------------------------------- 1 | export * from './step.types' 2 | export * from './scene.types' 3 | 4 | export { SceneContext } from './scene' 5 | export { StepSceneContext } from './step' 6 | -------------------------------------------------------------------------------- /packages/scenes/src/contexts/scene.types.ts: -------------------------------------------------------------------------------- 1 | import { ContextInterface } from '../types' 2 | import { SceneRepository } from '../scene-manager.types' 3 | 4 | export interface SceneContextOptions { 5 | context: ContextInterface 6 | 7 | repository: SceneRepository 8 | } 9 | 10 | export interface SceneContextEnterOptions = Record> { 11 | /** Logging into a handler without executing it */ 12 | silent?: boolean 13 | 14 | /** The standard state for the scene */ 15 | state?: S 16 | } 17 | 18 | export interface SceneContextLeaveOptions { 19 | /** Logging into a handler without executing it */ 20 | silent?: boolean 21 | 22 | /** Cancelled scene */ 23 | cancelled?: boolean 24 | } 25 | 26 | export enum LastAction { 27 | None = 'none', 28 | Enter = 'enter', 29 | Leave = 'leave' 30 | } 31 | -------------------------------------------------------------------------------- /packages/scenes/src/contexts/step.types.ts: -------------------------------------------------------------------------------- 1 | import { 2 | StepContext, 3 | StepSceneHandler 4 | } from '../scenes' 5 | 6 | export interface StepContextOptions = Record> { 7 | context: StepContext 8 | 9 | steps: StepSceneHandler[] 10 | } 11 | 12 | export interface StepContextGoOptions { 13 | /** Logging into a handler without executing it */ 14 | silent?: boolean 15 | } 16 | -------------------------------------------------------------------------------- /packages/scenes/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './scenes/index' 2 | export * from './contexts/index' 3 | 4 | export * from './types' 5 | export * from './scene-manager.types' 6 | 7 | export { SceneManager } from './scene-manager' 8 | -------------------------------------------------------------------------------- /packages/scenes/src/scene-manager.ts: -------------------------------------------------------------------------------- 1 | import { SceneInterface } from './scenes' 2 | 3 | import { ContextInterface, Middleware } from './types' 4 | import { SceneContext } from './contexts' 5 | import { CacheRepository } from './cache-repository' 6 | import { SceneRepository, SceneManagerOptions } from './scene-manager.types' 7 | 8 | export class SceneManager { 9 | private repository: SceneRepository = new CacheRepository() 10 | 11 | constructor (rawOptions: SceneManagerOptions | SceneInterface[] = {}) { 12 | const options = Array.isArray(rawOptions) 13 | ? { scenes: rawOptions } 14 | : rawOptions 15 | 16 | if (options.scenes) { 17 | this.addScenes(options.scenes) 18 | } 19 | } 20 | 21 | /** Checks for has a scene */ 22 | hasScene (slug: string) { 23 | return this.repository.has(slug) 24 | } 25 | 26 | /** Adds scenes to the repository */ 27 | addScenes (scenes: SceneInterface[]) { 28 | for (const scene of scenes) { 29 | this.repository.set(scene.slug, scene) 30 | } 31 | 32 | return this 33 | } 34 | 35 | /** Returns the middleware for embedding */ 36 | get middleware (): Middleware { 37 | return (context: ContextInterface, next: Function) => { 38 | context.scene = new SceneContext({ 39 | context, 40 | repository: this.repository 41 | }) 42 | 43 | return next() 44 | } 45 | } 46 | 47 | /** Returns the middleware for intercept */ 48 | get middlewareIntercept (): Middleware { 49 | return (context: ContextInterface, next: Function) => { 50 | if (!context.scene.current) { 51 | return next() 52 | } 53 | 54 | return context.scene.reenter() 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/scenes/src/scene-manager.types.ts: -------------------------------------------------------------------------------- 1 | import { SceneInterface } from './scenes' 2 | import { CacheRepository } from './cache-repository' 3 | 4 | export type SceneRepository = CacheRepository 5 | 6 | export interface SceneManagerOptions { 7 | /** Scenes on the interface SceneInterface */ 8 | scenes?: SceneInterface[] 9 | } 10 | -------------------------------------------------------------------------------- /packages/scenes/src/scenes/index.ts: -------------------------------------------------------------------------------- 1 | export * from './step.types' 2 | 3 | export { SceneInterface } from './scene' 4 | export { StepScene } from './step' 5 | -------------------------------------------------------------------------------- /packages/scenes/src/scenes/scene.ts: -------------------------------------------------------------------------------- 1 | import { ContextInterface } from '../types' 2 | 3 | export interface SceneInterface { 4 | /** The unique name of the scene */ 5 | slug: string 6 | 7 | /** Enter handler for the scene */ 8 | enterHandler(context: ContextInterface): unknown 9 | 10 | /** Leave handler for the scene */ 11 | leaveHandler(context: ContextInterface): unknown 12 | } 13 | -------------------------------------------------------------------------------- /packages/scenes/src/scenes/step.ts: -------------------------------------------------------------------------------- 1 | import { MessageContext } from 'puregram' 2 | 3 | import { SceneInterface } from './scene' 4 | 5 | import { StepSceneContext, LastAction } from '../contexts' 6 | 7 | import { 8 | StepSceneHandler, 9 | StepContext, 10 | StepSceneOptions 11 | } from './step.types' 12 | 13 | export class StepScene implements SceneInterface { 14 | slug: string 15 | 16 | private readonly steps: StepSceneHandler[] 17 | private readonly onEnterHandler: NonNullable['enterHandler']> 18 | private readonly onLeaveHandler: NonNullable['leaveHandler']> 19 | 20 | constructor (slug: string, rawOptions: StepSceneOptions | StepSceneHandler[]) { 21 | const options = Array.isArray(rawOptions) 22 | ? { steps: rawOptions } 23 | : rawOptions 24 | 25 | this.slug = slug 26 | this.steps = options.steps 27 | this.onEnterHandler = options.enterHandler || (() => { }) 28 | this.onLeaveHandler = options.leaveHandler || (() => { }) 29 | } 30 | 31 | async enterHandler (context: StepContext & T) { 32 | context.scene.step = new StepSceneContext({ 33 | context, 34 | // @ts-expect-error T does not extend {} :shrug: 35 | steps: this.steps 36 | }) 37 | 38 | await this.onEnterHandler(context) 39 | 40 | if (context.scene.lastAction !== LastAction.Leave) { 41 | await context.scene.step.reenter() 42 | } 43 | } 44 | 45 | leaveHandler (context: StepContext & T) { 46 | return Promise.resolve(this.onLeaveHandler(context)) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/scenes/src/scenes/step.types.ts: -------------------------------------------------------------------------------- 1 | import { ContextInterface } from '../types' 2 | 3 | import { 4 | SceneContext, 5 | StepSceneContext 6 | } from '../contexts' 7 | 8 | export interface StepContext = {}> extends ContextInterface { 9 | scene: SceneContext & { 10 | /** Stepping scene control context */ 11 | step: StepSceneContext 12 | } 13 | } 14 | 15 | export type StepSceneHandler = Record> = (context: StepContext & T) => unknown 16 | 17 | export interface StepSceneOptions { 18 | steps: StepSceneHandler[] 19 | 20 | enterHandler?: StepSceneHandler 21 | 22 | leaveHandler?: StepSceneHandler 23 | } 24 | -------------------------------------------------------------------------------- /packages/scenes/src/types.ts: -------------------------------------------------------------------------------- 1 | import { Context } from 'puregram' 2 | 3 | import { SceneContext } from './contexts' 4 | 5 | export type Middleware = (context: T, next: Function) => unknown 6 | 7 | export interface SessionContext { 8 | [key: string]: any 9 | } 10 | 11 | export interface ContextInterface extends Context { 12 | scene: SceneContext & T 13 | 14 | [key: string]: any 15 | } 16 | -------------------------------------------------------------------------------- /packages/scenes/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2019", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "outDir": "lib", 7 | "pretty": true, 8 | 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "strictNullChecks": true, 12 | "strictFunctionTypes": true, 13 | "strictBindCallApply": true, 14 | "strictPropertyInitialization": true, 15 | "noImplicitThis": true, 16 | "alwaysStrict": true, 17 | 18 | "esModuleInterop": true, 19 | 20 | "skipLibCheck": true, 21 | "forceConsistentCasingInFileNames": true 22 | }, 23 | 24 | "include": ["./src"] 25 | } 26 | -------------------------------------------------------------------------------- /packages/session/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@puregram/session", 3 | "version": "3.2.4", 4 | "description": "puregram sessions available to everyone!", 5 | "main": "lib/index", 6 | "engines": { 7 | "node": ">=18.18.0" 8 | }, 9 | "scripts": { 10 | "build": "tsc --project tsconfig.json" 11 | }, 12 | "keywords": [ 13 | "puregram", 14 | "telegram", 15 | "session" 16 | ], 17 | "files": [ 18 | "lib" 19 | ], 20 | "author": "starkow", 21 | "license": "WTFPL", 22 | "peerDependencies": { 23 | "puregram": "^2.25.0" 24 | }, 25 | "types": "./lib/index.d.ts", 26 | "directories": { 27 | "lib": "lib" 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/nitreojs/puregram/tree/lord/packages/session" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/session/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './storages' 2 | export * from './types' 3 | 4 | export { session, ttl } from './session' 5 | -------------------------------------------------------------------------------- /packages/session/src/storages/index.ts: -------------------------------------------------------------------------------- 1 | export { SessionStorage } from './storage' 2 | 3 | export { 4 | MemoryStorage, 5 | MemoryStorageOptions, 6 | MemoryStoreLike 7 | } from './memory' 8 | -------------------------------------------------------------------------------- /packages/session/src/storages/memory.ts: -------------------------------------------------------------------------------- 1 | import { SessionStorage } from './storage' 2 | 3 | export interface MemoryStoreLike { 4 | get(key: K): V | undefined 5 | set(key: K, value: V): this | undefined 6 | has(key: K): boolean 7 | delete(key: K): boolean 8 | } 9 | 10 | export interface MemoryStorageOptions { 11 | store: MemoryStoreLike 12 | } 13 | 14 | export class MemoryStorage implements SessionStorage { 15 | private store: MemoryStorageOptions['store'] 16 | 17 | constructor ({ store = new Map() }: Partial = {}) { 18 | this.store = store 19 | } 20 | 21 | async get (key: string) { 22 | return this.store.get(key) 23 | } 24 | 25 | async set (key: string, value: any) { 26 | this.store.set(key, value) 27 | 28 | return true 29 | } 30 | 31 | async has (key: string) { 32 | return this.store.has(key) 33 | } 34 | 35 | async delete (key: string) { 36 | return this.store.delete(key) 37 | } 38 | 39 | async touch () { } 40 | } 41 | -------------------------------------------------------------------------------- /packages/session/src/storages/storage.ts: -------------------------------------------------------------------------------- 1 | export interface SessionStorage { 2 | get(key: string): Promise 3 | set(key: string, value: any): Promise 4 | has(key: string): Promise 5 | delete(key: string): Promise 6 | touch(key: string): Promise 7 | } 8 | -------------------------------------------------------------------------------- /packages/session/src/types.ts: -------------------------------------------------------------------------------- 1 | import { Context } from 'puregram' 2 | 3 | export type Middleware = (context: T, next: Function) => unknown 4 | 5 | export interface ContextInterface extends Context { 6 | [key: string]: any 7 | } 8 | 9 | export type SessionContext = S & { 10 | $forceUpdate(): Promise 11 | 12 | [key: string]: any 13 | } 14 | 15 | export interface SessionLayer { 16 | session: SessionContext 17 | } 18 | 19 | // extending contexts! :3 :3333 >_< 20 | declare module 'puregram' { 21 | interface Context { 22 | session: SessionContext 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/session/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2019", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "outDir": "lib", 7 | "pretty": true, 8 | 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "strictNullChecks": true, 12 | "strictFunctionTypes": true, 13 | "strictBindCallApply": true, 14 | "strictPropertyInitialization": true, 15 | "noImplicitThis": true, 16 | "alwaysStrict": true, 17 | 18 | "esModuleInterop": true, 19 | 20 | "skipLibCheck": true, 21 | "forceConsistentCasingInFileNames": true 22 | }, 23 | 24 | "include": ["./src"] 25 | } 26 | -------------------------------------------------------------------------------- /packages/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@puregram/utils", 3 | "version": "1.0.1", 4 | "description": "Package, containing some useful utilities for puregram", 5 | "main": "lib/index", 6 | "engines": { 7 | "node": ">=12.0.0" 8 | }, 9 | "scripts": { 10 | "build": "tsc --project tsconfig.json" 11 | }, 12 | "keywords": [ 13 | "puregram", 14 | "telegram", 15 | "utils" 16 | ], 17 | "files": [ 18 | "lib" 19 | ], 20 | "author": "nitrojs", 21 | "license": "MIT", 22 | "peerDependencies": { 23 | "puregram": "^2.0.0" 24 | }, 25 | "types": "./lib/index.d.ts", 26 | "directories": { 27 | "lib": "lib" 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/nitreojs/puregram/tree/lord/packages/utils" 32 | } 33 | } -------------------------------------------------------------------------------- /packages/utils/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './utils' 2 | -------------------------------------------------------------------------------- /packages/utils/src/utils/get-casino-values.ts: -------------------------------------------------------------------------------- 1 | enum CasinoValue { 2 | Bar = 'bar', 3 | Grapes = 'grapes', 4 | Lemon = 'lemon', 5 | Seven = 'seven' 6 | } 7 | 8 | type SlotMachineValue = [CasinoValue, CasinoValue, CasinoValue] 9 | 10 | const casinoValues = [ 11 | CasinoValue.Bar, 12 | CasinoValue.Grapes, 13 | CasinoValue.Lemon, 14 | CasinoValue.Seven 15 | ] 16 | 17 | /** Converts base-10 number to base-4 */ 18 | const toBase4 = (number: number) => { 19 | let result: number[] = [] 20 | 21 | while (number > 0) { 22 | result.push(number % 4) 23 | 24 | number = Math.floor(number / 4) 25 | } 26 | 27 | result = result.reverse() 28 | 29 | return Number.parseInt(result.join('')) - 1 30 | } 31 | 32 | /** Returns slot machine's values */ 33 | export const getCasinoValues = (source: number | string) => { 34 | const rawNumber = toBase4( 35 | typeof source === 'string' 36 | ? Number.parseInt(source) 37 | : source 38 | ) 39 | 40 | const number = String(rawNumber).padStart(3, '0') 41 | let result = [] 42 | 43 | for (const char of number) { 44 | let int = Number.parseInt(char) 45 | 46 | if (int > 3) { 47 | int = 3 48 | } 49 | 50 | result.push(casinoValues[int % 4]) 51 | } 52 | 53 | result = result.reverse() as SlotMachineValue 54 | 55 | return result 56 | } 57 | -------------------------------------------------------------------------------- /packages/utils/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './get-casino-values' 2 | export * from './web-app' 3 | -------------------------------------------------------------------------------- /packages/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2019", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "outDir": "lib", 7 | "pretty": true, 8 | 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "strictNullChecks": true, 12 | "strictFunctionTypes": true, 13 | "strictBindCallApply": true, 14 | "strictPropertyInitialization": true, 15 | "noImplicitThis": true, 16 | "alwaysStrict": true, 17 | 18 | "esModuleInterop": true, 19 | 20 | "skipLibCheck": true, 21 | "forceConsistentCasingInFileNames": true 22 | }, 23 | 24 | "include": ["./src"] 25 | } 26 | -------------------------------------------------------------------------------- /scripts/generate-common-structures/constants.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path' 2 | 3 | export const PUREGRAM_SRC_PATH = path.resolve(__dirname, '..', '..', 'packages', 'puregram', 'src') 4 | export const PUREGRAM_STRUCTURES_PATH = path.resolve(PUREGRAM_SRC_PATH, 'common', 'structures') 5 | export const PUREGRAM_GENERATED_INTERFACES_PATH = path.resolve(PUREGRAM_SRC_PATH, 'generated', 'telegram-interfaces.ts') 6 | 7 | export const IGNORED_TYPES = ['InputFile', 'PossibleParseMode', 'ReplyMarkupUnion', 'Currency'] 8 | -------------------------------------------------------------------------------- /scripts/generate-common-structures/field.ts: -------------------------------------------------------------------------------- 1 | import ts from 'typescript' 2 | 3 | import { getText } from './utils' 4 | 5 | import { Type } from './type' 6 | 7 | export class Field { 8 | constructor (public signature: ts.PropertySignature) {} 9 | 10 | get name () { 11 | return getText(this.signature.name) 12 | } 13 | 14 | get type () { 15 | return new Type(this.signature.type!) 16 | } 17 | 18 | isOptional () { 19 | return this.signature.questionToken !== undefined 20 | } 21 | 22 | hasComment () { 23 | return this.comment !== '' 24 | } 25 | 26 | get comment () { 27 | // @ts-expect-error where the fuck are `jsDoc`s located at?! 28 | let comment: string = this.signature.jsDoc.map(d => d.comment).join('\n') 29 | 30 | if (this.isOptional() || comment.startsWith('*Optional*')) { 31 | comment = comment.slice('*Optional*. '.length) 32 | } 33 | 34 | return comment 35 | } 36 | 37 | hasVerb () { 38 | return /^(?:can|has|is)/.test(this.name) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /scripts/generate-common-structures/index.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs/promises' 2 | import path from 'node:path' 3 | 4 | import ts from 'typescript' 5 | 6 | import { Visitor } from './visitor' 7 | import { Variables } from './variables' 8 | 9 | import { PUREGRAM_GENERATED_INTERFACES_PATH } from './constants' 10 | import { CodeGenerator } from './code-generator' 11 | 12 | const getFile = async (srcPath: string) => { 13 | const abspath = path.resolve(__dirname, '..', '..', 'packages', 'puregram', 'src', srcPath) 14 | const contents = await fs.readFile(abspath, 'utf-8') 15 | 16 | return contents 17 | } 18 | 19 | const main = async () => { 20 | const pathParts = PUREGRAM_GENERATED_INTERFACES_PATH.split('/') 21 | const filename = pathParts[pathParts.length - 1] 22 | 23 | const contents = await getFile(PUREGRAM_GENERATED_INTERFACES_PATH) 24 | 25 | const file = ts.createSourceFile(filename, contents, ts.ScriptTarget.ES2019) 26 | const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }) 27 | 28 | ts.forEachChild(file, Visitor.visit) 29 | 30 | const printNode = (node: ts.Node) => console.log(printer.printNode(ts.EmitHint.Unspecified, node, file)) 31 | const print = (nodes: ts.Node | ts.Node[]) => Array.isArray(nodes) ? nodes.forEach(printNode) : printNode(nodes) 32 | 33 | // console.log(Variables.interfaces.length) 34 | 35 | const klass = Variables.interfaces[4] 36 | 37 | print(CodeGenerator.class(klass)) 38 | } 39 | 40 | main().catch(console.error) 41 | -------------------------------------------------------------------------------- /scripts/generate-common-structures/interface.ts: -------------------------------------------------------------------------------- 1 | import ts from 'typescript' 2 | 3 | import { getText } from './utils' 4 | 5 | import { Field } from './field' 6 | 7 | export class Interface { 8 | constructor (public declaration: ts.InterfaceDeclaration) {} 9 | 10 | get name () { 11 | return getText(this.declaration.name) 12 | } 13 | 14 | get fields () { 15 | return this.declaration.members 16 | .filter(ts.isPropertySignature) 17 | .map(s => new Field(s)) 18 | } 19 | 20 | get (field: string) { 21 | return this.declaration.members 22 | .find(m => getText(m.name!) === field)! 23 | } 24 | 25 | hasComment () { 26 | return this.comment !== '' 27 | } 28 | 29 | get comment () { 30 | // @ts-expect-error where the fuck are `jsDoc`s located at?! 31 | const comment: string = this.declaration.jsDoc.map(d => d.comment).join('\n') 32 | 33 | return comment 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /scripts/generate-common-structures/test.ts: -------------------------------------------------------------------------------- 1 | import ts from 'typescript' 2 | 3 | import { CodeGenerator } from './code-generator' 4 | 5 | const file = ts.createSourceFile('test.ts', '', ts.ScriptTarget.ES2019) 6 | const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }) 7 | 8 | const print = (node: ts.Node) => console.log(printer.printNode(ts.EmitHint.Unspecified, node, file)) 9 | 10 | // print(CodeGenerator.get('')) 11 | -------------------------------------------------------------------------------- /scripts/generate-common-structures/type.ts: -------------------------------------------------------------------------------- 1 | import ts from 'typescript' 2 | 3 | import { typeNodeToString } from './utils' 4 | 5 | export class Type { 6 | constructor (public node: ts.TypeNode) {} 7 | 8 | get value () { 9 | return this.node 10 | } 11 | 12 | isArray () { 13 | return this.node.kind === ts.SyntaxKind.ArrayType 14 | } 15 | 16 | isTuple () { 17 | return this.node.kind === ts.SyntaxKind.TupleType 18 | } 19 | 20 | isTypeReference () { 21 | return this.node.kind === ts.SyntaxKind.TypeReference 22 | } 23 | 24 | toString () { 25 | return typeNodeToString(this.value) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /scripts/generate-common-structures/variables.ts: -------------------------------------------------------------------------------- 1 | import { Interface } from './interface' 2 | 3 | export class Variables { 4 | static innerReferenceNames: string[] = [] 5 | static interfaces: Interface[] = [] 6 | } 7 | -------------------------------------------------------------------------------- /scripts/generate-index/index.ts: -------------------------------------------------------------------------------- 1 | import { writeFile, readdir } from 'node:fs/promises' 2 | import { resolve } from 'node:path' 3 | 4 | const args = process.argv.slice(2) 5 | 6 | if (args.length === 0) { 7 | console.error('[generate-index] expected directory path') 8 | 9 | process.exit(-1) 10 | } 11 | 12 | const STRUCTURES_PATH = resolve(__dirname, '..', '..', 'packages', 'puregram', 'src', args[0]) 13 | const INDEX_PATH = resolve(STRUCTURES_PATH, 'index.ts') 14 | 15 | const main = async () => { 16 | const rawFiles = await readdir(STRUCTURES_PATH) 17 | 18 | const filenames = rawFiles 19 | .filter(file => file.endsWith('.ts')) 20 | .filter(file => file !== 'index.ts') 21 | .map(file => file.slice(0, -3)) 22 | 23 | const content = filenames.map(filename => `export * from './${filename}'`).join('\n') + '\n' 24 | 25 | await writeFile(INDEX_PATH, content) 26 | 27 | console.log(`[generate-index] successfully generated ${filenames.length} exports in ${args[0]}/index.ts`) 28 | } 29 | 30 | main().catch(console.error) 31 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2019", 4 | "module": "commonjs", 5 | "experimentalDecorators": true, 6 | "declaration": true, 7 | "pretty": true, 8 | 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "strictNullChecks": true, 12 | "strictFunctionTypes": true, 13 | "strictBindCallApply": true, 14 | "strictPropertyInitialization": true, 15 | "noImplicitThis": true, 16 | "alwaysStrict": true, 17 | 18 | "esModuleInterop": true, 19 | 20 | "skipLibCheck": true, 21 | "forceConsistentCasingInFileNames": true 22 | } 23 | } 24 | --------------------------------------------------------------------------------