telegix 1.1.3-a1 → 1.1.4

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.
package/index.d.ts CHANGED
@@ -442,6 +442,15 @@ export class Telegix extends Composer {
442
442
  stop(reason?: string): Promise<void>;
443
443
  launch(options?: { polling?: boolean | object; webhook?: object; dropPendingUpdates?: boolean }): Promise<User>;
444
444
  webhookCallback(path?: string, options?: object): (req: any, res: any, next?: Function) => Promise<void>;
445
+ pagesWebhookHandler(options?: {
446
+ secretToken?: string | ((env: any) => string);
447
+ path?: string;
448
+ waitUntil?: boolean;
449
+ respondOnError?: number;
450
+ enableHealthCheck?: boolean;
451
+ onUpdate?: (update: any, context: any) => Promise<void> | void;
452
+ onError?: (err: Error, context: any) => any;
453
+ }): (context: any, env?: any, ctx?: any) => Promise<Response>;
445
454
  }
446
455
 
447
456
  export class MemorySessionStore {
@@ -656,4 +665,39 @@ export class TelegramError extends TelegixError {
656
665
  export class NetworkError extends TelegixError {}
657
666
  export class PollingError extends TelegixError {}
658
667
 
668
+ export function createWebhookCallback(
669
+ bot: Telegix,
670
+ path?: string,
671
+ options?: { secretToken?: string }
672
+ ): (req: any, res: any, next?: Function) => Promise<void>;
673
+
674
+ export function createPagesWebhookHandler(
675
+ botOrFactory?: Telegix | ((env: any, context?: any) => Telegix),
676
+ options?: {
677
+ secretToken?: string | ((env: any) => string);
678
+ path?: string;
679
+ waitUntil?: boolean;
680
+ respondOnError?: number;
681
+ enableHealthCheck?: boolean;
682
+ onUpdate?: (update: any, context: any) => Promise<void> | void;
683
+ onError?: (err: Error, context: any) => any;
684
+ }
685
+ ): (context: any, env?: any, ctx?: any) => Promise<Response>;
686
+
687
+ export function createCloudflareWebhookCallback(
688
+ botOrFactory?: Telegix | ((env: any, context?: any) => Telegix),
689
+ options?: object
690
+ ): (context: any, env?: any, ctx?: any) => Promise<Response>;
691
+
692
+ export function handleCloudflareWebhook(
693
+ context: any,
694
+ bot: Telegix,
695
+ options?: object
696
+ ): Promise<Response>;
697
+
698
+ export function createPagesSetWebhookHandler(
699
+ botOrFactory?: Telegix | ((env: any) => Telegix),
700
+ options?: { webhookPath?: string; secretToken?: string }
701
+ ): (context: any) => Promise<Response>;
702
+
659
703
  export default Telegix;
package/index.js CHANGED
@@ -11,7 +11,13 @@ export { Composer, compose } from './lib/composer.js';
11
11
  export { Markup, KeyboardBuilder } from './lib/markup.js';
12
12
  export { session, MemorySessionStore, FileSessionStore } from './lib/session.js';
13
13
  export { Polling } from './lib/polling.js';
14
- export { createWebhookCallback } from './lib/webhook.js';
14
+ export {
15
+ createWebhookCallback,
16
+ createPagesWebhookHandler,
17
+ createCloudflareWebhookCallback,
18
+ handleCloudflareWebhook,
19
+ createPagesSetWebhookHandler,
20
+ } from './lib/webhook.js';
15
21
  export { fmt, Format, escapeHtml, escapeMarkdown, html, markdown } from './lib/format.js';
16
22
  export { Table, InputRichBlockTable, RichBlockTable } from './lib/table.js';
17
23
  export { EphemeralMessageParameters, ReplyParameters, BotCommand } from './lib/ephemeral.js';
package/lib/api.js CHANGED
@@ -30,7 +30,13 @@ export function isUploadableFile(value, key = '') {
30
30
  ) {
31
31
  return false;
32
32
  }
33
- if (value instanceof Blob || value instanceof Uint8Array || Buffer.isBuffer(value)) return true;
33
+ if (
34
+ value instanceof Blob ||
35
+ value instanceof Uint8Array ||
36
+ (typeof Buffer !== 'undefined' && typeof Buffer.isBuffer === 'function' && Buffer.isBuffer(value))
37
+ ) {
38
+ return true;
39
+ }
34
40
  if (typeof value === 'object') {
35
41
  // If it's a LinkPreview or has link preview options properties, it's not a file
36
42
  if (
@@ -57,20 +63,24 @@ export function isUploadableFile(value, key = '') {
57
63
  */
58
64
  export async function normalizeFileSource(input, defaultFilename = 'file') {
59
65
  if (typeof input === 'string') {
60
- // If it's a file path on local filesystem
61
- if (fs.existsSync(input)) {
62
- const buffer = await fs.promises.readFile(input);
63
- const filename = path.basename(input) || defaultFilename;
64
- return {
65
- blob: new Blob([buffer]),
66
- filename,
67
- };
66
+ // If it's a file path on local filesystem (Node.js environment)
67
+ try {
68
+ if (fs && typeof fs.existsSync === 'function' && fs.existsSync(input)) {
69
+ const buffer = await fs.promises.readFile(input);
70
+ const filename = (path && typeof path.basename === 'function' && path.basename(input)) || defaultFilename;
71
+ return {
72
+ blob: new Blob([buffer]),
73
+ filename,
74
+ };
75
+ }
76
+ } catch {
77
+ // Ignored in non-filesystem/edge environments
68
78
  }
69
79
  // Otherwise it's a file_id or URL string
70
80
  return { blob: input };
71
81
  }
72
82
 
73
- if (Buffer.isBuffer(input) || input instanceof Uint8Array) {
83
+ if ((typeof Buffer !== 'undefined' && typeof Buffer.isBuffer === 'function' && Buffer.isBuffer(input)) || input instanceof Uint8Array) {
74
84
  return {
75
85
  blob: new Blob([input]),
76
86
  filename: defaultFilename,
@@ -93,16 +103,20 @@ export async function normalizeFileSource(input, defaultFilename = 'file') {
93
103
 
94
104
  if (input.source) {
95
105
  if (typeof input.source === 'string') {
96
- if (fs.existsSync(input.source)) {
97
- const buffer = await fs.promises.readFile(input.source);
98
- return {
99
- blob: new Blob([buffer]),
100
- filename: input.filename || path.basename(input.source) || defaultFilename,
101
- };
106
+ try {
107
+ if (fs && typeof fs.existsSync === 'function' && fs.existsSync(input.source)) {
108
+ const buffer = await fs.promises.readFile(input.source);
109
+ return {
110
+ blob: new Blob([buffer]),
111
+ filename: input.filename || (path && typeof path.basename === 'function' && path.basename(input.source)) || defaultFilename,
112
+ };
113
+ }
114
+ } catch {
115
+ // Ignored
102
116
  }
103
117
  return { blob: input.source };
104
118
  }
105
- if (Buffer.isBuffer(input.source) || input.source instanceof Uint8Array) {
119
+ if ((typeof Buffer !== 'undefined' && typeof Buffer.isBuffer === 'function' && Buffer.isBuffer(input.source)) || input.source instanceof Uint8Array) {
106
120
  return {
107
121
  blob: new Blob([input.source]),
108
122
  filename,
@@ -1954,7 +1968,9 @@ export class Telegram {
1954
1968
  sendCardTables(chatId, tables, options = {}) {
1955
1969
  if (options.asImage || options.photo || options.image) {
1956
1970
  const svg = Table.multiCardSvg(tables, options);
1957
- const buffer = Buffer.from(svg, 'utf-8');
1971
+ const buffer = typeof Buffer !== 'undefined' && typeof Buffer.from === 'function'
1972
+ ? Buffer.from(svg, 'utf-8')
1973
+ : new Blob([svg], { type: 'image/svg+xml' });
1958
1974
  return this.sendPhoto(chatId, {
1959
1975
  source: buffer,
1960
1976
  filename: 'tables-cards.svg',
package/lib/context.js CHANGED
@@ -1019,7 +1019,7 @@ export class Context {
1019
1019
  rows = [
1020
1020
  ['Engine', data.engine || 'Telegix'],
1021
1021
  ['Runtime', data.runtime || '0h 19m 32s'],
1022
- ['Node', data.node || process.version || 'v23.11'],
1022
+ ['Node', data.node || (typeof process !== 'undefined' && process.version ? process.version : 'Cloudflare Edge') || 'v23.11'],
1023
1023
  ['Features', data.features ?? 514],
1024
1024
  ['Groups', data.groups ?? 168],
1025
1025
  ['Users', data.users ?? 9528],
package/lib/telegix.js CHANGED
@@ -7,7 +7,7 @@ import { Composer } from './composer.js';
7
7
  import { Telegram } from './api.js';
8
8
  import { Context } from './context.js';
9
9
  import { Polling } from './polling.js';
10
- import { createWebhookCallback } from './webhook.js';
10
+ import { createWebhookCallback, createPagesWebhookHandler } from './webhook.js';
11
11
  import { TelegixError } from './errors.js';
12
12
 
13
13
  export class Telegix extends Composer {
@@ -173,4 +173,13 @@ export class Telegix extends Composer {
173
173
  webhookCallback(path = '/', options = {}) {
174
174
  return createWebhookCallback(this, path, options);
175
175
  }
176
+
177
+ /**
178
+ * Returns a Cloudflare Pages Functions / Cloudflare Workers / Fetch API webhook handler
179
+ * @param {object} [options]
180
+ * @returns {Function}
181
+ */
182
+ pagesWebhookHandler(options = {}) {
183
+ return createPagesWebhookHandler(this, options);
184
+ }
176
185
  }
package/lib/webhook.js CHANGED
@@ -1,5 +1,7 @@
1
1
  /**
2
2
  * Telegix - Webhook Handler & Adapter
3
+ * Supports standard Node.js HTTP servers (Express, Fastify, Connect)
4
+ * AND Cloudflare Pages Functions, Cloudflare Workers, and Web Fetch API.
3
5
  * @module telegix/webhook
4
6
  */
5
7
 
@@ -55,7 +57,9 @@ export function createWebhookCallback(bot, path = '/', options = {}) {
55
57
  for await (const chunk of req) {
56
58
  chunks.push(chunk);
57
59
  }
58
- const rawBody = Buffer.concat(chunks).toString('utf8');
60
+ const rawBody = (typeof Buffer !== 'undefined' && Buffer.concat)
61
+ ? Buffer.concat(chunks).toString('utf8')
62
+ : chunks.map((c) => (typeof c === 'string' ? c : new TextDecoder().decode(c))).join('');
59
63
  update = JSON.parse(rawBody);
60
64
  }
61
65
 
@@ -84,3 +88,403 @@ export function createWebhookCallback(bot, path = '/', options = {}) {
84
88
  }
85
89
  };
86
90
  }
91
+
92
+ /**
93
+ * Creates a Cloudflare Pages Functions / Cloudflare Workers / Web Fetch API webhook handler.
94
+ * Compatible with:
95
+ * - Cloudflare Pages Functions: `export const onRequest = createPagesWebhookHandler(bot, options);`
96
+ * - Cloudflare Pages POST only: `export const onRequestPost = createPagesWebhookHandler(bot, options);`
97
+ * - Cloudflare Workers: `export default { fetch: createPagesWebhookHandler(bot, options) };`
98
+ *
99
+ * @param {import('./telegix.js').Telegix | ((env: any, context: any) => import('./telegix.js').Telegix)} [botOrFactory]
100
+ * @param {object} [options]
101
+ * @param {string|((env: any) => string)} [options.secretToken] - Secret token for header verification or getter function
102
+ * @param {string} [options.path] - Optional path restriction (e.g. '/webhook')
103
+ * @param {boolean} [options.waitUntil=true] - Use context.waitUntil() to respond 200 OK instantly and process in background
104
+ * @param {number} [options.respondOnError=200] - Status to respond with on unhandled update error (default 200 prevents Telegram retry storm)
105
+ * @param {boolean} [options.enableHealthCheck=true] - If true, GET requests return a JSON health check status
106
+ * @param {Function} [options.onUpdate] - Optional callback when update is received
107
+ * @param {Function} [options.onError] - Custom error handler
108
+ * @returns {Function} Universal Cloudflare Pages / Workers handler
109
+ */
110
+ export function createPagesWebhookHandler(botOrFactory, options = {}) {
111
+ const opts = {
112
+ waitUntil: true,
113
+ respondOnError: 200,
114
+ enableHealthCheck: true,
115
+ ...options,
116
+ };
117
+
118
+ // Cache for bot instance when initialized via factory
119
+ let cachedBot = typeof botOrFactory === 'object' && botOrFactory !== null ? botOrFactory : null;
120
+
121
+ return async function handlePagesRequest(arg1, arg2, arg3) {
122
+ let request;
123
+ let env = {};
124
+ let waitUntil = null;
125
+
126
+ // Detect Cloudflare Pages context vs Cloudflare Workers vs standard Fetch
127
+ if (arg1 && typeof arg1 === 'object' && 'request' in arg1) {
128
+ // Cloudflare Pages: context = { request, env, waitUntil, next, params, data }
129
+ request = arg1.request;
130
+ env = arg1.env || {};
131
+ if (typeof arg1.waitUntil === 'function') {
132
+ waitUntil = arg1.waitUntil.bind(arg1);
133
+ }
134
+ } else {
135
+ // Cloudflare Workers: (request, env, ctx) or Fetch: (request)
136
+ request = arg1;
137
+ env = arg2 || {};
138
+ if (arg3 && typeof arg3.waitUntil === 'function') {
139
+ waitUntil = arg3.waitUntil.bind(arg3);
140
+ }
141
+ }
142
+
143
+ if (!request || typeof request.method !== 'string') {
144
+ return new Response('Invalid Request Object', { status: 400 });
145
+ }
146
+
147
+ const method = request.method.toUpperCase();
148
+ const url = new URL(request.url);
149
+
150
+ // 1. CORS Preflight
151
+ if (method === 'OPTIONS') {
152
+ return new Response(null, {
153
+ status: 204,
154
+ headers: {
155
+ 'Access-Control-Allow-Origin': '*',
156
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
157
+ 'Access-Control-Allow-Headers': 'Content-Type, X-Telegram-Bot-Api-Secret-Token',
158
+ },
159
+ });
160
+ }
161
+
162
+ // 2. Path validation if specified
163
+ if (opts.path && opts.path !== '/' && url.pathname !== opts.path) {
164
+ return new Response('Not Found', { status: 404 });
165
+ }
166
+
167
+ // 3. GET Method: Health check & diagnostics
168
+ if (method === 'GET') {
169
+ if (opts.enableHealthCheck) {
170
+ const hasToken = Boolean(
171
+ (env && (env.BOT_TOKEN || env.TELEGRAM_BOT_TOKEN)) ||
172
+ cachedBot?.telegram?.token
173
+ );
174
+ const hasSecret = Boolean(
175
+ opts.secretToken ||
176
+ (env && (env.WEBHOOK_SECRET || env.SECRET_TOKEN))
177
+ );
178
+
179
+ return new Response(
180
+ JSON.stringify(
181
+ {
182
+ status: 'ok',
183
+ engine: 'Telegix',
184
+ runtime: 'Cloudflare Pages Functions / Workers',
185
+ service: 'Telegram Bot Webhook Endpoint',
186
+ timestamp: new Date().toISOString(),
187
+ endpoint: url.pathname,
188
+ configured: {
189
+ botToken: hasToken,
190
+ secretTokenVerification: hasSecret,
191
+ backgroundExecution: Boolean(opts.waitUntil && waitUntil),
192
+ },
193
+ hint: 'Send POST updates from Telegram to this URL.',
194
+ },
195
+ null,
196
+ 2
197
+ ),
198
+ {
199
+ status: 200,
200
+ headers: {
201
+ 'Content-Type': 'application/json; charset=utf-8',
202
+ 'Access-Control-Allow-Origin': '*',
203
+ },
204
+ }
205
+ );
206
+ }
207
+ return new Response('Method Not Allowed', { status: 405 });
208
+ }
209
+
210
+ // 4. Webhook updates MUST be POST
211
+ if (method !== 'POST') {
212
+ return new Response('Method Not Allowed', { status: 405 });
213
+ }
214
+
215
+ // 5. Secret Token Verification
216
+ let secretToken = opts.secretToken;
217
+ if (typeof secretToken === 'function') {
218
+ secretToken = secretToken(env);
219
+ } else if (!secretToken && env) {
220
+ secretToken = env.WEBHOOK_SECRET || env.SECRET_TOKEN;
221
+ }
222
+
223
+ if (secretToken) {
224
+ const receivedToken = request.headers.get('x-telegram-bot-api-secret-token');
225
+ if (receivedToken !== secretToken) {
226
+ return new Response('Forbidden: Invalid Webhook Secret Token', {
227
+ status: 403,
228
+ headers: { 'Content-Type': 'text/plain' },
229
+ });
230
+ }
231
+ }
232
+
233
+ // 6. Resolve Bot Instance
234
+ let bot = cachedBot;
235
+ if (!bot) {
236
+ if (typeof botOrFactory === 'function') {
237
+ bot = botOrFactory(env, { request, env, waitUntil });
238
+ cachedBot = bot;
239
+ } else if (opts.getBot && typeof opts.getBot === 'function') {
240
+ bot = opts.getBot(env, { request, env, waitUntil });
241
+ } else if (env && (env.BOT_TOKEN || env.TELEGRAM_BOT_TOKEN)) {
242
+ const token = env.BOT_TOKEN || env.TELEGRAM_BOT_TOKEN;
243
+ const { Telegix } = await import('./telegix.js');
244
+ bot = new Telegix(token);
245
+ cachedBot = bot;
246
+ }
247
+ }
248
+
249
+ if (!bot) {
250
+ return new Response(
251
+ 'Server Configuration Error: Telegix Bot instance or BOT_TOKEN is missing in Cloudflare environment.',
252
+ {
253
+ status: 500,
254
+ headers: { 'Content-Type': 'text/plain' },
255
+ }
256
+ );
257
+ }
258
+
259
+ // 7. Parse incoming Telegram Update JSON
260
+ let update = null;
261
+ try {
262
+ update = await request.json();
263
+ } catch {
264
+ return new Response('Bad Request: Invalid JSON Payload', {
265
+ status: 400,
266
+ headers: { 'Content-Type': 'text/plain' },
267
+ });
268
+ }
269
+
270
+ if (!update || typeof update !== 'object') {
271
+ return new Response('Bad Request: Expected Telegram update object', {
272
+ status: 400,
273
+ headers: { 'Content-Type': 'text/plain' },
274
+ });
275
+ }
276
+
277
+ // 8. Optional user hook before processing
278
+ if (typeof opts.onUpdate === 'function') {
279
+ try {
280
+ await opts.onUpdate(update, { request, env, waitUntil, bot });
281
+ } catch (hookErr) {
282
+ console.warn('[Telegix Webhook] onUpdate hook error:', hookErr);
283
+ }
284
+ }
285
+
286
+ // 9. Pipeline execution
287
+ const processTask = (async () => {
288
+ try {
289
+ await bot.handleUpdate(update);
290
+ } catch (err) {
291
+ console.error('[Telegix Webhook] Error processing update:', err);
292
+ if (typeof opts.onError === 'function') {
293
+ opts.onError(err, { update, request, env, bot });
294
+ } else if (bot.errorHandler) {
295
+ bot.errorHandler(err);
296
+ }
297
+ }
298
+ })();
299
+
300
+ // 10. If waitUntil is enabled and supported by Cloudflare, return 200 OK immediately
301
+ // to prevent Telegram webhook timeouts (< 5 seconds)!
302
+ if (opts.waitUntil && typeof waitUntil === 'function') {
303
+ waitUntil(processTask);
304
+ return new Response(JSON.stringify({ ok: true }), {
305
+ status: 200,
306
+ headers: {
307
+ 'Content-Type': 'application/json',
308
+ 'Access-Control-Allow-Origin': '*',
309
+ },
310
+ });
311
+ }
312
+
313
+ // Otherwise await synchronously
314
+ try {
315
+ await processTask;
316
+ return new Response(JSON.stringify({ ok: true }), {
317
+ status: 200,
318
+ headers: {
319
+ 'Content-Type': 'application/json',
320
+ 'Access-Control-Allow-Origin': '*',
321
+ },
322
+ });
323
+ } catch (err) {
324
+ const status = typeof opts.respondOnError === 'number' ? opts.respondOnError : 200;
325
+ return new Response(JSON.stringify({ ok: false, error: err.message }), {
326
+ status,
327
+ headers: {
328
+ 'Content-Type': 'application/json',
329
+ 'Access-Control-Allow-Origin': '*',
330
+ },
331
+ });
332
+ }
333
+ };
334
+ }
335
+
336
+ /**
337
+ * Direct function to handle a Cloudflare Pages or Workers request
338
+ * @param {object} context - Cloudflare Pages context or request
339
+ * @param {import('./telegix.js').Telegix} bot
340
+ * @param {object} [options]
341
+ * @returns {Promise<Response>}
342
+ */
343
+ export async function handleCloudflareWebhook(context, bot, options = {}) {
344
+ const handler = createPagesWebhookHandler(bot, options);
345
+ return handler(context);
346
+ }
347
+
348
+ /**
349
+ * Alias for createPagesWebhookHandler for Cloudflare Workers / Edge environments
350
+ */
351
+ export const createCloudflareWebhookCallback = createPagesWebhookHandler;
352
+
353
+ /**
354
+ * Helper handler for Cloudflare Pages to set, check, or delete Telegram Webhook via HTTP
355
+ * Place in `functions/setWebhook.js` for instant webhook registration in your browser or curl.
356
+ *
357
+ * @param {import('./telegix.js').Telegix | ((env: any) => import('./telegix.js').Telegix)} [botOrFactory]
358
+ * @param {object} [options]
359
+ * @param {string} [options.webhookPath='/webhook']
360
+ * @returns {Function} Cloudflare Pages Request Handler
361
+ */
362
+ export function createPagesSetWebhookHandler(botOrFactory, options = {}) {
363
+ const webhookPath = options.webhookPath || '/webhook';
364
+
365
+ return async function handleSetWebhook(context) {
366
+ const request = context.request || context;
367
+ const env = context.env || {};
368
+ const url = new URL(request.url);
369
+ const action = url.searchParams.get('action') || (request.method === 'POST' ? 'set' : 'info');
370
+
371
+ // Resolve bot instance
372
+ let bot = typeof botOrFactory === 'object' && botOrFactory !== null ? botOrFactory : null;
373
+ if (!bot) {
374
+ if (typeof botOrFactory === 'function') {
375
+ bot = botOrFactory(env);
376
+ } else if (env && (env.BOT_TOKEN || env.TELEGRAM_BOT_TOKEN)) {
377
+ const token = env.BOT_TOKEN || env.TELEGRAM_BOT_TOKEN;
378
+ const { Telegix } = await import('./telegix.js');
379
+ bot = new Telegix(token);
380
+ }
381
+ }
382
+
383
+ if (!bot) {
384
+ return new Response(
385
+ JSON.stringify(
386
+ {
387
+ ok: false,
388
+ error: 'BOT_TOKEN is not configured in Cloudflare environment variables.',
389
+ },
390
+ null,
391
+ 2
392
+ ),
393
+ { status: 500, headers: { 'Content-Type': 'application/json' } }
394
+ );
395
+ }
396
+
397
+ const secretToken = options.secretToken || env.WEBHOOK_SECRET || env.SECRET_TOKEN || undefined;
398
+ const targetWebhookUrl = `${url.origin}${webhookPath}`;
399
+
400
+ try {
401
+ if (action === 'set') {
402
+ const dropPending = url.searchParams.get('drop_pending_updates') === 'true';
403
+ const result = await bot.telegram.setWebhook(targetWebhookUrl, {
404
+ secret_token: secretToken,
405
+ drop_pending_updates: dropPending,
406
+ });
407
+
408
+ const info = await bot.telegram.getWebhookInfo();
409
+
410
+ return new Response(
411
+ JSON.stringify(
412
+ {
413
+ ok: true,
414
+ action: 'setWebhook',
415
+ message: 'Telegram Webhook successfully set for Cloudflare Pages!',
416
+ webhookUrl: targetWebhookUrl,
417
+ secretTokenSet: Boolean(secretToken),
418
+ telegramResponse: result,
419
+ currentWebhookInfo: info,
420
+ },
421
+ null,
422
+ 2
423
+ ),
424
+ { status: 200, headers: { 'Content-Type': 'application/json' } }
425
+ );
426
+ }
427
+
428
+ if (action === 'delete') {
429
+ const dropPending = url.searchParams.get('drop_pending_updates') === 'true';
430
+ const result = await bot.telegram.deleteWebhook({
431
+ drop_pending_updates: dropPending,
432
+ });
433
+
434
+ return new Response(
435
+ JSON.stringify(
436
+ {
437
+ ok: true,
438
+ action: 'deleteWebhook',
439
+ message: 'Telegram Webhook successfully deleted.',
440
+ telegramResponse: result,
441
+ },
442
+ null,
443
+ 2
444
+ ),
445
+ { status: 200, headers: { 'Content-Type': 'application/json' } }
446
+ );
447
+ }
448
+
449
+ // Default: show current Webhook Info
450
+ const info = await bot.telegram.getWebhookInfo();
451
+ const me = await bot.telegram.getMe().catch(() => null);
452
+
453
+ return new Response(
454
+ JSON.stringify(
455
+ {
456
+ ok: true,
457
+ action: 'getWebhookInfo',
458
+ bot: me
459
+ ? { id: me.id, username: me.username, first_name: me.first_name }
460
+ : 'Unknown',
461
+ targetWebhookUrl,
462
+ currentWebhookInfo: info,
463
+ actions: {
464
+ setWebhook: `${url.origin}/setWebhook?action=set`,
465
+ deleteWebhook: `${url.origin}/setWebhook?action=delete`,
466
+ setWithDropUpdates: `${url.origin}/setWebhook?action=set&drop_pending_updates=true`,
467
+ },
468
+ },
469
+ null,
470
+ 2
471
+ ),
472
+ { status: 200, headers: { 'Content-Type': 'application/json' } }
473
+ );
474
+ } catch (err) {
475
+ return new Response(
476
+ JSON.stringify(
477
+ {
478
+ ok: false,
479
+ error: err.message,
480
+ code: err.code || err.error_code,
481
+ },
482
+ null,
483
+ 2
484
+ ),
485
+ { status: 500, headers: { 'Content-Type': 'application/json' } }
486
+ );
487
+ }
488
+ };
489
+ }
490
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "telegix",
3
- "version": "1.1.3-a1",
3
+ "version": "1.1.4",
4
4
  "description": "Lightweight Telegram Bot API framework for Node.js.",
5
5
  "type": "module",
6
6
  "main": "./index.cjs",
@@ -38,5 +38,11 @@
38
38
  "repository": {
39
39
  "type": "git",
40
40
  "url": "https://github.com/KazeDevID/telegix.git"
41
+ },
42
+ "scripts": {
43
+ "dev": "node server.js",
44
+ "build": "node -e 'console.log(\"Telegix build complete\")'",
45
+ "start": "node server.js",
46
+ "lint": "node -c index.js server.js lib/*.js"
41
47
  }
42
48
  }