@xbibzlibrary/telebibz 0.1.18 → 0.2.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 (90) hide show
  1. package/CHANGELOG.md +28 -8
  2. package/CONTRIBUTING.md +8 -3
  3. package/README.id.md +50 -10
  4. package/README.md +50 -12
  5. package/README.zh-CN.md +50 -10
  6. package/RELEASE_AUTOMATION.md +17 -5
  7. package/SHOWCASE.md +29 -0
  8. package/bin/telebibz.mjs +1 -1
  9. package/dist/src/api/client.d.ts +3 -1
  10. package/dist/src/api/client.d.ts.map +1 -1
  11. package/dist/src/api/client.js +3 -1
  12. package/dist/src/api/client.js.map +1 -1
  13. package/dist/src/api/transport.d.ts +3 -1
  14. package/dist/src/api/transport.d.ts.map +1 -1
  15. package/dist/src/api/transport.js +3 -2
  16. package/dist/src/api/transport.js.map +1 -1
  17. package/dist/src/branding/terminal.d.ts +62 -0
  18. package/dist/src/branding/terminal.d.ts.map +1 -1
  19. package/dist/src/branding/terminal.js +258 -0
  20. package/dist/src/branding/terminal.js.map +1 -1
  21. package/dist/src/cli.d.ts.map +1 -1
  22. package/dist/src/cli.js +7 -3
  23. package/dist/src/cli.js.map +1 -1
  24. package/dist/src/context/context.d.ts +24 -1
  25. package/dist/src/context/context.d.ts.map +1 -1
  26. package/dist/src/context/context.js +102 -8
  27. package/dist/src/context/context.js.map +1 -1
  28. package/dist/src/core/bot.d.ts +18 -1
  29. package/dist/src/core/bot.d.ts.map +1 -1
  30. package/dist/src/core/bot.js +106 -23
  31. package/dist/src/core/bot.js.map +1 -1
  32. package/dist/src/keyboard/index.d.ts +12 -0
  33. package/dist/src/keyboard/index.d.ts.map +1 -1
  34. package/dist/src/keyboard/index.js +13 -1
  35. package/dist/src/keyboard/index.js.map +1 -1
  36. package/dist/src/observability/logger.d.ts +28 -1
  37. package/dist/src/observability/logger.d.ts.map +1 -1
  38. package/dist/src/observability/logger.js +110 -0
  39. package/dist/src/observability/logger.js.map +1 -1
  40. package/dist/src/plugins/plugin.d.ts +2 -0
  41. package/dist/src/plugins/plugin.d.ts.map +1 -1
  42. package/dist/src/plugins/plugin.js +11 -4
  43. package/dist/src/plugins/plugin.js.map +1 -1
  44. package/dist/src/router/router.d.ts +19 -0
  45. package/dist/src/router/router.d.ts.map +1 -1
  46. package/dist/src/router/router.js +125 -23
  47. package/dist/src/router/router.js.map +1 -1
  48. package/dist/src/state/forms.d.ts +0 -1
  49. package/dist/src/state/forms.d.ts.map +1 -1
  50. package/dist/src/state/forms.js +27 -24
  51. package/dist/src/state/forms.js.map +1 -1
  52. package/dist/src/storage/storage.d.ts +10 -0
  53. package/dist/src/storage/storage.d.ts.map +1 -1
  54. package/dist/src/storage/storage.js +20 -2
  55. package/dist/src/storage/storage.js.map +1 -1
  56. package/dist/src/utils/text.d.ts +22 -0
  57. package/dist/src/utils/text.d.ts.map +1 -1
  58. package/dist/src/utils/text.js +0 -0
  59. package/dist/src/utils/text.js.map +1 -1
  60. package/dist/src/webhook/handler.d.ts +3 -0
  61. package/dist/src/webhook/handler.d.ts.map +1 -1
  62. package/dist/src/webhook/handler.js +85 -0
  63. package/dist/src/webhook/handler.js.map +1 -1
  64. package/dist-cjs/src/api/client.js +3 -1
  65. package/dist-cjs/src/api/transport.js +3 -2
  66. package/dist-cjs/src/branding/terminal.js +264 -1
  67. package/dist-cjs/src/cli.js +7 -3
  68. package/dist-cjs/src/context/context.js +102 -8
  69. package/dist-cjs/src/core/bot.js +104 -21
  70. package/dist-cjs/src/keyboard/index.js +13 -1
  71. package/dist-cjs/src/observability/logger.js +113 -1
  72. package/dist-cjs/src/plugins/plugin.js +11 -4
  73. package/dist-cjs/src/router/router.js +126 -24
  74. package/dist-cjs/src/state/forms.js +27 -24
  75. package/dist-cjs/src/storage/storage.js +20 -2
  76. package/dist-cjs/src/utils/text.js +0 -0
  77. package/dist-cjs/src/webhook/handler.js +86 -0
  78. package/docs/API.id.md +57 -3
  79. package/docs/API.md +59 -3
  80. package/docs/API.zh-CN.md +56 -2
  81. package/docs/GETTING_STARTED.id.md +85 -0
  82. package/docs/GETTING_STARTED.md +85 -0
  83. package/docs/GETTING_STARTED.zh-CN.md +85 -0
  84. package/docs/README.md +12 -4
  85. package/examples/README.md +37 -0
  86. package/examples/minimal.ts +12 -0
  87. package/examples/tsconfig.json +9 -0
  88. package/examples/webhook.ts +42 -0
  89. package/examples/wizard-registration.ts +42 -0
  90. package/package.json +22 -5
@@ -28,6 +28,91 @@ export function createWebhookHandler(bot, options = {}) {
28
28
  }
29
29
  };
30
30
  }
31
+ export function webhookCallback(bot, _framework = "express", options = {}) {
32
+ const maxBodyBytes = options.maxBodyBytes ?? 1_048_576;
33
+ return async (req, res) => {
34
+ const rawReq = req;
35
+ const rawRes = res;
36
+ const sendResponse = (status, message) => {
37
+ if (rawRes && typeof rawRes.writeHead === "function" && typeof rawRes.end === "function") {
38
+ rawRes.writeHead(status, { "Content-Type": "text/plain" });
39
+ rawRes.end(message);
40
+ return;
41
+ }
42
+ const expressLike = rawRes;
43
+ if (typeof expressLike?.status === "function" && typeof expressLike.send === "function") {
44
+ expressLike.status(status).send(message);
45
+ return;
46
+ }
47
+ const koaLike = rawRes;
48
+ if (koaLike !== undefined) {
49
+ koaLike.status = status;
50
+ koaLike.body = message;
51
+ }
52
+ };
53
+ if (rawReq.method !== "POST") {
54
+ sendResponse(405, "Method Not Allowed");
55
+ return;
56
+ }
57
+ if (options.secretToken) {
58
+ if (!secureEqual(readHeader(rawReq, "x-telegram-bot-api-secret-token"), options.secretToken)) {
59
+ sendResponse(401, "Unauthorized");
60
+ return;
61
+ }
62
+ }
63
+ try {
64
+ let update;
65
+ if (typeof rawReq.arrayBuffer === "function") {
66
+ // Web-standard Request objects (e.g. Deno, Bun, WinterCG runtimes, or
67
+ // a converted fetch Request) expose the body through arrayBuffer().
68
+ // Checked before `body` because a Request's `body` is a ReadableStream.
69
+ const raw = await rawReq.arrayBuffer();
70
+ if (raw.byteLength > maxBodyBytes) {
71
+ sendResponse(413, "Payload Too Large");
72
+ return;
73
+ }
74
+ update = JSON.parse(new TextDecoder().decode(raw));
75
+ }
76
+ else if (rawReq.body && typeof rawReq.body === "object") {
77
+ update = rawReq.body;
78
+ }
79
+ else {
80
+ const chunks = [];
81
+ let totalBytes = 0;
82
+ for await (const chunk of rawReq) {
83
+ const buffer = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
84
+ totalBytes += buffer.length;
85
+ if (totalBytes > maxBodyBytes) {
86
+ sendResponse(413, "Payload Too Large");
87
+ return;
88
+ }
89
+ chunks.push(buffer);
90
+ }
91
+ const raw = Buffer.concat(chunks).toString("utf8");
92
+ update = JSON.parse(raw);
93
+ }
94
+ if (!Number.isInteger(update?.update_id)) {
95
+ sendResponse(400, "Bad Request");
96
+ return;
97
+ }
98
+ await bot.handleUpdate(update);
99
+ sendResponse(200, "OK");
100
+ }
101
+ catch (error) {
102
+ await options.onError?.(error);
103
+ sendResponse(500, "Internal Server Error");
104
+ }
105
+ };
106
+ }
107
+ function readHeader(req, name) {
108
+ const headers = req.headers;
109
+ if (!headers || typeof headers !== "object")
110
+ return "";
111
+ if (typeof headers.get === "function")
112
+ return headers.get(name) ?? "";
113
+ const value = headers[name];
114
+ return Array.isArray(value) ? value[0] ?? "" : value ?? "";
115
+ }
31
116
  function secureEqual(left, right) {
32
117
  const leftBuffer = Buffer.from(left, "utf8");
33
118
  const rightBuffer = Buffer.from(right, "utf8");
@@ -1 +1 @@
1
- {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/webhook/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAM9C,MAAM,UAAU,oBAAoB,CAAmB,GAAW,EAAE,UAA0B,EAAE;IAC9F,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,SAAS,CAAC;IACvD,OAAO,KAAK,EAAE,OAAgB,EAAqB,EAAE;QACnD,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM;YAAE,OAAO,IAAI,QAAQ,CAAC,oBAAoB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QACtH,IAAI,OAAO,CAAC,WAAW,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,IAAI,EAAE,EAAE,OAAO,CAAC,WAAW,CAAC;YAAE,OAAO,IAAI,QAAQ,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACjL,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;QAC9D,IAAI,CAAC,kCAAkC,CAAC,IAAI,CAAC,WAAW,CAAC;YAAE,OAAO,IAAI,QAAQ,CAAC,wBAAwB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAC1H,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;QACzE,IAAI,aAAa,GAAG,YAAY;YAAE,OAAO,IAAI,QAAQ,CAAC,mBAAmB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5F,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC;YACxC,IAAI,GAAG,CAAC,UAAU,GAAG,YAAY;gBAAE,OAAO,IAAI,QAAQ,CAAC,mBAAmB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;YAC7F,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAW,CAAC;YACnE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC;gBAAE,OAAO,IAAI,QAAQ,CAAC,aAAa,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;YAC7F,MAAM,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YAC/B,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;YAC/B,OAAO,IAAI,QAAQ,CAAC,uBAAuB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAChE,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,IAAY,EAAE,KAAa;IAC9C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7C,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC/C,OAAO,UAAU,CAAC,MAAM,KAAK,WAAW,CAAC,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AAC9F,CAAC"}
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/webhook/handler.ts"],"names":[],"mappings":"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"}
@@ -24,7 +24,7 @@ class ApiClient {
24
24
  });
25
25
  }
26
26
  async call(method, ...args) { return this.request(method, args[0]); }
27
- async request(method, payload, signal) {
27
+ async request(method, payload, signal, options) {
28
28
  const context = { method, payload, startedAt: Date.now() };
29
29
  await this.hooks.onRequest?.(context);
30
30
  try {
@@ -33,6 +33,8 @@ class ApiClient {
33
33
  request.payload = payload;
34
34
  if (signal !== undefined)
35
35
  request.signal = signal;
36
+ if (options?.timeoutMs !== undefined)
37
+ request.timeoutMs = options.timeoutMs;
36
38
  const response = await this.transport.request(request);
37
39
  context.durationMs = Date.now() - context.startedAt;
38
40
  context.response = response.data;
@@ -25,7 +25,8 @@ class FetchTransport {
25
25
  this.jitter = options.jitter ?? 0.2;
26
26
  this.headers = options.headers ?? {};
27
27
  }
28
- async request({ method, payload = {}, signal }) {
28
+ async request({ method, payload = {}, signal, timeoutMs }) {
29
+ const effectiveTimeoutMs = timeoutMs ?? this.timeoutMs;
29
30
  const hasUpload = await containsUpload(payload);
30
31
  let body;
31
32
  const headers = new Headers(this.headers);
@@ -43,7 +44,7 @@ class FetchTransport {
43
44
  while (true) {
44
45
  let responseStatus;
45
46
  const controller = new AbortController();
46
- const timeout = setTimeout(() => controller.abort(new Error(`Request timed out after ${this.timeoutMs}ms`)), this.timeoutMs);
47
+ const timeout = setTimeout(() => controller.abort(new Error(`Request timed out after ${effectiveTimeoutMs}ms`)), effectiveTimeoutMs);
47
48
  const onAbort = () => controller.abort(signal?.reason);
48
49
  signal?.addEventListener("abort", onAbort, { once: true });
49
50
  try {
@@ -1,13 +1,28 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TERMINAL_BRAND_TEXT = void 0;
3
+ exports.TELE_BIBZ_ASCII = exports.TERMINAL_BRAND_TEXT = void 0;
4
+ exports.paintRainbow = paintRainbow;
5
+ exports.runStartupSequence = runStartupSequence;
6
+ exports.printTeleBibzBanner = printTeleBibzBanner;
7
+ exports.startTeleBibzBanner = startTeleBibzBanner;
8
+ exports.printStatusLine = printStatusLine;
4
9
  exports.buildTerminalBranding = buildTerminalBranding;
5
10
  exports.printTerminalBranding = printTerminalBranding;
6
11
  exports.startTerminalAnimation = startTerminalAnimation;
7
12
  exports.TERMINAL_BRAND_TEXT = "Library Bot Telegram By @xbibzofficial";
13
+ /** "Tele Bibz" rendered with the figlet Speed font. */
14
+ exports.TELE_BIBZ_ASCII = [
15
+ "________ ______ ___________________ _______",
16
+ "___ __/_______ /____ ___ __ )__(_)__ /_______",
17
+ "__ / _ _ \\_ /_ _ \\ __ __ |_ /__ __ \\__ /",
18
+ "_ / / __/ / / __/ _ /_/ /_ / _ /_/ /_ /_",
19
+ "/_/ \\___//_/ \\___/ /_____/ /_/ /_.___/_____/",
20
+ ];
8
21
  const ANSI = {
9
22
  reset: "\u001b[0m",
23
+ bold: "\u001b[1m",
10
24
  clearLine: "\u001b[2K",
25
+ cursorUp: "\u001b[1A",
11
26
  hideCursor: "\u001b[?25l",
12
27
  showCursor: "\u001b[?25h",
13
28
  blue: "\u001b[34m",
@@ -15,6 +30,8 @@ const ANSI = {
15
30
  cyan: "\u001b[36m",
16
31
  green: "\u001b[32m",
17
32
  yellow: "\u001b[33m",
33
+ red: "\u001b[31m",
34
+ white: "\u001b[97m",
18
35
  dim: "\u001b[2m",
19
36
  };
20
37
  function pad(value, width) {
@@ -23,6 +40,252 @@ function pad(value, width) {
23
40
  function useColor(options, stream) {
24
41
  return options.color ?? Boolean(stream.isTTY && !process.env.NO_COLOR);
25
42
  }
43
+ function sleep(delayMs) {
44
+ return new Promise((resolve) => setTimeout(resolve, delayMs));
45
+ }
46
+ function easeInOutCubic(progress) {
47
+ return progress < 0.5 ? 4 * progress ** 3 : 1 - (-2 * progress + 2) ** 3 / 2;
48
+ }
49
+ function hslToRgb(hue, saturation, lightness) {
50
+ const normalizedHue = ((hue % 360) + 360) % 360;
51
+ const chroma = (1 - Math.abs(2 * lightness - 1)) * saturation;
52
+ const hueSegment = normalizedHue / 60;
53
+ const secondary = chroma * (1 - Math.abs((hueSegment % 2) - 1));
54
+ let red = 0;
55
+ let green = 0;
56
+ let blue = 0;
57
+ if (hueSegment < 1) {
58
+ red = chroma;
59
+ green = secondary;
60
+ }
61
+ else if (hueSegment < 2) {
62
+ red = secondary;
63
+ green = chroma;
64
+ }
65
+ else if (hueSegment < 3) {
66
+ green = chroma;
67
+ blue = secondary;
68
+ }
69
+ else if (hueSegment < 4) {
70
+ green = secondary;
71
+ blue = chroma;
72
+ }
73
+ else if (hueSegment < 5) {
74
+ red = secondary;
75
+ blue = chroma;
76
+ }
77
+ else {
78
+ red = chroma;
79
+ blue = secondary;
80
+ }
81
+ const shift = lightness - chroma / 2;
82
+ return [Math.round((red + shift) * 255), Math.round((green + shift) * 255), Math.round((blue + shift) * 255)];
83
+ }
84
+ function rgbForegroundColor(red, green, blue) {
85
+ return `\u001b[38;2;${red};${green};${blue}m`;
86
+ }
87
+ /**
88
+ * Paints multi-line text with a rainbow gradient across columns (the classic
89
+ * "Rainbow" color filter). Spaces stay unstyled so the art keeps its shape.
90
+ */
91
+ function paintRainbow(text, options = {}) {
92
+ if (!options.color)
93
+ return text;
94
+ const lines = text.split("\n");
95
+ const width = Math.max(...lines.map((line) => [...line].length), 1);
96
+ const offset = options.offset ?? 0;
97
+ const spread = options.spread ?? 340;
98
+ const saturation = options.saturation ?? 1;
99
+ const lightness = options.lightness ?? 0.58;
100
+ return lines
101
+ .map((line) => {
102
+ const characters = [...line];
103
+ let painted = "";
104
+ for (let index = 0; index < characters.length; index += 1) {
105
+ const character = characters[index];
106
+ if (character === " ") {
107
+ painted += character;
108
+ continue;
109
+ }
110
+ const hue = offset + (index / width) * spread;
111
+ const [red, green, blue] = hslToRgb(hue, saturation, lightness);
112
+ painted += `${rgbForegroundColor(red, green, blue)}${character}${ANSI.reset}`;
113
+ }
114
+ return painted;
115
+ })
116
+ .join("\n");
117
+ }
118
+ function renderGlassBar(progress, shinePosition, width, colored) {
119
+ const filled = Math.round(progress * width);
120
+ let bar = "";
121
+ for (let index = 0; index < width; index += 1) {
122
+ const isFilled = index < filled;
123
+ const shineDistance = Math.abs(index - shinePosition);
124
+ const isShine = shineDistance <= 1;
125
+ const character = isFilled ? "█" : "░";
126
+ if (!colored) {
127
+ bar += character;
128
+ continue;
129
+ }
130
+ if (isShine) {
131
+ bar += `${ANSI.bold}${ANSI.white}${character === "█" ? "█" : "▒"}${ANSI.reset}`;
132
+ continue;
133
+ }
134
+ if (isFilled) {
135
+ const hue = 190 + (index / width) * 150;
136
+ const [red, green, blue] = hslToRgb(hue, 0.85, 0.6);
137
+ bar += `${rgbForegroundColor(red, green, blue)}${character}${ANSI.reset}`;
138
+ }
139
+ else {
140
+ bar += `${ANSI.dim}${character}${ANSI.reset}`;
141
+ }
142
+ }
143
+ return bar;
144
+ }
145
+ /**
146
+ * Plays the startup sequence on a TTY: a typing effect for the label
147
+ * (default "Installing Dependencies"), a trailing run of dots, and a
148
+ * glass progress bar with a sweeping highlight that fills to 100%.
149
+ * No-ops when the stream is not an interactive TTY.
150
+ */
151
+ async function runStartupSequence(options = {}) {
152
+ const stream = options.stream ?? process.stdout;
153
+ if (!stream.isTTY)
154
+ return;
155
+ const colored = useColor(options, stream);
156
+ const label = options.label ?? "Installing Dependencies";
157
+ const typeDelayMs = options.typeDelayMs ?? 24;
158
+ const dotDelayMs = options.dotDelayMs ?? 140;
159
+ const dots = options.dots ?? 6;
160
+ const barWidth = Math.max(10, options.barWidth ?? 44);
161
+ const barDurationMs = Math.max(0, options.barDurationMs ?? 1_400);
162
+ const barFrameMs = Math.max(16, options.barFrameMs ?? 40);
163
+ if (colored)
164
+ stream.write(`${ANSI.bold}${ANSI.cyan}`);
165
+ for (const character of label) {
166
+ stream.write(character);
167
+ if (typeDelayMs > 0)
168
+ await sleep(typeDelayMs);
169
+ }
170
+ for (let index = 0; index < dots; index += 1) {
171
+ if (dotDelayMs > 0)
172
+ await sleep(dotDelayMs);
173
+ stream.write(".");
174
+ }
175
+ if (colored)
176
+ stream.write(ANSI.reset);
177
+ stream.write("\n");
178
+ const startedAt = Date.now();
179
+ let frameIndex = 0;
180
+ while (true) {
181
+ const elapsed = Date.now() - startedAt;
182
+ const progress = barDurationMs === 0 ? 1 : Math.min(1, easeInOutCubic(elapsed / barDurationMs));
183
+ const sweep = (frameIndex * barFrameMs) % 1_600;
184
+ const triangle = sweep < 800 ? sweep / 800 : 2 - sweep / 800;
185
+ const shinePosition = triangle * (barWidth - 1);
186
+ const percentage = Math.round(progress * 100);
187
+ stream.write(`\r${ANSI.clearLine}${renderGlassBar(progress, shinePosition, barWidth, colored)} ${ANSI.dim}${String(percentage).padStart(3, " ")}%${ANSI.reset}`);
188
+ if (progress >= 1)
189
+ break;
190
+ frameIndex += 1;
191
+ await sleep(barFrameMs);
192
+ }
193
+ stream.write(` ${ANSI.green}${ANSI.bold}✓${ANSI.reset}\n`);
194
+ }
195
+ function bannerFrame(subtitle, offset, colored) {
196
+ const artWidth = Math.max(...exports.TELE_BIBZ_ASCII.map((line) => [...line].length));
197
+ const leading = Math.max(0, Math.floor((artWidth - [...exports.TERMINAL_BRAND_TEXT].length) / 2));
198
+ const tagline = " ".repeat(leading) + exports.TERMINAL_BRAND_TEXT;
199
+ const lines = paintRainbow(exports.TELE_BIBZ_ASCII.join("\n"), { color: colored, offset }).split("\n");
200
+ lines.push(colored ? `${ANSI.dim}${tagline}${ANSI.reset}` : tagline);
201
+ if (subtitle)
202
+ lines.push(colored ? `${ANSI.cyan}${ANSI.bold}${subtitle}${ANSI.reset}` : subtitle);
203
+ return lines;
204
+ }
205
+ function tonePrefix(tone, colored) {
206
+ if (!colored)
207
+ return "";
208
+ if (tone === "success")
209
+ return ANSI.green;
210
+ if (tone === "error")
211
+ return ANSI.red;
212
+ return ANSI.cyan;
213
+ }
214
+ /**
215
+ * Prints the static "Tele Bibz" banner (rainbow-painted once, no animation).
216
+ * Suitable for short-lived CLI commands and non-interactive streams.
217
+ */
218
+ function printTeleBibzBanner(options = {}) {
219
+ const stream = options.stream ?? process.stdout;
220
+ const colored = useColor(options, stream);
221
+ const lines = bannerFrame(options.subtitle, 0, colored);
222
+ if (options.message) {
223
+ const prefix = options.tone === "error" ? "✗ " : options.tone === "success" ? "✓ " : "";
224
+ lines.push(colored ? `${tonePrefix(options.tone ?? "info", colored)}${prefix}${options.message}${ANSI.reset}` : `${prefix}${options.message}`);
225
+ }
226
+ stream.write(`${lines.join("\n")}\n`);
227
+ }
228
+ /**
229
+ * Prints the animated rainbow "Tele Bibz" banner. The rainbow flows until
230
+ * `stop()` is called (typically once the bot is connected), then the banner
231
+ * freezes and an optional status line is printed.
232
+ */
233
+ function startTeleBibzBanner(options = {}) {
234
+ const stream = options.stream ?? process.stdout;
235
+ const colored = useColor(options, stream);
236
+ const frameMs = Math.max(16, options.frameMs ?? 70);
237
+ const subtitle = options.subtitle;
238
+ if (!stream.isTTY) {
239
+ printTeleBibzBanner({ ...options, subtitle });
240
+ return { stop: () => undefined };
241
+ }
242
+ let stopped = false;
243
+ let linesPrinted = 0;
244
+ const writeFrame = (offset) => {
245
+ const lines = bannerFrame(subtitle, offset, colored);
246
+ linesPrinted = lines.length;
247
+ stream.write(lines.join("\n") + "\n");
248
+ };
249
+ const clearFrame = () => {
250
+ for (let index = 0; index < linesPrinted; index += 1)
251
+ stream.write(`${ANSI.cursorUp}${ANSI.clearLine}`);
252
+ stream.write("\r");
253
+ };
254
+ stream.write(ANSI.hideCursor);
255
+ writeFrame(0);
256
+ void (async () => {
257
+ let offset = 0;
258
+ while (!stopped) {
259
+ await sleep(frameMs);
260
+ if (stopped)
261
+ break;
262
+ offset = (offset + 14) % 360;
263
+ clearFrame();
264
+ writeFrame(offset);
265
+ }
266
+ })();
267
+ return {
268
+ stop(message, tone = "success") {
269
+ if (stopped)
270
+ return;
271
+ stopped = true;
272
+ clearFrame();
273
+ writeFrame(0);
274
+ if (message) {
275
+ const prefix = tone === "error" ? "✗ " : tone === "success" ? "✓ " : "";
276
+ const line = colored ? `${tonePrefix(tone, colored)}${ANSI.bold}${prefix}${message}${ANSI.reset}` : `${prefix}${message}`;
277
+ stream.write(`${line}\n`);
278
+ }
279
+ stream.write(ANSI.showCursor);
280
+ },
281
+ };
282
+ }
283
+ /** Prints a single dim status line (used for "Listening for updates..." style messages). */
284
+ function printStatusLine(text, options = {}) {
285
+ const stream = options.stream ?? process.stdout;
286
+ const colored = useColor(options, stream);
287
+ stream.write(colored ? `${ANSI.dim}${text}${ANSI.reset}\n` : `${text}\n`);
288
+ }
26
289
  function buildTerminalBranding(options = {}) {
27
290
  const stream = process.stdout;
28
291
  const colored = useColor(options, stream);
@@ -5,11 +5,13 @@ const promises_1 = require("node:fs/promises");
5
5
  const node_child_process_1 = require("node:child_process");
6
6
  const handler_js_1 = require("./webhook/handler.js");
7
7
  const bot_js_1 = require("./core/bot.js");
8
+ const terminal_js_1 = require("./branding/terminal.js");
8
9
  async function commandDoctor() {
10
+ (0, terminal_js_1.printTeleBibzBanner)({ subtitle: "telebibz doctor" });
9
11
  const token = process.env.TELEGRAM_BOT_TOKEN;
10
12
  console.log(JSON.stringify({ node: process.version, tokenPresent: Boolean(token), cwd: process.cwd(), package: "@xbibzlibrary/telebibz" }, null, 2));
11
13
  if (token) {
12
- const bot = new bot_js_1.Bot(token);
14
+ const bot = new bot_js_1.Bot({ token, branding: false });
13
15
  const health = await bot.health();
14
16
  console.log(JSON.stringify(health, null, 2));
15
17
  if (!health.apiReachable)
@@ -25,6 +27,7 @@ async function commandStart() {
25
27
  }
26
28
  async function commandInit(name) {
27
29
  const dir = name || "my-telebibz-bot";
30
+ (0, terminal_js_1.printTeleBibzBanner)({ subtitle: "telebibz init" });
28
31
  await (0, promises_1.mkdir)(dir, { recursive: true });
29
32
  await (0, promises_1.writeFile)(`${dir}/index.ts`, `import { Bot } from "@xbibzlibrary/telebibz";\n\nconst bot = new Bot(process.env.TELEGRAM_BOT_TOKEN!);\nbot.command("start", (ctx) => ctx.reply("Hello from telebibz"));\nawait bot.start();\n`);
30
33
  await (0, promises_1.writeFile)(`${dir}/.env.example`, "TELEGRAM_BOT_TOKEN=\n");
@@ -61,11 +64,12 @@ async function main(argv = process.argv.slice(2)) {
61
64
  const token = process.env.TELEGRAM_BOT_TOKEN;
62
65
  if (!token)
63
66
  throw new Error("TELEGRAM_BOT_TOKEN is required");
64
- const bot = new bot_js_1.Bot(token);
67
+ const bot = new bot_js_1.Bot({ token, branding: false });
68
+ (0, terminal_js_1.printTeleBibzBanner)({ subtitle: "telebibz webhook", message: "Webhook handler ready" });
65
69
  const webhookOptions = process.env.TELEGRAM_WEBHOOK_SECRET ? { secretToken: process.env.TELEGRAM_WEBHOOK_SECRET } : {};
66
70
  const handler = (0, handler_js_1.createWebhookHandler)(bot, webhookOptions);
67
71
  await (0, promises_1.access)(".");
68
- console.log(`Webhook handler ready: ${typeof handler}`);
72
+ console.log(`Handler type: ${typeof handler}`);
69
73
  break;
70
74
  }
71
75
  case "inspect":
@@ -8,11 +8,15 @@ class Context {
8
8
  state = Object.create(null);
9
9
  services;
10
10
  params = Object.create(null);
11
+ me;
12
+ match;
13
+ args;
11
14
  constructor(options) {
12
15
  this.update = options.update;
13
16
  this.api = options.api;
14
17
  this.session = options.session;
15
18
  this.services = options.services;
19
+ this.me = options.me;
16
20
  }
17
21
  get message() {
18
22
  return this.update.message
@@ -32,13 +36,21 @@ class Context {
32
36
  ?? this.pollAnswer?.voter_chat;
33
37
  }
34
38
  get from() {
35
- return this.message?.from
36
- ?? this.callbackQuery?.from
39
+ return this.callbackQuery?.from
37
40
  ?? this.inlineQuery?.from
41
+ ?? this.update.chosen_inline_result?.from
42
+ ?? this.update.message?.from
43
+ ?? this.update.edited_message?.from
44
+ ?? this.update.channel_post?.from
45
+ ?? this.update.edited_channel_post?.from
46
+ ?? this.update.business_message?.from
47
+ ?? this.update.edited_business_message?.from
48
+ ?? this.update.guest_message?.from
38
49
  ?? this.update.chat_member?.from
39
50
  ?? this.update.my_chat_member?.from
40
51
  ?? this.update.chat_join_request?.from
41
- ?? this.pollAnswer?.user;
52
+ ?? this.pollAnswer?.user
53
+ ?? this.message?.from;
42
54
  }
43
55
  get sender() { return this.from; }
44
56
  get callbackQuery() { return this.update.callback_query; }
@@ -50,20 +62,102 @@ class Context {
50
62
  get chatJoinRequest() { return this.update.chat_join_request; }
51
63
  get reaction() { return this.update.message_reaction; }
52
64
  get boost() { return this.update.chat_boost ?? this.update.removed_chat_boost; }
53
- async reply(text, extra = {}) {
65
+ replyExtras(extra) {
66
+ const { reply_parameters, reply_markup, ...rest } = extra;
67
+ const quoted = this.message?.message_id !== undefined ? { message_id: this.message.message_id } : undefined;
68
+ const replyParameters = quoted === undefined && reply_parameters === undefined ? undefined : { ...(quoted ?? {}), ...(reply_parameters ?? {}) };
69
+ return { replyParameters, replyMarkup: reply_markup ?? this.state.reply_markup, rest };
70
+ }
71
+ sendMethod(method, payload, extra = {}) {
54
72
  if (!this.chat)
55
- throw new Error("Cannot reply without a chat in this update.");
56
- return this.api.methods.sendMessage({ chat_id: this.chat.id, text, reply_parameters: { message_id: this.message?.message_id }, ...extra });
73
+ throw new Error(`Cannot send ${method} without a chat in this update.`);
74
+ const { replyParameters, replyMarkup, rest } = this.replyExtras(extra);
75
+ return this.api.call(method, {
76
+ chat_id: this.chat.id,
77
+ ...payload,
78
+ ...rest,
79
+ ...(replyParameters ? { reply_parameters: replyParameters } : {}),
80
+ ...(replyMarkup ? { reply_markup: replyMarkup } : {}),
81
+ });
82
+ }
83
+ async reply(text, extra = {}) {
84
+ return this.sendMethod("sendMessage", { text }, extra);
57
85
  }
58
86
  async send(text, extra = {}) {
59
87
  if (!this.chat)
60
88
  throw new Error("Cannot send without a chat in this update.");
61
- return this.api.methods.sendMessage({ chat_id: this.chat.id, text, ...extra });
89
+ const { replyMarkup, rest } = this.replyExtras(extra);
90
+ return this.api.methods.sendMessage({
91
+ chat_id: this.chat.id,
92
+ text,
93
+ ...rest,
94
+ ...(replyMarkup ? { reply_markup: replyMarkup } : {}),
95
+ });
62
96
  }
63
97
  async edit(text, extra = {}) {
64
98
  if (!this.chat || !this.message)
65
99
  throw new Error("Cannot edit without a chat and message in this update.");
66
- return this.api.methods.editMessageText({ chat_id: this.chat.id, message_id: this.message.message_id, text, ...extra });
100
+ const { replyMarkup, rest } = this.replyExtras(extra);
101
+ return this.api.methods.editMessageText({
102
+ chat_id: this.chat.id,
103
+ message_id: this.message.message_id,
104
+ text,
105
+ ...rest,
106
+ ...(replyMarkup ? { reply_markup: replyMarkup } : {}),
107
+ });
108
+ }
109
+ async replyWithHTML(text, extra = {}) {
110
+ return this.reply(text, { parse_mode: "HTML", ...extra });
111
+ }
112
+ async replyWithMarkdown(text, extra = {}) {
113
+ return this.reply(text, { parse_mode: "MarkdownV2", ...extra });
114
+ }
115
+ async replyWithPhoto(photo, extra = {}) {
116
+ return this.sendMethod("sendPhoto", { photo }, extra);
117
+ }
118
+ async replyWithDocument(document, extra = {}) {
119
+ return this.sendMethod("sendDocument", { document }, extra);
120
+ }
121
+ async replyWithAudio(audio, extra = {}) {
122
+ return this.sendMethod("sendAudio", { audio }, extra);
123
+ }
124
+ async replyWithVideo(video, extra = {}) {
125
+ return this.sendMethod("sendVideo", { video }, extra);
126
+ }
127
+ async replyWithVoice(voice, extra = {}) {
128
+ return this.sendMethod("sendVoice", { voice }, extra);
129
+ }
130
+ async replyWithAnimation(animation, extra = {}) {
131
+ return this.sendMethod("sendAnimation", { animation }, extra);
132
+ }
133
+ async replyWithVideoNote(videoNote, extra = {}) {
134
+ return this.sendMethod("sendVideoNote", { video_note: videoNote }, extra);
135
+ }
136
+ async replyWithSticker(sticker, extra = {}) {
137
+ return this.sendMethod("sendSticker", { sticker }, extra);
138
+ }
139
+ async replyWithMediaGroup(media, extra = {}) {
140
+ return this.sendMethod("sendMediaGroup", { media }, extra);
141
+ }
142
+ async replyWithLocation(latitude, longitude, extra = {}) {
143
+ return this.sendMethod("sendLocation", { latitude, longitude }, extra);
144
+ }
145
+ async replyWithVenue(latitude, longitude, title, address, extra = {}) {
146
+ return this.sendMethod("sendVenue", { latitude, longitude, title, address }, extra);
147
+ }
148
+ async replyWithContact(phoneNumber, firstName, extra = {}) {
149
+ return this.sendMethod("sendContact", { phone_number: phoneNumber, first_name: firstName }, extra);
150
+ }
151
+ async replyWithPoll(question, options, extra = {}) {
152
+ return this.sendMethod("sendPoll", { question, options }, extra);
153
+ }
154
+ async replyWithDice(emoji, extra = {}) {
155
+ return this.sendMethod("sendDice", emoji === undefined ? {} : { emoji }, extra);
156
+ }
157
+ async sendChatAction(action, extra = {}) {
158
+ if (!this.chat)
159
+ throw new Error("Cannot send chat action without a chat in this update.");
160
+ return this.api.call("sendChatAction", { chat_id: this.chat.id, action, ...extra });
67
161
  }
68
162
  async delete() {
69
163
  if (!this.chat || !this.message)