@xbibzlibrary/telebibz 0.4.4 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/CHANGELOG.md +35 -138
  2. package/LICENSE +1 -1
  3. package/NOTICE.md +9 -4
  4. package/README.md +173 -242
  5. package/examples/01-quickstart.js +13 -0
  6. package/examples/02-menu-tombol.js +22 -0
  7. package/examples/03-wizard.js +29 -0
  8. package/examples/04-broadcast.js +25 -0
  9. package/examples/05-kirim-file.js +19 -0
  10. package/examples/06-menu.js +35 -0
  11. package/examples/07-inline-query.js +18 -0
  12. package/index.d.ts +81 -0
  13. package/index.js +42 -0
  14. package/lib/api.js +154 -0
  15. package/lib/broadcast.js +35 -0
  16. package/lib/composer.js +174 -0
  17. package/lib/context.js +190 -0
  18. package/lib/errors.js +35 -0
  19. package/lib/file.js +41 -0
  20. package/lib/inline-query.js +28 -0
  21. package/lib/keyboard.js +83 -0
  22. package/lib/logger.js +38 -0
  23. package/lib/menus.js +90 -0
  24. package/lib/net.js +115 -0
  25. package/lib/ratelimit.js +61 -0
  26. package/lib/runner.js +45 -0
  27. package/lib/session.js +36 -0
  28. package/lib/telebibz.js +190 -0
  29. package/lib/wizard.js +81 -0
  30. package/package.json +35 -97
  31. package/test/all.test.js +334 -0
  32. package/CODE_OF_CONDUCT.md +0 -37
  33. package/CONTRIBUTING.md +0 -59
  34. package/CONTRIBUTION_RULES.md +0 -41
  35. package/GOVERNANCE.md +0 -47
  36. package/README.id.md +0 -292
  37. package/README.zh-CN.md +0 -292
  38. package/RELEASE_AUTOMATION.md +0 -78
  39. package/RELEASE_POLICY.md +0 -32
  40. package/SECURITY.md +0 -47
  41. package/SHOWCASE.md +0 -29
  42. package/SUPPORT.md +0 -30
  43. package/assets/readme-preview.html +0 -75
  44. package/assets/telebibz-logo.png +0 -0
  45. package/assets/telebibz-readme-preview.png +0 -0
  46. package/bin/telebibz.mjs +0 -3
  47. package/dist/generated/api.d.ts +0 -13
  48. package/dist/generated/api.d.ts.map +0 -1
  49. package/dist/generated/api.js +0 -192
  50. package/dist/generated/api.js.map +0 -1
  51. package/dist/src/api/client.d.ts +0 -62
  52. package/dist/src/api/client.d.ts.map +0 -1
  53. package/dist/src/api/client.js +0 -104
  54. package/dist/src/api/client.js.map +0 -1
  55. package/dist/src/api/errors.d.ts +0 -45
  56. package/dist/src/api/errors.d.ts.map +0 -1
  57. package/dist/src/api/errors.js +0 -65
  58. package/dist/src/api/errors.js.map +0 -1
  59. package/dist/src/api/index.d.ts +0 -6
  60. package/dist/src/api/index.d.ts.map +0 -1
  61. package/dist/src/api/index.js +0 -6
  62. package/dist/src/api/index.js.map +0 -1
  63. package/dist/src/api/telegram-types/LICENSE +0 -21
  64. package/dist/src/api/telegram-types/api.d.ts +0 -22
  65. package/dist/src/api/telegram-types/checklist.d.ts +0 -72
  66. package/dist/src/api/telegram-types/inline.d.ts +0 -692
  67. package/dist/src/api/telegram-types/langs.d.ts +0 -193
  68. package/dist/src/api/telegram-types/manage.d.ts +0 -1144
  69. package/dist/src/api/telegram-types/markup.d.ts +0 -268
  70. package/dist/src/api/telegram-types/message.d.ts +0 -1537
  71. package/dist/src/api/telegram-types/methods.d.ts +0 -2870
  72. package/dist/src/api/telegram-types/mod.d.ts +0 -14
  73. package/dist/src/api/telegram-types/passport.d.ts +0 -163
  74. package/dist/src/api/telegram-types/payment.d.ts +0 -570
  75. package/dist/src/api/telegram-types/rich.d.ts +0 -1010
  76. package/dist/src/api/telegram-types/settings.d.ts +0 -120
  77. package/dist/src/api/telegram-types/story.d.ts +0 -89
  78. package/dist/src/api/telegram-types/update.d.ts +0 -84
  79. package/dist/src/api/telegram.d.ts +0 -7
  80. package/dist/src/api/telegram.d.ts.map +0 -1
  81. package/dist/src/api/telegram.js +0 -2
  82. package/dist/src/api/telegram.js.map +0 -1
  83. package/dist/src/api/transport.d.ts +0 -68
  84. package/dist/src/api/transport.d.ts.map +0 -1
  85. package/dist/src/api/transport.js +0 -264
  86. package/dist/src/api/transport.js.map +0 -1
  87. package/dist/src/api/types.d.ts +0 -466
  88. package/dist/src/api/types.d.ts.map +0 -1
  89. package/dist/src/api/types.js +0 -2
  90. package/dist/src/api/types.js.map +0 -1
  91. package/dist/src/branding/terminal.d.ts +0 -77
  92. package/dist/src/branding/terminal.d.ts.map +0 -1
  93. package/dist/src/branding/terminal.js +0 -328
  94. package/dist/src/branding/terminal.js.map +0 -1
  95. package/dist/src/broadcast/broadcast.d.ts +0 -50
  96. package/dist/src/broadcast/broadcast.d.ts.map +0 -1
  97. package/dist/src/broadcast/broadcast.js +0 -56
  98. package/dist/src/broadcast/broadcast.js.map +0 -1
  99. package/dist/src/cache/cache.d.ts +0 -34
  100. package/dist/src/cache/cache.d.ts.map +0 -1
  101. package/dist/src/cache/cache.js +0 -41
  102. package/dist/src/cache/cache.js.map +0 -1
  103. package/dist/src/cli.d.ts +0 -2
  104. package/dist/src/cli.d.ts.map +0 -1
  105. package/dist/src/cli.js +0 -84
  106. package/dist/src/cli.js.map +0 -1
  107. package/dist/src/context/context.d.ts +0 -124
  108. package/dist/src/context/context.d.ts.map +0 -1
  109. package/dist/src/context/context.js +0 -302
  110. package/dist/src/context/context.js.map +0 -1
  111. package/dist/src/core/bot.d.ts +0 -204
  112. package/dist/src/core/bot.d.ts.map +0 -1
  113. package/dist/src/core/bot.js +0 -506
  114. package/dist/src/core/bot.js.map +0 -1
  115. package/dist/src/core/events.d.ts +0 -75
  116. package/dist/src/core/events.d.ts.map +0 -1
  117. package/dist/src/core/events.js +0 -35
  118. package/dist/src/core/events.js.map +0 -1
  119. package/dist/src/core/webhook-reply.d.ts +0 -34
  120. package/dist/src/core/webhook-reply.d.ts.map +0 -1
  121. package/dist/src/core/webhook-reply.js +0 -37
  122. package/dist/src/core/webhook-reply.js.map +0 -1
  123. package/dist/src/index.d.ts +0 -24
  124. package/dist/src/index.d.ts.map +0 -1
  125. package/dist/src/index.js +0 -24
  126. package/dist/src/index.js.map +0 -1
  127. package/dist/src/keyboard/index.d.ts +0 -46
  128. package/dist/src/keyboard/index.d.ts.map +0 -1
  129. package/dist/src/keyboard/index.js +0 -55
  130. package/dist/src/keyboard/index.js.map +0 -1
  131. package/dist/src/middleware/compose.d.ts +0 -5
  132. package/dist/src/middleware/compose.d.ts.map +0 -1
  133. package/dist/src/middleware/compose.js +0 -17
  134. package/dist/src/middleware/compose.js.map +0 -1
  135. package/dist/src/observability/logger.d.ts +0 -78
  136. package/dist/src/observability/logger.d.ts.map +0 -1
  137. package/dist/src/observability/logger.js +0 -285
  138. package/dist/src/observability/logger.js.map +0 -1
  139. package/dist/src/plugins/plugin.d.ts +0 -38
  140. package/dist/src/plugins/plugin.d.ts.map +0 -1
  141. package/dist/src/plugins/plugin.js +0 -59
  142. package/dist/src/plugins/plugin.js.map +0 -1
  143. package/dist/src/queue/queue.d.ts +0 -77
  144. package/dist/src/queue/queue.d.ts.map +0 -1
  145. package/dist/src/queue/queue.js +0 -213
  146. package/dist/src/queue/queue.js.map +0 -1
  147. package/dist/src/router/router.d.ts +0 -61
  148. package/dist/src/router/router.d.ts.map +0 -1
  149. package/dist/src/router/router.js +0 -183
  150. package/dist/src/router/router.js.map +0 -1
  151. package/dist/src/state/conversation.d.ts +0 -56
  152. package/dist/src/state/conversation.d.ts.map +0 -1
  153. package/dist/src/state/conversation.js +0 -133
  154. package/dist/src/state/conversation.js.map +0 -1
  155. package/dist/src/state/forms.d.ts +0 -34
  156. package/dist/src/state/forms.d.ts.map +0 -1
  157. package/dist/src/state/forms.js +0 -44
  158. package/dist/src/state/forms.js.map +0 -1
  159. package/dist/src/state/menu.d.ts +0 -78
  160. package/dist/src/state/menu.d.ts.map +0 -1
  161. package/dist/src/state/menu.js +0 -127
  162. package/dist/src/state/menu.js.map +0 -1
  163. package/dist/src/storage/storage.d.ts +0 -146
  164. package/dist/src/storage/storage.d.ts.map +0 -1
  165. package/dist/src/storage/storage.js +0 -195
  166. package/dist/src/storage/storage.js.map +0 -1
  167. package/dist/src/telegram-features.d.ts +0 -33
  168. package/dist/src/telegram-features.d.ts.map +0 -1
  169. package/dist/src/telegram-features.js +0 -71
  170. package/dist/src/telegram-features.js.map +0 -1
  171. package/dist/src/testing.d.ts +0 -24
  172. package/dist/src/testing.d.ts.map +0 -1
  173. package/dist/src/testing.js +0 -38
  174. package/dist/src/testing.js.map +0 -1
  175. package/dist/src/utils/concurrency.d.ts +0 -25
  176. package/dist/src/utils/concurrency.d.ts.map +0 -1
  177. package/dist/src/utils/concurrency.js +0 -52
  178. package/dist/src/utils/concurrency.js.map +0 -1
  179. package/dist/src/utils/files.d.ts +0 -45
  180. package/dist/src/utils/files.d.ts.map +0 -1
  181. package/dist/src/utils/files.js +0 -53
  182. package/dist/src/utils/files.js.map +0 -1
  183. package/dist/src/utils/text.d.ts +0 -39
  184. package/dist/src/utils/text.d.ts.map +0 -1
  185. package/dist/src/utils/text.js +0 -56
  186. package/dist/src/utils/text.js.map +0 -1
  187. package/dist/src/webhook/handler.d.ts +0 -19
  188. package/dist/src/webhook/handler.d.ts.map +0 -1
  189. package/dist/src/webhook/handler.js +0 -141
  190. package/dist/src/webhook/handler.js.map +0 -1
  191. package/dist-cjs/generated/api.js +0 -194
  192. package/dist-cjs/package.json +0 -3
  193. package/dist-cjs/src/api/client.js +0 -107
  194. package/dist-cjs/src/api/errors.js +0 -74
  195. package/dist-cjs/src/api/index.js +0 -21
  196. package/dist-cjs/src/api/telegram-types/LICENSE +0 -21
  197. package/dist-cjs/src/api/telegram-types/api.d.ts +0 -22
  198. package/dist-cjs/src/api/telegram-types/checklist.d.ts +0 -72
  199. package/dist-cjs/src/api/telegram-types/inline.d.ts +0 -692
  200. package/dist-cjs/src/api/telegram-types/langs.d.ts +0 -193
  201. package/dist-cjs/src/api/telegram-types/manage.d.ts +0 -1144
  202. package/dist-cjs/src/api/telegram-types/markup.d.ts +0 -268
  203. package/dist-cjs/src/api/telegram-types/message.d.ts +0 -1537
  204. package/dist-cjs/src/api/telegram-types/methods.d.ts +0 -2870
  205. package/dist-cjs/src/api/telegram-types/mod.d.ts +0 -14
  206. package/dist-cjs/src/api/telegram-types/passport.d.ts +0 -163
  207. package/dist-cjs/src/api/telegram-types/payment.d.ts +0 -570
  208. package/dist-cjs/src/api/telegram-types/rich.d.ts +0 -1010
  209. package/dist-cjs/src/api/telegram-types/settings.d.ts +0 -120
  210. package/dist-cjs/src/api/telegram-types/story.d.ts +0 -89
  211. package/dist-cjs/src/api/telegram-types/update.d.ts +0 -84
  212. package/dist-cjs/src/api/telegram.js +0 -2
  213. package/dist-cjs/src/api/transport.js +0 -267
  214. package/dist-cjs/src/api/types.js +0 -2
  215. package/dist-cjs/src/branding/terminal.js +0 -338
  216. package/dist-cjs/src/broadcast/broadcast.js +0 -58
  217. package/dist-cjs/src/cache/cache.js +0 -45
  218. package/dist-cjs/src/cli.js +0 -86
  219. package/dist-cjs/src/context/context.js +0 -305
  220. package/dist-cjs/src/core/bot.js +0 -510
  221. package/dist-cjs/src/core/events.js +0 -38
  222. package/dist-cjs/src/core/webhook-reply.js +0 -42
  223. package/dist-cjs/src/index.js +0 -47
  224. package/dist-cjs/src/keyboard/index.js +0 -61
  225. package/dist-cjs/src/middleware/compose.js +0 -20
  226. package/dist-cjs/src/observability/logger.js +0 -293
  227. package/dist-cjs/src/plugins/plugin.js +0 -63
  228. package/dist-cjs/src/queue/queue.js +0 -219
  229. package/dist-cjs/src/router/router.js +0 -186
  230. package/dist-cjs/src/state/conversation.js +0 -139
  231. package/dist-cjs/src/state/forms.js +0 -47
  232. package/dist-cjs/src/state/menu.js +0 -133
  233. package/dist-cjs/src/storage/storage.js +0 -202
  234. package/dist-cjs/src/telegram-features.js +0 -76
  235. package/dist-cjs/src/testing.js +0 -45
  236. package/dist-cjs/src/utils/concurrency.js +0 -57
  237. package/dist-cjs/src/utils/files.js +0 -58
  238. package/dist-cjs/src/utils/text.js +0 -63
  239. package/dist-cjs/src/webhook/handler.js +0 -144
  240. package/docs/API.id.md +0 -1935
  241. package/docs/API.md +0 -1969
  242. package/docs/API.zh-CN.md +0 -1929
  243. package/docs/GETTING_STARTED.id.md +0 -85
  244. package/docs/GETTING_STARTED.md +0 -85
  245. package/docs/GETTING_STARTED.zh-CN.md +0 -85
  246. package/docs/GITHUB_PACKAGES.id.md +0 -82
  247. package/docs/GITHUB_PACKAGES.md +0 -82
  248. package/docs/GITHUB_PACKAGES.zh-CN.md +0 -82
  249. package/docs/README.md +0 -48
  250. package/docs/STORAGE.id.md +0 -105
  251. package/docs/STORAGE.md +0 -105
  252. package/docs/STORAGE.zh-CN.md +0 -105
  253. package/examples/README.md +0 -37
  254. package/examples/files.ts +0 -35
  255. package/examples/minimal.ts +0 -12
  256. package/examples/tsconfig.json +0 -9
  257. package/examples/webhook.ts +0 -42
  258. package/examples/wizard-registration.ts +0 -42
@@ -0,0 +1,61 @@
1
+ // lib/ratelimit.js — auto-retry 429, throttler antre, dan batas laju per-user.
2
+ 'use strict';
3
+
4
+ const dbg = require('debug')('telebibz:ratelimit');
5
+
6
+ /** Transformer 429: hormati retry_after Telegram (maks maxRetry kali).
7
+ * Pasang: bot.api.config.use(autoRetry()) */
8
+ function autoRetry({ maxRetry = 5, baseDelayMs = 500 } = {}) {
9
+ return async (prev, method, payload) => {
10
+ let attempt = 0;
11
+ for (;;) {
12
+ try { return await prev(method, payload); }
13
+ catch (err) {
14
+ const ra = err && err.parameters && err.parameters.retry_after;
15
+ if (ra !== undefined && attempt < maxRetry) {
16
+ attempt++;
17
+ const wait = ra * 1000 + baseDelayMs * attempt;
18
+ dbg('429 pada %s — tidur %dms (attempt %d)', method, wait, attempt);
19
+ await new Promise((r) => setTimeout(r, wait));
20
+ continue;
21
+ }
22
+ throw err;
23
+ }
24
+ }
25
+ };
26
+ }
27
+
28
+ /** Transformer antrean: jaga maks `perSecond` panggilan API global.
29
+ * Pasang: bot.api.config.use(throttler()) */
30
+ function throttler({ perSecond = 28 } = {}) {
31
+ const interval = 1000 / perSecond;
32
+ let last = 0; let chain = Promise.resolve();
33
+ return (prev, method, payload) => {
34
+ chain = chain.then(async () => {
35
+ const wait = last + interval - Date.now();
36
+ if (wait > 0) await new Promise((r) => setTimeout(r, wait));
37
+ last = Date.now();
38
+ return prev(method, payload);
39
+ });
40
+ return chain;
41
+ };
42
+ }
43
+
44
+ /** Middleware anti-spam: maks `limit` update per user per `windowMs`. */
45
+ function limiter({ windowMs = 2000, limit = 3, onExceeded } = {}) {
46
+ const bucket = new Map();
47
+ return async (ctx, next) => {
48
+ const key = ctx.from ? ctx.from.id : (ctx.chatId || '?');
49
+ const now = Date.now();
50
+ const arr = bucket.get(key) || [];
51
+ const alive = arr.filter((t) => now - t < windowMs);
52
+ if (alive.length >= limit) {
53
+ if (onExceeded) return onExceeded(ctx);
54
+ return; // diamkan spam
55
+ }
56
+ alive.push(now); bucket.set(key, alive);
57
+ return next();
58
+ };
59
+ }
60
+
61
+ module.exports = { autoRetry, throttler, limiter };
package/lib/runner.js ADDED
@@ -0,0 +1,45 @@
1
+ // lib/runner.js — long polling tahan banting (retry 409 & jaringan, backoff halus).
2
+ 'use strict';
3
+
4
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
5
+
6
+ /**
7
+ * Loop getUpdates; memanggil handleUpdate per update.
8
+ * stop() mengamaninya keluar loop dengan bersih.
9
+ * Perilaku:
10
+ * - error jaringan (fetch gagal) → retry 1 dtk
11
+ * - 409 (instance lain masih polling) → log callback onConflict + retry 5 dtk
12
+ * - error API lain → oper ke onFatal (default: berhenti bersih)
13
+ */
14
+ async function pollLoop({ api, handleUpdate, allowedUpdates, dropPending, onConflict, onFatal, shouldStop, conflictDelay = 5000 }) {
15
+ let offset = 0;
16
+ if (dropPending) {
17
+ try {
18
+ const u = await api.callApi('getUpdates', { offset: -1, timeout: 0, allowed_updates: allowedUpdates });
19
+ if (u.length) offset = u[u.length - 1].update_id + 1;
20
+ } catch { /* abaikan — loop utama yang menangani */ }
21
+ }
22
+
23
+ while (!shouldStop()) {
24
+ let updates;
25
+ try {
26
+ updates = await api.callApi('getUpdates', { offset, timeout: 25, allowed_updates: allowedUpdates });
27
+ if (!Array.isArray(updates)) updates = [];
28
+ } catch (err) {
29
+ const code = err && (err.error_code || err.code);
30
+ if (shouldStop()) break;
31
+ if (code === 409) { if (onConflict) onConflict(err); await sleep(conflictDelay); continue; }
32
+ const fatal = code && code !== 429;
33
+ if (fatal) { if (onFatal) onFatal(err); break; }
34
+ await sleep(1000); continue; // koneksi putus / 429 → napas sebentar
35
+ }
36
+
37
+ for (const u of updates) {
38
+ if (shouldStop()) break;
39
+ offset = u.update_id + 1;
40
+ try { await handleUpdate(u); } catch { /* sudah ditangani error handler bot */ }
41
+ }
42
+ }
43
+ }
44
+
45
+ module.exports = { pollLoop };
package/lib/session.js ADDED
@@ -0,0 +1,36 @@
1
+ // lib/session.js — sesi per-user-per-chat, tanpa konfigurasi.
2
+ 'use strict';
3
+
4
+ /**
5
+ * session({ initial, getKey, storage })
6
+ * - default getKey: from.id + chat.id (khas), fallback chat.id.
7
+ * - default storage: Map di memori. Boleh kirim storage custom { read(key), write(key,val), delete(key) }.
8
+ */
9
+ function session(opts = {}) {
10
+ const initial = opts.initial || (() => ({}));
11
+ const store = opts.storage || new Map();
12
+ const getKey = opts.getKey || ((ctx) => {
13
+ const from = ctx.from && ctx.from.id;
14
+ const chat = ctx.chat && ctx.chat.id;
15
+ if (from !== undefined && chat !== undefined) return `${from}:${chat}`;
16
+ return chat !== undefined ? String(chat) : undefined;
17
+ });
18
+
19
+ const read = (k) => (store.read ? store.read(k) : store.get(k));
20
+ const write = (k, v) => (store.write ? store.write(k, v) : store.set(k, v));
21
+ const del = (k) => (store.delete ? store.delete(k) : store.delete(k));
22
+
23
+ return async (ctx, next) => {
24
+ const key = getKey(ctx);
25
+ if (key === undefined) { ctx.session = {}; return next(); }
26
+ let s = await read(key);
27
+ if (s === undefined || s === null) { s = initial(); await write(key, s); }
28
+ // Proxy: properti __deleted di akhir → hapus dari store
29
+ ctx.session = new Proxy(s, {
30
+ get: (t, p) => t[p], set: (t, p, v) => { t[p] = v; return true; },
31
+ });
32
+ return next();
33
+ };
34
+ }
35
+
36
+ module.exports = { session };
@@ -0,0 +1,190 @@
1
+ // lib/telebibz.js — kelas utama: 100% kode sendiri, 0 dependency.
2
+ 'use strict';
3
+
4
+ const { makeApi } = require('./api');
5
+ const { Context } = require('./context');
6
+ const { Composer } = require('./composer');
7
+ const { session } = require('./session');
8
+ const { matchInlineQuery } = require('./inline-query');
9
+ const { Menu, MenuContainer } = require('./menus');
10
+ const { pollLoop } = require('./runner');
11
+ const wizard = require('./wizard');
12
+ const log = require('./logger');
13
+ const { humanize } = require('./errors');
14
+ const { broadcast } = require('./broadcast');
15
+
16
+ const DEFAULT_UPDATES = [
17
+ 'message', 'edited_message', 'callback_query', 'inline_query',
18
+ 'my_chat_member', 'chat_member', 'message_reaction',
19
+ 'business_connection', 'business_message', 'edited_business_message',
20
+ ];
21
+
22
+ class TeleBibz {
23
+ /**
24
+ * new TeleBibz('123:ABC', {
25
+ * allowedUpdates: [...], onError(err, ctx), silent, dropPending,
26
+ * transport: (method, payload) => Promise<result>, // ← suntik untuk test
27
+ * session: {...opsi session}, apiRoot: 'https://api.telegram.org'
28
+ * })
29
+ */
30
+ constructor(token, opts = {}) {
31
+ if (!token || !/^\d+:[\w-]+$/.test(token)) {
32
+ throw new Error('TeleBibz: token tidak valid. Ambil dari @BotFather → /newbot.');
33
+ }
34
+ this.opts = opts;
35
+ this.token = token;
36
+ this.api = makeApi(token, opts.transport);
37
+ this.botInfo = undefined;
38
+
39
+ this._handlers = new Composer(); // composer publik (use/on/cmd/dll)
40
+ this._report = async (bare) => {
41
+ const err = bare && bare.error ? bare.error : bare;
42
+ const ctx = bare && bare.ctx;
43
+ if (typeof this.opts.onError === 'function') return this.opts.onError(err, ctx);
44
+ this.printError(err, ctx);
45
+ };
46
+
47
+ // Pohon eksekusi: session → wizard → user handlers (dilindungi boundary)
48
+ this._root = new Composer()
49
+ .use(session(opts.session || {}))
50
+ .use(wizard.middleware());
51
+ this._safe = this._root.errorBoundary(this._report);
52
+ }
53
+
54
+ /* ---------- shortcut publik ---------- */
55
+ use(...mw) { this._handlers.use(...mw); return this; }
56
+ cmd(names, ...mw) { this._handlers.command(names, ...mw); return this; }
57
+ hears(match, ...mw) {
58
+ this._handlers.hears(match instanceof RegExp || Array.isArray(match) ? match : new RegExp(`^${escapeRe(match)}$`, 'i'), ...mw);
59
+ return this;
60
+ }
61
+ action(trigs, ...mw) { this._handlers.callbackQuery(trigs, ...mw); return this; }
62
+
63
+ /** Mode inline: bot.inlineQuery(/kucing/, handler) atau bot.inlineQuery('*', h) */
64
+ branch(...a) { this._handlers.branch(...a); return this; }
65
+ filter(...a) { this._handlers.filter(...a); return this; }
66
+ drop(...a) { this._handlers.drop(...a); return this; }
67
+ route(...a) { this._handlers.route(...a); return this; }
68
+ lazy(...a) { this._handlers.lazy(...a); return this; }
69
+ fork(...a) { this._handlers.fork(...a); return this; }
70
+
71
+ inlineQuery(trigger, ...mw) { this._handlers.use(async (ctx, next) => (matchInlineQuery(trigger)(ctx) ? runChain(mw, ctx, next) : next())); return this; }
72
+
73
+ /** Shortcut shortcut: daftarkan daftar perintah ke tombol menu Telegram. */
74
+ setMyCommands(commands, extra = {}) { return this.api.setMyCommands(commands, extra); }
75
+ on(filter, ...mw) { this._handlers.on(filter, ...mw); return this; }
76
+ start(replies) {
77
+ const h = typeof replies === 'function' ? replies : async (ctx) => ctx.reply(replies);
78
+ return this.cmd('start', h);
79
+ }
80
+
81
+ /* ---------- wizard ---------- */
82
+ wizard(id, def, bindCommand = true) {
83
+ wizard.define(id, def);
84
+ if (bindCommand) this.cmd(id, (ctx) => wizard.start(ctx, id));
85
+ return this;
86
+ }
87
+ wizardStart(ctx, id) { return wizard.start(ctx, id); }
88
+ wizardActive(ctx) { return wizard.active(ctx); }
89
+
90
+ /* ---------- broadcast ---------- */
91
+ broadcast(ids, pesan, opts) { return broadcast(this.api, ids, pesan, opts); }
92
+
93
+ /* ---------- siklus hidup ---------- */
94
+
95
+ /** Ambil identitas bot (dipanggil otomatis oleh launch; panggil manual untuk webhook). */
96
+ async init() {
97
+ const me = await this.api.getMe();
98
+ this.botInfo = me;
99
+ return me;
100
+ }
101
+
102
+ /** Tangani SATU update mentah (webhook/serverless/test). */
103
+ async handleUpdate(update) {
104
+ if (this._wired !== true) this._wire();
105
+ const ctx = new Context(update, this.api, this.botInfo);
106
+ try { await this._root.run(ctx); }
107
+ catch (err) { await this._report({ error: err, ctx }); }
108
+ }
109
+
110
+ _wire() {
111
+ this._wired = true;
112
+ // Pasang handler publik SETELAH boundary agar semuanya terlindungi
113
+ this._root.use(this._handlers.middleware());
114
+ }
115
+
116
+ /** Nyalakan long polling (dengan retry 409 & backoff jaringan). */
117
+ async launch(launchOpts = {}) {
118
+ await this.init();
119
+ const me = this.botInfo;
120
+ if (!this.opts.silent) {
121
+ log.banner('🤖 TeleBibz ON', [
122
+ `bot : @${me.username} (id ${me.id})`,
123
+ 'mode : long-polling',
124
+ `library : telebibz ${require('../package.json').version} (0 dependency)`,
125
+ 'brand : //—Xbibz Official—//',
126
+ ]);
127
+ log.ok('menunggu update… (Ctrl+C untuk berhenti)');
128
+ }
129
+ this._stopping = false;
130
+ this._runPromise = pollLoop({
131
+ api: this.api,
132
+ handleUpdate: (u) => this.handleUpdate(u),
133
+ allowedUpdates: this.opts.allowedUpdates || DEFAULT_UPDATES,
134
+ dropPending: this.opts.dropPending || launchOpts.dropPending || false,
135
+ shouldStop: () => this._stopping,
136
+ conflictDelay: launchOpts.conflictDelay || 5000,
137
+ onConflict: () => { if (!this.opts.silent) log.warn('bot lain masih polling (409) — coba lagi 5 detik…'); },
138
+ onFatal: (err) => this._report({ error: err }),
139
+ });
140
+ // Ctrl+C → berhenti bersih
141
+ if (!this.opts.silent && !launchOpts.noSignalHandlers) {
142
+ const stop = () => { log.warn('mematikan…'); this.stop(); };
143
+ process.once('SIGINT', stop); process.once('SIGTERM', stop);
144
+ }
145
+ return this;
146
+ }
147
+
148
+ /** Berhenti polling (resolve runPromise). */
149
+ stop() { this._stopping = true; }
150
+ /** Promise loop polling — ditunggu utk graceful shutdown/test. */
151
+ get runPromise() { return this._runPromise; }
152
+
153
+ /**
154
+ * Handler webhook gaya Node/Express:
155
+ * const server = bot.webhook();
156
+ * http.createServer((req,res) => req.url==='/tg' ? server(req,res) : ...)
157
+ * — framework mana pun: (req, res) pasangan Request/Response Node.
158
+ */
159
+ webhook() {
160
+ return async (req, res) => {
161
+ try {
162
+ const chunks = [];
163
+ for await (const c of req) chunks.push(Buffer.from(c));
164
+ const update = JSON.parse(Buffer.concat(chunks).toString('utf8'));
165
+ await this.handleUpdate(update);
166
+ res.statusCode = 200; res.setHeader('Content-Type', 'application/json'); res.end('{}');
167
+ } catch (e) { res.statusCode = 400; res.end('bad request'); }
168
+ };
169
+ }
170
+
171
+ /* ---------- error cantik ---------- */
172
+ printError(err, ctx) {
173
+ const h = humanize(err);
174
+ log.error(`Telegram error${h.code ? ` (${h.code})` : ''}: ${h.pesan}`);
175
+ if (h.method) log.error(` saat memanggil : ${h.method}`);
176
+ const c = ctx && ctx.chat ? ctx.chat.id : '-';
177
+ if (c !== '-') log.error(` di chat : ${c}`);
178
+ if (h.saran) log.warn(` 💡 saran: ${h.saran}`);
179
+ }
180
+ }
181
+
182
+ function runChain(mws, ctx, next) {
183
+ let i = 0;
184
+ const step = () => (i < mws.length ? mws[i++](ctx, step) : next());
185
+ return step();
186
+ }
187
+
188
+ function escapeRe(s) { return String(s).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }
189
+
190
+ module.exports = { TeleBibz };
package/lib/wizard.js ADDED
@@ -0,0 +1,81 @@
1
+ // lib/wizard.js — percakapan tanya-jawab berurutan (form) berbasis sesi.
2
+ 'use strict';
3
+
4
+ const KEY = '__telebibz_wizard';
5
+
6
+ /**
7
+ * Definisi wizard:
8
+ * {
9
+ * steps: [
10
+ * { key:'nama', ask:'Siapa namamu?' },
11
+ * { key:'umur', ask:'Umur berapa?', parse: Number,
12
+ * validate: (n) => (n>0 && n<120) ? null : 'Umur tidak masuk akal, ulangi:' },
13
+ * ],
14
+ * done: async (answers, ctx) => {},
15
+ * cancelWords: ['batal', '/batal', 'cancel'], // ops, default ada
16
+ * onCancel: (ctx) => ctx.reply('Dibatalkan.'), // ops
17
+ * }
18
+ */
19
+ const wizards = new Map();
20
+
21
+ function define(id, def) {
22
+ if (!def || !Array.isArray(def.steps) || !def.steps.length || typeof def.done !== 'function') {
23
+ throw new Error(`wizard "${id}" butuh steps[] dan done(answers, ctx)`);
24
+ }
25
+ const cancelWords = new Set((def.cancelWords || ['batal', '/batal', 'cancel']).map((s) => String(s).toLowerCase()));
26
+ wizards.set(id, { ...def, cancelWords });
27
+ return id;
28
+ }
29
+
30
+ function get(id) { return wizards.get(id); }
31
+
32
+ /** Mulai wizard dari handler mana pun (command/action/dll). */
33
+ async function start(ctx, id) {
34
+ const def = wizards.get(id);
35
+ if (!def) throw new Error(`wizard "${id}" belum didefinisikan`);
36
+ if (!ctx.session) throw new Error('telebibz: session belum aktif (lib internal)');
37
+ ctx.session[KEY] = { id, i: 0, ans: {} };
38
+ const s0 = def.steps[0];
39
+ return ctx.reply(typeof s0.ask === 'function' ? await s0.ask(ctx) : s0.ask, s0.opts || {});
40
+ }
41
+
42
+ /** Middleware global: memproses jawaban wizard yang sedang berjalan. */
43
+ function middleware() {
44
+ return async (ctx, next) => {
45
+ const st = ctx.session && ctx.session[KEY];
46
+ if (!st) return next();
47
+ const def = wizards.get(st.id);
48
+ if (!def) { delete ctx.session[KEY]; return next(); }
49
+
50
+ const text = ctx.message && typeof ctx.message.text === 'string' ? ctx.message.text.trim() : null;
51
+ if (text === null) return; // pesan non-teks (foto/stiker) — diamkan, wizard menunggu
52
+
53
+ if (def.cancelWords.has(text.toLowerCase())) {
54
+ delete ctx.session[KEY];
55
+ if (def.onCancel) return def.onCancel(ctx);
56
+ return ctx.reply('✖️ Sesi dibatalkan.');
57
+ }
58
+
59
+ const step = def.steps[st.i];
60
+ let value = text;
61
+ if (step.parse) value = await step.parse(text, ctx);
62
+ if (step.validate) {
63
+ const errMsg = await step.validate(value, ctx);
64
+ if (errMsg) return ctx.reply(errMsg);
65
+ }
66
+ st.ans[step.key] = value;
67
+ st.i += 1;
68
+
69
+ if (st.i >= def.steps.length) {
70
+ delete ctx.session[KEY];
71
+ return def.done(st.ans, ctx);
72
+ }
73
+ const ns = def.steps[st.i];
74
+ return ctx.reply(typeof ns.ask === 'function' ? await ns.ask(ctx) : ns.ask, ns.opts || {});
75
+ };
76
+ }
77
+
78
+ /** True kalau user ini sedang di tengah wizard. */
79
+ function active(ctx) { return Boolean(ctx.session && ctx.session[KEY]); }
80
+
81
+ module.exports = { define, get, start, middleware, active, KEY };
package/package.json CHANGED
@@ -1,114 +1,52 @@
1
1
  {
2
2
  "name": "@xbibzlibrary/telebibz",
3
- "version": "0.4.4",
4
- "description": "Telegram Bot framework for Node.js and TypeScript with a typed API client, routing, middleware, webhooks, keyboards, conversations, plugins, queues, and a polished terminal experience.",
5
- "keywords": [
6
- "telegram",
7
- "telegram-bot",
8
- "telegram-bot-api",
9
- "telegram-bot-framework",
10
- "nodejs",
11
- "typescript",
12
- "telegram-webhook",
13
- "long-polling",
14
- "conversation-wizard",
15
- "inline-keyboard",
16
- "telegram-mini-app",
17
- "bot-framework"
18
- ],
19
- "type": "module",
20
- "private": false,
21
- "publishConfig": {
22
- "access": "public",
23
- "provenance": false
24
- },
3
+ "version": "3.0.1",
4
+ "description": "Library Telegram Indonesia production-grade set fitur penuh setara grammY: proxy-api segala metode, transformer, menus, inline query, media group, throttler & auto-retry, session swappable, webhook, polling tahan-409. //—Xbibz Official—//",
5
+ "main": "index.js",
6
+ "types": "index.d.ts",
7
+ "type": "commonjs",
25
8
  "license": "MIT",
9
+ "author": "Xbibz Official",
26
10
  "repository": {
27
11
  "type": "git",
28
12
  "url": "https://github.com/XbibzOfficial777/telebibz.git"
29
13
  },
30
14
  "homepage": "https://github.com/XbibzOfficial777/telebibz#readme",
31
- "bugs": {
32
- "url": "https://github.com/XbibzOfficial777/telebibz/issues"
33
- },
15
+ "keywords": [
16
+ "telegram",
17
+ "telegram-bot",
18
+ "bot",
19
+ "grammy",
20
+ "telegram-api",
21
+ "inline-keyboard",
22
+ "wizard",
23
+ "broadcast",
24
+ "indonesia",
25
+ "nodejs",
26
+ "zero-dependency",
27
+ "tanpa-dependency"
28
+ ],
34
29
  "engines": {
35
- "node": ">=22"
30
+ "node": ">=18"
36
31
  },
37
- "scripts": {
38
- "generate": "node scripts/generate-api.mjs",
39
- "update:telegram": "node scripts/fetch-telegram-api.mjs && npm run generate",
40
- "build": "tsc -p tsconfig.json && tsc -p tsconfig.cjs.json && node scripts/create-cjs-package.mjs && node scripts/copy-telegram-types.mjs",
41
- "typecheck": "tsc -p tsconfig.json --noEmit",
42
- "lint": "tsc -p tsconfig.json --noEmit && eslint scripts/*.mjs bin/*.mjs --no-error-on-unmatched-pattern",
43
- "test": "vitest run",
44
- "test:watch": "vitest",
45
- "test:integration": "vitest run tests/integration/**/*.test.ts",
46
- "test:e2e": "vitest run tests/e2e",
47
- "test:types": "tsc -p tests/tsconfig.json --noEmit",
48
- "test:examples": "tsc -p examples/tsconfig.json --noEmit",
49
- "benchmark": "tsx tests/benchmark.ts",
50
- "package:check": "npm run build && npm pack --dry-run",
51
- "security": "npm audit --audit-level=high --package-lock-only",
52
- "release:check": "node scripts/release-check.mjs",
53
- "doctor": "tsx src/cli.ts doctor",
54
- "start": "tsx src/cli.ts start",
55
- "dev": "tsx examples/minimal.ts",
56
- "prepack": "npm run build",
57
- "prepublishOnly": "npm run typecheck && npm run test:types && npm run test:examples && npm run lint && npm test && npm run build && npm run security && npm run release:check"
58
- },
59
- "bin": {
60
- "telebibz": "./bin/telebibz.mjs"
32
+ "dependencies": {
33
+ "axios": "^1.20.0",
34
+ "mime-types": "^3.0.2",
35
+ "https-proxy-agent": "^9.1.0",
36
+ "debug": "^4.4.3"
61
37
  },
62
- "exports": {
63
- ".": {
64
- "types": "./dist/src/index.d.ts",
65
- "import": "./dist/src/index.js",
66
- "require": "./dist-cjs/src/index.js"
67
- },
68
- "./api": {
69
- "types": "./dist/src/api/index.d.ts",
70
- "import": "./dist/src/api/index.js",
71
- "require": "./dist-cjs/src/api/index.js"
72
- },
73
- "./keyboard": {
74
- "types": "./dist/src/keyboard/index.d.ts",
75
- "import": "./dist/src/keyboard/index.js",
76
- "require": "./dist-cjs/src/keyboard/index.js"
77
- },
78
- "./testing": {
79
- "types": "./dist/src/testing.d.ts",
80
- "import": "./dist/src/testing.js",
81
- "require": "./dist-cjs/src/testing.js"
82
- }
38
+ "scripts": {
39
+ "test": "node test/all.test.js"
83
40
  },
84
41
  "files": [
85
- "dist",
86
- "dist-cjs",
87
- "bin",
42
+ "index.js",
43
+ "index.d.ts",
44
+ "lib/",
45
+ "examples/",
46
+ "test/",
88
47
  "README.md",
89
- "README.id.md",
90
- "README.zh-CN.md",
91
48
  "LICENSE",
92
- "CHANGELOG.md",
93
- "SECURITY.md",
94
- "CODE_OF_CONDUCT.md",
95
- "CONTRIBUTING.md",
96
- "CONTRIBUTION_RULES.md",
97
- "GOVERNANCE.md",
98
- "SUPPORT.md",
99
49
  "NOTICE.md",
100
- "RELEASE_POLICY.md",
101
- "RELEASE_AUTOMATION.md",
102
- "SHOWCASE.md",
103
- "assets",
104
- "docs",
105
- "examples"
106
- ],
107
- "devDependencies": {
108
- "@types/node": "^22.10.0",
109
- "eslint": "^9.17.0",
110
- "tsx": "^4.19.2",
111
- "typescript": "^5.7.2",
112
- "vitest": "^4.1.11"
113
- }
50
+ "CHANGELOG.md"
51
+ ]
114
52
  }