teledzik 1.0.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 (198) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +1126 -0
  3. package/filters.d.ts +1 -0
  4. package/filters.js +1 -0
  5. package/format.d.ts +1 -0
  6. package/format.js +1 -0
  7. package/future.d.ts +1 -0
  8. package/future.js +1 -0
  9. package/lib/button.js +101 -0
  10. package/lib/cli.mjs +105 -0
  11. package/lib/composer.js +581 -0
  12. package/lib/context.js +1300 -0
  13. package/lib/core/helpers/ai-stream.js +69 -0
  14. package/lib/core/helpers/args.js +58 -0
  15. package/lib/core/helpers/check.js +56 -0
  16. package/lib/core/helpers/compact.js +17 -0
  17. package/lib/core/helpers/deunionize.js +13 -0
  18. package/lib/core/helpers/formatting.js +89 -0
  19. package/lib/core/helpers/input-box.js +87 -0
  20. package/lib/core/helpers/rich-sanitizer.js +31 -0
  21. package/lib/core/helpers/smart-queue.js +70 -0
  22. package/lib/core/helpers/util.js +50 -0
  23. package/lib/core/network/client.js +318 -0
  24. package/lib/core/network/error.js +21 -0
  25. package/lib/core/network/multipart-stream.js +61 -0
  26. package/lib/core/network/polling.js +86 -0
  27. package/lib/core/network/webhook.js +54 -0
  28. package/lib/core/types/rich-message.js +287 -0
  29. package/lib/core/types/typegram.js +18 -0
  30. package/lib/filters.js +69 -0
  31. package/lib/format.js +38 -0
  32. package/lib/future.js +166 -0
  33. package/lib/index.js +61 -0
  34. package/lib/input.js +61 -0
  35. package/lib/markup.js +111 -0
  36. package/lib/middleware.js +2 -0
  37. package/lib/paginated.js +76 -0
  38. package/lib/reactions.js +81 -0
  39. package/lib/router.js +45 -0
  40. package/lib/scenes/base.js +39 -0
  41. package/lib/scenes/context.js +99 -0
  42. package/lib/scenes/form-scene.js +23 -0
  43. package/lib/scenes/index.js +21 -0
  44. package/lib/scenes/stage.js +49 -0
  45. package/lib/scenes/wizard/context.js +30 -0
  46. package/lib/scenes/wizard/index.js +45 -0
  47. package/lib/scenes.js +17 -0
  48. package/lib/session.js +163 -0
  49. package/lib/telegraf.js +274 -0
  50. package/lib/telegram-types.js +6 -0
  51. package/lib/telegram.js +1286 -0
  52. package/lib/types.js +2 -0
  53. package/lib/utils.js +5 -0
  54. package/markup.d.ts +1 -0
  55. package/markup.js +1 -0
  56. package/package.json +141 -0
  57. package/scenes.d.ts +1 -0
  58. package/scenes.js +1 -0
  59. package/session.d.ts +1 -0
  60. package/session.js +1 -0
  61. package/src/button.ts +182 -0
  62. package/src/composer.ts +1008 -0
  63. package/src/context.ts +1778 -0
  64. package/src/core/helpers/ai-stream.ts +96 -0
  65. package/src/core/helpers/args.ts +63 -0
  66. package/src/core/helpers/check.ts +71 -0
  67. package/src/core/helpers/compact.ts +18 -0
  68. package/src/core/helpers/deunionize.ts +26 -0
  69. package/src/core/helpers/formatting.ts +119 -0
  70. package/src/core/helpers/input-box.ts +86 -0
  71. package/src/core/helpers/rich-sanitizer.ts +36 -0
  72. package/src/core/helpers/smart-queue.ts +89 -0
  73. package/src/core/helpers/util.ts +96 -0
  74. package/src/core/network/client.ts +396 -0
  75. package/src/core/network/error.ts +29 -0
  76. package/src/core/network/multipart-stream.ts +45 -0
  77. package/src/core/network/polling.ts +94 -0
  78. package/src/core/network/webhook.ts +58 -0
  79. package/src/core/types/rich-message.ts +375 -0
  80. package/src/core/types/typegram.ts +44 -0
  81. package/src/filters.js +69 -0
  82. package/src/filters.ts +109 -0
  83. package/src/format.js +38 -0
  84. package/src/format.ts +110 -0
  85. package/src/future.js +147 -0
  86. package/src/future.ts +231 -0
  87. package/src/index.ts +27 -0
  88. package/src/input.ts +59 -0
  89. package/src/markup.js +93 -0
  90. package/src/markup.ts +142 -0
  91. package/src/middleware.ts +24 -0
  92. package/src/paginated.ts +75 -0
  93. package/src/reactions.ts +118 -0
  94. package/src/router.ts +55 -0
  95. package/src/scenes/base.ts +52 -0
  96. package/src/scenes/context.ts +136 -0
  97. package/src/scenes/form-scene.ts +34 -0
  98. package/src/scenes/index.ts +21 -0
  99. package/src/scenes/stage.ts +71 -0
  100. package/src/scenes/wizard/context.ts +58 -0
  101. package/src/scenes/wizard/index.ts +63 -0
  102. package/src/scenes.js +17 -0
  103. package/src/scenes.ts +1 -0
  104. package/src/session.js +175 -0
  105. package/src/session.ts +204 -0
  106. package/src/telegraf.ts +385 -0
  107. package/src/telegram-types.ts +256 -0
  108. package/src/telegram.ts +1700 -0
  109. package/src/types.js +2 -0
  110. package/src/types.ts +2 -0
  111. package/src/utils.js +5 -0
  112. package/src/utils.ts +1 -0
  113. package/types.d.ts +1 -0
  114. package/types.js +1 -0
  115. package/typings/button.d.ts +35 -0
  116. package/typings/button.d.ts.map +1 -0
  117. package/typings/composer.d.ts +226 -0
  118. package/typings/composer.d.ts.map +1 -0
  119. package/typings/context.d.ts +711 -0
  120. package/typings/context.d.ts.map +1 -0
  121. package/typings/core/helpers/ai-stream.d.ts +33 -0
  122. package/typings/core/helpers/args.d.ts +10 -0
  123. package/typings/core/helpers/args.d.ts.map +1 -0
  124. package/typings/core/helpers/check.d.ts +55 -0
  125. package/typings/core/helpers/check.d.ts.map +1 -0
  126. package/typings/core/helpers/compact.d.ts +3 -0
  127. package/typings/core/helpers/compact.d.ts.map +1 -0
  128. package/typings/core/helpers/deunionize.d.ts +17 -0
  129. package/typings/core/helpers/deunionize.d.ts.map +1 -0
  130. package/typings/core/helpers/formatting.d.ts +29 -0
  131. package/typings/core/helpers/formatting.d.ts.map +1 -0
  132. package/typings/core/helpers/input-box.d.ts +32 -0
  133. package/typings/core/helpers/rich-sanitizer.d.ts +5 -0
  134. package/typings/core/helpers/smart-queue.d.ts +18 -0
  135. package/typings/core/helpers/util.d.ts +26 -0
  136. package/typings/core/helpers/util.d.ts.map +1 -0
  137. package/typings/core/network/client.d.ts +54 -0
  138. package/typings/core/network/client.d.ts.map +1 -0
  139. package/typings/core/network/error.d.ts +15 -0
  140. package/typings/core/network/error.d.ts.map +1 -0
  141. package/typings/core/network/multipart-stream.d.ts +19 -0
  142. package/typings/core/network/multipart-stream.d.ts.map +1 -0
  143. package/typings/core/network/polling.d.ts +15 -0
  144. package/typings/core/network/polling.d.ts.map +1 -0
  145. package/typings/core/network/webhook.d.ts +6 -0
  146. package/typings/core/network/webhook.d.ts.map +1 -0
  147. package/typings/core/types/rich-message.d.ts +143 -0
  148. package/typings/core/types/rich-message.d.ts.map +1 -0
  149. package/typings/core/types/typegram.d.ts +36 -0
  150. package/typings/core/types/typegram.d.ts.map +1 -0
  151. package/typings/filters.d.ts +17 -0
  152. package/typings/filters.d.ts.map +1 -0
  153. package/typings/format.d.ts +21 -0
  154. package/typings/format.d.ts.map +1 -0
  155. package/typings/future.d.ts +11 -0
  156. package/typings/future.d.ts.map +1 -0
  157. package/typings/index.d.ts +21 -0
  158. package/typings/index.d.ts.map +1 -0
  159. package/typings/input.d.ts +58 -0
  160. package/typings/input.d.ts.map +1 -0
  161. package/typings/markup.d.ts +26 -0
  162. package/typings/markup.d.ts.map +1 -0
  163. package/typings/middleware.d.ts +7 -0
  164. package/typings/middleware.d.ts.map +1 -0
  165. package/typings/paginated.d.ts +20 -0
  166. package/typings/reactions.d.ts +31 -0
  167. package/typings/reactions.d.ts.map +1 -0
  168. package/typings/router.d.ts +20 -0
  169. package/typings/router.d.ts.map +1 -0
  170. package/typings/scenes/base.d.ts +21 -0
  171. package/typings/scenes/base.d.ts.map +1 -0
  172. package/typings/scenes/context.d.ts +35 -0
  173. package/typings/scenes/context.d.ts.map +1 -0
  174. package/typings/scenes/form-scene.d.ts +17 -0
  175. package/typings/scenes/index.d.ts +10 -0
  176. package/typings/scenes/index.d.ts.map +1 -0
  177. package/typings/scenes/stage.d.ts +23 -0
  178. package/typings/scenes/stage.d.ts.map +1 -0
  179. package/typings/scenes/wizard/context.d.ts +28 -0
  180. package/typings/scenes/wizard/context.d.ts.map +1 -0
  181. package/typings/scenes/wizard/index.d.ts +15 -0
  182. package/typings/scenes/wizard/index.d.ts.map +1 -0
  183. package/typings/scenes.d.ts +1 -0
  184. package/typings/scenes.d.ts.map +1 -0
  185. package/typings/session.d.ts +54 -0
  186. package/typings/session.d.ts.map +1 -0
  187. package/typings/telegraf.d.ts +118 -0
  188. package/typings/telegraf.d.ts.map +1 -0
  189. package/typings/telegram-types.d.ts +140 -0
  190. package/typings/telegram-types.d.ts.map +1 -0
  191. package/typings/telegram.d.ts +697 -0
  192. package/typings/telegram.d.ts.map +1 -0
  193. package/typings/types.d.ts +2 -0
  194. package/typings/types.d.ts.map +1 -0
  195. package/typings/utils.d.ts +1 -0
  196. package/typings/utils.d.ts.map +1 -0
  197. package/utils.d.ts +1 -0
  198. package/utils.js +1 -0
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AIStreamAdapter = void 0;
4
+ /**
5
+ * AI Live Stream Adapter for Telegram Bots.
6
+ * Throttles live token stream edits to prevent Telegram rate limit bans.
7
+ */
8
+ class AIStreamAdapter {
9
+ constructor(ctx, options = {}) {
10
+ this.buffer = '';
11
+ this.lastUpdate = 0;
12
+ this.timer = null;
13
+ this.ctx = ctx;
14
+ this.options = options;
15
+ this.minInterval = options.minUpdateIntervalMs ?? 800;
16
+ }
17
+ /**
18
+ * Append new token chunk from LLM stream.
19
+ */
20
+ async push(chunk) {
21
+ this.buffer += chunk;
22
+ await this.scheduleUpdate();
23
+ }
24
+ /**
25
+ * Finalize the stream and send the full final content.
26
+ */
27
+ async end(finalContent) {
28
+ if (this.timer) {
29
+ clearTimeout(this.timer);
30
+ this.timer = null;
31
+ }
32
+ if (finalContent !== undefined) {
33
+ this.buffer = finalContent;
34
+ }
35
+ return this.flush(true);
36
+ }
37
+ async scheduleUpdate() {
38
+ const now = Date.now();
39
+ const elapsed = now - this.lastUpdate;
40
+ if (elapsed >= this.minInterval) {
41
+ await this.flush();
42
+ }
43
+ else if (!this.timer) {
44
+ this.timer = setTimeout(async () => {
45
+ this.timer = null;
46
+ await this.flush();
47
+ }, this.minInterval - elapsed);
48
+ }
49
+ }
50
+ async flush(isFinal = false) {
51
+ if (!this.buffer)
52
+ return;
53
+ this.lastUpdate = Date.now();
54
+ if (this.options.useDraft && this.options.draftId) {
55
+ const richMsg = { html: `<p>${this.buffer}${isFinal ? '' : ' ▍'}</p>` };
56
+ return this.ctx.sendRichMessageDraft(this.options.draftId, richMsg);
57
+ }
58
+ const text = `${this.buffer}${isFinal ? '' : ' ▍'}`;
59
+ if (!this.sentMessageId) {
60
+ const sent = await this.ctx.reply(text, { parse_mode: 'HTML' });
61
+ this.sentMessageId = sent.message_id;
62
+ return sent;
63
+ }
64
+ else {
65
+ return this.ctx.telegram.editMessageText(this.ctx.chat?.id, this.sentMessageId, undefined, text, { parse_mode: 'HTML' });
66
+ }
67
+ }
68
+ }
69
+ exports.AIStreamAdapter = AIStreamAdapter;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.argsParser = void 0;
4
+ const SINGLE_QUOTE = "'";
5
+ const DOUBLE_QUOTE = '"';
6
+ function argsParser(str, entities = [], entityOffset = 0) {
7
+ const mentions = {};
8
+ for (const entity of entities) // extract all text_mentions into an { offset: length } map
9
+ if (entity.type === 'text_mention' || entity.type === 'text_link')
10
+ mentions[entity.offset - entityOffset] = entity.length;
11
+ const args = [];
12
+ let done = 0;
13
+ let inside = undefined;
14
+ let buf = '';
15
+ function flush(to) {
16
+ if (done !== to)
17
+ args.push(buf + str.slice(done, to)), (inside = undefined);
18
+ buf = '';
19
+ done = to + 1;
20
+ }
21
+ for (let i = 0; i < str.length; i++) {
22
+ const char = str[i];
23
+ // quick lookup length of mention starting at i
24
+ const mention = mentions[i];
25
+ if (mention) {
26
+ // if we're inside a quote, eagerly flush existing state
27
+ flush(i);
28
+ // this also consumes current index, so decrement
29
+ done--;
30
+ // fast forward to end of mention
31
+ i += mention;
32
+ flush(i);
33
+ }
34
+ else if (char === SINGLE_QUOTE || char === DOUBLE_QUOTE)
35
+ if (inside)
36
+ if (inside === char)
37
+ flush(i);
38
+ else
39
+ continue;
40
+ else
41
+ flush(i), (inside = char);
42
+ else if (char === ' ')
43
+ if (inside)
44
+ continue;
45
+ else
46
+ flush(i);
47
+ else if (char === '\n')
48
+ flush(i);
49
+ else if (char === '\\')
50
+ (buf += str.slice(done, i)), (done = ++i); // skip parsing the next char
51
+ else
52
+ continue;
53
+ }
54
+ if (done < str.length)
55
+ flush(str.length);
56
+ return args;
57
+ }
58
+ exports.argsParser = argsParser;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.is2D = exports.hasPropType = exports.hasProp = void 0;
4
+ /**
5
+ * Checks if a given object has a property with a given name.
6
+ *
7
+ * Example invocation:
8
+ * ```js
9
+ * let obj = { 'foo': 'bar', 'baz': () => {} }
10
+ * hasProp(obj, 'foo') // true
11
+ * hasProp(obj, 'baz') // true
12
+ * hasProp(obj, 'abc') // false
13
+ * ```
14
+ *
15
+ * @param obj An object to test
16
+ * @param prop The name of the property
17
+ */
18
+ function hasProp(obj, prop) {
19
+ return obj !== undefined && prop in obj;
20
+ }
21
+ exports.hasProp = hasProp;
22
+ /**
23
+ * Checks if a given object has a property with a given name.
24
+ * Furthermore performs a `typeof` check on the property if it exists.
25
+ *
26
+ * Example invocation:
27
+ * ```js
28
+ * let obj = { 'foo': 'bar', 'baz': () => {} }
29
+ * hasPropType(obj, 'foo', 'string') // true
30
+ * hasPropType(obj, 'baz', 'function') // true
31
+ * hasPropType(obj, 'abc', 'number') // false
32
+ * ```
33
+ *
34
+ * @param obj An object to test
35
+ * @param prop The name of the property
36
+ * @param type The type the property is expected to have
37
+ */
38
+ function hasPropType(obj, prop, type) {
39
+ return hasProp(obj, prop) && type === typeof obj[prop];
40
+ }
41
+ exports.hasPropType = hasPropType;
42
+ /**
43
+ * Checks if the supplied array has two dimensions or not.
44
+ *
45
+ * Example invocations:
46
+ * is2D([]) // false
47
+ * is2D([[]]) // true
48
+ * is2D([[], []]) // true
49
+ * is2D([42]) // false
50
+ *
51
+ * @param arr an array with one or two dimensions
52
+ */
53
+ function is2D(arr) {
54
+ return Array.isArray(arr[0]);
55
+ }
56
+ exports.is2D = is2D;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.compactOptions = void 0;
4
+ function compactOptions(options) {
5
+ if (!options) {
6
+ return options;
7
+ }
8
+ const compacted = {};
9
+ for (const key in options)
10
+ if (
11
+ // todo(mkr): replace with Object.hasOwn in v5 (Node 16+)
12
+ Object.prototype.hasOwnProperty.call(options, key) &&
13
+ options[key] !== undefined)
14
+ compacted[key] = options[key];
15
+ return compacted;
16
+ }
17
+ exports.compactOptions = compactOptions;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deunionize = void 0;
4
+ /**
5
+ * Expose properties from all union variants.
6
+ * @deprectated
7
+ * @see https://github.com/telegraf/telegraf/issues/1388#issuecomment-791573609
8
+ * @see https://millsp.github.io/ts-toolbelt/modules/union_strict.html
9
+ */
10
+ function deunionize(t) {
11
+ return t;
12
+ }
13
+ exports.deunionize = deunionize;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.linkOrMention = exports.createFmt = exports.join = exports.FmtString = void 0;
4
+ const util_1 = require("./util");
5
+ class FmtString {
6
+ constructor(text, entities) {
7
+ this.text = text;
8
+ if (entities) {
9
+ this.entities = entities;
10
+ // force parse_mode to undefined if entities are present
11
+ this.parse_mode = undefined;
12
+ }
13
+ }
14
+ static normalise(content) {
15
+ if (content instanceof FmtString)
16
+ return content;
17
+ return new FmtString(String(content));
18
+ }
19
+ }
20
+ exports.FmtString = FmtString;
21
+ const isArray = Array.isArray;
22
+ /** Given a base FmtString and something to append to it, mutates the base */
23
+ const _add = (base, next) => {
24
+ const len = base.text.length;
25
+ if (next instanceof FmtString) {
26
+ base.text = `${base.text}${next.text}`;
27
+ // next.entities could be undefined and condition will fail
28
+ for (let i = 0; i < (next.entities?.length || 0); i++) {
29
+ // because of the above condition, next.entities[i] cannot be undefined
30
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
31
+ const entity = next.entities[i];
32
+ // base.entities is ensured by caller
33
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
34
+ base.entities.push({ ...entity, offset: entity.offset + len });
35
+ }
36
+ }
37
+ else
38
+ base.text = `${base.text}${next}`;
39
+ };
40
+ /**
41
+ * Given an `Iterable<FmtString | string | Any>` and a separator, flattens the list into a single FmtString.
42
+ * Analogous to Array#join -> string, but for FmtString
43
+ */
44
+ const join = (fragments, separator) => {
45
+ const result = new FmtString('');
46
+ // ensure entities array so loop doesn't need to check
47
+ result.entities = [];
48
+ const iter = fragments[Symbol.iterator]();
49
+ let curr = iter.next();
50
+ while (!curr.done) {
51
+ _add(result, curr.value);
52
+ curr = iter.next();
53
+ if (separator && !curr.done)
54
+ _add(result, separator);
55
+ }
56
+ // set parse_mode: undefined if entities are present
57
+ if (result.entities.length)
58
+ result.parse_mode = undefined;
59
+ // remove entities array if not relevant
60
+ else
61
+ delete result.entities;
62
+ return result;
63
+ };
64
+ exports.join = join;
65
+ /** Internal constructor for all fmt helpers */
66
+ function createFmt(kind, opts) {
67
+ return function fmt(parts, ...items) {
68
+ parts = isArray(parts) ? parts : [parts];
69
+ const result = (0, exports.join)((0, util_1.zip)(parts, items));
70
+ if (kind) {
71
+ result.entities ??= [];
72
+ result.entities.unshift({
73
+ type: kind,
74
+ offset: 0,
75
+ length: result.text.length,
76
+ ...opts,
77
+ });
78
+ result.parse_mode = undefined;
79
+ }
80
+ return result;
81
+ };
82
+ }
83
+ exports.createFmt = createFmt;
84
+ const linkOrMention = (content, data) => {
85
+ const { text, entities = [] } = FmtString.normalise(content);
86
+ entities.unshift(Object.assign(data, { offset: 0, length: text.length }));
87
+ return new FmtString(text, entities);
88
+ };
89
+ exports.linkOrMention = linkOrMention;
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.InputBox = void 0;
27
+ const Markup = __importStar(require("../../markup"));
28
+ /**
29
+ * Interactive In-Chat Form Box Card for Telegram Messages.
30
+ * Render boxed form cards with dynamic real-time field updates.
31
+ */
32
+ class InputBox {
33
+ constructor(id) {
34
+ this.title = '📋 FORM INPUT';
35
+ this.fields = [];
36
+ this.id = id;
37
+ }
38
+ setTitle(title) {
39
+ this.title = title;
40
+ return this;
41
+ }
42
+ addField(key, label, options = {}) {
43
+ this.fields.push({ key, label, ...options });
44
+ return this;
45
+ }
46
+ onComplete(handler) {
47
+ this.completionHandler = handler;
48
+ return this;
49
+ }
50
+ /**
51
+ * Render formatted HTML box card text.
52
+ */
53
+ renderText(data = {}) {
54
+ const lines = [];
55
+ lines.push(`<b>┌─ ${this.title.toUpperCase()} ─┐</b>`);
56
+ this.fields.forEach((field, idx) => {
57
+ const val = data[field.key] ? `<b>${data[field.key]}</b>` : `<i>[ ${field.placeholder ?? 'Belum diisi'} ]</i>`;
58
+ lines.push(`│ ${idx + 1}. <b>${field.label}</b>: ${val}`);
59
+ });
60
+ const isComplete = this.fields.every((f) => Boolean(data[f.key]));
61
+ lines.push(`<b>└${'─'.repeat(30)}┘</b>`);
62
+ lines.push(isComplete ? '<b>Status:</b> ✅ <i>Lengkap (Siap Dikirim)</i>' : '<b>Status:</b> ⌛ <i>Menunggu Pengisian...</i>');
63
+ return lines.join('\n');
64
+ }
65
+ /**
66
+ * Render inline keyboard with field edit buttons and submit action.
67
+ */
68
+ renderKeyboard(data = {}) {
69
+ const buttons = [];
70
+ // Field buttons
71
+ this.fields.forEach((field) => {
72
+ const filled = Boolean(data[field.key]);
73
+ const icon = filled ? '✅' : '✏️';
74
+ buttons.push([Markup.button.callback(`${icon} ${field.label}`, `inputbox:${this.id}:edit:${field.key}`)]);
75
+ });
76
+ // Action row
77
+ const isComplete = this.fields.every((f) => Boolean(data[f.key]));
78
+ if (isComplete) {
79
+ buttons.push([
80
+ Markup.button.callback('🚀 Submit Form', `inputbox:${this.id}:submit`),
81
+ Markup.button.callback('🔄 Reset', `inputbox:${this.id}:reset`),
82
+ ]);
83
+ }
84
+ return Markup.inlineKeyboard(buttons);
85
+ }
86
+ }
87
+ exports.InputBox = InputBox;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sanitizeRichHtml = void 0;
4
+ /**
5
+ * Converts Rich HTML strings containing tags like <h1>, <h2>, <p>, <hr>
6
+ * into standard Telegram HTML compatible with parse_mode: 'HTML' (editMessageText/sendMessage).
7
+ */
8
+ function sanitizeRichHtml(html) {
9
+ if (!html)
10
+ return html;
11
+ let result = html;
12
+ // Convert H1: <h1>Text</h1> -> <b>TEXT</b>
13
+ result = result.replace(/<h1[^>]*>(.*?)<\/h1>/gis, (_, content) => `<b>${content.trim().toUpperCase()}</b>\n\n`);
14
+ // Convert H2..H6: <h2>Text</h2> -> <b>Text</b>
15
+ result = result.replace(/<h[2-6][^>]*>(.*?)<\/h[2-6]>/gis, (_, content) => `<b>${content.trim()}</b>\n\n`);
16
+ // Convert Paragraphs: <p>Text</p> -> Text\n\n
17
+ result = result.replace(/<p[^>]*>(.*?)<\/p>/gis, (_, content) => `${content.trim()}\n\n`);
18
+ // Convert Footer: <footer>Text</footer> -> <i>Text</i>
19
+ result = result.replace(/<footer[^>]*>(.*?)<\/footer>/gis, (_, content) => `<i>${content.trim()}</i>\n`);
20
+ // Convert Horizontal Rules: <hr/> or <hr> -> ──────────
21
+ result = result.replace(/<hr\s*\/?>/gi, '──────────\n');
22
+ // Convert Marks: <mark>Text</mark> -> <b>[Text]</b>
23
+ result = result.replace(/<mark[^>]*>(.*?)<\/mark>/gis, (_, content) => `<b>[${content.trim()}]</b>`);
24
+ // Strip unsupported sub/sup tags but keep text
25
+ result = result.replace(/<sub[^>]*>(.*?)<\/sub>/gis, '$1');
26
+ result = result.replace(/<sup[^>]*>(.*?)<\/sup>/gis, '$1');
27
+ // Trim extra trailing newlines (> 2 consecutive newlines)
28
+ result = result.replace(/\n{3,}/g, '\n\n');
29
+ return result.trim();
30
+ }
31
+ exports.sanitizeRichHtml = sanitizeRichHtml;
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SmartQueue = void 0;
4
+ /**
5
+ * Smart Queue & Rate-Limit Manager for Telegram Bot API calls.
6
+ * Prevents 429 Too Many Requests by enforcing min delay between calls per target key (e.g. chatId).
7
+ */
8
+ class SmartQueue {
9
+ constructor(options = {}) {
10
+ this.queues = new Map();
11
+ this.processing = new Set();
12
+ this.minDelayMs = options.minDelayMs ?? 50;
13
+ }
14
+ static getInstance() {
15
+ if (!SmartQueue.instance) {
16
+ SmartQueue.instance = new SmartQueue();
17
+ }
18
+ return SmartQueue.instance;
19
+ }
20
+ enqueue(key, task, options) {
21
+ return new Promise((resolve, reject) => {
22
+ if (!this.queues.has(key)) {
23
+ this.queues.set(key, []);
24
+ }
25
+ this.queues.get(key).push({
26
+ task,
27
+ resolve,
28
+ reject,
29
+ retries: 0,
30
+ });
31
+ this.processQueue(key, options);
32
+ });
33
+ }
34
+ async processQueue(key, options) {
35
+ if (this.processing.has(key))
36
+ return;
37
+ this.processing.add(key);
38
+ const queue = this.queues.get(key);
39
+ const maxRetries = options?.maxRetries ?? 3;
40
+ const minDelay = options?.minDelayMs ?? this.minDelayMs;
41
+ while (queue && queue.length > 0) {
42
+ const item = queue[0];
43
+ try {
44
+ const result = await item.task();
45
+ queue.shift();
46
+ item.resolve(result);
47
+ }
48
+ catch (err) {
49
+ // Handle Telegram 429 Too Many Requests (retry_after)
50
+ const retryAfter = err?.parameters?.retry_after ?? err?.response?.parameters?.retry_after;
51
+ if (retryAfter && item.retries < maxRetries) {
52
+ item.retries++;
53
+ const waitTime = (retryAfter + 0.5) * 1000;
54
+ await new Promise((res) => setTimeout(res, waitTime));
55
+ continue;
56
+ }
57
+ queue.shift();
58
+ item.reject(err);
59
+ }
60
+ if (queue.length > 0) {
61
+ await new Promise((res) => setTimeout(res, minDelay));
62
+ }
63
+ }
64
+ this.processing.delete(key);
65
+ if (queue && queue.length === 0) {
66
+ this.queues.delete(key);
67
+ }
68
+ }
69
+ }
70
+ exports.SmartQueue = SmartQueue;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.indexed = exports.zip = exports.fmtCaption = exports.env = void 0;
4
+ exports.env = process.env;
5
+ function fmtCaption(extra) {
6
+ if (!extra)
7
+ return;
8
+ const caption = extra.caption;
9
+ if (!caption || typeof caption === 'string')
10
+ return extra;
11
+ const { text, entities } = caption;
12
+ return {
13
+ ...extra,
14
+ caption: text,
15
+ ...(entities && {
16
+ caption_entities: entities,
17
+ parse_mode: undefined,
18
+ }),
19
+ };
20
+ }
21
+ exports.fmtCaption = fmtCaption;
22
+ function* zip(xs, ys) {
23
+ const x = xs[Symbol.iterator]();
24
+ const y = ys[Symbol.iterator]();
25
+ let x1 = x.next();
26
+ let y1 = y.next();
27
+ while (!x1.done) {
28
+ yield x1.value;
29
+ if (!y1.done)
30
+ yield y1.value;
31
+ x1 = x.next();
32
+ y1 = y.next();
33
+ }
34
+ while (!y1.done) {
35
+ yield y1.value;
36
+ y1 = y.next();
37
+ }
38
+ }
39
+ exports.zip = zip;
40
+ function indexed(target, indexer) {
41
+ return new Proxy(target, {
42
+ get: function (target, prop, receiver) {
43
+ if ((typeof prop === 'string' || typeof prop === 'number') &&
44
+ !isNaN(+prop))
45
+ return indexer.call(target, +prop);
46
+ return Reflect.get(target, prop, receiver);
47
+ },
48
+ });
49
+ }
50
+ exports.indexed = indexed;