@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.
- package/dist/cjs/bot/factory/_service.js +59 -0
- package/dist/cjs/bot/factory/client-config.js +68 -0
- package/dist/cjs/bot/factory/make-bot.js +59 -0
- package/dist/cjs/bot/message-handler/_service.js +51 -0
- package/dist/cjs/bot/message-handler/types.js +5 -0
- package/dist/cjs/bot/message-handler/utils.js +19 -0
- package/dist/cjs/bot/run.js +10 -0
- package/dist/cjs/bot/update-poller/_service.js +78 -0
- package/dist/cjs/bot/update-poller/errors.js +5 -0
- package/dist/cjs/bot/update-poller/fetch-updates.js +109 -0
- package/dist/cjs/bot/update-poller/poll-and-handle.js +89 -0
- package/dist/cjs/bot/update-poller/settings.js +23 -0
- package/dist/cjs/client/_client.js +56 -14
- package/dist/cjs/client/config.js +56 -0
- package/dist/cjs/client/errors.js +47 -9
- package/dist/cjs/client/execute-request/_service.js +59 -0
- package/dist/cjs/client/execute-request/execute.js +98 -0
- package/dist/cjs/client/{request.js → execute-request/payload.js} +2 -2
- package/dist/cjs/client/file/_service.js +61 -0
- package/dist/cjs/client/file/get-file.js +77 -0
- package/dist/cjs/client/guards.js +12 -0
- package/dist/cjs/const.js +20 -0
- package/dist/cjs/index.js +24 -22
- package/dist/dts/bot/factory/_service.d.ts +37 -0
- package/dist/dts/bot/factory/client-config.d.ts +3 -0
- package/dist/dts/bot/factory/make-bot.d.ts +7 -0
- package/dist/dts/bot/message-handler/_service.d.ts +6 -0
- package/dist/dts/bot/message-handler/types.d.ts +16 -0
- package/dist/dts/bot/message-handler/utils.d.ts +6 -0
- package/dist/dts/bot/run.d.ts +7 -0
- package/dist/dts/bot/update-poller/_service.d.ts +21 -0
- package/dist/dts/bot/update-poller/errors.d.ts +1 -0
- package/dist/dts/bot/update-poller/fetch-updates.d.ts +17 -0
- package/dist/dts/bot/update-poller/poll-and-handle.d.ts +16 -0
- package/dist/dts/bot/update-poller/settings.d.ts +6 -0
- package/dist/dts/client/_client.d.ts +6 -17
- package/dist/dts/client/config.d.ts +8 -0
- package/dist/dts/client/errors.d.ts +6 -4
- package/dist/dts/client/execute-request/_service.d.ts +15 -0
- package/dist/dts/client/execute-request/execute.d.ts +5 -0
- package/dist/dts/client/file/_service.d.ts +16 -0
- package/dist/dts/client/file/get-file.d.ts +5 -0
- package/dist/dts/client/guards.d.ts +17 -0
- package/dist/dts/index.d.ts +4 -1
- package/dist/dts/specification/api.d.ts +14 -14
- package/dist/dts/specification/types.d.ts +77 -77
- package/dist/esm/bot/factory/_service.js +49 -0
- package/dist/esm/bot/factory/client-config.js +57 -0
- package/dist/esm/bot/factory/make-bot.js +46 -0
- package/dist/esm/bot/message-handler/_service.js +41 -0
- package/dist/esm/bot/message-handler/types.js +2 -0
- package/dist/esm/bot/message-handler/utils.js +16 -0
- package/dist/esm/bot/run.js +10 -0
- package/dist/esm/bot/update-poller/_service.js +68 -0
- package/dist/esm/bot/update-poller/errors.js +2 -0
- package/dist/esm/bot/update-poller/fetch-updates.js +86 -0
- package/dist/esm/bot/update-poller/poll-and-handle.js +74 -0
- package/dist/esm/bot/update-poller/settings.js +19 -0
- package/dist/esm/client/_client.js +50 -12
- package/dist/esm/client/config.js +46 -0
- package/dist/esm/client/errors.js +42 -8
- package/dist/esm/client/execute-request/_service.js +49 -0
- package/dist/esm/client/execute-request/execute.js +74 -0
- package/dist/esm/client/{request.js → execute-request/payload.js} +7 -5
- package/dist/esm/client/file/_service.js +51 -0
- package/dist/esm/client/file/get-file.js +61 -0
- package/dist/esm/client/guards.js +13 -0
- package/dist/esm/const.js +17 -0
- package/dist/esm/index.js +21 -4
- package/dist/esm/specification/api.js +2 -1
- package/dist/esm/specification/types.js +2 -1
- package/package.json +13 -9
- package/readme.md +75 -25
- package/dist/cjs/client/const.js +0 -20
- package/dist/cjs/client/download-file.js +0 -44
- package/dist/cjs/client/execute-request.js +0 -69
- package/dist/cjs/client/response.js +0 -22
- package/dist/dts/client/download-file.d.ts +0 -13
- package/dist/dts/client/execute-request.d.ts +0 -13
- package/dist/dts/client/response.d.ts +0 -7
- package/dist/esm/client/const.js +0 -13
- package/dist/esm/client/download-file.js +0 -36
- package/dist/esm/client/execute-request.js +0 -62
- package/dist/esm/client/response.js +0 -15
- /package/dist/dts/client/{request.d.ts → execute-request/payload.d.ts} +0 -0
- /package/dist/dts/{client/const.d.ts → const.d.ts} +0 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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 (
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
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
|
|
4
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
|
|
42
|
+
"vitest": "^2.1.8"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"effect": "^3.4.0"
|
|
43
46
|
},
|
|
44
47
|
"scripts": {
|
|
45
|
-
"
|
|
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
|
-

|
|
1
|
+
[](https://www.npmjs.com/package/@effect-ak/tg-bot-client)
|
|
2
|
+
[](https://effect-ak.github.io/telegram-bot-api/)
|
|
3
|
+

|
|
4
|
+

|
|
2
5
|
|
|
3
|
-
[OpenApi Specification](https://effect-ak.github.io/telegram-bot-api/)
|
|
4
6
|
|
|
5
|
-
### What is it?
|
|
6
7
|
|
|
7
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
155
|
+
To start your chatbot, execute the following command in your terminal:
|
|
108
156
|
|
|
109
|
-
|
|
157
|
+
```bash
|
|
158
|
+
node bot.js
|
|
159
|
+
```
|
package/dist/cjs/client/const.js
DELETED
|
@@ -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 {};
|
package/dist/esm/client/const.js
DELETED
|
@@ -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
|
-
};
|