feat: initial commit — GramJS Telegram relay for OpenClaw inject
Telegram userbot relay that monitors specified group chats and forwards bot messages to OpenClaw's inject-http endpoint via webhook. Features: - GramJS (MTProto) for reading bot messages (invisible to Bot API) - Media download + multipart form upload - BOT_EXCLUDE filter (by user ID or @username) - HTML entity formatting (bold, italic, code, pre, links, etc.) - Graceful shutdown on SIGINT/SIGTERM - .env configuration with validation
This commit is contained in:
commit
cd56658c7f
9 changed files with 1345 additions and 0 deletions
9
.env.example
Normal file
9
.env.example
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
TG_API_ID=你的api_id
|
||||||
|
TG_API_HASH=你的api_hash
|
||||||
|
TG_SESSION_NAME=intergram-js
|
||||||
|
SOURCE_CHATS=-100123456789
|
||||||
|
WEBHOOK_URL=http://openclaw-gateway:18789/telegram/inject
|
||||||
|
INJECT_TOKEN=optional_bearer_token
|
||||||
|
ACCOUNT_ID=your_account_id
|
||||||
|
MAX_MEDIA_SIZE=52428800
|
||||||
|
BOT_EXCLUDE=133770478,@BaldEagleBot
|
||||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
node_modules/
|
||||||
|
.env
|
||||||
|
*.session
|
||||||
27
CLAUDE.md
Normal file
27
CLAUDE.md
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Intergram-JS - GramJS Telegram Relay
|
||||||
|
|
||||||
|
Telegram userbot,監聽指定群組訊息並轉發到 Webhook endpoint。
|
||||||
|
GramJS (Node.js) 版本,對標 Python Telethon 版 intergram。
|
||||||
|
|
||||||
|
## 技術棧
|
||||||
|
|
||||||
|
- Node.js >= 22 (ESM)
|
||||||
|
- telegram (GramJS) - Telegram userbot client
|
||||||
|
- 原生 fetch + FormData (Node 22+ 內建)
|
||||||
|
|
||||||
|
## 常用指令
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 安裝依賴
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# 啟動
|
||||||
|
node main.js
|
||||||
|
```
|
||||||
|
|
||||||
|
## 架構
|
||||||
|
|
||||||
|
- `main.js` - 入口點
|
||||||
|
- `src/config.js` - 環境變數載入與驗證
|
||||||
|
- `src/formatter.js` - Telegram Message → Webhook JSON 轉換
|
||||||
|
- `src/relay.js` - GramJS 事件監聽 + fetch 轉發
|
||||||
6
main.js
Normal file
6
main.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { run } from "./src/relay.js";
|
||||||
|
|
||||||
|
run().catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
855
package-lock.json
generated
Normal file
855
package-lock.json
generated
Normal file
|
|
@ -0,0 +1,855 @@
|
||||||
|
{
|
||||||
|
"name": "intergram-js",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "intergram-js",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"input": "^1.0.1",
|
||||||
|
"telegram": "^2.26.22"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cryptography/aes": {
|
||||||
|
"version": "0.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cryptography/aes/-/aes-0.1.1.tgz",
|
||||||
|
"integrity": "sha512-PcYz4FDGblO6tM2kSC+VzhhK62vml6k6/YAkiWtyPvrgJVfnDRoHGDtKn5UiaRRUrvUTTocBpvc2rRgTCqxjsg==",
|
||||||
|
"license": "GPL-3.0-or-later"
|
||||||
|
},
|
||||||
|
"node_modules/ansi-escapes": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-wiXutNjDUlNEDWHcYH3jtZUhd3c4/VojassD8zHdHCY13xbZy2XbW+NKQwA0tWGBVzDA9qEzYwfoSsWmviidhw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ansi-regex": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ansi-styles": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/async-mutex": {
|
||||||
|
"version": "0.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.3.2.tgz",
|
||||||
|
"integrity": "sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/babel-runtime": {
|
||||||
|
"version": "6.26.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
|
||||||
|
"integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"core-js": "^2.4.0",
|
||||||
|
"regenerator-runtime": "^0.11.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/base64-js": {
|
||||||
|
"version": "1.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||||
|
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/big-integer": {
|
||||||
|
"version": "1.6.52",
|
||||||
|
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz",
|
||||||
|
"integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==",
|
||||||
|
"license": "Unlicense",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/buffer": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"base64-js": "^1.3.1",
|
||||||
|
"ieee754": "^1.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/bufferutil": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"node-gyp-build": "^4.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.14.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/chalk": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^2.2.1",
|
||||||
|
"escape-string-regexp": "^1.0.2",
|
||||||
|
"has-ansi": "^2.0.0",
|
||||||
|
"strip-ansi": "^3.0.0",
|
||||||
|
"supports-color": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cli-cursor": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-25tABq090YNKkF6JH7lcwO0zFJTRke4Jcq9iX2nr/Sz0Cjjv4gckmwlW6Ty/aoyFd6z3ysR2hMGC2GFugmBo6A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"restore-cursor": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cli-width": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/code-point-at": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/core-js": {
|
||||||
|
"version": "2.6.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
|
||||||
|
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
|
||||||
|
"deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/d": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"es5-ext": "^0.10.64",
|
||||||
|
"type": "^2.7.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dom-serializer": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.0.1",
|
||||||
|
"domhandler": "^4.2.0",
|
||||||
|
"entities": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/domelementtype": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/fb55"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "BSD-2-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/domhandler": {
|
||||||
|
"version": "4.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
|
||||||
|
"integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/domutils": {
|
||||||
|
"version": "2.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
|
||||||
|
"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"dom-serializer": "^1.0.1",
|
||||||
|
"domelementtype": "^2.2.0",
|
||||||
|
"domhandler": "^4.2.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/entities": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es5-ext": {
|
||||||
|
"version": "0.10.64",
|
||||||
|
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz",
|
||||||
|
"integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"es6-iterator": "^2.0.3",
|
||||||
|
"es6-symbol": "^3.1.3",
|
||||||
|
"esniff": "^2.0.1",
|
||||||
|
"next-tick": "^1.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es6-iterator": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"d": "1",
|
||||||
|
"es5-ext": "^0.10.35",
|
||||||
|
"es6-symbol": "^3.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es6-symbol": {
|
||||||
|
"version": "3.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz",
|
||||||
|
"integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d": "^1.0.2",
|
||||||
|
"ext": "^1.7.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/escape-string-regexp": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/esniff": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d": "^1.0.1",
|
||||||
|
"es5-ext": "^0.10.62",
|
||||||
|
"event-emitter": "^0.3.5",
|
||||||
|
"type": "^2.7.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/event-emitter": {
|
||||||
|
"version": "0.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
|
||||||
|
"integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"d": "1",
|
||||||
|
"es5-ext": "~0.10.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/exit-hook": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-MsG3prOVw1WtLXAZbM3KiYtooKR1LvxHh3VHsVtIy0uiUu8usxgB/94DP2HxtD/661lLdB6yzQ09lGJSQr6nkg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ext": {
|
||||||
|
"version": "1.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
|
||||||
|
"integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"type": "^2.7.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/figures": {
|
||||||
|
"version": "1.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
|
||||||
|
"integrity": "sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"escape-string-regexp": "^1.0.5",
|
||||||
|
"object-assign": "^4.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/graceful-fs": {
|
||||||
|
"version": "4.2.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||||
|
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/has-ansi": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/htmlparser2": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/fb55/htmlparser2?sponsor=1",
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/fb55"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.0.1",
|
||||||
|
"domhandler": "^4.0.0",
|
||||||
|
"domutils": "^2.5.2",
|
||||||
|
"entities": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ieee754": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/imurmurhash": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
||||||
|
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8.19"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/input": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/input/-/input-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-5DKQKQ7Nm/CaPGYKF74uUvk5ftC3S04fLYWcDrNG2rOVhhRgB4E2J8JNb7AAh+RlQ/954ukas4bEbrRQ3/kPGA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"babel-runtime": "^6.6.1",
|
||||||
|
"chalk": "^1.1.1",
|
||||||
|
"inquirer": "^0.12.0",
|
||||||
|
"lodash": "^4.6.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/inquirer": {
|
||||||
|
"version": "0.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz",
|
||||||
|
"integrity": "sha512-bOetEz5+/WpgaW4D1NYOk1aD+JCqRjqu/FwRFgnIfiP7FC/zinsrfyO1vlS3nyH/R7S0IH3BIHBu4DBIDSqiGQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-escapes": "^1.1.0",
|
||||||
|
"ansi-regex": "^2.0.0",
|
||||||
|
"chalk": "^1.0.0",
|
||||||
|
"cli-cursor": "^1.0.1",
|
||||||
|
"cli-width": "^2.0.0",
|
||||||
|
"figures": "^1.3.5",
|
||||||
|
"lodash": "^4.3.0",
|
||||||
|
"readline2": "^1.0.1",
|
||||||
|
"run-async": "^0.1.0",
|
||||||
|
"rx-lite": "^3.1.2",
|
||||||
|
"string-width": "^1.0.1",
|
||||||
|
"strip-ansi": "^3.0.0",
|
||||||
|
"through": "^2.3.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ip-address": {
|
||||||
|
"version": "10.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz",
|
||||||
|
"integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-fullwidth-code-point": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"number-is-nan": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-typedarray": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash": {
|
||||||
|
"version": "4.17.23",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
|
||||||
|
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/mime": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"mime": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/mute-stream": {
|
||||||
|
"version": "0.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz",
|
||||||
|
"integrity": "sha512-EbrziT4s8cWPmzr47eYVW3wimS4HsvlnV5ri1xw1aR6JQo/OrJX5rkl32K/QQHdxeabJETtfeaROGhd8W7uBgg==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/next-tick": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/node-gyp-build": {
|
||||||
|
"version": "4.8.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
|
||||||
|
"integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"node-gyp-build": "bin.js",
|
||||||
|
"node-gyp-build-optional": "optional.js",
|
||||||
|
"node-gyp-build-test": "build-test.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-localstorage": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-localstorage/-/node-localstorage-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-vv8fJuOUCCvSPjDjBLlMqYMHob4aGjkmrkaE42/mZr0VT+ZAU10jRF8oTnX9+pgU9/vYJ8P7YT3Vd6ajkmzSCw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"write-file-atomic": "^1.1.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/number-is-nan": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/object-assign": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/once": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"wrappy": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/onetime": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-GZ+g4jayMqzCRMgB2sol7GiCLjKfS1PINkjmx8spcKce1LiVqcbQreXwqs2YAFXC6R03VIG28ZS31t8M866v6A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pako": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
|
||||||
|
"license": "(MIT AND Zlib)"
|
||||||
|
},
|
||||||
|
"node_modules/path-browserify": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/readline2": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-8/td4MmwUB6PkZUbV25uKz7dfrmjYWxsW8DVfibWdlHRk/l/DfHKn4pU+dfcoGLFgWOdyGCzINRQD7jn+Bv+/g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"code-point-at": "^1.0.0",
|
||||||
|
"is-fullwidth-code-point": "^1.0.0",
|
||||||
|
"mute-stream": "0.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/real-cancellable-promise": {
|
||||||
|
"version": "1.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/real-cancellable-promise/-/real-cancellable-promise-1.2.3.tgz",
|
||||||
|
"integrity": "sha512-hBI5Gy/55VEeeMtImMgEirD7eq5UmqJf1J8dFZtbJZA/3rB0pYFZ7PayMGueb6v4UtUtpKpP+05L0VwyE1hI9Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/regenerator-runtime": {
|
||||||
|
"version": "0.11.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
|
||||||
|
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/restore-cursor": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-reSjH4HuiFlxlaBaFCiS6O76ZGG2ygKoSlCsipKdaZuKSPx/+bt9mULkn4l0asVzbEfQQmXRg6Wp6gv6m0wElw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"exit-hook": "^1.0.0",
|
||||||
|
"onetime": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/run-async": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-qOX+w+IxFgpUpJfkv2oGN0+ExPs68F4sZHfaRRx4dDexAQkG83atugKVEylyT5ARees3HBbfmuvnjbrd8j9Wjw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"once": "^1.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rx-lite": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-1I1+G2gteLB8Tkt8YI1sJvSIfa0lWuRtC8GjvtyPBcLSF5jBCCJJqKrpER5JU5r6Bhe+i9/pK3VMuUcXu0kdwQ=="
|
||||||
|
},
|
||||||
|
"node_modules/slide": {
|
||||||
|
"version": "1.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz",
|
||||||
|
"integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/smart-buffer": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6.0.0",
|
||||||
|
"npm": ">= 3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/socks": {
|
||||||
|
"version": "2.8.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz",
|
||||||
|
"integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ip-address": "^10.0.1",
|
||||||
|
"smart-buffer": "^4.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0",
|
||||||
|
"npm": ">= 3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/store2": {
|
||||||
|
"version": "2.14.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/store2/-/store2-2.14.4.tgz",
|
||||||
|
"integrity": "sha512-srTItn1GOvyvOycgxjAnPA63FZNwy0PTyUBFMHRM+hVFltAeoh0LmNBz9SZqUS9mMqGk8rfyWyXn3GH5ReJ8Zw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/string-width": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"code-point-at": "^1.0.0",
|
||||||
|
"is-fullwidth-code-point": "^1.0.0",
|
||||||
|
"strip-ansi": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/strip-ansi": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/supports-color": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/telegram": {
|
||||||
|
"version": "2.26.22",
|
||||||
|
"resolved": "https://registry.npmjs.org/telegram/-/telegram-2.26.22.tgz",
|
||||||
|
"integrity": "sha512-EIj7Yrjiu0Yosa3FZ/7EyPg9s6UiTi/zDQrFmR/2Mg7pIUU+XjAit1n1u9OU9h2oRnRM5M+67/fxzQluZpaJJg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cryptography/aes": "^0.1.1",
|
||||||
|
"async-mutex": "^0.3.0",
|
||||||
|
"big-integer": "^1.6.48",
|
||||||
|
"buffer": "^6.0.3",
|
||||||
|
"htmlparser2": "^6.1.0",
|
||||||
|
"mime": "^3.0.0",
|
||||||
|
"node-localstorage": "^2.2.1",
|
||||||
|
"pako": "^2.0.3",
|
||||||
|
"path-browserify": "^1.0.1",
|
||||||
|
"real-cancellable-promise": "^1.1.1",
|
||||||
|
"socks": "^2.6.2",
|
||||||
|
"store2": "^2.13.0",
|
||||||
|
"ts-custom-error": "^3.2.0",
|
||||||
|
"websocket": "^1.0.34"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"bufferutil": "^4.0.3",
|
||||||
|
"utf-8-validate": "^5.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/through": {
|
||||||
|
"version": "2.3.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||||
|
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/ts-custom-error": {
|
||||||
|
"version": "3.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.3.1.tgz",
|
||||||
|
"integrity": "sha512-5OX1tzOjxWEgsr/YEUWSuPrQ00deKLh6D7OTWcvNHm12/7QPyRh8SYpyWvA4IZv8H/+GQWQEh/kwo95Q9OVW1A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tslib": {
|
||||||
|
"version": "2.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
|
"license": "0BSD"
|
||||||
|
},
|
||||||
|
"node_modules/type": {
|
||||||
|
"version": "2.7.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz",
|
||||||
|
"integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/typedarray-to-buffer": {
|
||||||
|
"version": "3.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
|
||||||
|
"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"is-typedarray": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/utf-8-validate": {
|
||||||
|
"version": "5.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz",
|
||||||
|
"integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"node-gyp-build": "^4.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.14.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/websocket": {
|
||||||
|
"version": "1.0.35",
|
||||||
|
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.35.tgz",
|
||||||
|
"integrity": "sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"debug": "^2.2.0",
|
||||||
|
"es5-ext": "^0.10.63",
|
||||||
|
"typedarray-to-buffer": "^3.1.5",
|
||||||
|
"utf-8-validate": "^5.0.2",
|
||||||
|
"yaeti": "^0.0.6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/wrappy": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/write-file-atomic": {
|
||||||
|
"version": "1.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz",
|
||||||
|
"integrity": "sha512-SdrHoC/yVBPpV0Xq/mUZQIpW2sWXAShb/V4pomcJXh92RuaO+f3UTWItiR3Px+pLnV2PvC2/bfn5cwr5X6Vfxw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"graceful-fs": "^4.1.11",
|
||||||
|
"imurmurhash": "^0.1.4",
|
||||||
|
"slide": "^1.1.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/yaeti": {
|
||||||
|
"version": "0.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
|
||||||
|
"integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==",
|
||||||
|
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.32"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
package.json
Normal file
13
package.json
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"name": "intergram-js",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"main": "main.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node main.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"telegram": "^2.26.22",
|
||||||
|
"input": "^1.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
70
src/config.js
Normal file
70
src/config.js
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
import { readFileSync, existsSync } from "fs";
|
||||||
|
import { resolve, dirname } from "path";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
function loadDotenv() {
|
||||||
|
const envPath = resolve(__dirname, "..", ".env");
|
||||||
|
if (!existsSync(envPath)) return;
|
||||||
|
for (const raw of readFileSync(envPath, "utf8").split("\n")) {
|
||||||
|
const line = raw.trim();
|
||||||
|
if (!line || line.startsWith("#")) continue;
|
||||||
|
const idx = line.indexOf("=");
|
||||||
|
if (idx === -1) continue;
|
||||||
|
const key = line.slice(0, idx).trim();
|
||||||
|
const value = line.slice(idx + 1).trim();
|
||||||
|
if (key && !(key in process.env)) {
|
||||||
|
process.env[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadDotenv();
|
||||||
|
|
||||||
|
function requireEnv(name) {
|
||||||
|
const val = process.env[name];
|
||||||
|
if (!val) {
|
||||||
|
console.error(`Missing required environment variable: ${name}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const API_ID = parseInt(requireEnv("TG_API_ID"), 10);
|
||||||
|
export const API_HASH = requireEnv("TG_API_HASH");
|
||||||
|
export const SESSION_NAME = process.env.TG_SESSION_NAME || "intergram-js";
|
||||||
|
|
||||||
|
export const SOURCE_CHATS = requireEnv("SOURCE_CHATS")
|
||||||
|
.split(",")
|
||||||
|
.map((c) => parseInt(c.trim(), 10));
|
||||||
|
|
||||||
|
export const WEBHOOK_URL = requireEnv("WEBHOOK_URL");
|
||||||
|
export const INJECT_TOKEN = process.env.INJECT_TOKEN || "";
|
||||||
|
export const ACCOUNT_ID = process.env.ACCOUNT_ID || "";
|
||||||
|
|
||||||
|
export const MAX_MEDIA_SIZE = parseInt(
|
||||||
|
process.env.MAX_MEDIA_SIZE || String(50 * 1024 * 1024),
|
||||||
|
10,
|
||||||
|
);
|
||||||
|
|
||||||
|
// BOT_EXCLUDE="133770478,@BaldEagleBot"
|
||||||
|
// Supports numeric user IDs and @username
|
||||||
|
function parseBotExclude(raw) {
|
||||||
|
if (!raw) return { ids: new Set(), usernames: new Set() };
|
||||||
|
const ids = new Set();
|
||||||
|
const usernames = new Set();
|
||||||
|
for (const token of raw.split(",")) {
|
||||||
|
const t = token.trim();
|
||||||
|
if (!t) continue;
|
||||||
|
if (t.startsWith("@")) {
|
||||||
|
usernames.add(t.slice(1).toLowerCase());
|
||||||
|
} else {
|
||||||
|
const n = parseInt(t, 10);
|
||||||
|
if (!isNaN(n)) ids.add(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { ids, usernames };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BOT_EXCLUDE = parseBotExclude(process.env.BOT_EXCLUDE);
|
||||||
197
src/formatter.js
Normal file
197
src/formatter.js
Normal file
|
|
@ -0,0 +1,197 @@
|
||||||
|
import { Api } from "telegram";
|
||||||
|
|
||||||
|
function escapeHtml(text) {
|
||||||
|
return text
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">")
|
||||||
|
.replace(/"/g, """);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function entitiesToHtml(text, entities) {
|
||||||
|
if (!text || !entities || entities.length === 0) {
|
||||||
|
return escapeHtml(text || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
const buf = Buffer.from(text, "utf16le");
|
||||||
|
const insertions = [];
|
||||||
|
|
||||||
|
for (const ent of entities) {
|
||||||
|
const start = ent.offset * 2;
|
||||||
|
const end = (ent.offset + ent.length) * 2;
|
||||||
|
let openTag = "";
|
||||||
|
let closeTag = "";
|
||||||
|
|
||||||
|
if (ent instanceof Api.MessageEntityBold) {
|
||||||
|
openTag = "<b>"; closeTag = "</b>";
|
||||||
|
} else if (ent instanceof Api.MessageEntityItalic) {
|
||||||
|
openTag = "<i>"; closeTag = "</i>";
|
||||||
|
} else if (ent instanceof Api.MessageEntityCode) {
|
||||||
|
openTag = "<code>"; closeTag = "</code>";
|
||||||
|
} else if (ent instanceof Api.MessageEntityPre) {
|
||||||
|
const lang = ent.language || "";
|
||||||
|
openTag = lang
|
||||||
|
? `<pre><code class="language-${escapeHtml(lang)}">`
|
||||||
|
: "<pre><code>";
|
||||||
|
closeTag = "</code></pre>";
|
||||||
|
} else if (ent instanceof Api.MessageEntityStrike) {
|
||||||
|
openTag = "<s>"; closeTag = "</s>";
|
||||||
|
} else if (ent instanceof Api.MessageEntityUnderline) {
|
||||||
|
openTag = "<u>"; closeTag = "</u>";
|
||||||
|
} else if (ent instanceof Api.MessageEntitySpoiler) {
|
||||||
|
openTag = '<span class="spoiler">'; closeTag = "</span>";
|
||||||
|
} else if (ent instanceof Api.MessageEntityTextUrl) {
|
||||||
|
openTag = `<a href="${escapeHtml(ent.url)}">`; closeTag = "</a>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (openTag) {
|
||||||
|
insertions.push({ start, end, openTag, closeTag });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build open/close maps by byte position
|
||||||
|
const opens = new Map();
|
||||||
|
const closes = new Map();
|
||||||
|
for (const { start, end, openTag, closeTag } of insertions) {
|
||||||
|
if (!opens.has(start)) opens.set(start, []);
|
||||||
|
opens.get(start).push(openTag);
|
||||||
|
if (!closes.has(end)) closes.set(end, []);
|
||||||
|
closes.get(end).unshift(closeTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
const positions = [
|
||||||
|
...new Set([...opens.keys(), ...closes.keys(), buf.length]),
|
||||||
|
].sort((a, b) => a - b);
|
||||||
|
|
||||||
|
const result = [];
|
||||||
|
let pos = 0;
|
||||||
|
|
||||||
|
for (const target of positions) {
|
||||||
|
if (target > pos) {
|
||||||
|
const chunk = buf.subarray(pos, target).toString("utf16le");
|
||||||
|
result.push(escapeHtml(chunk));
|
||||||
|
pos = target;
|
||||||
|
}
|
||||||
|
for (const tag of closes.get(target) || []) result.push(tag);
|
||||||
|
for (const tag of opens.get(target) || []) result.push(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos < buf.length) {
|
||||||
|
result.push(escapeHtml(buf.subarray(pos).toString("utf16le")));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mediaType(message) {
|
||||||
|
const media = message.media;
|
||||||
|
if (!media) return null;
|
||||||
|
if (media instanceof Api.MessageMediaPhoto) return "photo";
|
||||||
|
if (media instanceof Api.MessageMediaDocument) {
|
||||||
|
const doc = media.document;
|
||||||
|
if (doc && doc.attributes) {
|
||||||
|
for (const attr of doc.attributes) {
|
||||||
|
if (attr instanceof Api.DocumentAttributeVideo) return "video";
|
||||||
|
if (attr instanceof Api.DocumentAttributeAudio) return "audio";
|
||||||
|
if (attr instanceof Api.DocumentAttributeSticker) return "sticker";
|
||||||
|
if (attr instanceof Api.DocumentAttributeAnimated) return "animation";
|
||||||
|
}
|
||||||
|
return "document";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (media instanceof Api.MessageMediaWebPage) return "webpage";
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mediaSize(message) {
|
||||||
|
const media = message.media;
|
||||||
|
if (media instanceof Api.MessageMediaDocument && media.document) {
|
||||||
|
return Number(media.document.size || 0);
|
||||||
|
}
|
||||||
|
if (media instanceof Api.MessageMediaPhoto && media.photo) {
|
||||||
|
const sizes = media.photo.sizes || [];
|
||||||
|
for (let i = sizes.length - 1; i >= 0; i--) {
|
||||||
|
if (sizes[i].size != null) return Number(sizes[i].size);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function chatType(chat) {
|
||||||
|
if (chat instanceof Api.Channel) {
|
||||||
|
return chat.megagroup ? "supergroup" : "channel";
|
||||||
|
}
|
||||||
|
if (chat instanceof Api.Chat) return "group";
|
||||||
|
return "private";
|
||||||
|
}
|
||||||
|
|
||||||
|
function toNum(v) {
|
||||||
|
return typeof v === "bigint" ? Number(v) : v;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function formatMessage(client, message, accountId = "") {
|
||||||
|
let sender = null;
|
||||||
|
if (message.senderId) {
|
||||||
|
try { sender = await client.getEntity(message.senderId); } catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let chat = null;
|
||||||
|
try { chat = await client.getEntity(message.chatId); } catch {}
|
||||||
|
|
||||||
|
// from (sender)
|
||||||
|
const fromObj = {};
|
||||||
|
if (sender) {
|
||||||
|
fromObj.id = toNum(sender.id);
|
||||||
|
fromObj.is_bot = sender.bot || false;
|
||||||
|
fromObj.first_name = sender.firstName || "";
|
||||||
|
if (sender.lastName) fromObj.last_name = sender.lastName;
|
||||||
|
if (sender.username) fromObj.username = sender.username;
|
||||||
|
}
|
||||||
|
|
||||||
|
// chat
|
||||||
|
const chatObj = {
|
||||||
|
id: toNum(message.chatId),
|
||||||
|
type: chat ? chatType(chat) : "unknown",
|
||||||
|
};
|
||||||
|
if (chat) {
|
||||||
|
if (chat.title) chatObj.title = chat.title;
|
||||||
|
if (chat.username) chatObj.username = chat.username;
|
||||||
|
}
|
||||||
|
|
||||||
|
// message body
|
||||||
|
const text = message.message || "";
|
||||||
|
const msgObj = {
|
||||||
|
message_id: message.id,
|
||||||
|
from: fromObj,
|
||||||
|
chat: chatObj,
|
||||||
|
date: message.date,
|
||||||
|
text,
|
||||||
|
text_html: entitiesToHtml(text, message.entities),
|
||||||
|
};
|
||||||
|
|
||||||
|
// reply
|
||||||
|
if (message.replyTo) {
|
||||||
|
msgObj.reply_to_message = {
|
||||||
|
message_id: message.replyTo.replyToMsgId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// media
|
||||||
|
const mt = mediaType(message);
|
||||||
|
if (mt && mt !== "webpage") {
|
||||||
|
msgObj.media_type = mt;
|
||||||
|
msgObj.has_media = true;
|
||||||
|
msgObj.media_size = mediaSize(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
update: {
|
||||||
|
update_id: message.id,
|
||||||
|
message: msgObj,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (accountId) result.accountId = accountId;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
165
src/relay.js
Normal file
165
src/relay.js
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
import { TelegramClient, Api } from "telegram";
|
||||||
|
import { StringSession } from "telegram/sessions/index.js";
|
||||||
|
import { NewMessage } from "telegram/events/index.js";
|
||||||
|
import { createInterface } from "readline/promises";
|
||||||
|
import { readFileSync, writeFileSync, existsSync } from "fs";
|
||||||
|
import * as config from "./config.js";
|
||||||
|
import { formatMessage } from "./formatter.js";
|
||||||
|
|
||||||
|
function ts() {
|
||||||
|
return new Date().toISOString();
|
||||||
|
}
|
||||||
|
|
||||||
|
const log = {
|
||||||
|
info: (...args) => console.log(ts(), "[INFO] intergram-js:", ...args),
|
||||||
|
error: (...args) => console.error(ts(), "[ERROR] intergram-js:", ...args),
|
||||||
|
};
|
||||||
|
|
||||||
|
function loadSession() {
|
||||||
|
const file = `${config.SESSION_NAME}.session`;
|
||||||
|
if (existsSync(file)) {
|
||||||
|
return new StringSession(readFileSync(file, "utf8").trim());
|
||||||
|
}
|
||||||
|
return new StringSession("");
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveSession(client) {
|
||||||
|
const file = `${config.SESSION_NAME}.session`;
|
||||||
|
writeFileSync(file, client.session.save(), "utf8");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendWebhook(payload, mediaBytes, filename) {
|
||||||
|
const headers = {};
|
||||||
|
if (config.INJECT_TOKEN) {
|
||||||
|
headers["Authorization"] = `Bearer ${config.INJECT_TOKEN}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
let resp;
|
||||||
|
if (mediaBytes && filename) {
|
||||||
|
const form = new FormData();
|
||||||
|
form.append("payload", JSON.stringify(payload));
|
||||||
|
form.append("media", new Blob([mediaBytes]), filename);
|
||||||
|
resp = await fetch(config.WEBHOOK_URL, {
|
||||||
|
method: "POST",
|
||||||
|
headers,
|
||||||
|
body: form,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
headers["Content-Type"] = "application/json";
|
||||||
|
resp = await fetch(config.WEBHOOK_URL, {
|
||||||
|
method: "POST",
|
||||||
|
headers,
|
||||||
|
body: JSON.stringify(payload),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = await resp.text();
|
||||||
|
return [resp.status, body];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function run() {
|
||||||
|
const session = loadSession();
|
||||||
|
const client = new TelegramClient(session, config.API_ID, config.API_HASH, {
|
||||||
|
connectionRetries: 5,
|
||||||
|
});
|
||||||
|
|
||||||
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
||||||
|
|
||||||
|
await client.start({
|
||||||
|
phoneNumber: () => rl.question("Phone number: "),
|
||||||
|
password: () => rl.question("Password (2FA): "),
|
||||||
|
phoneCode: () => rl.question("Code: "),
|
||||||
|
onError: (err) => log.error("Auth error:", err),
|
||||||
|
});
|
||||||
|
|
||||||
|
rl.close();
|
||||||
|
saveSession(client);
|
||||||
|
|
||||||
|
const me = await client.getMe();
|
||||||
|
log.info(`Logged in as ${me.firstName}`);
|
||||||
|
log.info(`Listening on chats: ${config.SOURCE_CHATS}`);
|
||||||
|
log.info(`Webhook: ${config.WEBHOOK_URL}`);
|
||||||
|
|
||||||
|
client.addEventHandler(async (event) => {
|
||||||
|
const message = event.message;
|
||||||
|
|
||||||
|
// Only relay messages from bots
|
||||||
|
let sender = null;
|
||||||
|
if (message.senderId) {
|
||||||
|
try { sender = await client.getEntity(message.senderId); } catch {}
|
||||||
|
}
|
||||||
|
const username = sender?.username || "";
|
||||||
|
if (!username.toLowerCase().endsWith("bot")) return;
|
||||||
|
|
||||||
|
// Check BOT_EXCLUDE (by id or @username)
|
||||||
|
const senderId = Number(message.senderId);
|
||||||
|
if (config.BOT_EXCLUDE.ids.has(senderId)) return;
|
||||||
|
if (username && config.BOT_EXCLUDE.usernames.has(username.toLowerCase())) return;
|
||||||
|
|
||||||
|
// Format
|
||||||
|
let payload;
|
||||||
|
try {
|
||||||
|
payload = await formatMessage(client, message, config.ACCOUNT_ID);
|
||||||
|
} catch (err) {
|
||||||
|
log.error(`Failed to format message ${message.id}:`, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const msg = payload.update.message;
|
||||||
|
let mediaBytes = null;
|
||||||
|
let filename = null;
|
||||||
|
|
||||||
|
// Download media if present and within size limit
|
||||||
|
if (msg.has_media) {
|
||||||
|
if ((msg.media_size || 0) <= config.MAX_MEDIA_SIZE) {
|
||||||
|
try {
|
||||||
|
const buf = await client.downloadMedia(message);
|
||||||
|
if (buf) mediaBytes = buf;
|
||||||
|
|
||||||
|
if (message.media?.document?.attributes) {
|
||||||
|
for (const attr of message.media.document.attributes) {
|
||||||
|
if (attr instanceof Api.DocumentAttributeFilename && attr.fileName) {
|
||||||
|
filename = attr.fileName;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!filename) {
|
||||||
|
filename = `${msg.media_type || "file"}_${message.id}`;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
log.error(`Failed to download media for message ${message.id}:`, err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.info(
|
||||||
|
`Skipping media for message ${message.id}: size ${msg.media_size || 0} exceeds limit`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send webhook
|
||||||
|
try {
|
||||||
|
const [status, body] = await sendWebhook(payload, mediaBytes, filename);
|
||||||
|
const senderName = msg.from?.first_name || "?";
|
||||||
|
const textPreview = (msg.text || "").slice(0, 80);
|
||||||
|
const mediaInfo = msg.has_media ? ` [${msg.media_type}]` : "";
|
||||||
|
log.info(
|
||||||
|
`Relayed #${message.id} ${senderName}: ${textPreview}${mediaInfo} → ${status} ${status >= 400 ? body.slice(0, 120) : "OK"}`,
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
log.error(`Failed to send webhook for message ${message.id}:`, err);
|
||||||
|
}
|
||||||
|
}, new NewMessage({ chats: config.SOURCE_CHATS }));
|
||||||
|
|
||||||
|
log.info("Intergram-JS relay is running.");
|
||||||
|
|
||||||
|
// Graceful shutdown
|
||||||
|
const shutdown = async () => {
|
||||||
|
log.info("Shutting down...");
|
||||||
|
await client.disconnect();
|
||||||
|
log.info("Bye.");
|
||||||
|
process.exit(0);
|
||||||
|
};
|
||||||
|
process.on("SIGINT", shutdown);
|
||||||
|
process.on("SIGTERM", shutdown);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue