tglfs 0.1.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 (81) hide show
  1. package/README.md +216 -0
  2. package/dist/auth.d.ts +58 -0
  3. package/dist/auth.js +187 -0
  4. package/dist/auth.js.map +1 -0
  5. package/dist/cli.d.ts +2 -0
  6. package/dist/cli.js +627 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/crypto.d.ts +8 -0
  9. package/dist/crypto.js +45 -0
  10. package/dist/crypto.js.map +1 -0
  11. package/dist/download.d.ts +26 -0
  12. package/dist/download.js +228 -0
  13. package/dist/download.js.map +1 -0
  14. package/dist/errors.d.ts +18 -0
  15. package/dist/errors.js +35 -0
  16. package/dist/errors.js.map +1 -0
  17. package/dist/file-ops.d.ts +71 -0
  18. package/dist/file-ops.js +234 -0
  19. package/dist/file-ops.js.map +1 -0
  20. package/dist/gramjs.d.ts +14 -0
  21. package/dist/gramjs.js +70 -0
  22. package/dist/gramjs.js.map +1 -0
  23. package/dist/interactive.d.ts +11 -0
  24. package/dist/interactive.js +81 -0
  25. package/dist/interactive.js.map +1 -0
  26. package/dist/json.d.ts +2 -0
  27. package/dist/json.js +4 -0
  28. package/dist/json.js.map +1 -0
  29. package/dist/progress.d.ts +16 -0
  30. package/dist/progress.js +62 -0
  31. package/dist/progress.js.map +1 -0
  32. package/dist/protocol.d.ts +5 -0
  33. package/dist/protocol.js +27 -0
  34. package/dist/protocol.js.map +1 -0
  35. package/dist/search.d.ts +23 -0
  36. package/dist/search.js +81 -0
  37. package/dist/search.js.map +1 -0
  38. package/dist/secrets.d.ts +12 -0
  39. package/dist/secrets.js +29 -0
  40. package/dist/secrets.js.map +1 -0
  41. package/dist/shared/archive.d.ts +9 -0
  42. package/dist/shared/archive.js +95 -0
  43. package/dist/shared/archive.js.map +1 -0
  44. package/dist/shared/constants.d.ts +5 -0
  45. package/dist/shared/constants.js +6 -0
  46. package/dist/shared/constants.js.map +1 -0
  47. package/dist/shared/file-cards.d.ts +31 -0
  48. package/dist/shared/file-cards.js +103 -0
  49. package/dist/shared/file-cards.js.map +1 -0
  50. package/dist/shared/telegram-files.d.ts +84 -0
  51. package/dist/shared/telegram-files.js +137 -0
  52. package/dist/shared/telegram-files.js.map +1 -0
  53. package/dist/shared/upload.d.ts +44 -0
  54. package/dist/shared/upload.js +181 -0
  55. package/dist/shared/upload.js.map +1 -0
  56. package/dist/store.d.ts +15 -0
  57. package/dist/store.js +97 -0
  58. package/dist/store.js.map +1 -0
  59. package/dist/types.d.ts +18 -0
  60. package/dist/types.js +2 -0
  61. package/dist/types.js.map +1 -0
  62. package/dist/ufid.d.ts +8 -0
  63. package/dist/ufid.js +65 -0
  64. package/dist/ufid.js.map +1 -0
  65. package/dist/upload.d.ts +19 -0
  66. package/dist/upload.js +101 -0
  67. package/dist/upload.js.map +1 -0
  68. package/man/tglfs-delete.1 +19 -0
  69. package/man/tglfs-download.1 +42 -0
  70. package/man/tglfs-inspect.1 +34 -0
  71. package/man/tglfs-login.1 +53 -0
  72. package/man/tglfs-logout.1 +17 -0
  73. package/man/tglfs-receive.1 +26 -0
  74. package/man/tglfs-rename.1 +8 -0
  75. package/man/tglfs-search.1 +37 -0
  76. package/man/tglfs-send.1 +22 -0
  77. package/man/tglfs-status.1 +12 -0
  78. package/man/tglfs-unsend.1 +37 -0
  79. package/man/tglfs-upload.1 +28 -0
  80. package/man/tglfs.1 +70 -0
  81. package/package.json +66 -0
@@ -0,0 +1,234 @@
1
+ import { coerceTelegramDocumentSize, inspectFileFromEncryptedParts, iterateEncryptedFile, } from "./download.js";
2
+ import { CliError, EXIT_CODES } from "./errors.js";
3
+ import { getGramJs } from "./gramjs.js";
4
+ import { validateDownloadableFileCard } from "./protocol.js";
5
+ import { deleteFileCardMessages, lookupFileCardByUfid, renameFileCardMessage, transferFileCard, unsendFileCard, } from "./shared/telegram-files.js";
6
+ import { formatFileCardDate, formatFileCardSize } from "./shared/file-cards.js";
7
+ function normalizePeer(peer, fallback = "me") {
8
+ const normalized = peer?.trim() ?? fallback;
9
+ if (normalized === "") {
10
+ throw new CliError("invalid_input", "Peer must not be empty.", EXIT_CODES.GENERAL_ERROR);
11
+ }
12
+ return normalized;
13
+ }
14
+ export async function resolveFileCardRecord(client, ufid, peer = "me") {
15
+ const normalizedPeer = normalizePeer(peer);
16
+ const record = await lookupFileCardByUfid(client, ufid.trim(), { peer: normalizedPeer });
17
+ if (!record) {
18
+ throw new CliError("file_not_found", `No TGLFS file card was found for UFID ${ufid.trim()} in ${normalizedPeer === "me" ? "Saved Messages" : normalizedPeer}.`, EXIT_CODES.FILE_NOT_FOUND);
19
+ }
20
+ return record;
21
+ }
22
+ export async function resolveFileCardRecords(client, ufids, peer = "me") {
23
+ const records = [];
24
+ for (const ufid of ufids) {
25
+ records.push(await resolveFileCardRecord(client, ufid, peer));
26
+ }
27
+ return records;
28
+ }
29
+ export async function renameFile(client, ufid, newName) {
30
+ const record = await resolveFileCardRecord(client, ufid, "me");
31
+ const trimmedName = newName.trim();
32
+ if (trimmedName === "") {
33
+ throw new CliError("invalid_input", "New file name must not be empty.", EXIT_CODES.GENERAL_ERROR);
34
+ }
35
+ const { Api } = getGramJs();
36
+ const updated = { ...record.data, name: trimmedName };
37
+ await renameFileCardMessage(client, {
38
+ Api: Api,
39
+ peer: "me",
40
+ msgId: record.msgId,
41
+ peerId: "me",
42
+ data: record.data,
43
+ newName: trimmedName,
44
+ });
45
+ return {
46
+ before: record,
47
+ after: {
48
+ ...record,
49
+ data: updated,
50
+ },
51
+ };
52
+ }
53
+ export async function deleteResolvedFiles(client, records) {
54
+ const { Api } = getGramJs();
55
+ for (const record of records) {
56
+ await deleteFileCardMessages(client, {
57
+ Api: Api,
58
+ msgId: record.msgId,
59
+ data: record.data,
60
+ });
61
+ }
62
+ return records;
63
+ }
64
+ export async function deleteFiles(client, ufids) {
65
+ const records = await resolveFileCardRecords(client, ufids, "me");
66
+ return deleteResolvedFiles(client, records);
67
+ }
68
+ export async function sendFiles(client, ufids, recipient) {
69
+ const normalizedRecipient = normalizePeer(recipient, "");
70
+ const { Api } = getGramJs();
71
+ const sent = [];
72
+ for (const ufid of ufids) {
73
+ const record = await resolveFileCardRecord(client, ufid, "me");
74
+ validateDownloadableFileCard(record.data);
75
+ const result = await transferFileCard(client, {
76
+ Api: Api,
77
+ record,
78
+ sourcePeer: "me",
79
+ targetPeer: normalizedRecipient,
80
+ silent: true,
81
+ });
82
+ sent.push({
83
+ source: record,
84
+ recipient: normalizedRecipient,
85
+ data: result.data,
86
+ });
87
+ }
88
+ return sent;
89
+ }
90
+ export async function receiveFiles(client, source, ufids) {
91
+ const normalizedSource = normalizePeer(source, "");
92
+ const { Api } = getGramJs();
93
+ const received = [];
94
+ for (const ufid of ufids) {
95
+ const record = await resolveFileCardRecord(client, ufid, normalizedSource);
96
+ validateDownloadableFileCard(record.data);
97
+ const result = await transferFileCard(client, {
98
+ Api: Api,
99
+ record,
100
+ sourcePeer: normalizedSource,
101
+ targetPeer: "me",
102
+ });
103
+ received.push({
104
+ source: normalizedSource,
105
+ original: record,
106
+ data: result.data,
107
+ });
108
+ }
109
+ return received;
110
+ }
111
+ export async function unsendFiles(client, source, ufids) {
112
+ const normalizedSource = normalizePeer(source, "");
113
+ const { Api } = getGramJs();
114
+ const unsent = [];
115
+ for (const ufid of ufids) {
116
+ const record = await resolveFileCardRecord(client, ufid, normalizedSource);
117
+ await unsendFileCard(client, {
118
+ Api: Api,
119
+ record,
120
+ peer: normalizedSource,
121
+ });
122
+ unsent.push(record);
123
+ }
124
+ return unsent;
125
+ }
126
+ async function inspectChunkMessages(client, peer, data) {
127
+ const messages = await client.getMessages(peer, { ids: data.chunks, waitTime: 0 });
128
+ const byId = new Map();
129
+ for (const message of messages) {
130
+ if (typeof message?.id === "number") {
131
+ byId.set(message.id, message);
132
+ }
133
+ }
134
+ return data.chunks.map((chunkId) => {
135
+ const message = byId.get(chunkId);
136
+ if (!message) {
137
+ return { msgId: chunkId, status: "missing" };
138
+ }
139
+ if (!message?.media?.document) {
140
+ return {
141
+ msgId: chunkId,
142
+ status: "not_document",
143
+ className: message.className,
144
+ };
145
+ }
146
+ const size = coerceTelegramDocumentSize(message.media.document.size);
147
+ if (size === null) {
148
+ return {
149
+ msgId: chunkId,
150
+ status: "invalid_size",
151
+ className: message.className,
152
+ };
153
+ }
154
+ return {
155
+ msgId: chunkId,
156
+ status: "ok",
157
+ size,
158
+ className: message.className,
159
+ };
160
+ });
161
+ }
162
+ export async function detectFileMode(expected, inspectMode) {
163
+ let lastError;
164
+ for (const mode of ["current", "legacy"]) {
165
+ try {
166
+ const result = await inspectMode(mode);
167
+ if (result.bytesWritten === expected.size && result.computedUfid === expected.ufid) {
168
+ return {
169
+ probe: {
170
+ mode,
171
+ bytesWritten: result.bytesWritten,
172
+ computedUfid: result.computedUfid,
173
+ },
174
+ };
175
+ }
176
+ lastError = `The ${mode} probe did not match the expected UFID.`;
177
+ }
178
+ catch (error) {
179
+ lastError = error instanceof Error ? error.message : String(error);
180
+ }
181
+ }
182
+ return { lastError };
183
+ }
184
+ async function probeFileMode(client, peer, data, password) {
185
+ return detectFileMode({ size: data.size, ufid: data.ufid }, (mode) => inspectFileFromEncryptedParts(data, password, iterateEncryptedFile(client, data, peer), mode));
186
+ }
187
+ export async function inspectFileCard(client, ufid, options = {}) {
188
+ const peer = normalizePeer(options.peer);
189
+ const record = await resolveFileCardRecord(client, ufid, peer);
190
+ const chunks = await inspectChunkMessages(client, peer, record.data);
191
+ const everyChunkReadable = chunks.every((chunk) => chunk.status === "ok");
192
+ let probe;
193
+ let probeError;
194
+ if (!options.probe) {
195
+ probeError = "Format probe skipped. Re-run with --probe to verify current vs legacy format.";
196
+ }
197
+ else if (everyChunkReadable) {
198
+ try {
199
+ const detection = await probeFileMode(client, peer, record.data, options.password ?? "");
200
+ probe = detection.probe;
201
+ if (!probe) {
202
+ probeError =
203
+ detection.lastError ??
204
+ (options.password === undefined
205
+ ? "Format probe could not distinguish current vs legacy with an empty password."
206
+ : "Format probe failed with the supplied password.");
207
+ }
208
+ }
209
+ catch (error) {
210
+ probeError = error instanceof Error ? error.message : String(error);
211
+ }
212
+ }
213
+ else {
214
+ probeError = "One or more Telegram chunk messages are missing or malformed.";
215
+ }
216
+ return {
217
+ peer,
218
+ msgId: record.msgId,
219
+ date: record.date,
220
+ data: record.data,
221
+ chunks,
222
+ format: probe?.mode ?? "unknown",
223
+ probe,
224
+ probeError,
225
+ };
226
+ }
227
+ export function formatDeleteConfirmation(records) {
228
+ const lines = [`Delete ${records.length} file(s) from Saved Messages?`, ""];
229
+ for (const record of records) {
230
+ lines.push(`${record.data.name} | ${formatFileCardSize(record.data.size)} | ${formatFileCardDate(record.date)} | ${record.data.ufid}`);
231
+ }
232
+ return lines.join("\n");
233
+ }
234
+ //# sourceMappingURL=file-ops.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-ops.js","sourceRoot":"","sources":["../src/file-ops.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { TelegramClient } from "telegram/client/TelegramClient.js";
2
+ import type { StringSession } from "telegram/sessions/StringSession.js";
3
+ type GramJsModules = {
4
+ TelegramClient: typeof import("telegram")["TelegramClient"];
5
+ Api: typeof import("telegram")["Api"];
6
+ StringSession: typeof import("telegram/sessions/StringSession.js")["StringSession"];
7
+ getFileInfo: typeof import("telegram/Utils.js")["getFileInfo"];
8
+ Logger: typeof import("telegram/extensions/Logger.js")["Logger"];
9
+ LogLevel: typeof import("telegram/extensions/Logger.js")["LogLevel"];
10
+ };
11
+ export declare function getGramJs(): GramJsModules;
12
+ export declare function createQuietTelegramClient(session: StringSession, apiId: number, apiHash: string): TelegramClient;
13
+ export declare function createStringSession(value: string): StringSession;
14
+ export {};
package/dist/gramjs.js ADDED
@@ -0,0 +1,70 @@
1
+ import { createRequire } from "node:module";
2
+ const require = createRequire(import.meta.url);
3
+ let gramJsModules = null;
4
+ function installLocalStorageShim() {
5
+ const descriptor = Object.getOwnPropertyDescriptor(globalThis, "localStorage");
6
+ if (!descriptor?.configurable || !descriptor.get) {
7
+ return;
8
+ }
9
+ const storage = new Map();
10
+ const shim = {
11
+ getItem(key) {
12
+ return storage.has(key) ? storage.get(key) : null;
13
+ },
14
+ setItem(key, value) {
15
+ storage.set(String(key), String(value));
16
+ },
17
+ removeItem(key) {
18
+ storage.delete(String(key));
19
+ },
20
+ clear() {
21
+ storage.clear();
22
+ },
23
+ key(index) {
24
+ return Array.from(storage.keys())[index] ?? null;
25
+ },
26
+ get length() {
27
+ return storage.size;
28
+ },
29
+ };
30
+ Object.defineProperty(globalThis, "localStorage", {
31
+ configurable: true,
32
+ enumerable: descriptor.enumerable,
33
+ writable: true,
34
+ value: shim,
35
+ });
36
+ }
37
+ function loadGramJsModules() {
38
+ installLocalStorageShim();
39
+ const telegram = require("telegram");
40
+ const stringSessionModule = require("telegram/sessions/StringSession.js");
41
+ const utilsModule = require("telegram/Utils.js");
42
+ const loggerModule = require("telegram/extensions/Logger.js");
43
+ return {
44
+ TelegramClient: telegram.TelegramClient,
45
+ Api: telegram.Api,
46
+ StringSession: stringSessionModule.StringSession,
47
+ getFileInfo: utilsModule.getFileInfo,
48
+ Logger: loggerModule.Logger,
49
+ LogLevel: loggerModule.LogLevel,
50
+ };
51
+ }
52
+ export function getGramJs() {
53
+ if (!gramJsModules) {
54
+ gramJsModules = loadGramJsModules();
55
+ }
56
+ return gramJsModules;
57
+ }
58
+ export function createQuietTelegramClient(session, apiId, apiHash) {
59
+ const { TelegramClient, Logger, LogLevel } = getGramJs();
60
+ const logger = new Logger(LogLevel.NONE);
61
+ return new TelegramClient(session, apiId, apiHash, {
62
+ connectionRetries: 5,
63
+ baseLogger: logger,
64
+ });
65
+ }
66
+ export function createStringSession(value) {
67
+ const { StringSession } = getGramJs();
68
+ return new StringSession(value);
69
+ }
70
+ //# sourceMappingURL=gramjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gramjs.js","sourceRoot":"","sources":["../src/gramjs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export declare function isInteractiveSession(): boolean;
2
+ export declare function readTrimmedStdin(message: string): Promise<string>;
3
+ export declare function promptText(message: string, initial?: string): Promise<string>;
4
+ export declare function promptOptionalText(message: string, initial?: string): Promise<string>;
5
+ export declare function promptPassword(message: string, initial?: string): Promise<string>;
6
+ export declare function promptConfirm(message: string, initial?: boolean): Promise<boolean>;
7
+ export declare function promptSelect<T extends string>(message: string, choices: Array<{
8
+ title: string;
9
+ value: T;
10
+ description?: string;
11
+ }>): Promise<T>;
@@ -0,0 +1,81 @@
1
+ import prompts from "prompts";
2
+ import { CliError, EXIT_CODES } from "./errors.js";
3
+ export function isInteractiveSession() {
4
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY);
5
+ }
6
+ export async function readTrimmedStdin(message) {
7
+ if (process.stdin.isTTY) {
8
+ throw new CliError("interactive_required", message, EXIT_CODES.INTERACTIVE_REQUIRED);
9
+ }
10
+ const chunks = [];
11
+ for await (const chunk of process.stdin) {
12
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
13
+ }
14
+ const value = Buffer.concat(chunks).toString("utf8").trim();
15
+ if (value === "") {
16
+ throw new CliError("interactive_required", message, EXIT_CODES.INTERACTIVE_REQUIRED);
17
+ }
18
+ return value;
19
+ }
20
+ async function ask(questions) {
21
+ const result = await prompts(questions, {
22
+ onCancel: () => {
23
+ throw new CliError("cancelled", "Operation cancelled.", EXIT_CODES.GENERAL_ERROR);
24
+ },
25
+ });
26
+ return result;
27
+ }
28
+ export async function promptText(message, initial) {
29
+ const response = await ask({
30
+ type: "text",
31
+ name: "value",
32
+ message,
33
+ initial,
34
+ validate: (value) => (value.trim() === "" ? "A value is required." : true),
35
+ });
36
+ return response.value?.trim() ?? "";
37
+ }
38
+ export async function promptOptionalText(message, initial = "") {
39
+ const response = await ask({
40
+ type: "text",
41
+ name: "value",
42
+ message,
43
+ initial,
44
+ });
45
+ return response.value?.trim() ?? "";
46
+ }
47
+ export async function promptPassword(message, initial = "") {
48
+ const response = await ask({
49
+ type: "password",
50
+ name: "value",
51
+ message,
52
+ initial,
53
+ });
54
+ return response.value ?? "";
55
+ }
56
+ export async function promptConfirm(message, initial = false) {
57
+ const response = await ask({
58
+ type: "confirm",
59
+ name: "value",
60
+ message,
61
+ initial,
62
+ });
63
+ return Boolean(response.value);
64
+ }
65
+ export async function promptSelect(message, choices) {
66
+ const response = await ask({
67
+ type: "select",
68
+ name: "value",
69
+ message,
70
+ choices: choices.map((choice) => ({
71
+ title: choice.title,
72
+ value: choice.value,
73
+ description: choice.description,
74
+ })),
75
+ });
76
+ if (!response.value) {
77
+ throw new CliError("cancelled", "Operation cancelled.", EXIT_CODES.GENERAL_ERROR);
78
+ }
79
+ return response.value;
80
+ }
81
+ //# sourceMappingURL=interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../src/interactive.ts"],"names":[],"mappings":"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"}
package/dist/json.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ import type { JsonEnvelope } from "./types.js";
2
+ export declare function printJson<T>(payload: JsonEnvelope<T>): void;
package/dist/json.js ADDED
@@ -0,0 +1,4 @@
1
+ export function printJson(payload) {
2
+ process.stdout.write(JSON.stringify(payload, null, 2) + "\n");
3
+ }
4
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,SAAS,CAAI,OAAwB;IACjD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;AACjE,CAAC"}
@@ -0,0 +1,16 @@
1
+ export type ProgressStream = {
2
+ isTTY?: boolean;
3
+ columns?: number;
4
+ write(chunk: string): boolean;
5
+ };
6
+ export declare function renderProgressLine(label: string, bytesWritten: number, totalBytes: number, width?: number): string;
7
+ export declare function createByteProgressReporter(options: {
8
+ label: string;
9
+ totalBytes: number;
10
+ stream?: ProgressStream;
11
+ enabled?: boolean;
12
+ }): {
13
+ update(bytesWritten: number): void;
14
+ complete(): void;
15
+ abort(): void;
16
+ };
@@ -0,0 +1,62 @@
1
+ import process from "node:process";
2
+ function formatBytes(bytes) {
3
+ const units = ["B", "KiB", "MiB", "GiB", "TiB"];
4
+ let value = Math.max(0, bytes);
5
+ let unitIndex = 0;
6
+ while (value >= 1024 && unitIndex < units.length - 1) {
7
+ value /= 1024;
8
+ unitIndex += 1;
9
+ }
10
+ const formatted = value >= 10 || unitIndex === 0 ? value.toFixed(0) : value.toFixed(1);
11
+ return `${formatted} ${units[unitIndex]}`;
12
+ }
13
+ export function renderProgressLine(label, bytesWritten, totalBytes, width = 24) {
14
+ const safeTotal = Math.max(totalBytes, 1);
15
+ const ratio = Math.min(Math.max(bytesWritten / safeTotal, 0), 1);
16
+ const filled = Math.round(ratio * width);
17
+ const bar = `${"#".repeat(filled)}${"-".repeat(width - filled)}`;
18
+ const percent = Math.round(ratio * 100);
19
+ return `${label} [${bar}] ${percent}% ${formatBytes(bytesWritten)} / ${formatBytes(totalBytes)}`;
20
+ }
21
+ export function createByteProgressReporter(options) {
22
+ const stream = options.stream ?? process.stderr;
23
+ const enabled = options.enabled ?? Boolean(stream.isTTY);
24
+ const minDelta = Math.max(64 * 1024, Math.floor(options.totalBytes / 100));
25
+ let lastRenderedBytes = -1;
26
+ let hasRendered = false;
27
+ const render = (bytesWritten) => {
28
+ if (!enabled) {
29
+ return;
30
+ }
31
+ const boundedBytes = Math.min(Math.max(bytesWritten, 0), options.totalBytes);
32
+ if (lastRenderedBytes >= 0 &&
33
+ boundedBytes !== options.totalBytes &&
34
+ boundedBytes - lastRenderedBytes < minDelta) {
35
+ return;
36
+ }
37
+ const columns = typeof stream.columns === "number" && stream.columns > 0 ? stream.columns : 80;
38
+ const line = renderProgressLine(options.label, boundedBytes, options.totalBytes).slice(0, Math.max(columns - 1, 20));
39
+ stream.write(`\r${line}`);
40
+ lastRenderedBytes = boundedBytes;
41
+ hasRendered = true;
42
+ };
43
+ return {
44
+ update(bytesWritten) {
45
+ render(bytesWritten);
46
+ },
47
+ complete() {
48
+ if (lastRenderedBytes !== options.totalBytes) {
49
+ render(options.totalBytes);
50
+ }
51
+ if (enabled && hasRendered) {
52
+ stream.write("\n");
53
+ }
54
+ },
55
+ abort() {
56
+ if (enabled && hasRendered) {
57
+ stream.write("\n");
58
+ }
59
+ },
60
+ };
61
+ }
62
+ //# sourceMappingURL=progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { TelegramClient } from "telegram";
2
+ import type { FileCardData, FileCardRecord } from "./types.js";
3
+ export { parseFileCardMessage } from "./shared/file-cards.js";
4
+ export declare function validateDownloadableFileCard(data: FileCardData): void;
5
+ export declare function getFileCardByUfid(client: TelegramClient, ufid: string, peer?: string): Promise<FileCardRecord>;
@@ -0,0 +1,27 @@
1
+ import { CliError, EXIT_CODES } from "./errors.js";
2
+ import { lookupFileCardByUfid } from "./shared/telegram-files.js";
3
+ export { parseFileCardMessage } from "./shared/file-cards.js";
4
+ export function validateDownloadableFileCard(data) {
5
+ if (!data.uploadComplete) {
6
+ throw new CliError("invalid_file_card", "The requested file is not marked as fully uploaded.", EXIT_CODES.INVALID_FILE_CARD);
7
+ }
8
+ if (data.ufid.trim() === "" || data.name.trim() === "" || data.IV.trim() === "") {
9
+ throw new CliError("invalid_file_card", "The requested file card is missing required metadata.", EXIT_CODES.INVALID_FILE_CARD);
10
+ }
11
+ if (data.size < 0 || !Number.isFinite(data.size) || data.chunks.length === 0) {
12
+ throw new CliError("invalid_file_card", "The requested file card is malformed or unsupported.", EXIT_CODES.INVALID_FILE_CARD);
13
+ }
14
+ }
15
+ export async function getFileCardByUfid(client, ufid, peer = "me") {
16
+ const trimmed = ufid.trim();
17
+ if (trimmed === "") {
18
+ throw new CliError("invalid_ufid", "UFID must not be empty.", EXIT_CODES.GENERAL_ERROR);
19
+ }
20
+ const match = await lookupFileCardByUfid(client, trimmed, { peer });
21
+ if (!match) {
22
+ throw new CliError("file_not_found", `No TGLFS file card was found for UFID ${trimmed} in ${peer === "me" ? "Saved Messages" : peer}.`, EXIT_CODES.FILE_NOT_FOUND);
23
+ }
24
+ validateDownloadableFileCard(match.data);
25
+ return match;
26
+ }
27
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAIlD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAGjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAE7D,MAAM,UAAU,4BAA4B,CAAC,IAAkB;IAC3D,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;QACvB,MAAM,IAAI,QAAQ,CACd,mBAAmB,EACnB,qDAAqD,EACrD,UAAU,CAAC,iBAAiB,CAC/B,CAAA;IACL,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC9E,MAAM,IAAI,QAAQ,CACd,mBAAmB,EACnB,uDAAuD,EACvD,UAAU,CAAC,iBAAiB,CAC/B,CAAA;IACL,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,QAAQ,CACd,mBAAmB,EACnB,sDAAsD,EACtD,UAAU,CAAC,iBAAiB,CAC/B,CAAA;IACL,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAAsB,EAAE,IAAY,EAAE,IAAI,GAAG,IAAI;IACrF,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;IAC3B,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,QAAQ,CAAC,cAAc,EAAE,yBAAyB,EAAE,UAAU,CAAC,aAAa,CAAC,CAAA;IAC3F,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,MAAa,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;IAC1E,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,MAAM,IAAI,QAAQ,CACd,gBAAgB,EAChB,yCAAyC,OAAO,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,GAAG,EACjG,UAAU,CAAC,cAAc,CAC5B,CAAA;IACL,CAAC;IAED,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACxC,OAAO,KAAK,CAAA;AAChB,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { TelegramClient } from "telegram/client/TelegramClient.js";
2
+ import type { FileCardRecord, FileCardSearchSort } from "./shared/file-cards.js";
3
+ export { FILE_CARD_SEARCH_SORT_VALUES } from "./shared/file-cards.js";
4
+ export type { FileCardSearchSort } from "./shared/file-cards.js";
5
+ export type SearchFileCardsOptions = {
6
+ peer?: string;
7
+ query?: string;
8
+ limit?: number;
9
+ offsetId?: number;
10
+ sort?: FileCardSearchSort;
11
+ };
12
+ export type SearchFileCardsResult = {
13
+ peer: string;
14
+ query: string;
15
+ sort: FileCardSearchSort;
16
+ limit: number;
17
+ offsetId?: number;
18
+ nextOffsetId?: number;
19
+ hasMore: boolean;
20
+ results: FileCardRecord[];
21
+ };
22
+ export declare function searchFileCards(client: TelegramClient, options?: SearchFileCardsOptions): Promise<SearchFileCardsResult>;
23
+ export declare function formatSearchResultsTable(result: SearchFileCardsResult): string;