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
package/dist/search.js ADDED
@@ -0,0 +1,81 @@
1
+ import { FILE_CARD_SEARCH_SORT_VALUES, formatFileCardDate, formatFileCardSize, sortFileCardRecords, } from "./shared/file-cards.js";
2
+ import { listFileCards } from "./shared/telegram-files.js";
3
+ export { FILE_CARD_SEARCH_SORT_VALUES } from "./shared/file-cards.js";
4
+ const DEFAULT_SEARCH_LIMIT = 50;
5
+ function shellQuote(value) {
6
+ if (value === "") {
7
+ return "''";
8
+ }
9
+ return `'${value.replace(/'/g, `'\\''`)}'`;
10
+ }
11
+ function padCell(value, width) {
12
+ return value.padEnd(width, " ");
13
+ }
14
+ export async function searchFileCards(client, options = {}) {
15
+ const peer = options.peer?.trim() || "me";
16
+ const query = options.query?.trim() ?? "";
17
+ const limit = options.limit ?? DEFAULT_SEARCH_LIMIT;
18
+ const sort = options.sort ?? FILE_CARD_SEARCH_SORT_VALUES[0];
19
+ const offsetId = options.offsetId;
20
+ const rawResults = await listFileCards(client, {
21
+ peer,
22
+ query,
23
+ limit,
24
+ offsetId,
25
+ });
26
+ const results = rawResults.slice();
27
+ sortFileCardRecords(results, sort);
28
+ return {
29
+ peer,
30
+ query,
31
+ sort,
32
+ limit,
33
+ offsetId,
34
+ nextOffsetId: rawResults.length === limit ? rawResults.at(-1)?.msgId : undefined,
35
+ hasMore: rawResults.length === limit,
36
+ results,
37
+ };
38
+ }
39
+ export function formatSearchResultsTable(result) {
40
+ const peer = result.peer ?? "me";
41
+ if (result.results.length === 0) {
42
+ const location = peer === "me" ? "Saved Messages" : peer;
43
+ return result.query === ""
44
+ ? peer === "me"
45
+ ? "No TGLFS files found."
46
+ : `No TGLFS files found in ${location}.`
47
+ : `No TGLFS files found for query ${shellQuote(result.query)} in ${location}.`;
48
+ }
49
+ const headers = ["Name", "Size", "Date", "UFID", "Status"];
50
+ const rows = result.results.map((record) => [
51
+ record.data.name,
52
+ formatFileCardSize(record.data.size),
53
+ formatFileCardDate(record.date),
54
+ record.data.ufid,
55
+ record.data.uploadComplete ? "Complete" : "Incomplete",
56
+ ]);
57
+ const widths = headers.map((header, index) => Math.max(header.length, ...rows.map((row) => row[index].length)));
58
+ const lines = [
59
+ headers.map((header, index) => padCell(header, widths[index])).join(" "),
60
+ widths.map((width) => "-".repeat(width)).join(" "),
61
+ ...rows.map((row) => row.map((cell, index) => padCell(cell, widths[index])).join(" ")),
62
+ "",
63
+ `Showing ${result.results.length} result(s).`,
64
+ ];
65
+ if (result.hasMore && result.nextOffsetId !== undefined) {
66
+ const parts = ["tglfs", "search"];
67
+ if (result.query !== "") {
68
+ parts.push(shellQuote(result.query));
69
+ }
70
+ if (peer !== "me") {
71
+ parts.push("--peer", shellQuote(peer));
72
+ }
73
+ parts.push("--limit", String(result.limit), "--offset-id", String(result.nextOffsetId));
74
+ if (result.sort !== FILE_CARD_SEARCH_SORT_VALUES[0]) {
75
+ parts.push("--sort", result.sort);
76
+ }
77
+ lines.push(`Next page: ${parts.join(" ")}`);
78
+ }
79
+ return lines.join("\n");
80
+ }
81
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ type ResolveOptionalPasswordOptions = {
2
+ password?: string;
3
+ passwordEnv?: string | boolean;
4
+ passwordStdin?: boolean;
5
+ defaultEnv: string;
6
+ promptMessage: string;
7
+ stdinMessage: string;
8
+ fallbackValue?: string;
9
+ promptOnInteractive?: boolean;
10
+ };
11
+ export declare function resolveOptionalPassword(options: ResolveOptionalPasswordOptions): Promise<string | undefined>;
12
+ export {};
@@ -0,0 +1,29 @@
1
+ import { CliError, EXIT_CODES } from "./errors.js";
2
+ import { isInteractiveSession, promptPassword, readTrimmedStdin } from "./interactive.js";
3
+ export async function resolveOptionalPassword(options) {
4
+ if (options.password !== undefined) {
5
+ return options.password;
6
+ }
7
+ const envName = typeof options.passwordEnv === "string" && options.passwordEnv.trim() !== ""
8
+ ? options.passwordEnv.trim()
9
+ : options.passwordEnv
10
+ ? options.defaultEnv
11
+ : undefined;
12
+ if (envName && process.env[envName] !== undefined) {
13
+ return process.env[envName] ?? "";
14
+ }
15
+ if (process.env[options.defaultEnv] !== undefined) {
16
+ return process.env[options.defaultEnv] ?? "";
17
+ }
18
+ if (options.passwordStdin) {
19
+ if (process.stdin.isTTY) {
20
+ throw new CliError("interactive_required", options.stdinMessage, EXIT_CODES.INTERACTIVE_REQUIRED);
21
+ }
22
+ return readTrimmedStdin(options.stdinMessage);
23
+ }
24
+ if (!isInteractiveSession() || options.promptOnInteractive === false) {
25
+ return options.fallbackValue;
26
+ }
27
+ return promptPassword(options.promptMessage);
28
+ }
29
+ //# sourceMappingURL=secrets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets.js","sourceRoot":"","sources":["../src/secrets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAClD,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAazF,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,OAAuC;IACjF,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,OAAO,CAAC,QAAQ,CAAA;IAC3B,CAAC;IAED,MAAM,OAAO,GACT,OAAO,OAAO,CAAC,WAAW,KAAK,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE;QACxE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE;QAC5B,CAAC,CAAC,OAAO,CAAC,WAAW;YACnB,CAAC,CAAC,OAAO,CAAC,UAAU;YACpB,CAAC,CAAC,SAAS,CAAA;IAErB,IAAI,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,SAAS,EAAE,CAAC;QAChD,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;IACrC,CAAC;IACD,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,SAAS,EAAE,CAAC;QAChD,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,CAAA;IAChD,CAAC;IACD,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QACxB,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACtB,MAAM,IAAI,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAC,YAAY,EAAE,UAAU,CAAC,oBAAoB,CAAC,CAAA;QACrG,CAAC;QACD,OAAO,gBAAgB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;IACjD,CAAC;IACD,IAAI,CAAC,oBAAoB,EAAE,IAAI,OAAO,CAAC,mBAAmB,KAAK,KAAK,EAAE,CAAC;QACnE,OAAO,OAAO,CAAC,aAAa,CAAA;IAChC,CAAC;IACD,OAAO,cAAc,CAAC,OAAO,CAAC,aAAa,CAAC,CAAA;AAChD,CAAC"}
@@ -0,0 +1,9 @@
1
+ export type ArchiveEntry = {
2
+ name: string;
3
+ size: number;
4
+ lastModified: number;
5
+ stream(): ReadableStream<Uint8Array> | Promise<ReadableStream<Uint8Array>>;
6
+ };
7
+ export declare function computeTarSize(files: ArchiveEntry[]): number;
8
+ export declare function defaultArchiveName(now?: Date): string;
9
+ export declare function createTarStream(files: ArchiveEntry[]): ReadableStream<Uint8Array>;
@@ -0,0 +1,95 @@
1
+ export function computeTarSize(files) {
2
+ const block = 512;
3
+ let total = 0;
4
+ for (const file of files) {
5
+ const dataSize = Math.ceil(file.size / block) * block;
6
+ total += block + dataSize;
7
+ }
8
+ total += block * 2;
9
+ return total;
10
+ }
11
+ export function defaultArchiveName(now = new Date()) {
12
+ const pad2 = (value) => value.toString().padStart(2, "0");
13
+ return `files_${now.getFullYear()}${pad2(now.getMonth() + 1)}${pad2(now.getDate())}_${pad2(now.getHours())}${pad2(now.getMinutes())}${pad2(now.getSeconds())}.tar`;
14
+ }
15
+ export function createTarStream(files) {
16
+ async function* generate() {
17
+ const block = 512;
18
+ const textEncoder = new TextEncoder();
19
+ const writeString = (buf, offset, value, length) => {
20
+ const bytes = textEncoder.encode(value);
21
+ const copied = Math.min(bytes.length, length);
22
+ buf.set(bytes.subarray(0, copied), offset);
23
+ for (let index = offset + copied; index < offset + length; index += 1) {
24
+ buf[index] = 0;
25
+ }
26
+ };
27
+ const writeOctal = (buf, offset, value, length) => {
28
+ const octal = value.toString(8);
29
+ writeString(buf, offset, octal.padStart(length - 1, "0") + "\0", length);
30
+ };
31
+ for (const file of files) {
32
+ const header = new Uint8Array(block);
33
+ writeString(header, 0, file.name.slice(0, 100), 100);
34
+ writeString(header, 100, "0000777\0", 8);
35
+ writeString(header, 108, "0000000\0", 8);
36
+ writeString(header, 116, "0000000\0", 8);
37
+ writeOctal(header, 124, file.size, 12);
38
+ writeOctal(header, 136, Math.floor(file.lastModified / 1000) || Math.floor(Date.now() / 1000), 12);
39
+ for (let index = 148; index < 156; index += 1) {
40
+ header[index] = 32;
41
+ }
42
+ header[156] = "0".charCodeAt(0);
43
+ writeString(header, 257, "ustar\0", 6);
44
+ writeString(header, 263, "00", 2);
45
+ writeString(header, 265, "user", 32);
46
+ writeString(header, 297, "group", 32);
47
+ writeString(header, 329, "\0", 8);
48
+ writeString(header, 337, "\0", 8);
49
+ let checksum = 0;
50
+ for (let index = 0; index < block; index += 1) {
51
+ checksum += header[index];
52
+ }
53
+ const checksumString = checksum.toString(8).padStart(6, "0");
54
+ for (let index = 0; index < 6; index += 1) {
55
+ header[148 + index] = checksumString.charCodeAt(index);
56
+ }
57
+ header[154] = 0;
58
+ header[155] = 32;
59
+ yield header;
60
+ const reader = (await file.stream()).getReader();
61
+ let totalRead = 0;
62
+ while (true) {
63
+ const { done, value } = await reader.read();
64
+ if (done) {
65
+ break;
66
+ }
67
+ if (value && value.length > 0) {
68
+ yield value;
69
+ totalRead += value.length;
70
+ }
71
+ }
72
+ const padding = (block - (totalRead % block)) % block;
73
+ if (padding > 0) {
74
+ yield new Uint8Array(padding);
75
+ }
76
+ }
77
+ yield new Uint8Array(block);
78
+ yield new Uint8Array(block);
79
+ }
80
+ return new ReadableStream({
81
+ async start(controller) {
82
+ try {
83
+ for await (const chunk of generate()) {
84
+ controller.enqueue(chunk);
85
+ }
86
+ }
87
+ catch (error) {
88
+ controller.error(error);
89
+ return;
90
+ }
91
+ controller.close();
92
+ },
93
+ });
94
+ }
95
+ //# sourceMappingURL=archive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive.js","sourceRoot":"","sources":["../../src/shared/archive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare const BUNDLED_CHUNK_SIZE: number;
2
+ export declare const DOWNLOAD_PART_SIZE: number;
3
+ export declare const UPLOAD_PART_SIZE: number;
4
+ export declare const BATCH_LIMIT = 50;
5
+ export declare const BATCH_DELAY_MS = 1000;
@@ -0,0 +1,6 @@
1
+ export const BUNDLED_CHUNK_SIZE = 1024 ** 3 * 2;
2
+ export const DOWNLOAD_PART_SIZE = 1024 * 1024;
3
+ export const UPLOAD_PART_SIZE = 512 * 1024;
4
+ export const BATCH_LIMIT = 50;
5
+ export const BATCH_DELAY_MS = 1000;
6
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/shared/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAA;AAC/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,GAAG,IAAI,CAAA;AAC7C,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,GAAG,IAAI,CAAA;AAC1C,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,CAAA;AAC7B,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAA"}
@@ -0,0 +1,31 @@
1
+ export type FileCardData = {
2
+ name: string;
3
+ ufid: string;
4
+ size: number;
5
+ uploadComplete: boolean;
6
+ chunks: number[];
7
+ IV: string;
8
+ };
9
+ export type FileCardRecord = {
10
+ msgId: number;
11
+ date: number;
12
+ data: FileCardData;
13
+ };
14
+ export type FileCardMessageLike = {
15
+ id: number;
16
+ date: number;
17
+ message?: string | null;
18
+ };
19
+ export declare const FILE_CARD_PREFIX = "tglfs:file";
20
+ export declare const FILE_CARD_SEARCH_SORT_VALUES: readonly ["date_desc", "date_asc", "name_asc", "name_desc", "size_desc", "size_asc"];
21
+ export type FileCardSearchSort = (typeof FILE_CARD_SEARCH_SORT_VALUES)[number];
22
+ export declare function isFileCardData(value: unknown): value is FileCardData;
23
+ export declare function parseFileCardMessage(message: string): FileCardData | null;
24
+ export declare function serializeFileCardMessage(data: FileCardData): string;
25
+ export declare function extractFileCardRecord(message: FileCardMessageLike): FileCardRecord | null;
26
+ export declare function extractFileCardRecords(messages: Iterable<FileCardMessageLike>): FileCardRecord[];
27
+ export declare function buildFileCardSearchQuery(query?: string): string;
28
+ export declare function buildFileCardUfidLookupQuery(ufid: string): string;
29
+ export declare function sortFileCardRecords(records: FileCardRecord[], sort: FileCardSearchSort): void;
30
+ export declare function formatFileCardSize(size: number): string;
31
+ export declare function formatFileCardDate(epochSec: number): string;
@@ -0,0 +1,103 @@
1
+ export const FILE_CARD_PREFIX = "tglfs:file";
2
+ export const FILE_CARD_SEARCH_SORT_VALUES = [
3
+ "date_desc",
4
+ "date_asc",
5
+ "name_asc",
6
+ "name_desc",
7
+ "size_desc",
8
+ "size_asc",
9
+ ];
10
+ export function isFileCardData(value) {
11
+ if (!value || typeof value !== "object") {
12
+ return false;
13
+ }
14
+ const candidate = value;
15
+ return (typeof candidate.name === "string" &&
16
+ typeof candidate.ufid === "string" &&
17
+ typeof candidate.size === "number" &&
18
+ typeof candidate.uploadComplete === "boolean" &&
19
+ Array.isArray(candidate.chunks) &&
20
+ candidate.chunks.every((chunk) => typeof chunk === "number") &&
21
+ typeof candidate.IV === "string");
22
+ }
23
+ export function parseFileCardMessage(message) {
24
+ if (!message.startsWith(FILE_CARD_PREFIX)) {
25
+ return null;
26
+ }
27
+ try {
28
+ const payload = JSON.parse(message.substring(message.indexOf("{")));
29
+ return isFileCardData(payload) ? payload : null;
30
+ }
31
+ catch {
32
+ return null;
33
+ }
34
+ }
35
+ export function serializeFileCardMessage(data) {
36
+ return `${FILE_CARD_PREFIX}\n${JSON.stringify(data)}`;
37
+ }
38
+ export function extractFileCardRecord(message) {
39
+ if (typeof message.message !== "string") {
40
+ return null;
41
+ }
42
+ const data = parseFileCardMessage(message.message);
43
+ if (!data) {
44
+ return null;
45
+ }
46
+ return {
47
+ msgId: message.id,
48
+ date: message.date,
49
+ data,
50
+ };
51
+ }
52
+ export function extractFileCardRecords(messages) {
53
+ const results = [];
54
+ for (const message of messages) {
55
+ const record = extractFileCardRecord(message);
56
+ if (record) {
57
+ results.push(record);
58
+ }
59
+ }
60
+ return results;
61
+ }
62
+ export function buildFileCardSearchQuery(query = "") {
63
+ return `${FILE_CARD_PREFIX} ${query.trim()}`.trim();
64
+ }
65
+ export function buildFileCardUfidLookupQuery(ufid) {
66
+ return `${FILE_CARD_PREFIX} "ufid":"${ufid.trim()}"`;
67
+ }
68
+ export function sortFileCardRecords(records, sort) {
69
+ records.sort((a, b) => {
70
+ switch (sort) {
71
+ case "date_desc":
72
+ return b.date - a.date;
73
+ case "date_asc":
74
+ return a.date - b.date;
75
+ case "name_asc":
76
+ return a.data.name.localeCompare(b.data.name);
77
+ case "name_desc":
78
+ return b.data.name.localeCompare(a.data.name);
79
+ case "size_desc":
80
+ return b.data.size - a.data.size;
81
+ case "size_asc":
82
+ return a.data.size - b.data.size;
83
+ }
84
+ });
85
+ }
86
+ export function formatFileCardSize(size) {
87
+ if (size <= 0 || !Number.isFinite(size)) {
88
+ return "0 B";
89
+ }
90
+ const units = ["B", "KiB", "MiB", "GiB", "TiB"];
91
+ const unitIndex = Math.floor(Math.log(size) / Math.log(1024));
92
+ const value = size / Math.pow(1024, unitIndex);
93
+ return `${value.toFixed(unitIndex === 0 ? 0 : 2)} ${units[unitIndex]}`;
94
+ }
95
+ export function formatFileCardDate(epochSec) {
96
+ const date = new Date(epochSec * 1000);
97
+ const pad = (value) => (value < 10 ? `0${value}` : String(value));
98
+ return [
99
+ `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`,
100
+ `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`,
101
+ ].join(" ");
102
+ }
103
+ //# sourceMappingURL=file-cards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-cards.js","sourceRoot":"","sources":["../../src/shared/file-cards.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ import type { FileCardData, FileCardRecord } from "./file-cards.js";
2
+ type ApiLike = {
3
+ messages: {
4
+ EditMessage: new (args: any) => any;
5
+ DeleteMessages: new (args: any) => any;
6
+ ForwardMessages: new (args: any) => any;
7
+ };
8
+ };
9
+ type TelegramFileClient = {
10
+ getMessages(peer: string, options: unknown): Promise<any[]>;
11
+ invoke(request: any): Promise<any>;
12
+ sendMessage(peer: string, options: {
13
+ message: string;
14
+ }): Promise<any>;
15
+ };
16
+ type ListFileCardsOptions = {
17
+ peer?: string;
18
+ query?: string;
19
+ limit?: number;
20
+ offsetId?: number;
21
+ };
22
+ type LookupFileCardByUfidOptions = {
23
+ peer?: string;
24
+ limit?: number;
25
+ };
26
+ type WriteFileCardOptions = {
27
+ Api: ApiLike;
28
+ peer?: string;
29
+ msgId?: number;
30
+ peerId?: unknown;
31
+ data: FileCardData;
32
+ };
33
+ type DeleteFileCardOptions = {
34
+ Api: ApiLike;
35
+ msgId: number;
36
+ data: FileCardData;
37
+ };
38
+ type ForwardChunkMessagesOptions = {
39
+ Api: ApiLike;
40
+ fromPeer?: string;
41
+ toPeer: string;
42
+ chunkIds: number[];
43
+ silent?: boolean;
44
+ batchLimit?: number;
45
+ batchDelayMs?: number;
46
+ onChunkForwarded?: (progress: {
47
+ completed: number;
48
+ total: number;
49
+ sourceChunkId: number;
50
+ targetChunkId: number;
51
+ }) => void;
52
+ };
53
+ type TransferFileCardOptions = {
54
+ Api: ApiLike;
55
+ record: FileCardRecord;
56
+ sourcePeer?: string;
57
+ targetPeer: string;
58
+ silent?: boolean;
59
+ batchLimit?: number;
60
+ batchDelayMs?: number;
61
+ onChunkForwarded?: ForwardChunkMessagesOptions["onChunkForwarded"];
62
+ };
63
+ type UnsendFileCardOptions = {
64
+ Api: ApiLike;
65
+ record: FileCardRecord;
66
+ peer?: string;
67
+ batchLimit?: number;
68
+ batchDelayMs?: number;
69
+ };
70
+ export declare function listFileCards(client: TelegramFileClient, options?: ListFileCardsOptions): Promise<FileCardRecord[]>;
71
+ export declare function lookupFileCardByUfid(client: TelegramFileClient, ufid: string, options?: LookupFileCardByUfidOptions): Promise<FileCardRecord | null>;
72
+ export declare function writeFileCardMessage(client: TelegramFileClient, options: WriteFileCardOptions): Promise<any>;
73
+ export declare function renameFileCardMessage(client: TelegramFileClient, options: WriteFileCardOptions & {
74
+ newName: string;
75
+ }): Promise<any>;
76
+ export declare function deleteFileCardMessages(client: TelegramFileClient, options: DeleteFileCardOptions): Promise<any>;
77
+ export declare function forwardChunkMessages(client: TelegramFileClient, options: ForwardChunkMessagesOptions): Promise<number[]>;
78
+ export declare function transferFileCard(client: TelegramFileClient & {
79
+ sendMessage(peer: string, options: {
80
+ message: string;
81
+ }): Promise<any>;
82
+ }, options: TransferFileCardOptions): Promise<FileCardRecord>;
83
+ export declare function unsendFileCard(client: TelegramFileClient, options: UnsendFileCardOptions): Promise<any>;
84
+ export {};
@@ -0,0 +1,137 @@
1
+ import { BATCH_DELAY_MS, BATCH_LIMIT } from "./constants.js";
2
+ import { buildFileCardSearchQuery, buildFileCardUfidLookupQuery, extractFileCardRecords, serializeFileCardMessage, } from "./file-cards.js";
3
+ function resolvePeer(peer) {
4
+ return peer?.trim() ? peer.trim() : "me";
5
+ }
6
+ function sleep(ms) {
7
+ return new Promise((resolve) => setTimeout(resolve, ms));
8
+ }
9
+ function extractForwardedMessageId(result) {
10
+ const updateWithId = result?.updates?.find?.((update) => typeof update?.id === "number");
11
+ const id = updateWithId?.id ?? result?.updates?.[0]?.id;
12
+ return typeof id === "number" ? id : null;
13
+ }
14
+ export async function listFileCards(client, options = {}) {
15
+ const peer = resolvePeer(options.peer);
16
+ const messages = await client.getMessages(peer, {
17
+ search: buildFileCardSearchQuery(options.query),
18
+ limit: options.limit ?? 50,
19
+ addOffset: 0,
20
+ minId: 0,
21
+ maxId: options.offsetId ?? 0,
22
+ waitTime: 0,
23
+ });
24
+ return extractFileCardRecords(messages);
25
+ }
26
+ export async function lookupFileCardByUfid(client, ufid, options = {}) {
27
+ const trimmed = ufid.trim();
28
+ if (trimmed === "") {
29
+ return null;
30
+ }
31
+ const peer = resolvePeer(options.peer);
32
+ const messages = await client.getMessages(peer, {
33
+ search: buildFileCardUfidLookupQuery(trimmed),
34
+ limit: options.limit ?? 10,
35
+ waitTime: 0,
36
+ });
37
+ return extractFileCardRecords(messages).find((record) => record.data.ufid === trimmed) ?? null;
38
+ }
39
+ export async function writeFileCardMessage(client, options) {
40
+ const peer = resolvePeer(options.peer);
41
+ const message = serializeFileCardMessage(options.data);
42
+ if (options.msgId === undefined) {
43
+ return client.sendMessage(peer, { message });
44
+ }
45
+ return client.invoke(new options.Api.messages.EditMessage({
46
+ peer: options.peerId ?? peer,
47
+ id: options.msgId,
48
+ message,
49
+ }));
50
+ }
51
+ export async function renameFileCardMessage(client, options) {
52
+ return writeFileCardMessage(client, {
53
+ ...options,
54
+ data: {
55
+ ...options.data,
56
+ name: options.newName,
57
+ },
58
+ });
59
+ }
60
+ export async function deleteFileCardMessages(client, options) {
61
+ return client.invoke(new options.Api.messages.DeleteMessages({
62
+ id: [...options.data.chunks, options.msgId],
63
+ }));
64
+ }
65
+ export async function forwardChunkMessages(client, options) {
66
+ const sourcePeer = resolvePeer(options.fromPeer);
67
+ const batchLimit = options.batchLimit ?? BATCH_LIMIT;
68
+ const batchDelayMs = options.batchDelayMs ?? BATCH_DELAY_MS;
69
+ const targetChunkIds = [];
70
+ for (let index = 0; index < options.chunkIds.length; index += 1) {
71
+ const sourceChunkId = options.chunkIds[index];
72
+ const result = await client.invoke(new options.Api.messages.ForwardMessages({
73
+ fromPeer: sourcePeer,
74
+ toPeer: options.toPeer,
75
+ id: [sourceChunkId],
76
+ silent: options.silent ?? false,
77
+ }));
78
+ const targetChunkId = extractForwardedMessageId(result);
79
+ if (targetChunkId === null) {
80
+ throw new Error(`Unable to determine forwarded Telegram message id for chunk ${sourceChunkId}.`);
81
+ }
82
+ targetChunkIds.push(targetChunkId);
83
+ options.onChunkForwarded?.({
84
+ completed: targetChunkIds.length,
85
+ total: options.chunkIds.length,
86
+ sourceChunkId,
87
+ targetChunkId,
88
+ });
89
+ const completed = index + 1;
90
+ if (completed % batchLimit === 0 && completed < options.chunkIds.length) {
91
+ await sleep(batchDelayMs);
92
+ }
93
+ }
94
+ return targetChunkIds;
95
+ }
96
+ export async function transferFileCard(client, options) {
97
+ const updatedChunks = await forwardChunkMessages(client, {
98
+ Api: options.Api,
99
+ fromPeer: options.sourcePeer,
100
+ toPeer: options.targetPeer,
101
+ chunkIds: options.record.data.chunks,
102
+ silent: options.silent,
103
+ batchLimit: options.batchLimit,
104
+ batchDelayMs: options.batchDelayMs,
105
+ onChunkForwarded: options.onChunkForwarded,
106
+ });
107
+ const updatedData = {
108
+ ...options.record.data,
109
+ chunks: updatedChunks,
110
+ };
111
+ const message = await client.sendMessage(resolvePeer(options.targetPeer), {
112
+ message: serializeFileCardMessage(updatedData),
113
+ });
114
+ return {
115
+ msgId: message.id,
116
+ date: message.date,
117
+ data: updatedData,
118
+ };
119
+ }
120
+ export async function unsendFileCard(client, options) {
121
+ const peer = resolvePeer(options.peer);
122
+ const batchLimit = options.batchLimit ?? BATCH_LIMIT;
123
+ const batchDelayMs = options.batchDelayMs ?? BATCH_DELAY_MS;
124
+ for (let index = 0; index < options.record.data.chunks.length; index += batchLimit) {
125
+ const batch = options.record.data.chunks.slice(index, index + batchLimit);
126
+ await client.invoke(new options.Api.messages.DeleteMessages({
127
+ id: batch,
128
+ }));
129
+ if (index + batch.length < options.record.data.chunks.length) {
130
+ await sleep(batchDelayMs);
131
+ }
132
+ }
133
+ return client.invoke(new options.Api.messages.DeleteMessages({
134
+ id: [options.record.msgId],
135
+ }));
136
+ }
137
+ //# sourceMappingURL=telegram-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram-files.js","sourceRoot":"","sources":["../../src/shared/telegram-files.ts"],"names":[],"mappings":"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"}