create-bunspace 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/templates/telegram-bot/CLAUDE.deploy.md +2 -3
  2. package/dist/templates/telegram-bot/CLAUDE.dev.md +304 -5
  3. package/dist/templates/telegram-bot/CLAUDE.md +166 -89
  4. package/dist/templates/telegram-bot/README.md +252 -129
  5. package/dist/templates/telegram-bot/bun.lock +146 -3
  6. package/dist/templates/telegram-bot/core/.env.example +6 -0
  7. package/dist/templates/telegram-bot/core/src/config/env.ts +130 -1
  8. package/dist/templates/telegram-bot/core/src/config/logging.ts +3 -1
  9. package/dist/templates/telegram-bot/core/src/handlers/config-export.ts +122 -0
  10. package/dist/templates/telegram-bot/core/src/handlers/control.ts +37 -11
  11. package/dist/templates/telegram-bot/core/src/handlers/health.ts +21 -26
  12. package/dist/templates/telegram-bot/core/src/handlers/info.ts +191 -0
  13. package/dist/templates/telegram-bot/core/src/handlers/listener.ts +168 -0
  14. package/dist/templates/telegram-bot/core/src/handlers/logs.ts +14 -7
  15. package/dist/templates/telegram-bot/core/src/index.ts +29 -0
  16. package/dist/templates/telegram-bot/core/src/utils/formatters.ts +55 -19
  17. package/dist/templates/telegram-bot/core/src/utils/instance-manager.ts +6 -2
  18. package/dist/templates/telegram-bot/core/src/utils/message-builder.ts +180 -0
  19. package/dist/templates/telegram-bot/docs/automatizacion_integral_de_bots_de_telegram_con_type_script.md +326 -0
  20. package/dist/templates/telegram-bot/docs/cli-commands.md +514 -5
  21. package/dist/templates/telegram-bot/docs/environment.md +191 -3
  22. package/dist/templates/telegram-bot/docs/getting-started.md +202 -15
  23. package/dist/templates/telegram-bot/package.json +5 -2
  24. package/dist/templates/telegram-bot/packages/utils/src/logger.ts +1 -0
  25. package/dist/templates/telegram-bot/tools/commands/doctor.ts +62 -0
  26. package/dist/templates/telegram-bot/tools/commands/setup.ts +984 -170
  27. package/package.json +1 -1
  28. package/templates/telegram-bot/CLAUDE.deploy.md +2 -3
  29. package/templates/telegram-bot/CLAUDE.dev.md +304 -5
  30. package/templates/telegram-bot/CLAUDE.md +166 -89
  31. package/templates/telegram-bot/README.md +252 -129
  32. package/templates/telegram-bot/bun.lock +146 -3
  33. package/templates/telegram-bot/core/.env.example +6 -0
  34. package/templates/telegram-bot/core/src/config/env.ts +130 -1
  35. package/templates/telegram-bot/core/src/config/logging.ts +3 -1
  36. package/templates/telegram-bot/core/src/handlers/config-export.ts +122 -0
  37. package/templates/telegram-bot/core/src/handlers/control.ts +37 -11
  38. package/templates/telegram-bot/core/src/handlers/health.ts +21 -26
  39. package/templates/telegram-bot/core/src/handlers/info.ts +191 -0
  40. package/templates/telegram-bot/core/src/handlers/listener.ts +168 -0
  41. package/templates/telegram-bot/core/src/handlers/logs.ts +14 -7
  42. package/templates/telegram-bot/core/src/index.ts +29 -0
  43. package/templates/telegram-bot/core/src/utils/formatters.ts +55 -19
  44. package/templates/telegram-bot/core/src/utils/instance-manager.ts +6 -2
  45. package/templates/telegram-bot/core/src/utils/message-builder.ts +180 -0
  46. package/templates/telegram-bot/docs/automatizacion_integral_de_bots_de_telegram_con_type_script.md +326 -0
  47. package/templates/telegram-bot/docs/cli-commands.md +514 -5
  48. package/templates/telegram-bot/docs/environment.md +191 -3
  49. package/templates/telegram-bot/docs/getting-started.md +202 -15
  50. package/templates/telegram-bot/package.json +5 -2
  51. package/templates/telegram-bot/packages/utils/src/logger.ts +1 -0
  52. package/templates/telegram-bot/tools/commands/doctor.ts +62 -0
  53. package/templates/telegram-bot/tools/commands/setup.ts +984 -170
@@ -4,11 +4,15 @@
4
4
  "": {
5
5
  "name": "mks-telegram-bot",
6
6
  "dependencies": {
7
+ "@flla/telegram-format": "^3.1.2",
7
8
  "@inquirer/prompts": "^8.1.0",
8
9
  "chalk": "^5.6.2",
9
10
  "commander": "^14.0.2",
10
11
  "dotenv": "^17.2.3",
11
12
  "glob": "^13.0.0",
13
+ "ora": "^9.0.0",
14
+ "telegraf": "^4.16.3",
15
+ "telegram": "^2.26.22",
12
16
  },
13
17
  "devDependencies": {
14
18
  "@types/bun": "latest",
@@ -27,6 +31,21 @@
27
31
  "zod": "^3.24.0",
28
32
  },
29
33
  },
34
+ "packages/bootstrapper": {
35
+ "name": "@mks2508/bootstrapper",
36
+ "version": "0.1.0",
37
+ "dependencies": {
38
+ "@inquirer/prompts": "^8.1.0",
39
+ "@mks2508/better-logger": "^4.0.0",
40
+ "big-integer": "^1.6.52",
41
+ "telegraf": "^4.16.3",
42
+ "telegram": "^2.26.22",
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^20",
46
+ "typescript": "^5",
47
+ },
48
+ },
30
49
  "packages/utils": {
31
50
  "name": "@mks2508/telegram-bot-utils",
32
51
  "version": "0.1.0",
@@ -37,6 +56,10 @@
37
56
  },
38
57
  },
39
58
  "packages": {
59
+ "@cryptography/aes": ["@cryptography/aes@0.1.1", "", {}, "sha512-PcYz4FDGblO6tM2kSC+VzhhK62vml6k6/YAkiWtyPvrgJVfnDRoHGDtKn5UiaRRUrvUTTocBpvc2rRgTCqxjsg=="],
60
+
61
+ "@flla/telegram-format": ["@flla/telegram-format@3.1.2", "", {}, "sha512-pmBcT0f2ay77WlVq0EX3KseFp07IXU7QYahsY/Halx4/YnsM70qYeLRBoKysukU/l0ZQ2u15xu9rMECm9ov2+A=="],
62
+
40
63
  "@inquirer/ansi": ["@inquirer/ansi@2.0.2", "", {}, "sha512-SYLX05PwJVnW+WVegZt1T4Ip1qba1ik+pNJPDiqvk6zS5Y/i8PhRzLpGEtVd7sW0G8cMtkD8t4AZYhQwm8vnww=="],
41
64
 
42
65
  "@inquirer/checkbox": ["@inquirer/checkbox@5.0.3", "", { "dependencies": { "@inquirer/ansi": "^2.0.2", "@inquirer/core": "^11.1.0", "@inquirer/figures": "^2.0.2", "@inquirer/type": "^4.0.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-xtQP2eXMFlOcAhZ4ReKP2KZvDIBb1AnCfZ81wWXG3DXLVH0f0g4obE0XDPH+ukAEMRcZT0kdX2AS1jrWGXbpxw=="],
@@ -75,6 +98,8 @@
75
98
 
76
99
  "@mks2508/better-logger": ["@mks2508/better-logger@4.0.0", "", { "dependencies": { "chalk": "^5.6.2" } }, "sha512-39PYkAKg7kC0ncPjcN5zAwTsLIS+iXoL4294gl3Cm4OAI6sAT7YJ+RccD42Ve5ybRC/TGgJnD0AUH5M26w0pWA=="],
77
100
 
101
+ "@mks2508/bootstrapper": ["@mks2508/bootstrapper@workspace:packages/bootstrapper"],
102
+
78
103
  "@mks2508/no-throw": ["@mks2508/no-throw@0.1.0", "", {}, "sha512-/CI8FqiO3oLw66XIQ07mw13b6PDNh1vit0cGzUBLq5MfJUTKDU0yaKFE0l9CqSpe6xv4n4+z4RWEytP5xePKZQ=="],
79
104
 
80
105
  "@mks2508/telegram-bot-core": ["@mks2508/telegram-bot-core@workspace:core"],
@@ -101,7 +126,7 @@
101
126
 
102
127
  "@types/bun": ["@types/bun@1.3.5", "", { "dependencies": { "bun-types": "1.3.5" } }, "sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w=="],
103
128
 
104
- "@types/node": ["@types/node@25.0.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA=="],
129
+ "@types/node": ["@types/node@20.19.27", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug=="],
105
130
 
106
131
  "@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20260106.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260106.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260106.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20260106.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260106.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20260106.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260106.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20260106.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-EeH81rQsgLjewxuVOBN0MnQWAyf5YNeHRP3+Et6wJyr4d7HuA7zFwfNaEdfX1k366kgpKOR5K6dakorBhKZGng=="],
107
132
 
@@ -125,38 +150,98 @@
125
150
 
126
151
  "ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
127
152
 
153
+ "async-mutex": ["async-mutex@0.3.2", "", { "dependencies": { "tslib": "^2.3.1" } }, "sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA=="],
154
+
155
+ "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
156
+
157
+ "big-integer": ["big-integer@1.6.52", "", {}, "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg=="],
158
+
159
+ "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
160
+
128
161
  "buffer-alloc": ["buffer-alloc@1.2.0", "", { "dependencies": { "buffer-alloc-unsafe": "^1.1.0", "buffer-fill": "^1.0.0" } }, "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow=="],
129
162
 
130
163
  "buffer-alloc-unsafe": ["buffer-alloc-unsafe@1.1.0", "", {}, "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg=="],
131
164
 
132
165
  "buffer-fill": ["buffer-fill@1.0.0", "", {}, "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ=="],
133
166
 
167
+ "bufferutil": ["bufferutil@4.1.0", "", { "dependencies": { "node-gyp-build": "^4.3.0" } }, "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw=="],
168
+
134
169
  "bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="],
135
170
 
136
171
  "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
137
172
 
138
173
  "chardet": ["chardet@2.1.1", "", {}, "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ=="],
139
174
 
175
+ "cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="],
176
+
177
+ "cli-spinners": ["cli-spinners@3.3.0", "", {}, "sha512-/+40ljC3ONVnYIttjMWrlL51nItDAbBrq2upN8BPyvGU/2n5Oxw3tbNwORCaNuNqLJnxGqOfjUuhsv7l5Q4IsQ=="],
178
+
140
179
  "cli-width": ["cli-width@4.1.0", "", {}, "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ=="],
141
180
 
142
181
  "commander": ["commander@14.0.2", "", {}, "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ=="],
143
182
 
183
+ "d": ["d@1.0.2", "", { "dependencies": { "es5-ext": "^0.10.64", "type": "^2.7.2" } }, "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw=="],
184
+
144
185
  "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
145
186
 
187
+ "dom-serializer": ["dom-serializer@1.4.1", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" } }, "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag=="],
188
+
189
+ "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="],
190
+
191
+ "domhandler": ["domhandler@4.3.1", "", { "dependencies": { "domelementtype": "^2.2.0" } }, "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ=="],
192
+
193
+ "domutils": ["domutils@2.8.0", "", { "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", "domhandler": "^4.2.0" } }, "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A=="],
194
+
146
195
  "dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="],
147
196
 
148
197
  "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
149
198
 
199
+ "entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="],
200
+
201
+ "es5-ext": ["es5-ext@0.10.64", "", { "dependencies": { "es6-iterator": "^2.0.3", "es6-symbol": "^3.1.3", "esniff": "^2.0.1", "next-tick": "^1.1.0" } }, "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg=="],
202
+
203
+ "es6-iterator": ["es6-iterator@2.0.3", "", { "dependencies": { "d": "1", "es5-ext": "^0.10.35", "es6-symbol": "^3.1.1" } }, "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g=="],
204
+
205
+ "es6-symbol": ["es6-symbol@3.1.4", "", { "dependencies": { "d": "^1.0.2", "ext": "^1.7.0" } }, "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg=="],
206
+
207
+ "esniff": ["esniff@2.0.1", "", { "dependencies": { "d": "^1.0.1", "es5-ext": "^0.10.62", "event-emitter": "^0.3.5", "type": "^2.7.2" } }, "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg=="],
208
+
209
+ "event-emitter": ["event-emitter@0.3.5", "", { "dependencies": { "d": "1", "es5-ext": "~0.10.14" } }, "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA=="],
210
+
150
211
  "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="],
151
212
 
213
+ "ext": ["ext@1.7.0", "", { "dependencies": { "type": "^2.7.2" } }, "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw=="],
214
+
152
215
  "get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="],
153
216
 
154
217
  "glob": ["glob@13.0.0", "", { "dependencies": { "minimatch": "^10.1.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA=="],
155
218
 
219
+ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
220
+
221
+ "htmlparser2": ["htmlparser2@6.1.0", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.0.0", "domutils": "^2.5.2", "entities": "^2.0.0" } }, "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A=="],
222
+
156
223
  "iconv-lite": ["iconv-lite@0.7.1", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw=="],
157
224
 
225
+ "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
226
+
227
+ "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
228
+
229
+ "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="],
230
+
231
+ "is-interactive": ["is-interactive@2.0.0", "", {}, "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ=="],
232
+
233
+ "is-typedarray": ["is-typedarray@1.0.0", "", {}, "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="],
234
+
235
+ "is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="],
236
+
237
+ "log-symbols": ["log-symbols@7.0.1", "", { "dependencies": { "is-unicode-supported": "^2.0.0", "yoctocolors": "^2.1.1" } }, "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg=="],
238
+
158
239
  "lru-cache": ["lru-cache@11.2.4", "", {}, "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg=="],
159
240
 
241
+ "mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
242
+
243
+ "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
244
+
160
245
  "minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="],
161
246
 
162
247
  "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
@@ -167,16 +252,34 @@
167
252
 
168
253
  "mute-stream": ["mute-stream@3.0.0", "", {}, "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw=="],
169
254
 
255
+ "next-tick": ["next-tick@1.1.0", "", {}, "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="],
256
+
170
257
  "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
171
258
 
259
+ "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="],
260
+
261
+ "node-localstorage": ["node-localstorage@2.2.1", "", { "dependencies": { "write-file-atomic": "^1.1.4" } }, "sha512-vv8fJuOUCCvSPjDjBLlMqYMHob4aGjkmrkaE42/mZr0VT+ZAU10jRF8oTnX9+pgU9/vYJ8P7YT3Vd6ajkmzSCw=="],
262
+
263
+ "onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
264
+
265
+ "ora": ["ora@9.0.0", "", { "dependencies": { "chalk": "^5.6.2", "cli-cursor": "^5.0.0", "cli-spinners": "^3.2.0", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.1.0", "log-symbols": "^7.0.1", "stdin-discarder": "^0.2.2", "string-width": "^8.1.0", "strip-ansi": "^7.1.2" } }, "sha512-m0pg2zscbYgWbqRR6ABga5c3sZdEon7bSgjnlXC64kxtxLOyjRcbbUkLj7HFyy/FTD+P2xdBWu8snGhYI0jc4A=="],
266
+
172
267
  "oxlint": ["oxlint@1.38.0", "", { "optionalDependencies": { "@oxlint/darwin-arm64": "1.38.0", "@oxlint/darwin-x64": "1.38.0", "@oxlint/linux-arm64-gnu": "1.38.0", "@oxlint/linux-arm64-musl": "1.38.0", "@oxlint/linux-x64-gnu": "1.38.0", "@oxlint/linux-x64-musl": "1.38.0", "@oxlint/win32-arm64": "1.38.0", "@oxlint/win32-x64": "1.38.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.10.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-XT7tBinQS+hVLxtfJOnokJ9qVBiQvZqng40tDgR6qEJMRMnpVq/JwYfbYyGntSq8MO+Y+N9M1NG4bAMFUtCJiw=="],
173
268
 
174
269
  "p-timeout": ["p-timeout@4.1.0", "", {}, "sha512-+/wmHtzJuWii1sXn3HCuH/FTwGhrp4tmJTxSKJbfS+vkipci6osxXM5mY0jUiRzWKMTgUT8l7HFbeSwZAynqHw=="],
175
270
 
271
+ "pako": ["pako@2.1.0", "", {}, "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug=="],
272
+
273
+ "path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="],
274
+
176
275
  "path-scurry": ["path-scurry@2.0.1", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA=="],
177
276
 
178
277
  "prettier": ["prettier@3.7.4", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA=="],
179
278
 
279
+ "real-cancellable-promise": ["real-cancellable-promise@1.2.3", "", {}, "sha512-hBI5Gy/55VEeeMtImMgEirD7eq5UmqJf1J8dFZtbJZA/3rB0pYFZ7PayMGueb6v4UtUtpKpP+05L0VwyE1hI9Q=="],
280
+
281
+ "restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="],
282
+
180
283
  "safe-compare": ["safe-compare@1.1.4", "", { "dependencies": { "buffer-alloc": "^1.2.0" } }, "sha512-b9wZ986HHCo/HbKrRpBJb2kqXMK9CEWIE1egeEvZsYn69ay3kdfl9nG3RyOcR+jInTDf7a86WQ1d4VJX7goSSQ=="],
181
284
 
182
285
  "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
@@ -185,24 +288,64 @@
185
288
 
186
289
  "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
187
290
 
188
- "string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
291
+ "slide": ["slide@1.1.6", "", {}, "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw=="],
292
+
293
+ "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="],
294
+
295
+ "socks": ["socks@2.8.7", "", { "dependencies": { "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" } }, "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A=="],
296
+
297
+ "stdin-discarder": ["stdin-discarder@0.2.2", "", {}, "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ=="],
298
+
299
+ "store2": ["store2@2.14.4", "", {}, "sha512-srTItn1GOvyvOycgxjAnPA63FZNwy0PTyUBFMHRM+hVFltAeoh0LmNBz9SZqUS9mMqGk8rfyWyXn3GH5ReJ8Zw=="],
300
+
301
+ "string-width": ["string-width@8.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.0", "strip-ansi": "^7.1.0" } }, "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg=="],
189
302
 
190
303
  "strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
191
304
 
192
305
  "telegraf": ["telegraf@4.16.3", "", { "dependencies": { "@telegraf/types": "^7.1.0", "abort-controller": "^3.0.0", "debug": "^4.3.4", "mri": "^1.2.0", "node-fetch": "^2.7.0", "p-timeout": "^4.1.0", "safe-compare": "^1.1.4", "sandwich-stream": "^2.0.2" }, "bin": { "telegraf": "lib/cli.mjs" } }, "sha512-yjEu2NwkHlXu0OARWoNhJlIjX09dRktiMQFsM678BAH/PEPVwctzL67+tvXqLCRQQvm3SDtki2saGO9hLlz68w=="],
193
306
 
307
+ "telegram": ["telegram@2.26.22", "", { "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" } }, "sha512-EIj7Yrjiu0Yosa3FZ/7EyPg9s6UiTi/zDQrFmR/2Mg7pIUU+XjAit1n1u9OU9h2oRnRM5M+67/fxzQluZpaJJg=="],
308
+
194
309
  "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
195
310
 
311
+ "ts-custom-error": ["ts-custom-error@3.3.1", "", {}, "sha512-5OX1tzOjxWEgsr/YEUWSuPrQ00deKLh6D7OTWcvNHm12/7QPyRh8SYpyWvA4IZv8H/+GQWQEh/kwo95Q9OVW1A=="],
312
+
313
+ "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
314
+
315
+ "type": ["type@2.7.3", "", {}, "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ=="],
316
+
317
+ "typedarray-to-buffer": ["typedarray-to-buffer@3.1.5", "", { "dependencies": { "is-typedarray": "^1.0.0" } }, "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q=="],
318
+
196
319
  "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
197
320
 
198
- "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
321
+ "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
322
+
323
+ "utf-8-validate": ["utf-8-validate@5.0.10", "", { "dependencies": { "node-gyp-build": "^4.3.0" } }, "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ=="],
199
324
 
200
325
  "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
201
326
 
327
+ "websocket": ["websocket@1.0.35", "", { "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" } }, "sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q=="],
328
+
202
329
  "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
203
330
 
204
331
  "wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="],
205
332
 
333
+ "write-file-atomic": ["write-file-atomic@1.3.4", "", { "dependencies": { "graceful-fs": "^4.1.11", "imurmurhash": "^0.1.4", "slide": "^1.1.5" } }, "sha512-SdrHoC/yVBPpV0Xq/mUZQIpW2sWXAShb/V4pomcJXh92RuaO+f3UTWItiR3Px+pLnV2PvC2/bfn5cwr5X6Vfxw=="],
334
+
335
+ "yaeti": ["yaeti@0.0.6", "", {}, "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug=="],
336
+
337
+ "yoctocolors": ["yoctocolors@2.1.2", "", {}, "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug=="],
338
+
206
339
  "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
340
+
341
+ "bun-types/@types/node": ["@types/node@25.0.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA=="],
342
+
343
+ "websocket/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
344
+
345
+ "wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
346
+
347
+ "bun-types/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
348
+
349
+ "websocket/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
207
350
  }
208
351
  }
@@ -7,6 +7,12 @@ TG_BOT_TOKEN=123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
7
7
  # Options: polling, webhook
8
8
  TG_MODE=polling
9
9
 
10
+ # === MTProto API Credentials (for bootstrap command) ===
11
+ # Get these from https://my.telegram.org
12
+ # Required for: bun run bootstrap
13
+ # TG_API_ID=12345678
14
+ # TG_API_HASH=abc123def456789...
15
+
10
16
  # === Required if TG_MODE=webhook ===
11
17
  # TG_WEBHOOK_URL=https://your-domain.com/webhook
12
18
  # TG_WEBHOOK_SECRET=random_secret_token_min_16_chars
@@ -1,5 +1,8 @@
1
1
  import { z } from 'zod'
2
2
  import { BotTimeouts, BotLimits } from '../types/constants.js'
3
+ import { readFileSync, existsSync, readlinkSync } from 'fs'
4
+ import { resolve, dirname } from 'path'
5
+ import { fileURLToPath } from 'url'
3
6
 
4
7
  export enum Environment {
5
8
  LOCAL = 'local',
@@ -85,13 +88,139 @@ const envSchema = z.object({
85
88
  message: 'TG_WEBHOOK_URL is required when TG_MODE=webhook and TG_NGROK_ENABLED=false',
86
89
  })
87
90
 
91
+ /**
92
+ * Get the directory of the current module
93
+ */
94
+ function getModuleDir(): string {
95
+ const __filename = fileURLToPath(import.meta.url)
96
+ return dirname(__filename)
97
+ }
98
+
99
+ /**
100
+ * Load .env file from the new .envs/ structure
101
+ * @param botUsername Bot username (without @)
102
+ * @param environment Environment (local, staging, production)
103
+ * @returns Parsed environment variables or null if file doesn't exist
104
+ */
105
+ function loadEnvFile(botUsername: string, environment: string): Record<string, string> | null {
106
+ const coreDir = resolve(getModuleDir(), '../..')
107
+ const envPath = resolve(coreDir, '.envs', botUsername, `${environment}.env`)
108
+
109
+ if (!existsSync(envPath)) {
110
+ return null
111
+ }
112
+
113
+ const content = readFileSync(envPath, 'utf-8')
114
+ const envVars: Record<string, string> = {}
115
+
116
+ for (const line of content.split('\n')) {
117
+ const trimmed = line.trim()
118
+ if (!trimmed || trimmed.startsWith('#')) {
119
+ continue
120
+ }
121
+
122
+ const [key, ...valueParts] = trimmed.split('=')
123
+ if (key && valueParts.length > 0) {
124
+ envVars[key] = valueParts.join('=')
125
+ }
126
+ }
127
+
128
+ return envVars
129
+ }
130
+
131
+ /**
132
+ * Get the active bot username from TG_BOT env var or .active symlink
133
+ * @returns Bot username or null if not found
134
+ */
135
+ function getActiveBot(): string | null {
136
+ // Check TG_BOT env var first
137
+ if (process.env.TG_BOT) {
138
+ return process.env.TG_BOT
139
+ }
140
+
141
+ // Check .active symlink
142
+ const coreDir = resolve(getModuleDir(), '../..')
143
+ const activeSymlink = resolve(coreDir, '.envs', '.active')
144
+
145
+ if (!existsSync(activeSymlink)) {
146
+ return null
147
+ }
148
+
149
+ try {
150
+ const target = readlinkSync(activeSymlink)
151
+ return target
152
+ } catch {
153
+ return null
154
+ }
155
+ }
156
+
88
157
  /**
89
158
  * Loads and validates environment variables.
159
+ * Supports both the new .envs/ structure and legacy .env.{environment} files.
90
160
  * @returns EnvConfig on success, throws on validation failure
91
161
  * @throws Error if environment variables are invalid or required variables are missing
92
162
  */
93
163
  export function loadEnvConfig(): EnvConfig {
94
- const result = envSchema.safeParse(process.env)
164
+ // Try to load from new .envs/ structure first
165
+ const activeBot = getActiveBot()
166
+ const environment = process.env.TG_ENV || 'local'
167
+
168
+ // Filter out undefined values from process.env
169
+ const processEnvClean: Record<string, string> = {}
170
+ for (const [key, value] of Object.entries(process.env)) {
171
+ if (value !== undefined) {
172
+ processEnvClean[key] = value
173
+ }
174
+ }
175
+
176
+ let envVars: Record<string, string> = { ...processEnvClean }
177
+
178
+ if (activeBot) {
179
+ // Load bot-specific environment file
180
+ const botEnvVars = loadEnvFile(activeBot, environment)
181
+ if (botEnvVars) {
182
+ // Merge bot env vars with process.env (bot vars take precedence)
183
+ envVars = { ...processEnvClean, ...botEnvVars }
184
+ } else {
185
+ // Fallback to old structure
186
+ const coreDir = resolve(getModuleDir(), '../..')
187
+ const oldEnvPath = resolve(coreDir, `.env.${environment}`)
188
+
189
+ if (existsSync(oldEnvPath)) {
190
+ const content = readFileSync(oldEnvPath, 'utf-8')
191
+ for (const line of content.split('\n')) {
192
+ const trimmed = line.trim()
193
+ if (!trimmed || trimmed.startsWith('#')) {
194
+ continue
195
+ }
196
+ const [key, ...valueParts] = trimmed.split('=')
197
+ if (key && valueParts.length > 0) {
198
+ envVars[key] = valueParts.join('=')
199
+ }
200
+ }
201
+ }
202
+ }
203
+ } else {
204
+ // No active bot, try old structure
205
+ const coreDir = resolve(getModuleDir(), '../..')
206
+ const oldEnvPath = resolve(coreDir, `.env.${environment}`)
207
+
208
+ if (existsSync(oldEnvPath)) {
209
+ const content = readFileSync(oldEnvPath, 'utf-8')
210
+ for (const line of content.split('\n')) {
211
+ const trimmed = line.trim()
212
+ if (!trimmed || trimmed.startsWith('#')) {
213
+ continue
214
+ }
215
+ const [key, ...valueParts] = trimmed.split('=')
216
+ if (key && valueParts.length > 0) {
217
+ envVars[key] = valueParts.join('=')
218
+ }
219
+ }
220
+ }
221
+ }
222
+
223
+ const result = envSchema.safeParse(envVars)
95
224
 
96
225
  if (!result.success) {
97
226
  const errors = result.error.errors.map((e) => ` ${e.path.join('.')}: ${e.message}`).join('\n')
@@ -13,7 +13,7 @@ export interface FileLoggingConfig {
13
13
  logDir: string
14
14
  maxFileSize: number
15
15
  maxFiles: number
16
- fileLogLevels: ('debug' | 'info' | 'warn' | 'error' | 'critical')[]
16
+ fileLogLevels: ('debug' | 'info' | 'success' | 'warn' | 'error' | 'critical')[]
17
17
  }
18
18
 
19
19
  const DEFAULT_CONFIG: FileLoggingConfig = {
@@ -22,7 +22,9 @@ const DEFAULT_CONFIG: FileLoggingConfig = {
22
22
  maxFileSize: Number(process.env.TG_LOG_MAX_SIZE) || 1024 * 1024, // 1MB default
23
23
  maxFiles: Number(process.env.TG_LOG_MAX_FILES) || 5,
24
24
  fileLogLevels: (process.env.TG_LOG_LEVELS?.split(',') || [
25
+ 'debug',
25
26
  'info',
27
+ 'success',
26
28
  'warn',
27
29
  'error',
28
30
  'critical',
@@ -0,0 +1,122 @@
1
+ import type { Context } from 'telegraf'
2
+ import { badge, kv, colors, colorText } from '../middleware/logging.js'
3
+ import { getConfig } from '../config/index.js'
4
+ import { configLogger } from '@mks2508/telegram-bot-utils'
5
+ import { MessageBuilder } from '../utils/message-builder.js'
6
+
7
+ const collectedTopics = new Map<number, string>()
8
+
9
+ export async function handleExportConfig(ctx: Context): Promise<void> {
10
+ const userId = ctx.from?.id ?? 'unknown'
11
+ const chat = ctx.chat
12
+
13
+ configLogger.info(
14
+ `${badge('CONFIG', 'rounded')} ${kv({
15
+ cmd: '/exportconfig',
16
+ user: colorText(String(userId), colors.user),
17
+ chat: chat?.id,
18
+ })}`
19
+ )
20
+
21
+ const config = getConfig()
22
+ const builder = MessageBuilder.markdown()
23
+
24
+ // Title
25
+ builder.title('🔧 Current Configuration')
26
+ builder.newline()
27
+
28
+ // Environment
29
+ builder.section('Environment:')
30
+ builder.line('TG_ENV', config.environment, { code: true })
31
+ builder.line('TG_INSTANCE_NAME', config.instanceName, { code: true })
32
+ builder.line('TG_MODE', config.mode, { code: true })
33
+ builder.newline()
34
+
35
+ // Bot Token (masked)
36
+ if (config.botToken) {
37
+ const masked = config.botToken.slice(0, 6) + '...' + config.botToken.slice(-6)
38
+ builder.section('Bot:')
39
+ builder.line('TG_BOT_TOKEN', masked, { code: true })
40
+ builder.newline()
41
+ }
42
+
43
+ // Control
44
+ builder.section('Control Commands:')
45
+ if (config.controlChatId) {
46
+ builder.line('TG_CONTROL_CHAT_ID', String(config.controlChatId), { code: true })
47
+ } else {
48
+ builder.text('# TG_CONTROL_CHAT_ID=not_set')
49
+ }
50
+ if (config.controlTopicId) {
51
+ builder.line('TG_CONTROL_TOPIC_ID', String(config.controlTopicId), { code: true })
52
+ } else {
53
+ builder.text('# TG_CONTROL_TOPIC_ID=not_set')
54
+ }
55
+ if (config.authorizedUserIds && config.authorizedUserIds.size > 0) {
56
+ builder.line('TG_AUTHORIZED_USER_IDS', [...config.authorizedUserIds].join(','), { code: true })
57
+ builder.newline()
58
+ } else {
59
+ builder.text('# TG_AUTHORIZED_USER_IDS=not_set')
60
+ builder.newline()
61
+ }
62
+
63
+ // Logging
64
+ builder.section('Logging:')
65
+ if (config.logChatId) {
66
+ builder.line('TG_LOG_CHAT_ID', String(config.logChatId), { code: true })
67
+ } else {
68
+ builder.text('# TG_LOG_CHAT_ID=not_set')
69
+ }
70
+ if (config.logTopicId) {
71
+ builder.line('TG_LOG_TOPIC_ID', String(config.logTopicId), { code: true })
72
+ builder.newline()
73
+ } else {
74
+ builder.text('# TG_LOG_TOPIC_ID=not_set')
75
+ builder.newline()
76
+ }
77
+
78
+ // Webhook
79
+ if (config.mode === 'webhook') {
80
+ builder.section('Webhook:')
81
+ builder.line('TG_WEBHOOK_URL', config.webhookUrl || 'not_set', { code: true })
82
+ builder.line('TG_WEBHOOK_SECRET', config.webhookSecret || 'not_set', { code: true })
83
+ builder.newline()
84
+ }
85
+
86
+ builder.newline()
87
+ builder.text('💡 Copy this to your .env file')
88
+ builder.newline()
89
+ builder.newline()
90
+
91
+ // Instructions
92
+ builder.section('📋 Quick Setup:')
93
+ builder.listItem('Create topics: General, Control, Logs')
94
+ builder.listItem('Mention @bot_username in each topic')
95
+ builder.listItem('Use /getinfo to get Thread IDs')
96
+ builder.listItem('Update .env with the IDs')
97
+
98
+ await ctx.reply(builder.build(), { parse_mode: builder.getParseMode() })
99
+ configLogger.success(`Config exported for user ${userId}`)
100
+ }
101
+
102
+ /**
103
+ * Register a topic when user mentions bot in a topic
104
+ * Call this from the mention middleware
105
+ */
106
+ export function registerTopic(threadId: number, topicName: string): void {
107
+ collectedTopics.set(threadId, topicName)
108
+ }
109
+
110
+ /**
111
+ * Get all collected topics
112
+ */
113
+ export function getCollectedTopics(): Map<number, string> {
114
+ return collectedTopics
115
+ }
116
+
117
+ /**
118
+ * Clear collected topics
119
+ */
120
+ export function clearCollectedTopics(): void {
121
+ collectedTopics.clear()
122
+ }