@pixelbyte-software/pixcode 1.54.7 → 1.54.8
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/CODE_OF_CONDUCT.md +41 -41
- package/CONTRIBUTING.md +155 -155
- package/LICENSE +718 -718
- package/README.de.md +169 -169
- package/README.ja.md +167 -167
- package/README.ko.md +167 -167
- package/README.md +418 -418
- package/README.ru.md +169 -169
- package/README.tr.md +298 -298
- package/README.zh-CN.md +167 -167
- package/SECURITY.md +46 -46
- package/dist/api-automation.html +110 -110
- package/dist/api-docs.html +548 -548
- package/dist/assets/{index-D-4VRH1a.js → index-BU3Z3zrh.js} +186 -184
- package/dist/assets/index-Dz1luE0u.css +32 -0
- package/dist/clear-cache.html +85 -85
- package/dist/convert-icons.md +52 -52
- package/dist/docs.html +308 -308
- package/dist/features.html +133 -133
- package/dist/generate-icons.js +48 -48
- package/dist/humans.txt +15 -15
- package/dist/icons/codex-white.svg +3 -3
- package/dist/icons/codex.svg +3 -3
- package/dist/icons/cursor-white.svg +11 -11
- package/dist/icons/qwen-logo.svg +14 -14
- package/dist/index.html +59 -59
- package/dist/landing.html +268 -268
- package/dist/llms-full.txt +119 -119
- package/dist/llms.txt +53 -53
- package/dist/manifest.json +60 -60
- package/dist/openapi.yaml +1696 -1696
- package/dist/orchestration.html +125 -125
- package/dist/robots.txt +4 -4
- package/dist/site.css +692 -692
- package/dist/sitemap.xml +51 -51
- package/dist/sw.js +132 -132
- package/dist-server/server/cli.js +100 -100
- package/dist-server/server/daemon/manager.js +33 -33
- package/dist-server/server/daemon-manager.js +64 -64
- package/dist-server/server/index.js +109 -12
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/routes/auth.js +17 -5
- package/dist-server/server/routes/auth.js.map +1 -1
- package/dist-server/server/routes/commands.js +25 -25
- package/dist-server/server/routes/git.js +17 -17
- package/dist-server/server/routes/live-view.js +46 -46
- package/dist-server/server/services/public-api-manifest.js +51 -51
- package/package.json +224 -224
- package/scripts/fix-node-pty.js +67 -67
- package/scripts/github/create-v1.38-issues.mjs +351 -351
- package/scripts/github/create-vscode-workbench-issues.mjs +121 -121
- package/scripts/smoke/backend-resource-bounds.mjs +152 -152
- package/scripts/smoke/changes-panel-layout.mjs +48 -48
- package/scripts/smoke/chat-composer-fixed-layout.mjs +55 -55
- package/scripts/smoke/chat-message-timeline-order.mjs +41 -41
- package/scripts/smoke/chat-realtime-hydration.mjs +44 -44
- package/scripts/smoke/chat-session-provider-pools.mjs +35 -35
- package/scripts/smoke/chat-session-state.mjs +19 -19
- package/scripts/smoke/code-editor-theme.mjs +55 -55
- package/scripts/smoke/code-editor-vscode-engine.mjs +91 -91
- package/scripts/smoke/command-center-agent-writes.mjs +79 -79
- package/scripts/smoke/command-center-non-git.mjs +46 -46
- package/scripts/smoke/context-packet.mjs +43 -43
- package/scripts/smoke/control-room-ux-redesign.mjs +91 -91
- package/scripts/smoke/daemon-entrypoint.mjs +20 -20
- package/scripts/smoke/default-landing-routing.mjs +33 -33
- package/scripts/smoke/desktop-native-notifications.mjs +30 -30
- package/scripts/smoke/desktop-tray-icon.mjs +33 -33
- package/scripts/smoke/discord-release-workflow.mjs +24 -24
- package/scripts/smoke/git-install-update.mjs +255 -255
- package/scripts/smoke/handoff-artifact-protocol.mjs +50 -50
- package/scripts/smoke/live-view-diagnostics.mjs +53 -53
- package/scripts/smoke/live-view-environment.mjs +92 -92
- package/scripts/smoke/live-view-integration.mjs +450 -450
- package/scripts/smoke/mac-desktop-runtime.mjs +37 -37
- package/scripts/smoke/mobile-tunnel-guidance.mjs +29 -29
- package/scripts/smoke/mobile-ux.mjs +76 -76
- package/scripts/smoke/model-registry.mjs +36 -36
- package/scripts/smoke/multi-project-ui.mjs +45 -45
- package/scripts/smoke/multi-worker-slots.mjs +42 -42
- package/scripts/smoke/notification-center.mjs +87 -87
- package/scripts/smoke/notification-inapp-preference.mjs +23 -23
- package/scripts/smoke/notification-taxonomy.mjs +58 -58
- package/scripts/smoke/orchestration-api.mjs +172 -172
- package/scripts/smoke/orchestration-execution-dashboard.mjs +33 -33
- package/scripts/smoke/orchestration-live-run.mjs +176 -176
- package/scripts/smoke/orchestration-mobile-scroll.mjs +29 -29
- package/scripts/smoke/orchestration-model-sync.mjs +30 -30
- package/scripts/smoke/orchestration-permission-fallback.mjs +34 -34
- package/scripts/smoke/orchestration-runtime-guards.mjs +48 -48
- package/scripts/smoke/orchestration-user-facing-output.mjs +25 -25
- package/scripts/smoke/permission-policy.mjs +50 -50
- package/scripts/smoke/pixcode-workbench-1-48.mjs +167 -167
- package/scripts/smoke/provider-models-opencode-live.mjs +66 -66
- package/scripts/smoke/provider-rest-api.mjs +124 -124
- package/scripts/smoke/provider-selection-status.mjs +52 -52
- package/scripts/smoke/run-state-refresh.mjs +52 -52
- package/scripts/smoke/runtime-manager.mjs +99 -99
- package/scripts/smoke/shell-manual-disconnect.mjs +30 -30
- package/scripts/smoke/side-panel-editor-layout.mjs +34 -34
- package/scripts/smoke/static-root-routing.mjs +21 -21
- package/scripts/smoke/strict-handoff-compact.mjs +60 -60
- package/scripts/smoke/taskmaster-config.mjs +24 -24
- package/scripts/smoke/taskmaster-execution-telegram.mjs +3 -3
- package/scripts/smoke/taskmaster-onboarding.mjs +3 -3
- package/scripts/smoke/taskmaster-run-graph.mjs +3 -3
- package/scripts/smoke/telegram-control.mjs +331 -331
- package/scripts/smoke/tunnel-persistence.mjs +56 -56
- package/scripts/smoke/update-issue-progress.mjs +69 -69
- package/scripts/smoke/update-ux.mjs +55 -55
- package/scripts/smoke/v138-completion.mjs +132 -132
- package/scripts/smoke/v138-desktop-release-hardening.mjs +69 -69
- package/scripts/smoke/v138-diagnostics.mjs +63 -63
- package/scripts/smoke/v138-issue-planner.mjs +33 -33
- package/scripts/smoke/v143-remote-control.mjs +76 -76
- package/scripts/smoke/v144-production-loop.mjs +47 -47
- package/scripts/smoke/v145-platformization.mjs +46 -46
- package/scripts/smoke/v146-control-room-ui.mjs +150 -150
- package/scripts/smoke/version-modal-autoshow.mjs +29 -29
- package/scripts/smoke/vscode-workbench-layout.mjs +63 -63
- package/scripts/smoke/vscode-workbench-polish.mjs +461 -461
- package/scripts/smoke/workflow-fallback-replay.mjs +56 -56
- package/scripts/smoke/workflow-templates.mjs +43 -43
- package/scripts/smoke/workflow-trace-timeline.mjs +46 -46
- package/scripts/update-git-install.mjs +298 -298
- package/server/claude-sdk.js +927 -927
- package/server/cli.js +1106 -1106
- package/server/constants/config.js +4 -4
- package/server/cursor-cli.js +344 -344
- package/server/daemon/manager.js +563 -563
- package/server/daemon-manager.js +964 -964
- package/server/database/db.js +988 -988
- package/server/database/json-store.js +197 -197
- package/server/gemini-cli.js +550 -550
- package/server/gemini-response-handler.js +79 -79
- package/server/index.js +5620 -5529
- package/server/load-env.js +35 -35
- package/server/middleware/account-lockout.js +112 -112
- package/server/middleware/auth.js +277 -277
- package/server/middleware/rate-limiter.js +87 -87
- package/server/modules/orchestration/a2a/adapter-registry.ts +108 -108
- package/server/modules/orchestration/a2a/adapters/abstract-a2a.adapter.ts +63 -63
- package/server/modules/orchestration/a2a/adapters/claude-code.adapter.ts +286 -286
- package/server/modules/orchestration/a2a/adapters/codex.adapter.ts +244 -244
- package/server/modules/orchestration/a2a/adapters/cursor.adapter.ts +249 -249
- package/server/modules/orchestration/a2a/adapters/gemini.adapter.ts +248 -248
- package/server/modules/orchestration/a2a/adapters/json-event.adapter.test.ts +60 -60
- package/server/modules/orchestration/a2a/adapters/json-event.adapter.ts +101 -101
- package/server/modules/orchestration/a2a/adapters/opencode.adapter.ts +248 -248
- package/server/modules/orchestration/a2a/adapters/qwen.adapter.ts +248 -248
- package/server/modules/orchestration/a2a/agent-card.ts +55 -55
- package/server/modules/orchestration/a2a/auth.middleware.ts +29 -29
- package/server/modules/orchestration/a2a/bus.ts +46 -46
- package/server/modules/orchestration/a2a/routes.ts +586 -586
- package/server/modules/orchestration/a2a/task-dispatcher.ts +345 -345
- package/server/modules/orchestration/a2a/task-store.ts +178 -178
- package/server/modules/orchestration/a2a/types.ts +126 -126
- package/server/modules/orchestration/a2a/validator.ts +113 -113
- package/server/modules/orchestration/index.ts +99 -99
- package/server/modules/orchestration/preview/port-watcher.ts +112 -112
- package/server/modules/orchestration/preview/preview-proxy.ts +60 -60
- package/server/modules/orchestration/preview/types.ts +19 -19
- package/server/modules/orchestration/security/permission-policy.ts +401 -401
- package/server/modules/orchestration/tasks/orchestration-task-store.ts +41 -41
- package/server/modules/orchestration/tasks/orchestration-task.routes.ts +81 -81
- package/server/modules/orchestration/tasks/orchestration-task.service.ts +201 -201
- package/server/modules/orchestration/tasks/orchestration-task.types.ts +40 -40
- package/server/modules/orchestration/tasks/task-run-graph.ts +155 -155
- package/server/modules/orchestration/workflows/approval-queue.ts +106 -106
- package/server/modules/orchestration/workflows/built-in-workflows.ts +127 -127
- package/server/modules/orchestration/workflows/context-packet.ts +186 -186
- package/server/modules/orchestration/workflows/handoff-artifact.ts +175 -175
- package/server/modules/orchestration/workflows/workflow-fallback-policy.ts +161 -161
- package/server/modules/orchestration/workflows/workflow-replay.ts +254 -254
- package/server/modules/orchestration/workflows/workflow-runner.ts +2062 -2062
- package/server/modules/orchestration/workflows/workflow-store.ts +97 -97
- package/server/modules/orchestration/workflows/workflow-templates.ts +272 -272
- package/server/modules/orchestration/workflows/workflow-trace.ts +424 -424
- package/server/modules/orchestration/workflows/workflow.routes.ts +586 -586
- package/server/modules/orchestration/workflows/workflow.types.ts +111 -111
- package/server/modules/orchestration/workflows/workspace-target.ts +122 -122
- package/server/modules/orchestration/workspace/docker-workspace.ts +136 -136
- package/server/modules/orchestration/workspace/path-safety.ts +55 -55
- package/server/modules/orchestration/workspace/types.ts +52 -52
- package/server/modules/orchestration/workspace/workspace-manager.ts +102 -102
- package/server/modules/orchestration/workspace/worktree-workspace.ts +126 -126
- package/server/modules/providers/index.ts +2 -2
- package/server/modules/providers/list/claude/claude-auth.provider.ts +146 -146
- package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -135
- package/server/modules/providers/list/claude/claude-sessions.provider.ts +306 -306
- package/server/modules/providers/list/claude/claude.provider.ts +15 -15
- package/server/modules/providers/list/codex/codex-auth.provider.ts +117 -117
- package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -135
- package/server/modules/providers/list/codex/codex-sessions.provider.ts +319 -319
- package/server/modules/providers/list/codex/codex.provider.ts +15 -15
- package/server/modules/providers/list/cursor/cursor-auth.provider.ts +147 -147
- package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -108
- package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +421 -421
- package/server/modules/providers/list/cursor/cursor.provider.ts +15 -15
- package/server/modules/providers/list/gemini/gemini-auth.provider.ts +173 -173
- package/server/modules/providers/list/gemini/gemini-mcp.provider.ts +110 -110
- package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +227 -227
- package/server/modules/providers/list/gemini/gemini.provider.ts +15 -15
- package/server/modules/providers/list/opencode/opencode-auth.provider.ts +131 -131
- package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +286 -286
- package/server/modules/providers/list/qwen/qwen-auth.provider.ts +146 -146
- package/server/modules/providers/list/qwen/qwen-sessions.provider.ts +265 -265
- package/server/modules/providers/provider.registry.ts +40 -40
- package/server/modules/providers/provider.routes.ts +982 -982
- package/server/modules/providers/services/mcp.service.ts +86 -86
- package/server/modules/providers/services/provider-auth.service.ts +26 -26
- package/server/modules/providers/services/sessions.service.ts +45 -45
- package/server/modules/providers/shared/base/abstract.provider.ts +20 -20
- package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -151
- package/server/modules/providers/tests/mcp.test.ts +293 -293
- package/server/openai-codex.js +468 -468
- package/server/opencode-cli.js +491 -491
- package/server/opencode-response-handler.js +111 -111
- package/server/projects.js +3125 -3125
- package/server/qwen-code-cli.js +410 -410
- package/server/routes/agent.js +1451 -1451
- package/server/routes/auth.js +298 -286
- package/server/routes/codex.js +20 -20
- package/server/routes/commands.js +581 -581
- package/server/routes/cursor.js +61 -61
- package/server/routes/diagnostics.js +44 -44
- package/server/routes/gemini.js +25 -25
- package/server/routes/git.js +1822 -1822
- package/server/routes/live-view.js +434 -434
- package/server/routes/mcp-utils.js +13 -13
- package/server/routes/messages.js +97 -97
- package/server/routes/network.js +143 -143
- package/server/routes/platformization.js +231 -231
- package/server/routes/plugins.js +690 -690
- package/server/routes/production-agent-loop.js +90 -90
- package/server/routes/projects.js +918 -918
- package/server/routes/public-api.js +34 -34
- package/server/routes/qwen.js +27 -27
- package/server/routes/remote.js +56 -56
- package/server/routes/settings.js +321 -321
- package/server/routes/telegram.js +163 -163
- package/server/routes/user.js +125 -125
- package/server/routes/webhooks.js +63 -63
- package/server/services/control-room.js +102 -102
- package/server/services/diagnostics.js +165 -165
- package/server/services/external-access.js +403 -403
- package/server/services/install-jobs.js +715 -715
- package/server/services/live-view.js +956 -956
- package/server/services/managed-runtimes.js +493 -493
- package/server/services/model-registry.js +144 -144
- package/server/services/notification-orchestrator.js +365 -365
- package/server/services/notification-taxonomy.js +204 -204
- package/server/services/platformization.js +1052 -1052
- package/server/services/production-agent-loop.js +248 -248
- package/server/services/provider-cli-versions.js +149 -149
- package/server/services/provider-credentials.js +189 -189
- package/server/services/provider-models.js +396 -396
- package/server/services/public-api-manifest.js +181 -181
- package/server/services/qr-login.js +126 -126
- package/server/services/remote-connection.js +127 -127
- package/server/services/runtime-manager.js +323 -323
- package/server/services/startup-update.js +259 -259
- package/server/services/telegram/bot.js +393 -393
- package/server/services/telegram/control-center.js +2453 -2453
- package/server/services/telegram/telegram-gateway.js +314 -314
- package/server/services/telegram/telegram-http-client.js +201 -201
- package/server/services/telegram/translations.js +470 -470
- package/server/services/webhooks.js +216 -216
- package/server/sessionManager.js +225 -225
- package/server/setup-wizard.js +283 -283
- package/server/shared/interfaces.ts +54 -54
- package/server/shared/types.ts +172 -172
- package/server/shared/utils.ts +193 -193
- package/server/tsconfig.json +36 -36
- package/server/utils/colors.js +21 -21
- package/server/utils/commandParser.js +305 -305
- package/server/utils/frontmatter.js +18 -18
- package/server/utils/gitConfig.js +34 -34
- package/server/utils/plugin-loader.js +461 -461
- package/server/utils/plugin-process-manager.js +185 -185
- package/server/utils/port-access.js +227 -227
- package/server/utils/runtime-paths.js +37 -37
- package/server/utils/security-log.js +84 -84
- package/server/utils/url-detection.js +71 -71
- package/server/vite-daemon.js +79 -79
- package/shared/modelConstants.js +161 -161
- package/shared/networkHosts.js +22 -22
- package/dist/assets/index-DvudRU5X.css +0 -32
|
@@ -1,201 +1,201 @@
|
|
|
1
|
-
import { EventEmitter } from 'node:events';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Minimal Telegram Bot API client.
|
|
5
|
-
*
|
|
6
|
-
* Replaces `node-telegram-bot-api` which pulled in the deprecated
|
|
7
|
-
* `request` / `har-validator` / `uuid@3` chain (~30 transitive packages,
|
|
8
|
-
* npm install warnings on every fresh box). The Bot API itself is just
|
|
9
|
-
* HTTP, and we only use a few endpoints (getUpdates polling + sendMessage +
|
|
10
|
-
* callback answers + message edits),
|
|
11
|
-
* so 100 lines of fetch is all that's needed. Exposes the same surface
|
|
12
|
-
* the bot.js consumer relied on: `getMe()`, `sendMessage()`,
|
|
13
|
-
* `editMessageText()`, `answerCallbackQuery()`,
|
|
14
|
-
* `on('message'|'callback_query'|'polling_error')`, `stopPolling()`.
|
|
15
|
-
*
|
|
16
|
-
* No third-party deps — uses Node 22's built-in `fetch`.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
const API_BASE = 'https://api.telegram.org/bot';
|
|
20
|
-
|
|
21
|
-
class TelegramApiError extends Error {
|
|
22
|
-
constructor(method, body, httpStatus) {
|
|
23
|
-
const description = body?.description || `HTTP ${httpStatus}`;
|
|
24
|
-
super(`Telegram ${method} failed: ${description}`);
|
|
25
|
-
this.name = 'TelegramApiError';
|
|
26
|
-
this.method = method;
|
|
27
|
-
this.httpStatus = httpStatus;
|
|
28
|
-
// Mirror the shape node-telegram-bot-api exposed so upstream error
|
|
29
|
-
// handling (401/409 checks in bot.js) keeps working unchanged.
|
|
30
|
-
this.response = { statusCode: httpStatus, body };
|
|
31
|
-
this.code = body?.error_code || httpStatus;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Call a Bot API method by name. Returns the `result` field on success,
|
|
37
|
-
* throws a TelegramApiError otherwise.
|
|
38
|
-
*/
|
|
39
|
-
async function callApi(token, method, params, { signal } = {}) {
|
|
40
|
-
const url = `${API_BASE}${token}/${method}`;
|
|
41
|
-
const res = await fetch(url, {
|
|
42
|
-
method: 'POST',
|
|
43
|
-
headers: { 'Content-Type': 'application/json' },
|
|
44
|
-
body: JSON.stringify(params || {}),
|
|
45
|
-
signal,
|
|
46
|
-
});
|
|
47
|
-
let body;
|
|
48
|
-
try { body = await res.json(); } catch { body = null; }
|
|
49
|
-
if (!res.ok || !body?.ok) {
|
|
50
|
-
throw new TelegramApiError(method, body, res.status);
|
|
51
|
-
}
|
|
52
|
-
return body.result;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export class TelegramHttpBot extends EventEmitter {
|
|
56
|
-
constructor(token, { polling = true, pollTimeoutSec = 30, pollLimit = 25, dropPendingUpdates = true } = {}) {
|
|
57
|
-
super();
|
|
58
|
-
if (!token) throw new Error('TelegramHttpBot: token is required');
|
|
59
|
-
this._token = token;
|
|
60
|
-
this._pollTimeoutSec = pollTimeoutSec;
|
|
61
|
-
this._pollLimit = pollLimit;
|
|
62
|
-
this._dropPendingUpdates = dropPendingUpdates;
|
|
63
|
-
this._offset = 0;
|
|
64
|
-
this._polling = false;
|
|
65
|
-
this._abortController = null;
|
|
66
|
-
this._pollingLoop = null;
|
|
67
|
-
this._pollingErrorCount = 0;
|
|
68
|
-
if (polling) this.startPolling();
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// ---------- Public API (mirrors node-telegram-bot-api surface) ----------
|
|
72
|
-
|
|
73
|
-
async getMe() {
|
|
74
|
-
return callApi(this._token, 'getMe', {});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
async sendMessage(chatId, text, extra = {}) {
|
|
78
|
-
return callApi(this._token, 'sendMessage', {
|
|
79
|
-
chat_id: chatId,
|
|
80
|
-
text,
|
|
81
|
-
...extra,
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async editMessageText(text, extra = {}) {
|
|
86
|
-
return callApi(this._token, 'editMessageText', {
|
|
87
|
-
text,
|
|
88
|
-
...extra,
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
async answerCallbackQuery(callbackQueryId, extra = {}) {
|
|
93
|
-
return callApi(this._token, 'answerCallbackQuery', {
|
|
94
|
-
callback_query_id: callbackQueryId,
|
|
95
|
-
...extra,
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async stopPolling(_opts = {}) {
|
|
100
|
-
this._polling = false;
|
|
101
|
-
try { this._abortController?.abort(); } catch { /* ignore */ }
|
|
102
|
-
this._abortController = null;
|
|
103
|
-
if (this._pollingLoop) {
|
|
104
|
-
await this._pollingLoop.catch(() => {});
|
|
105
|
-
this._pollingLoop = null;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// ---------- Polling loop ----------
|
|
110
|
-
|
|
111
|
-
async startPolling({ dropPendingUpdates = this._dropPendingUpdates } = {}) {
|
|
112
|
-
if (this._polling) return;
|
|
113
|
-
this._polling = true;
|
|
114
|
-
this._pollingLoop = this._runPollingLoop({ dropPendingUpdates });
|
|
115
|
-
await Promise.resolve();
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
async _dropPendingUpdatesBeforePolling() {
|
|
119
|
-
try {
|
|
120
|
-
await callApi(this._token, 'deleteWebhook', { drop_pending_updates: true });
|
|
121
|
-
return;
|
|
122
|
-
} catch (err) {
|
|
123
|
-
this.emit('polling_error', err);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Fallback for environments where deleteWebhook is rejected: a negative
|
|
127
|
-
// offset asks Telegram to forget older queued updates.
|
|
128
|
-
try {
|
|
129
|
-
const updates = await callApi(this._token, 'getUpdates', {
|
|
130
|
-
offset: -1,
|
|
131
|
-
limit: 1,
|
|
132
|
-
timeout: 0,
|
|
133
|
-
allowed_updates: ['message', 'callback_query'],
|
|
134
|
-
});
|
|
135
|
-
const lastUpdate = Array.isArray(updates) ? updates.at(-1) : null;
|
|
136
|
-
if (typeof lastUpdate?.update_id === 'number') {
|
|
137
|
-
this._offset = lastUpdate.update_id + 1;
|
|
138
|
-
}
|
|
139
|
-
} catch (err) {
|
|
140
|
-
this.emit('polling_error', err);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
async _emitSerial(eventName, payload) {
|
|
145
|
-
const listeners = this.listeners(eventName);
|
|
146
|
-
for (const listener of listeners) {
|
|
147
|
-
try {
|
|
148
|
-
await listener(payload);
|
|
149
|
-
} catch (err) {
|
|
150
|
-
this.emit('polling_error', err);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
async _runPollingLoop({ dropPendingUpdates }) {
|
|
156
|
-
if (dropPendingUpdates) {
|
|
157
|
-
await this._dropPendingUpdatesBeforePolling();
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Each iteration long-polls getUpdates for up to pollTimeoutSec, then
|
|
161
|
-
// loops immediately. We deliberately serialize update handling because a
|
|
162
|
-
// stale Telegram backlog can otherwise fan out into many expensive scans.
|
|
163
|
-
while (this._polling) {
|
|
164
|
-
this._abortController = new AbortController();
|
|
165
|
-
try {
|
|
166
|
-
const updates = await callApi(
|
|
167
|
-
this._token,
|
|
168
|
-
'getUpdates',
|
|
169
|
-
{
|
|
170
|
-
offset: this._offset,
|
|
171
|
-
limit: this._pollLimit,
|
|
172
|
-
timeout: this._pollTimeoutSec,
|
|
173
|
-
allowed_updates: ['message', 'callback_query'],
|
|
174
|
-
},
|
|
175
|
-
{ signal: this._abortController.signal },
|
|
176
|
-
);
|
|
177
|
-
for (const update of updates) {
|
|
178
|
-
if (typeof update.update_id === 'number') {
|
|
179
|
-
this._offset = Math.max(this._offset, update.update_id + 1);
|
|
180
|
-
}
|
|
181
|
-
if (update.message) {
|
|
182
|
-
await this._emitSerial('message', update.message);
|
|
183
|
-
}
|
|
184
|
-
if (update.callback_query) {
|
|
185
|
-
await this._emitSerial('callback_query', update.callback_query);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
this._pollingErrorCount = 0;
|
|
189
|
-
} catch (err) {
|
|
190
|
-
// AbortError is the expected path when stopPolling() is called.
|
|
191
|
-
if (err?.name === 'AbortError' || !this._polling) break;
|
|
192
|
-
this.emit('polling_error', err);
|
|
193
|
-
const status = err?.response?.statusCode || err?.code;
|
|
194
|
-
const baseDelay = status === 409 ? 2000 : 1000;
|
|
195
|
-
const delay = Math.min(60_000, baseDelay * 2 ** this._pollingErrorCount);
|
|
196
|
-
this._pollingErrorCount = Math.min(this._pollingErrorCount + 1, 6);
|
|
197
|
-
await new Promise((r) => setTimeout(r, delay));
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Minimal Telegram Bot API client.
|
|
5
|
+
*
|
|
6
|
+
* Replaces `node-telegram-bot-api` which pulled in the deprecated
|
|
7
|
+
* `request` / `har-validator` / `uuid@3` chain (~30 transitive packages,
|
|
8
|
+
* npm install warnings on every fresh box). The Bot API itself is just
|
|
9
|
+
* HTTP, and we only use a few endpoints (getUpdates polling + sendMessage +
|
|
10
|
+
* callback answers + message edits),
|
|
11
|
+
* so 100 lines of fetch is all that's needed. Exposes the same surface
|
|
12
|
+
* the bot.js consumer relied on: `getMe()`, `sendMessage()`,
|
|
13
|
+
* `editMessageText()`, `answerCallbackQuery()`,
|
|
14
|
+
* `on('message'|'callback_query'|'polling_error')`, `stopPolling()`.
|
|
15
|
+
*
|
|
16
|
+
* No third-party deps — uses Node 22's built-in `fetch`.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const API_BASE = 'https://api.telegram.org/bot';
|
|
20
|
+
|
|
21
|
+
class TelegramApiError extends Error {
|
|
22
|
+
constructor(method, body, httpStatus) {
|
|
23
|
+
const description = body?.description || `HTTP ${httpStatus}`;
|
|
24
|
+
super(`Telegram ${method} failed: ${description}`);
|
|
25
|
+
this.name = 'TelegramApiError';
|
|
26
|
+
this.method = method;
|
|
27
|
+
this.httpStatus = httpStatus;
|
|
28
|
+
// Mirror the shape node-telegram-bot-api exposed so upstream error
|
|
29
|
+
// handling (401/409 checks in bot.js) keeps working unchanged.
|
|
30
|
+
this.response = { statusCode: httpStatus, body };
|
|
31
|
+
this.code = body?.error_code || httpStatus;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Call a Bot API method by name. Returns the `result` field on success,
|
|
37
|
+
* throws a TelegramApiError otherwise.
|
|
38
|
+
*/
|
|
39
|
+
async function callApi(token, method, params, { signal } = {}) {
|
|
40
|
+
const url = `${API_BASE}${token}/${method}`;
|
|
41
|
+
const res = await fetch(url, {
|
|
42
|
+
method: 'POST',
|
|
43
|
+
headers: { 'Content-Type': 'application/json' },
|
|
44
|
+
body: JSON.stringify(params || {}),
|
|
45
|
+
signal,
|
|
46
|
+
});
|
|
47
|
+
let body;
|
|
48
|
+
try { body = await res.json(); } catch { body = null; }
|
|
49
|
+
if (!res.ok || !body?.ok) {
|
|
50
|
+
throw new TelegramApiError(method, body, res.status);
|
|
51
|
+
}
|
|
52
|
+
return body.result;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class TelegramHttpBot extends EventEmitter {
|
|
56
|
+
constructor(token, { polling = true, pollTimeoutSec = 30, pollLimit = 25, dropPendingUpdates = true } = {}) {
|
|
57
|
+
super();
|
|
58
|
+
if (!token) throw new Error('TelegramHttpBot: token is required');
|
|
59
|
+
this._token = token;
|
|
60
|
+
this._pollTimeoutSec = pollTimeoutSec;
|
|
61
|
+
this._pollLimit = pollLimit;
|
|
62
|
+
this._dropPendingUpdates = dropPendingUpdates;
|
|
63
|
+
this._offset = 0;
|
|
64
|
+
this._polling = false;
|
|
65
|
+
this._abortController = null;
|
|
66
|
+
this._pollingLoop = null;
|
|
67
|
+
this._pollingErrorCount = 0;
|
|
68
|
+
if (polling) this.startPolling();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ---------- Public API (mirrors node-telegram-bot-api surface) ----------
|
|
72
|
+
|
|
73
|
+
async getMe() {
|
|
74
|
+
return callApi(this._token, 'getMe', {});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async sendMessage(chatId, text, extra = {}) {
|
|
78
|
+
return callApi(this._token, 'sendMessage', {
|
|
79
|
+
chat_id: chatId,
|
|
80
|
+
text,
|
|
81
|
+
...extra,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async editMessageText(text, extra = {}) {
|
|
86
|
+
return callApi(this._token, 'editMessageText', {
|
|
87
|
+
text,
|
|
88
|
+
...extra,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async answerCallbackQuery(callbackQueryId, extra = {}) {
|
|
93
|
+
return callApi(this._token, 'answerCallbackQuery', {
|
|
94
|
+
callback_query_id: callbackQueryId,
|
|
95
|
+
...extra,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async stopPolling(_opts = {}) {
|
|
100
|
+
this._polling = false;
|
|
101
|
+
try { this._abortController?.abort(); } catch { /* ignore */ }
|
|
102
|
+
this._abortController = null;
|
|
103
|
+
if (this._pollingLoop) {
|
|
104
|
+
await this._pollingLoop.catch(() => {});
|
|
105
|
+
this._pollingLoop = null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ---------- Polling loop ----------
|
|
110
|
+
|
|
111
|
+
async startPolling({ dropPendingUpdates = this._dropPendingUpdates } = {}) {
|
|
112
|
+
if (this._polling) return;
|
|
113
|
+
this._polling = true;
|
|
114
|
+
this._pollingLoop = this._runPollingLoop({ dropPendingUpdates });
|
|
115
|
+
await Promise.resolve();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async _dropPendingUpdatesBeforePolling() {
|
|
119
|
+
try {
|
|
120
|
+
await callApi(this._token, 'deleteWebhook', { drop_pending_updates: true });
|
|
121
|
+
return;
|
|
122
|
+
} catch (err) {
|
|
123
|
+
this.emit('polling_error', err);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Fallback for environments where deleteWebhook is rejected: a negative
|
|
127
|
+
// offset asks Telegram to forget older queued updates.
|
|
128
|
+
try {
|
|
129
|
+
const updates = await callApi(this._token, 'getUpdates', {
|
|
130
|
+
offset: -1,
|
|
131
|
+
limit: 1,
|
|
132
|
+
timeout: 0,
|
|
133
|
+
allowed_updates: ['message', 'callback_query'],
|
|
134
|
+
});
|
|
135
|
+
const lastUpdate = Array.isArray(updates) ? updates.at(-1) : null;
|
|
136
|
+
if (typeof lastUpdate?.update_id === 'number') {
|
|
137
|
+
this._offset = lastUpdate.update_id + 1;
|
|
138
|
+
}
|
|
139
|
+
} catch (err) {
|
|
140
|
+
this.emit('polling_error', err);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async _emitSerial(eventName, payload) {
|
|
145
|
+
const listeners = this.listeners(eventName);
|
|
146
|
+
for (const listener of listeners) {
|
|
147
|
+
try {
|
|
148
|
+
await listener(payload);
|
|
149
|
+
} catch (err) {
|
|
150
|
+
this.emit('polling_error', err);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async _runPollingLoop({ dropPendingUpdates }) {
|
|
156
|
+
if (dropPendingUpdates) {
|
|
157
|
+
await this._dropPendingUpdatesBeforePolling();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Each iteration long-polls getUpdates for up to pollTimeoutSec, then
|
|
161
|
+
// loops immediately. We deliberately serialize update handling because a
|
|
162
|
+
// stale Telegram backlog can otherwise fan out into many expensive scans.
|
|
163
|
+
while (this._polling) {
|
|
164
|
+
this._abortController = new AbortController();
|
|
165
|
+
try {
|
|
166
|
+
const updates = await callApi(
|
|
167
|
+
this._token,
|
|
168
|
+
'getUpdates',
|
|
169
|
+
{
|
|
170
|
+
offset: this._offset,
|
|
171
|
+
limit: this._pollLimit,
|
|
172
|
+
timeout: this._pollTimeoutSec,
|
|
173
|
+
allowed_updates: ['message', 'callback_query'],
|
|
174
|
+
},
|
|
175
|
+
{ signal: this._abortController.signal },
|
|
176
|
+
);
|
|
177
|
+
for (const update of updates) {
|
|
178
|
+
if (typeof update.update_id === 'number') {
|
|
179
|
+
this._offset = Math.max(this._offset, update.update_id + 1);
|
|
180
|
+
}
|
|
181
|
+
if (update.message) {
|
|
182
|
+
await this._emitSerial('message', update.message);
|
|
183
|
+
}
|
|
184
|
+
if (update.callback_query) {
|
|
185
|
+
await this._emitSerial('callback_query', update.callback_query);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
this._pollingErrorCount = 0;
|
|
189
|
+
} catch (err) {
|
|
190
|
+
// AbortError is the expected path when stopPolling() is called.
|
|
191
|
+
if (err?.name === 'AbortError' || !this._polling) break;
|
|
192
|
+
this.emit('polling_error', err);
|
|
193
|
+
const status = err?.response?.statusCode || err?.code;
|
|
194
|
+
const baseDelay = status === 409 ? 2000 : 1000;
|
|
195
|
+
const delay = Math.min(60_000, baseDelay * 2 ** this._pollingErrorCount);
|
|
196
|
+
this._pollingErrorCount = Math.min(this._pollingErrorCount + 1, 6);
|
|
197
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|