@2byte/tgbot-framework 1.0.17 → 1.0.18

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2byte/tgbot-framework",
3
- "version": "1.0.17",
3
+ "version": "1.0.18",
4
4
  "description": "A TypeScript framework for creating Telegram bots with sections-based architecture (Bun optimized)",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
package/src/core/App.ts CHANGED
@@ -279,12 +279,7 @@ export class App {
279
279
  ? startPayload.split("key=")[1] || null
280
280
  : null;
281
281
  }
282
- this.debugLog(
283
- "exists storage",
284
- this.config.userStorage.exists(tgUsername),
285
- "remeber:",
286
- this.rememberUser(tgUsername)
287
- );
282
+
288
283
  // Check access by username and register user if not exists
289
284
  if (!this.config.userStorage.exists(tgUsername) && !this.rememberUser(tgUsername)) {
290
285
  const isAuthByUsername = !this.config.accessPublic && !accessKey;
@@ -907,7 +902,7 @@ export class App {
907
902
  }
908
903
  sectionClass = this.sectionClasses.get(sectionId) as typeof Section;
909
904
  }
910
- this.debugLog("Using section class:", sectionClass.constructor.name);
905
+ this.debugLog("Using section class:", sectionClass.name);
911
906
 
912
907
  let sectionInstance: Section | undefined;
913
908
 
@@ -921,6 +916,10 @@ export class App {
921
916
  };
922
917
 
923
918
  const createRunnedSection = (instance: Section, route: RunSectionRoute): RunnedSection => {
919
+ if (route.hasCallbackParams()) {
920
+ instance.setCallbackParams(route.getCallbackParams());
921
+ this.debugLog("Set callback params for section instance:", route.getCallbackParams());
922
+ }
924
923
  return {
925
924
  instance,
926
925
  route,
@@ -38,6 +38,16 @@ export class InlineKeyboard {
38
38
  return this;
39
39
  }
40
40
 
41
+ appendArray(rows: any[][]): InlineKeyboard {
42
+ rows.forEach(row => this.append(row));
43
+ return this;
44
+ }
45
+
46
+ prependArray(rows: any[][]): InlineKeyboard {
47
+ rows.forEach(row => this.prepend(row));
48
+ return this;
49
+ }
50
+
41
51
  prepend(...row: any[]): InlineKeyboard {
42
52
  if (!Array.isArray(row)) {
43
53
  this.keyboard.unshift([row]);
@@ -202,7 +202,7 @@ export default class Message2byte {
202
202
  if (message) {
203
203
  if ("media_group_id" in message || "caption" in message) {
204
204
  const editMessageCaption = this.editMessageCaption(this.messageValue, this.messageExtra);
205
-
205
+
206
206
  if (editMessageCaption && "message_id" in editMessageCaption) {
207
207
  this.messageId = editMessageCaption.message_id as number;
208
208
  }
@@ -74,6 +74,10 @@ export class RunSectionRoute {
74
74
  getTriggers(): RunSectionRouteTrigger[] {
75
75
  return this.runParams.triggers;
76
76
  }
77
+
78
+ hasCallbackParams(): boolean {
79
+ return this.runParams.callbackParams && Array.from(this.runParams.callbackParams).length > 0;
80
+ }
77
81
 
78
82
  getMethod(): string | null {
79
83
  return this.runParams.method;
@@ -3,9 +3,9 @@ import crypto from "crypto";
3
3
  import { UserModel } from "../user/UserModel";
4
4
 
5
5
  export interface AccessKeyData {
6
- id?: number;
6
+ id: number;
7
7
  user_id: number;
8
- key?: string;
8
+ key: string;
9
9
  used?: number;
10
10
  used_user_id?: number | null;
11
11
  created_at?: string;
@@ -41,31 +41,31 @@ export class AccessKey extends Model {
41
41
  return key;
42
42
  }
43
43
 
44
- static async findByKey(key: string): Promise<AccessKeyData | null> {
44
+ static findByKey(key: string): AccessKeyData | null {
45
45
  return this.queryOne(`SELECT * FROM ${this.tableName} WHERE key = ?`, [key]);
46
46
  }
47
47
 
48
- static async findById(id: number): Promise<AccessKeyData | null> {
48
+ static findById(id: number): AccessKeyData | null {
49
49
  return this.queryOne(`SELECT * FROM ${this.tableName} WHERE id = ?`, [id]);
50
50
  }
51
51
 
52
- static markUsed(key: string, usedUserId?: number): Promise<void> {
52
+ static markUsed(key: string, usedUserId?: number): void {
53
53
  this.execute(
54
54
  `UPDATE ${this.tableName} SET used = 1, used_user_id = ?, created_at = created_at WHERE key = ?`,
55
55
  [usedUserId || null, key]
56
56
  );
57
57
  }
58
58
 
59
- static async revoke(key: string): Promise<void> {
60
- await this.execute(`DELETE FROM ${this.tableName} WHERE key = ?`, [key]);
59
+ static revoke(key: string): void {
60
+ this.execute(`DELETE FROM ${this.tableName} WHERE key = ?`, [key]);
61
61
  }
62
62
 
63
- static async getAll(limit = 100): Promise<AccessKeyData[]> {
63
+ static getAll(limit = 100): AccessKeyData[] {
64
64
  return this.query(`SELECT * FROM ${this.tableName} ORDER BY created_at DESC LIMIT ?`, [limit]);
65
65
  }
66
66
 
67
67
  /** Get all access keys for a given user */
68
- static async findByUser(userId: number, limit = 100): Promise<AccessKeyData[]> {
68
+ static findByUser(userId: number, limit = 100): AccessKeyData[] {
69
69
  return this.query(
70
70
  `SELECT * FROM ${this.tableName} WHERE user_id = ? ORDER BY created_at DESC LIMIT ?`,
71
71
  [userId, limit]
@@ -73,8 +73,19 @@ export class AccessKey extends Model {
73
73
  }
74
74
 
75
75
  /** Return the owner `UserModel` for a given access entry or null */
76
- static async getUserByEntry(entry: AccessKeyData): Promise<any | null> {
77
- const userData = await this.queryOne(`SELECT * FROM users WHERE id = ?`, [entry.user_id]);
76
+ static getUserByEntry(entry: AccessKeyData): any | null {
77
+ const userData = this.queryOne(`SELECT * FROM users WHERE id = ?`, [entry.user_id]);
78
+ if (!userData) return null;
79
+ try {
80
+ return UserModel.make(userData);
81
+ } catch (e) {
82
+ return userData;
83
+ }
84
+ }
85
+
86
+ static getUsedUserByEntry(entry: AccessKeyData): any | null {
87
+ if (!entry.used_user_id) return null;
88
+ const userData = this.queryOne(`SELECT * FROM users WHERE id = ?`, [entry.used_user_id]);
78
89
  if (!userData) return null;
79
90
  try {
80
91
  return UserModel.make(userData);
@@ -84,8 +95,8 @@ export class AccessKey extends Model {
84
95
  }
85
96
 
86
97
  /** Find owner by key string */
87
- static async getUserByKey(key: string): Promise<any | null> {
88
- const entry = await this.findByKey(key);
98
+ static getUserByKey(key: string): any | null {
99
+ const entry = this.findByKey(key);
89
100
  if (!entry) return null;
90
101
  return this.getUserByEntry(entry as AccessKeyData);
91
102
  }
@@ -29,13 +29,13 @@ export abstract class Model {
29
29
  return this.db.transaction(callback)();
30
30
  }
31
31
 
32
- public static async paginate(paginateParams: ModelPaginateParams): Promise<PaginateResult> {
32
+ public static paginate(paginateParams: ModelPaginateParams): PaginateResult {
33
33
  const { page, route, routeParams, limit, whereSql, whereParams } = paginateParams;
34
34
  const offset = (page - 1) * limit;
35
35
  const sql = `SELECT * FROM ${this.tableName} ${whereSql} LIMIT ${offset}, ${limit}`;
36
36
 
37
- const result = await this.query(sql, whereParams);
38
- const queryTotal = await this.queryOne(`SELECT COUNT(*) as count FROM ${this.tableName} ${whereSql}`, whereParams);
37
+ const result = this.query(sql, whereParams);
38
+ const queryTotal = this.queryOne(`SELECT COUNT(*) as count FROM ${this.tableName} ${whereSql}`, whereParams);
39
39
  const total = queryTotal ? queryTotal.count : 0;
40
40
  const totalPages = Math.ceil(total / limit);
41
41
  const hasPreviousPage = page > 1;
@@ -232,6 +232,15 @@ export class UserModel extends Model {
232
232
  return undefined;
233
233
  }
234
234
 
235
+ static delete(id: number): boolean {
236
+ if (this.db) {
237
+ const result = this.db.run(`DELETE FROM ${this.tableName} WHERE id = ?`, [id]);
238
+ return result.changes > 0;
239
+ } else {
240
+ throw new Error("Database connection is not set.");
241
+ }
242
+ }
243
+
235
244
  get username(): string {
236
245
  return this.attributes.tg_username;
237
246
  }
@@ -116,4 +116,23 @@ export class UserStore {
116
116
  });
117
117
  }, 60 * 1000);
118
118
  }
119
+
120
+ deleteByUsername(tgUsername: string): boolean {
121
+ const user = this.usersMap.get(tgUsername);
122
+ if (user) {
123
+ this.usersSession.delete(user);
124
+ return this.usersMap.delete(tgUsername);
125
+ }
126
+ return false;
127
+ }
128
+
129
+ deleteById(userId: number): boolean {
130
+ const userEntry = Array.from(this.usersMap).find(([_, user]) => user.id === userId);
131
+ if (userEntry) {
132
+ const [tgUsername, user] = userEntry;
133
+ this.usersSession.delete(user);
134
+ return this.usersMap.delete(tgUsername);
135
+ }
136
+ return false;
137
+ }
119
138
  }
@@ -0,0 +1,12 @@
1
+ -- UP
2
+ CREATE TABLE IF NOT EXISTS access_keys (
3
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
4
+ user_id INTEGER NOT NULL,
5
+ key TEXT NOT NULL UNIQUE,
6
+ used INTEGER NOT NULL DEFAULT 0,
7
+ used_user_id INTEGER DEFAULT NULL,
8
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
9
+ );
10
+
11
+ -- DOWN
12
+ DROP TABLE IF EXISTS access_keys;
@@ -21,7 +21,7 @@
21
21
  "author": "{{author}}",
22
22
  "license": "MIT",
23
23
  "dependencies": {
24
- "@2byte/tgbot-framework": "^1.0.17"
24
+ "@2byte/tgbot-framework": "^1.0.18"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@types/node": "^20.19.8",