tgbox 0.0.0-stage → 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.
package/fileService.js ADDED
@@ -0,0 +1,155 @@
1
+ const fs = require('fs');
2
+
3
+ class FileService {
4
+ constructor(client) {
5
+ this.client = client;
6
+ }
7
+
8
+ async upload(filePath, targetChat = 'me') {
9
+ try {
10
+ if (!fs.existsSync(filePath)) {
11
+ throw new Error(`File not found at path: ${filePath}`);
12
+ }
13
+
14
+ const result = await this.client.sendFile(targetChat, {
15
+ file: filePath,
16
+ workers: 2,
17
+ });
18
+
19
+ return {
20
+ success: true,
21
+ messageId: result.id,
22
+ fileName: filePath.split(/[\\/]/).pop(),
23
+ };
24
+ } catch (error) {
25
+ return { success: false, error: error.message };
26
+ }
27
+ }
28
+
29
+ async download(messageId, outputPath, targetChat = 'me') {
30
+ try {
31
+ const messages = await this.client.getMessages(targetChat, {
32
+ ids: [messageId],
33
+ });
34
+
35
+ if (!messages || messages.length === 0) {
36
+ throw new Error('Message not found.');
37
+ }
38
+
39
+ await this.client.downloadMedia(messages[0], {
40
+ outputFile: outputPath,
41
+ });
42
+
43
+ return { success: true, path: outputPath };
44
+ } catch (error) {
45
+ return { success: false, error: error.message };
46
+ }
47
+ }
48
+
49
+ async deleteFile(messageId, targetChat = 'me') {
50
+ const messageIds = Array.isArray(messageId) ? messageId : [messageId];
51
+ if (
52
+ messageIds.length === 0 ||
53
+ messageIds.some((id) => !Number.isInteger(Number(id)) || Number(id) <= 0)
54
+ ) {
55
+ return { success: false, error: 'A valid file message ID is required.' };
56
+ }
57
+
58
+ try {
59
+ await this.client.deleteMessages(
60
+ targetChat,
61
+ messageIds.map(Number),
62
+ { revoke: true },
63
+ );
64
+
65
+ return { success: true, messageIds: messageIds.map(Number) };
66
+ } catch (error) {
67
+ return { success: false, error: error.message };
68
+ }
69
+ }
70
+
71
+ async listFiles(targetChat = 'me') {
72
+ try {
73
+ const files = [];
74
+
75
+ for await (const message of this.client.iterMessages(targetChat, {
76
+ limit: 0,
77
+ })) {
78
+ if (!message.document) {
79
+ continue;
80
+ }
81
+
82
+ const fileNameAttribute = message.document.attributes.find(
83
+ (attribute) => attribute.className === 'DocumentAttributeFilename',
84
+ );
85
+
86
+ files.push({
87
+ messageId: message.id,
88
+ fileName: fileNameAttribute ? fileNameAttribute.fileName : null,
89
+ size: Number(message.document.size),
90
+ mimeType: message.document.mimeType,
91
+ date: message.date,
92
+ caption: message.message || null,
93
+ telegram: {
94
+ message: message.toJSON(),
95
+ document: message.document.toJSON(),
96
+ },
97
+ });
98
+ }
99
+
100
+ return { success: true, files };
101
+ } catch (error) {
102
+ return { success: false, error: error.message };
103
+ }
104
+ }
105
+
106
+ async searchFiles(query, targetChat = 'me') {
107
+ if (typeof query !== 'string' || query.trim() === '') {
108
+ return { success: false, error: 'Search query must not be empty.' };
109
+ }
110
+
111
+ const result = await this.listFiles(targetChat);
112
+ if (!result.success) {
113
+ return result;
114
+ }
115
+
116
+ const normalizedQuery = query.trim().toLowerCase();
117
+ const files = result.files.filter((file) => {
118
+ const fileName = file.fileName || '';
119
+ const caption = file.caption || '';
120
+ const messageId = String(file.messageId);
121
+ return (
122
+ messageId === normalizedQuery ||
123
+ `${fileName} ${caption}`.toLowerCase().includes(normalizedQuery)
124
+ );
125
+ });
126
+
127
+ return { success: true, files };
128
+ }
129
+
130
+ async findFile(identifier, targetChat = 'me') {
131
+ if (typeof identifier !== 'string' && typeof identifier !== 'number') {
132
+ return { success: false, error: 'File ID or name is required.' };
133
+ }
134
+
135
+ const query = String(identifier).trim();
136
+ if (!query) {
137
+ return { success: false, error: 'File ID or name must not be empty.' };
138
+ }
139
+
140
+ const result = await this.listFiles(targetChat);
141
+ if (!result.success) {
142
+ return result;
143
+ }
144
+
145
+ const files = result.files.filter(
146
+ (item) =>
147
+ String(item.messageId) === query ||
148
+ (item.fileName && item.fileName.toLowerCase() === query.toLowerCase()),
149
+ );
150
+
151
+ return { success: true, files };
152
+ }
153
+ }
154
+
155
+ module.exports = FileService;
package/index.js ADDED
@@ -0,0 +1,69 @@
1
+ const { TelegramClient } = require('telegram');
2
+ const { StringSession } = require('telegram/sessions');
3
+ const input = require('input');
4
+ const fs = require('fs');
5
+ const FileService = require('./fileService');
6
+
7
+ class TgBox {
8
+ constructor(apiId, apiHash, sessionFilePath = 'session.txt') {
9
+ if (!apiId || !apiHash) {
10
+ throw new Error('TgBox requires apiId and apiHash.');
11
+ }
12
+ this.apiId = Number(apiId);
13
+ this.apiHash = apiHash;
14
+ this.sessionFilePath = sessionFilePath;
15
+ this.fileService = null;
16
+
17
+ let savedSession = '';
18
+ if (fs.existsSync(this.sessionFilePath)) {
19
+ savedSession = fs.readFileSync(this.sessionFilePath, 'utf8').trim();
20
+ }
21
+
22
+ this.stringSession = new StringSession(savedSession);
23
+ }
24
+
25
+ async init() {
26
+ this.client = new TelegramClient(this.stringSession, this.apiId, this.apiHash, {
27
+ connectionRetries: 5,
28
+ });
29
+ this.fileService = new FileService(this.client);
30
+
31
+ await this.client.start({
32
+ phoneNumber: async () => await input.text('[INFO] Type your phonenumber in: '),
33
+ password: async () => await input.text('[INFO] 2FA Code: '),
34
+ phoneCode: async () => await input.text('[INFO] Telegram code: '),
35
+ onError: (err) => console.log("[ERROR] " + err),
36
+ });
37
+
38
+ console.log('[INFO] Successfully logged in!');
39
+
40
+
41
+ const currentSession = this.client.session.save();
42
+ fs.writeFileSync(this.sessionFilePath, currentSession);
43
+ }
44
+ async upload(filePath, targetChat = 'me') {
45
+ return this.fileService.upload(filePath, targetChat);
46
+ }
47
+
48
+ async download(messageId, outputPath, targetChat = 'me') {
49
+ return this.fileService.download(messageId, outputPath, targetChat);
50
+ }
51
+
52
+ async deleteFile(messageId, targetChat = 'me') {
53
+ return this.fileService.deleteFile(messageId, targetChat);
54
+ }
55
+
56
+ async listFiles(targetChat = 'me') {
57
+ return this.fileService.listFiles(targetChat);
58
+ }
59
+
60
+ async searchFiles(query, targetChat = 'me') {
61
+ return this.fileService.searchFiles(query, targetChat);
62
+ }
63
+
64
+ async findFile(identifier, targetChat = 'me') {
65
+ return this.fileService.findFile(identifier, targetChat);
66
+ }
67
+ }
68
+
69
+ module.exports = TgBox;
package/package.json CHANGED
@@ -1,6 +1,28 @@
1
1
  {
2
2
  "name": "tgbox",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.0",
4
+ "description": "A lightweight free cloud storage solution using Telegram as backend.",
5
+ "main": "index.js",
6
+ "files": [
7
+ "index.js",
8
+ "fileService.js"
9
+ ],
10
+ "scripts": {
11
+ "test": "echo \"Error: no test specified\" && exit 1"
12
+ },
13
+ "keywords": [
14
+ "telegram",
15
+ "storage",
16
+ "cloud",
17
+ "backup",
18
+ "files"
19
+ ],
20
+ "author": "Dein Name",
21
+ "license": "MIT",
22
+ "dependencies": {
23
+ "axios": "^1.7.9",
24
+ "form-data": "^4.0.1",
25
+ "input": "^1.0.1",
26
+ "telegram": "^2.26.22"
27
+ }
28
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.