@effect-ak/tg-bot-client 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/cjs/bot/factory/_service.js +59 -0
  2. package/dist/cjs/bot/factory/client-config.js +68 -0
  3. package/dist/cjs/bot/factory/make-bot.js +59 -0
  4. package/dist/cjs/bot/message-handler/_service.js +51 -0
  5. package/dist/cjs/bot/message-handler/types.js +5 -0
  6. package/dist/cjs/bot/message-handler/utils.js +19 -0
  7. package/dist/cjs/bot/run.js +10 -0
  8. package/dist/cjs/bot/update-poller/_service.js +78 -0
  9. package/dist/cjs/bot/update-poller/errors.js +5 -0
  10. package/dist/cjs/bot/update-poller/fetch-updates.js +109 -0
  11. package/dist/cjs/bot/update-poller/poll-and-handle.js +89 -0
  12. package/dist/cjs/bot/update-poller/settings.js +23 -0
  13. package/dist/cjs/client/_client.js +56 -14
  14. package/dist/cjs/client/config.js +56 -0
  15. package/dist/cjs/client/errors.js +47 -9
  16. package/dist/cjs/client/execute-request/_service.js +59 -0
  17. package/dist/cjs/client/execute-request/execute.js +98 -0
  18. package/dist/cjs/client/{request.js → execute-request/payload.js} +2 -2
  19. package/dist/cjs/client/file/_service.js +61 -0
  20. package/dist/cjs/client/file/get-file.js +77 -0
  21. package/dist/cjs/client/guards.js +12 -0
  22. package/dist/cjs/const.js +20 -0
  23. package/dist/cjs/index.js +24 -22
  24. package/dist/dts/bot/factory/_service.d.ts +37 -0
  25. package/dist/dts/bot/factory/client-config.d.ts +3 -0
  26. package/dist/dts/bot/factory/make-bot.d.ts +7 -0
  27. package/dist/dts/bot/message-handler/_service.d.ts +6 -0
  28. package/dist/dts/bot/message-handler/types.d.ts +16 -0
  29. package/dist/dts/bot/message-handler/utils.d.ts +6 -0
  30. package/dist/dts/bot/run.d.ts +7 -0
  31. package/dist/dts/bot/update-poller/_service.d.ts +21 -0
  32. package/dist/dts/bot/update-poller/errors.d.ts +1 -0
  33. package/dist/dts/bot/update-poller/fetch-updates.d.ts +17 -0
  34. package/dist/dts/bot/update-poller/poll-and-handle.d.ts +16 -0
  35. package/dist/dts/bot/update-poller/settings.d.ts +6 -0
  36. package/dist/dts/client/_client.d.ts +6 -17
  37. package/dist/dts/client/config.d.ts +8 -0
  38. package/dist/dts/client/errors.d.ts +6 -4
  39. package/dist/dts/client/execute-request/_service.d.ts +15 -0
  40. package/dist/dts/client/execute-request/execute.d.ts +5 -0
  41. package/dist/dts/client/file/_service.d.ts +16 -0
  42. package/dist/dts/client/file/get-file.d.ts +5 -0
  43. package/dist/dts/client/guards.d.ts +17 -0
  44. package/dist/dts/index.d.ts +4 -1
  45. package/dist/dts/specification/api.d.ts +14 -14
  46. package/dist/dts/specification/types.d.ts +77 -77
  47. package/dist/esm/bot/factory/_service.js +49 -0
  48. package/dist/esm/bot/factory/client-config.js +57 -0
  49. package/dist/esm/bot/factory/make-bot.js +46 -0
  50. package/dist/esm/bot/message-handler/_service.js +41 -0
  51. package/dist/esm/bot/message-handler/types.js +2 -0
  52. package/dist/esm/bot/message-handler/utils.js +16 -0
  53. package/dist/esm/bot/run.js +10 -0
  54. package/dist/esm/bot/update-poller/_service.js +68 -0
  55. package/dist/esm/bot/update-poller/errors.js +2 -0
  56. package/dist/esm/bot/update-poller/fetch-updates.js +86 -0
  57. package/dist/esm/bot/update-poller/poll-and-handle.js +74 -0
  58. package/dist/esm/bot/update-poller/settings.js +19 -0
  59. package/dist/esm/client/_client.js +50 -12
  60. package/dist/esm/client/config.js +46 -0
  61. package/dist/esm/client/errors.js +42 -8
  62. package/dist/esm/client/execute-request/_service.js +49 -0
  63. package/dist/esm/client/execute-request/execute.js +74 -0
  64. package/dist/esm/client/{request.js → execute-request/payload.js} +7 -5
  65. package/dist/esm/client/file/_service.js +51 -0
  66. package/dist/esm/client/file/get-file.js +61 -0
  67. package/dist/esm/client/guards.js +13 -0
  68. package/dist/esm/const.js +17 -0
  69. package/dist/esm/index.js +21 -4
  70. package/dist/esm/specification/api.js +2 -1
  71. package/dist/esm/specification/types.js +2 -1
  72. package/package.json +13 -9
  73. package/readme.md +75 -25
  74. package/dist/cjs/client/const.js +0 -20
  75. package/dist/cjs/client/download-file.js +0 -44
  76. package/dist/cjs/client/execute-request.js +0 -69
  77. package/dist/cjs/client/response.js +0 -22
  78. package/dist/dts/client/download-file.d.ts +0 -13
  79. package/dist/dts/client/execute-request.d.ts +0 -13
  80. package/dist/dts/client/response.d.ts +0 -7
  81. package/dist/esm/client/const.js +0 -13
  82. package/dist/esm/client/download-file.js +0 -36
  83. package/dist/esm/client/execute-request.js +0 -62
  84. package/dist/esm/client/response.js +0 -15
  85. /package/dist/dts/client/{request.d.ts → execute-request/payload.d.ts} +0 -0
  86. /package/dist/dts/{client/const.d.ts → const.d.ts} +0 -0
@@ -1,7 +1,8 @@
1
- const hasFileContent = (input) => (typeof input == "object" && input != null) &&
2
- ("file_content" in input && input.file_content instanceof Uint8Array) &&
3
- ("file_name" in input && typeof input.file_name === "string" && input.file_name.length > 0);
4
- export const makePayload = (body) => {
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makePayload = void 0;
4
+ const guards_js_1 = require("../guards.js");
5
+ const makePayload = (body) => {
5
6
  const entries = Object.entries(body);
6
7
  if (entries.length == 0)
7
8
  return undefined;
@@ -12,7 +13,7 @@ export const makePayload = (body) => {
12
13
  if (typeof value != "object") {
13
14
  result.append(key, `${value}`);
14
15
  }
15
- else if (hasFileContent(value)) {
16
+ else if ((0, guards_js_1.isFileContent)(value)) {
16
17
  result.append(key, new Blob([value.file_content]), value.file_name);
17
18
  }
18
19
  else {
@@ -21,3 +22,4 @@ export const makePayload = (body) => {
21
22
  }
22
23
  return result;
23
24
  };
25
+ exports.makePayload = makePayload;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ClientFileServiceDefault = exports.ClientFileService = void 0;
37
+ const Micro = __importStar(require("effect/Micro"));
38
+ const Context = __importStar(require("effect/Context"));
39
+ const config_js_1 = require("../config.js");
40
+ const _service_js_1 = require("../execute-request/_service.js");
41
+ const get_file_js_1 = require("./get-file.js");
42
+ class ClientFileService extends Context.Tag("ClientFileService")() {
43
+ }
44
+ exports.ClientFileService = ClientFileService;
45
+ exports.ClientFileServiceDefault = Micro.gen(function* () {
46
+ const config = yield* Micro.service(config_js_1.TgBotClientConfig);
47
+ const execute = yield* Micro.service(_service_js_1.ClientExecuteRequestService);
48
+ return {
49
+ getFile: (input) => (0, get_file_js_1.getFile)(input.file_id, config, execute)
50
+ };
51
+ }).pipe(Micro.provideServiceEffect(_service_js_1.ClientExecuteRequestService, _service_js_1.ClientExecuteRequestServiceDefault));
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getFile = void 0;
37
+ const Micro = __importStar(require("effect/Micro"));
38
+ const errors_js_1 = require("../errors.js");
39
+ const getFile = (fileId, config, execute) => Micro.gen(function* () {
40
+ const response = yield* execute.execute("get_file", { file_id: fileId });
41
+ const file_path = response.file_path;
42
+ if (!file_path || file_path.length == 0) {
43
+ return yield* Micro.fail(new errors_js_1.TgBotClientError({
44
+ reason: {
45
+ type: "UnableToGetFile",
46
+ cause: "File path not defined"
47
+ }
48
+ }));
49
+ }
50
+ const file_name = file_path.replaceAll("/", "-");
51
+ const url = `${config["base-url"]}/file/bot${config["bot-token"]}/${file_path}`;
52
+ const fileContent = yield* Micro.tryPromise({
53
+ try: () => fetch(url).then(_ => _.arrayBuffer()),
54
+ catch: cause => new errors_js_1.TgBotClientError({
55
+ reason: { type: "UnableToGetFile", cause }
56
+ })
57
+ });
58
+ const file = new File([new Uint8Array(fileContent)], file_name);
59
+ return file;
60
+ });
61
+ exports.getFile = getFile;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isTgBotClientSettingsInput = exports.isTgBotApiResponse = exports.isFileContent = void 0;
4
+ const isFileContent = (input) => (typeof input == "object" && input != null) &&
5
+ ("file_content" in input && input.file_content instanceof Uint8Array) &&
6
+ ("file_name" in input && typeof input.file_name == "string");
7
+ exports.isFileContent = isFileContent;
8
+ const isTgBotApiResponse = (input) => (typeof input == "object" && input != null) &&
9
+ ("ok" in input && typeof input.ok == "boolean");
10
+ exports.isTgBotApiResponse = isTgBotApiResponse;
11
+ const isTgBotClientSettingsInput = (input) => (typeof input == "object" && input != null) &&
12
+ ("bot-token" in input && typeof input["bot-token"] == "string");
13
+ exports.isTgBotClientSettingsInput = isTgBotClientSettingsInput;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isMessageEffect = exports.messageEffectIdCodes = exports.MESSAGE_EFFECTS = exports.defaultBaseUrl = void 0;
4
+ exports.defaultBaseUrl = "https://api.telegram.org";
5
+ exports.MESSAGE_EFFECTS = {
6
+ "🔥": "5104841245755180586",
7
+ "👍": "5107584321108051014",
8
+ "👎": "5104858069142078462",
9
+ "❤️": "5159385139981059251",
10
+ "🎉": "5046509860389126442",
11
+ "💩": "5046589136895476101"
12
+ };
13
+ exports.messageEffectIdCodes = Object.keys(exports.MESSAGE_EFFECTS);
14
+ const isMessageEffect = (input) => {
15
+ return typeof input === "string" && input in exports.MESSAGE_EFFECTS;
16
+ };
17
+ exports.isMessageEffect = isMessageEffect;
package/dist/esm/index.js CHANGED
@@ -1,4 +1,21 @@
1
- export * from "./client/const.js";
2
- export * from "./client/_client.js";
3
- // export * from "./specification/api.js"
4
- // export * from "./specification/types.js"
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./client/_client.js"), exports);
18
+ __exportStar(require("./bot/run.js"), exports);
19
+ __exportStar(require("./specification/api.js"), exports);
20
+ __exportStar(require("./specification/types.js"), exports);
21
+ __exportStar(require("./const.js"), exports);
@@ -1 +1,2 @@
1
- export {};
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1 +1,2 @@
1
- export {};
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@effect-ak/tg-bot-client",
3
- "version": "0.1.0",
4
- "type": "module",
3
+ "version": "0.2.1",
4
+ "homepage": "https://effect-ak.github.io/telegram-bot-client",
5
5
  "author": {
6
6
  "name": "Aleksandr Kondaurov",
7
7
  "email": "kondaurov.dev@gmail.com"
@@ -30,22 +30,26 @@
30
30
  "@babel/plugin-transform-export-namespace-from": "^7.25.9",
31
31
  "@babel/plugin-transform-modules-commonjs": "^7.26.3",
32
32
  "@types/node": "^22.10.1",
33
- "effect": "^3.11.4",
33
+ "@types/js-yaml": "^4.0.9",
34
+ "js-yaml": "^4.1.0",
34
35
  "node-html-parser": "^6.1.13",
35
36
  "openapi-types": "^12.1.3",
36
37
  "ts-morph": "^24.0.0",
37
38
  "tsc-alias": "^1.8.10",
38
- "type-fest": "^4.30.0",
39
+ "tsx": "^4.19.2",
39
40
  "typescript": "^5.7.2",
40
41
  "vite-tsconfig-paths": "^5.1.4",
41
- "vitest": "^2.1.8",
42
- "@redocly/cli": "^1.26.0"
42
+ "vitest": "^2.1.8"
43
+ },
44
+ "dependencies": {
45
+ "effect": "^3.4.0"
43
46
  },
44
47
  "scripts": {
45
- "gen": "bun run ./codegen/main",
48
+ "docgen": "docgen",
49
+ "gen": "tsx ./codegen/main",
50
+ "run-bot": "tsx ./src/bot/run",
46
51
  "build": "pnpm build-esm && pnpm build-cjs",
47
52
  "build-esm": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
48
- "build-cjs": "babel dist/esm --out-dir dist/cjs",
49
- "gen-html": "redocly build-docs --output ../effect-ak.github.io/telegram-bot-api/index.html"
53
+ "build-cjs": "babel dist/esm --out-dir dist/cjs"
50
54
  }
51
55
  }
package/readme.md CHANGED
@@ -1,34 +1,29 @@
1
- ![NPM Version](https://img.shields.io/npm/v/%40effect-ak%2Ftg-bot-client)
1
+ [![NPM Version](https://img.shields.io/npm/v/%40effect-ak%2Ftg-bot-client)](https://www.npmjs.com/package/@effect-ak/tg-bot-client)
2
+ [![OpenAPI](https://img.shields.io/badge/OpenAPI-3.1-blue.svg)](https://effect-ak.github.io/telegram-bot-api/)
3
+ ![NPM Unpacked Size](https://img.shields.io/npm/unpacked-size/%40effect-ak%2Ftg-bot-client)
4
+ ![NPM Downloads](https://img.shields.io/npm/dw/%40effect-ak%2Ftg-bot-client)
2
5
 
3
- [OpenApi Specification](https://effect-ak.github.io/telegram-bot-api/)
4
6
 
5
- ### What is it?
6
7
 
7
- This is a client for interacting with the Telegram Bot API.
8
- The main reason for creating this package is that Telegram does not provide an SDK for working with their API.
8
+ ### Motivation
9
9
 
10
- They only provide documentation in the form of a massive HTML page, which is very inconvenient for navigating and understanding what the Telegram Bot API offers.
10
+ The official documentation is available as a comprehensive [HTML page](https://core.telegram.org/bots/api), providing basic navigation. While functional, relying solely on this format can be somewhat inconvenient during bot development.
11
11
 
12
- ## Features:
13
- - **Pure TypeScript Client**: This is a clean client written in TypeScript with no abstractions.
14
- - **Complete**: The entire API is generated from the official documentation [https://core.telegram.org/bots/api](https://core.telegram.org/bots/api) using a [code generator](./codegen/main.ts).
15
- - ~~**Inline Documentation**: No need to read lengthy official documentation. All types and comments are available in JS DOC, allowing you to develop your bot without leaving your IDE.~~
16
- - Codegenerator produces TypeScript code and OpenApi specification now! Documentation was removed from TypeScript interfaces in order to keep npm package smaller.
12
+ This client facilitates interaction with the Telegram Bot API. It was created primarily because Telegram does not offer an official SDK for their API.
17
13
 
14
+ ## Features:
15
+ - **Typesafe Client**: This is a clean client written in TypeScript with no abstractions.
16
+ - **Complete**: The entire API is generated from [the official documentation](https://core.telegram.org/bots/api) using a [code generator](./codegen/main.ts)
17
+ - **Readable Method Names**: Method names, such as `setChatAdministratorCustomTitle`, are converted to snake_case for easier code readability, e.g., `set_chat_administrator_custom_title`.
18
18
  - **Type Mapping**: Types from the documentation are converted to TypeScript types:
19
19
  - `Integer` becomes `number`
20
20
  - `True` becomes `boolean`
21
21
  - `String or Number` becomes `string | number`
22
22
  - Enumerated types, such as `Type of the chat, can be either “private”, “group”, “supergroup” or “channel”` becomes a standard union of literal types `"private"| "group" | "supergroup" | "channel"`
23
23
  - And so on
24
- - **Readable Method Names**: Method names, such as `SetChatAdministratorCustomTitleInput`, are converted to snake_case for easier code readability, e.g., `set_chat_administrator_custom_title`.
25
24
 
26
25
  ### Usage example
27
26
 
28
- #### Install
29
-
30
- `npm i @effect-ak/tg-bot-client`
31
-
32
27
  #### Creating a Client
33
28
 
34
29
  ```typescript
@@ -39,17 +34,13 @@ const client = makeTgBotClient({
39
34
  });
40
35
  ```
41
36
 
42
- #### Executing api methods, typesafety
37
+ #### Executing api methods
43
38
 
44
39
  `client` has an `execute` method which requires two arguments
45
40
 
46
41
  - the first is the API method, e.g. `send_message`
47
42
  - the second is an object containing the arguments for that method, e.g. `text`
48
43
 
49
- `execute` never returns failed promise, instead, it gives an object with two fields, `success`, `error`.
50
-
51
- if you want, you can use unsafe alternative, `unsafeExecute`, which gives you the result of method or throws an Error
52
-
53
44
  #### 1. Sending a Message with an Effect
54
45
 
55
46
  ```typescript
@@ -99,11 +90,70 @@ const file =
99
90
  await client.getFile({
100
91
  file_id: fileId
101
92
  });
102
- // file is File
103
93
  ```
104
94
 
105
- ---
95
+ ### Chatbot Support
96
+
97
+ You can write the logic for your chatbot and run it locally.
98
+
99
+ Take a look at [example](./example/echo-bot.ts)
100
+
101
+ The Telegram bot supports both push and pull notification models for messages. This package uses the **pull** model for several reasons:
102
+
103
+ - **Flexibility in Handler Deployment:** Allows you to run the bot handler on any JS platform (NodeJs, Browser)
104
+ - **Sequential Message Processing:** Messages in the queue are read one by one, and the handler is invoked for each message. If an error occurs in the handler, the next message remains in the queue, and the bot stops running. When the handler successfully processes a message, it proceeds to the next one.
105
+
106
+ ### Setup Instructions
107
+
108
+ 1. **Create a `config.json` File**
109
+
110
+ In the root of your project, create a `config.json` file with the following content:
111
+
112
+ ```json
113
+ {
114
+ "bot-token": "your-token"
115
+ }
116
+ ```
117
+
118
+ Replace `"your-token"` with your actual Telegram bot token.
119
+
120
+ 2. **Create `bot.js` and Implement Your Bot's Logic**
121
+
122
+ Create a file named `bot.js` and add your bot's logic as shown below:
123
+
124
+ ```typescript
125
+ import { MESSAGE_EFFECTS, runTgChatBot } from "@effect-ak/tg-bot-client"
126
+
127
+ runTgChatBot({
128
+ type: "fromJsonFile",
129
+ on_message: (msg) => {
130
+ if (msg?.text === "bye") {
131
+ return {
132
+ type: "message",
133
+ text: "See you later!",
134
+ message_effect_id: MESSAGE_EFFECTS["❤️"]
135
+ }
136
+ }
137
+
138
+ return {
139
+ type: "message",
140
+ text: "I'm a simple bot"
141
+ }
142
+ }
143
+ })
144
+ ```
145
+
146
+ **Explanation:**
147
+ - **Import Statements:** Import necessary modules from the `@effect-ak/tg-bot-client` package.
148
+ - **`runTgChatBot` Function:** Initializes the Telegram chatbot using the configuration from the `config.json` file.
149
+ - **`on_message` Handler:** Defines the logic for handling incoming messages.
150
+ - If the message text is `"bye"`, the bot responds with `"See you later!"` and adds a heart emoji effect.
151
+ - For any other message, the bot responds with `"I'm a simple bot"`.
152
+
153
+ 3. **Run the Bot**
106
154
 
107
- ### Summary
155
+ To start your chatbot, execute the following command in your terminal:
108
156
 
109
- This code generator and client will continue to be developed. However, for now, I have generated all the methods and types. If you find any errors, please let me know.
157
+ ```bash
158
+ node bot.js
159
+ ```
@@ -1,20 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.messageEffectIdCodes = exports.isMessageEffect = exports.defaultBaseUrl = exports.MESSAGE_EFFECTS = void 0;
7
- const defaultBaseUrl = exports.defaultBaseUrl = "https://api.telegram.org";
8
- const MESSAGE_EFFECTS = exports.MESSAGE_EFFECTS = {
9
- "🔥": "5104841245755180586",
10
- "👍": "5107584321108051014",
11
- "👎": "5104858069142078462",
12
- "❤️": "5159385139981059251",
13
- "🎉": "5046509860389126442",
14
- "💩": "5046589136895476101"
15
- };
16
- const messageEffectIdCodes = exports.messageEffectIdCodes = Object.keys(MESSAGE_EFFECTS);
17
- const isMessageEffect = input => {
18
- return typeof input === "string" && input in MESSAGE_EFFECTS;
19
- };
20
- exports.isMessageEffect = isMessageEffect;
@@ -1,44 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.makeDownloadFile = void 0;
7
- var _errors = require("./errors.js");
8
- const makeDownloadFile = (config, execute) => {
9
- const getFile = async input => {
10
- const response = await execute.execute("get_file", input);
11
- if (response.error) return {
12
- error: response.error
13
- };
14
- const file_path = response.success?.file_path;
15
- if (!file_path || file_path.length == 0) {
16
- return {
17
- error: new _errors.TgBotClientError({
18
- type: "UnableToGetFile",
19
- cause: "File path not defined"
20
- })
21
- };
22
- }
23
- const file_name = file_path.replaceAll("/", "-");
24
- const url = `${config.baseUrl}/file/bot${config.token}/${file_path}`;
25
- try {
26
- const fileContent = await fetch(url).then(_ => _.arrayBuffer());
27
- const file = new File([new Uint8Array(fileContent)], file_name);
28
- return {
29
- success: file
30
- };
31
- } catch (cause) {
32
- return {
33
- error: new _errors.TgBotClientError({
34
- type: "UnableToGetFile",
35
- cause
36
- })
37
- };
38
- }
39
- };
40
- return {
41
- getFile
42
- };
43
- };
44
- exports.makeDownloadFile = makeDownloadFile;
@@ -1,69 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.makeExecute = void 0;
7
- var _request = require("./request.js");
8
- var _response = require("./response.js");
9
- var _errors = require("./errors.js");
10
- const makeExecute = config => {
11
- const execute = async (method, input) => {
12
- try {
13
- const httpResponse = await fetch(`${config.baseUrl}/bot${config.token}/${snakeToCamel(method)}`, {
14
- body: (0, _request.makePayload)(input) ?? null,
15
- method: "POST"
16
- });
17
- const response = await httpResponse.json();
18
- if (!(0, _response.isTgBotApiResponse)(response)) {
19
- return {
20
- error: new _errors.TgBotClientError({
21
- type: "UnexpectedResponse",
22
- response
23
- })
24
- };
25
- }
26
- if (!httpResponse.ok) {
27
- return {
28
- error: new _errors.TgBotClientError({
29
- type: "NotOkResponse",
30
- ...(response.error_code ? {
31
- errorCode: response.error_code
32
- } : undefined),
33
- ...(response.description ? {
34
- details: response.description
35
- } : undefined)
36
- })
37
- };
38
- }
39
- return {
40
- success: response.result
41
- };
42
- } catch (cause) {
43
- return {
44
- error: new _errors.TgBotClientError({
45
- type: "ClientInternalError",
46
- cause
47
- })
48
- };
49
- }
50
- };
51
- const unsafeExecute = async (method, input) => {
52
- const result = await execute(method, input);
53
- if (result.error) throw result.error;
54
- if (!("success" in result)) throw _errors.TgBotClientError.missingSuccess;
55
- return result.success;
56
- };
57
- return {
58
- execute,
59
- unsafeExecute
60
- };
61
- };
62
- exports.makeExecute = makeExecute;
63
- const snakeToCamel = methodName => methodName.split("_").reduce((result, word, step) => {
64
- if (step == 0) {
65
- return word;
66
- } else {
67
- return result + word.at(0)?.toUpperCase() + word.slice(1);
68
- }
69
- }, "");
@@ -1,22 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.isTgBotApiResponse = void 0;
7
- const isTgBotApiResponse = input => {
8
- if (typeof input !== "object" || input == null) {
9
- return false;
10
- }
11
- if (!("ok" in input && typeof input.ok == "boolean")) {
12
- return false;
13
- }
14
- if ("error_code" in input && typeof input.error_code != "number") {
15
- return false;
16
- }
17
- if ("description" in input && typeof input.description != "string") {
18
- return false;
19
- }
20
- return true;
21
- };
22
- exports.isTgBotApiResponse = isTgBotApiResponse;
@@ -1,13 +0,0 @@
1
- import type { BotConfig } from "./_client.js";
2
- import { TgBotClientError } from "./errors.js";
3
- import type { ExecuteRequest } from "./execute-request.js";
4
- type GetFileResult = {
5
- success?: File;
6
- error?: TgBotClientError;
7
- };
8
- export declare const makeDownloadFile: (config: BotConfig, execute: ExecuteRequest) => {
9
- readonly getFile: (input: {
10
- file_id: string;
11
- }) => Promise<GetFileResult>;
12
- };
13
- export {};
@@ -1,13 +0,0 @@
1
- import type { BotConfig } from "./_client.js";
2
- import type { Api } from "../specification/api.js";
3
- import { TgBotClientError } from "./errors.js";
4
- export type ExecuteRequest = ReturnType<typeof makeExecute>;
5
- type SafeExecuteResult<M extends keyof Api> = {
6
- success?: ReturnType<Api[M]>;
7
- error?: TgBotClientError;
8
- };
9
- export declare const makeExecute: (config: BotConfig) => {
10
- readonly execute: <M extends keyof Api>(method: M, input: Parameters<Api[M]>[0]) => Promise<SafeExecuteResult<M>>;
11
- readonly unsafeExecute: <M extends keyof Api>(method: M, input: Parameters<Api[M]>[0]) => Promise<ReturnType<Api[M]>>;
12
- };
13
- export {};
@@ -1,7 +0,0 @@
1
- export type TgBotApiResponse<O> = {
2
- ok: boolean;
3
- error_code?: number;
4
- description?: string;
5
- result?: O;
6
- };
7
- export declare const isTgBotApiResponse: <O>(input: unknown) => input is TgBotApiResponse<O>;
@@ -1,13 +0,0 @@
1
- export const defaultBaseUrl = "https://api.telegram.org";
2
- export const MESSAGE_EFFECTS = {
3
- "🔥": "5104841245755180586",
4
- "👍": "5107584321108051014",
5
- "👎": "5104858069142078462",
6
- "❤️": "5159385139981059251",
7
- "🎉": "5046509860389126442",
8
- "💩": "5046589136895476101"
9
- };
10
- export const messageEffectIdCodes = Object.keys(MESSAGE_EFFECTS);
11
- export const isMessageEffect = (input) => {
12
- return typeof input === "string" && input in MESSAGE_EFFECTS;
13
- };
@@ -1,36 +0,0 @@
1
- import { TgBotClientError } from "./errors.js";
2
- export const makeDownloadFile = (config, execute) => {
3
- const getFile = async (input) => {
4
- const response = await execute.execute("get_file", input);
5
- if (response.error)
6
- return { error: response.error };
7
- const file_path = response.success?.file_path;
8
- if (!file_path || file_path.length == 0) {
9
- return {
10
- error: new TgBotClientError({
11
- type: "UnableToGetFile",
12
- cause: "File path not defined"
13
- })
14
- };
15
- }
16
- const file_name = file_path.replaceAll("/", "-");
17
- const url = `${config.baseUrl}/file/bot${config.token}/${file_path}`;
18
- try {
19
- const fileContent = await fetch(url).then(_ => _.arrayBuffer());
20
- const file = new File([new Uint8Array(fileContent)], file_name);
21
- return {
22
- success: file
23
- };
24
- }
25
- catch (cause) {
26
- return {
27
- error: new TgBotClientError({
28
- type: "UnableToGetFile", cause
29
- })
30
- };
31
- }
32
- };
33
- return {
34
- getFile
35
- };
36
- };