tmpbox.me 1.0.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 TmpBox
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,222 @@
1
+ # tmpbox.me
2
+
3
+ Official TmpBox.me uploader SDK and CLI for Node.js.
4
+
5
+ - No account required for guest uploads
6
+ - Guest limit: **100MB per file**
7
+ - Logged-in user limit: **500MB per file**
8
+ - Uploads **4 chunks at the same time** by default
9
+ - Supports CommonJS, ES Module, TypeScript types, and CLI
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npm install tmpbox
15
+ ```
16
+
17
+ Node.js 18 or newer is required.
18
+
19
+ ## Quick start as guest
20
+
21
+ No username, password, or token is required.
22
+
23
+ ### CommonJS
24
+
25
+ ```js
26
+ const { uploadFile } = require("tmpbox");
27
+
28
+ const result = await uploadFile("./video.mp4");
29
+ console.log(result.fullUrl);
30
+ ```
31
+
32
+ ### ES Module
33
+
34
+ ```js
35
+ import { uploadFile } from "tmpbox";
36
+
37
+ const result = await uploadFile("./video.mp4");
38
+ console.log(result.fullUrl);
39
+ ```
40
+
41
+ Guest uploads are limited to **100MB per file**.
42
+
43
+ ## Login with username and password
44
+
45
+ Use username and password when you need the **500MB per file** user limit.
46
+
47
+ ```js
48
+ import { uploadFile } from "tmpbox";
49
+
50
+ const result = await uploadFile("./large-video.mp4", {
51
+ username: "your_username",
52
+ password: "your_password",
53
+ });
54
+
55
+ console.log(result.fullUrl);
56
+ ```
57
+
58
+ You can also use an existing token:
59
+
60
+ ```js
61
+ import { uploadFile } from "tmpbox";
62
+
63
+ const result = await uploadFile("./large-video.mp4", {
64
+ token: "YOUR_TOKEN",
65
+ });
66
+ ```
67
+
68
+ ## Upload progress
69
+
70
+ ```js
71
+ import { uploadFile } from "tmpbox";
72
+
73
+ const result = await uploadFile("./file.zip", {
74
+ onProgress(state) {
75
+ console.log(state.status, state.progress);
76
+ },
77
+ });
78
+
79
+ console.log(result.fullUrl);
80
+ ```
81
+
82
+ ## Chunk concurrency
83
+
84
+ By default, the SDK uploads **4 chunks at once**.
85
+
86
+ ```js
87
+ await uploadFile("./file.zip", {
88
+ chunkConcurrency: 4,
89
+ });
90
+ ```
91
+
92
+ ## Upload multiple files
93
+
94
+ ```js
95
+ import { uploadFiles } from "tmpbox";
96
+
97
+ const results = await uploadFiles([
98
+ "./image.png",
99
+ "./video.mp4",
100
+ "./archive.zip",
101
+ ]);
102
+
103
+ console.log(results.map((item) => item.fullUrl));
104
+ ```
105
+
106
+ ## CLI
107
+
108
+ ### Guest upload
109
+
110
+ ```bash
111
+ tmpbox-upload ./video.mp4
112
+ ```
113
+
114
+ ### User upload
115
+
116
+ ```bash
117
+ tmpbox-upload ./video.mp4 -u your_username -p your_password
118
+ ```
119
+
120
+ ### Upload with token
121
+
122
+ ```bash
123
+ tmpbox-upload ./video.mp4 -t "$TMPBOX_TOKEN"
124
+ ```
125
+
126
+ ### Upload multiple files
127
+
128
+ ```bash
129
+ tmpbox-upload ./a.zip ./b.pdf ./c.mp4
130
+ ```
131
+
132
+ ### JSON output
133
+
134
+ ```bash
135
+ tmpbox-upload ./video.mp4 --json
136
+ ```
137
+
138
+ ### Change chunk concurrency
139
+
140
+ ```bash
141
+ tmpbox-upload ./video.mp4 --chunk-concurrency 4
142
+ ```
143
+
144
+ ## Environment variables
145
+
146
+ The CLI and SDK can read these automatically:
147
+
148
+ ```bash
149
+ TMPBOX_USERNAME=your_username
150
+ TMPBOX_PASSWORD=your_password
151
+ ```
152
+
153
+ or:
154
+
155
+ ```bash
156
+ TMPBOX_TOKEN=your_token
157
+ ```
158
+
159
+ Legacy token environment variables are also supported:
160
+
161
+ ```bash
162
+ FILESTORAGE_TOKEN=your_token
163
+ UPLOAD_TOKEN=your_token
164
+ ```
165
+
166
+ If no account or token is provided, upload runs in guest mode.
167
+
168
+ ## API
169
+
170
+ ### `uploadFile(filePath, options?)`
171
+
172
+ Uploads one file.
173
+
174
+ ```ts
175
+ uploadFile(filePath: string, options?: UploadOptions): Promise<UploadResult>
176
+ ```
177
+
178
+ ### `uploadFiles(filePaths, options?)`
179
+
180
+ Uploads multiple files one by one.
181
+
182
+ ```ts
183
+ uploadFiles(filePaths: string[], options?: UploadOptions): Promise<UploadResult[]>
184
+ ```
185
+
186
+ ### `login(username, password)`
187
+
188
+ Logs in and returns an auth token.
189
+
190
+ ```ts
191
+ login(username: string, password: string): Promise<LoginResult>
192
+ ```
193
+
194
+ ## Options
195
+
196
+ ```ts
197
+ interface UploadOptions {
198
+ token?: string;
199
+ username?: string;
200
+ password?: string;
201
+ ttl?: string;
202
+ filename?: string;
203
+ mimetype?: string;
204
+ chunkSize?: number;
205
+ chunkConcurrency?: number;
206
+ wait?: boolean;
207
+ timeoutMs?: number;
208
+ pollIntervalMs?: number;
209
+ onProgress?: (state: UploadState) => void;
210
+ }
211
+ ```
212
+
213
+ ## Limits
214
+
215
+ | Mode | Auth required | Limit |
216
+ | ----- | -------------------------- | -------------- |
217
+ | Guest | No | 100MB per file |
218
+ | User | Username/password or token | 500MB per file |
219
+
220
+ ## License
221
+
222
+ MIT
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/env node
2
+ const path = require("path");
3
+ const {
4
+ login,
5
+ uploadFile,
6
+ BASE_URL,
7
+ DEFAULT_CHUNK_CONCURRENCY,
8
+ GUEST_MAX_FILE_SIZE,
9
+ USER_MAX_FILE_SIZE
10
+ } = require("../lib/index.cjs");
11
+
12
+ function formatMB(bytes) {
13
+ return `${Math.round(bytes / 1024 / 1024)}MB`;
14
+ }
15
+
16
+ function usage() {
17
+ console.log(`Usage:
18
+ tmpbox <file...> [--ttl 30d]
19
+ tmpbox <file...> --username <username> --password <password> [--ttl 30d]
20
+ tmpbox <file...> --token <jwt-token> [--ttl 30d]
21
+
22
+ Options:
23
+ --username, -u TmpBox username. Default: TMPBOX_USERNAME
24
+ --password, -p TmpBox password. Default: TMPBOX_PASSWORD
25
+ --token, -t Existing JWT token. Default: TMPBOX_TOKEN, FILESTORAGE_TOKEN, or UPLOAD_TOKEN
26
+ --ttl TTL sent to backend. Default: 30d
27
+ --chunk-concurrency Number of chunks uploaded at once. Default: ${DEFAULT_CHUNK_CONCURRENCY}
28
+ --no-wait Return after chunks are queued, without waiting for backend completion
29
+ --json Print final result as JSON
30
+ --help, -h Show help
31
+
32
+ Limits:
33
+ Guest upload: ${formatMB(GUEST_MAX_FILE_SIZE)} per file
34
+ User upload: ${formatMB(USER_MAX_FILE_SIZE)} per file
35
+
36
+ Examples:
37
+ tmpbox ./video.mp4
38
+ tmpbox ./video.mp4 -u myuser -p mypassword
39
+ TMPBOX_USERNAME=myuser TMPBOX_PASSWORD=mypassword tmpbox ./a.zip ./b.pdf
40
+ tmpbox ./video.mp4 -t "$TMPBOX_TOKEN"
41
+ `);
42
+ }
43
+
44
+ function parseArgs(argv) {
45
+ const args = { files: [], wait: true, json: false };
46
+
47
+ for (let i = 0; i < argv.length; i++) {
48
+ const arg = argv[i];
49
+ if (arg === "--help" || arg === "-h") args.help = true;
50
+ else if (arg === "--username" || arg === "-u") args.username = argv[++i];
51
+ else if (arg === "--password" || arg === "-p") args.password = argv[++i];
52
+ else if (arg === "--token" || arg === "-t") args.token = argv[++i];
53
+ else if (arg === "--ttl") args.ttl = argv[++i];
54
+ else if (arg === "--chunk-concurrency") args.chunkConcurrency = Number(argv[++i]);
55
+ else if (arg === "--no-wait") args.wait = false;
56
+ else if (arg === "--json") args.json = true;
57
+ else if (arg.startsWith("-")) throw new Error(`Unknown option: ${arg}`);
58
+ else args.files.push(arg);
59
+ }
60
+
61
+ if (args.chunkConcurrency && (!Number.isInteger(args.chunkConcurrency) || args.chunkConcurrency < 1)) {
62
+ throw new Error("--chunk-concurrency must be a positive integer");
63
+ }
64
+
65
+ return args;
66
+ }
67
+
68
+ (async () => {
69
+ try {
70
+ const args = parseArgs(process.argv.slice(2));
71
+ if (args.help || args.files.length === 0) {
72
+ usage();
73
+ process.exit(args.help ? 0 : 1);
74
+ }
75
+
76
+ args.username = args.username || process.env.TMPBOX_USERNAME;
77
+ args.password = args.password || process.env.TMPBOX_PASSWORD;
78
+ args.token = args.token || process.env.TMPBOX_TOKEN || process.env.FILESTORAGE_TOKEN || process.env.UPLOAD_TOKEN;
79
+
80
+ if (!args.token && args.username && args.password) {
81
+ if (!args.json) console.log(`Logging in as ${args.username}...`);
82
+ const auth = await login(args.username, args.password);
83
+ args.token = auth.token;
84
+ if (!args.json) console.log("Login successful. User limit enabled.");
85
+ } else if (!args.token && !args.json) {
86
+ console.log(`Uploading as guest. Limit: ${formatMB(GUEST_MAX_FILE_SIZE)} per file.`);
87
+ }
88
+
89
+ const allResults = [];
90
+
91
+ for (const file of args.files) {
92
+ const fileName = path.basename(file);
93
+ if (!args.json) console.log(`Uploading ${fileName}...`);
94
+
95
+ const result = await uploadFile(file, {
96
+ token: args.token,
97
+ username: args.username,
98
+ password: args.password,
99
+ ttl: args.ttl,
100
+ wait: args.wait,
101
+ chunkConcurrency: args.chunkConcurrency,
102
+ onProgress: args.json
103
+ ? undefined
104
+ : (state) => {
105
+ const p = state.progress || {};
106
+ if (state.status === "initialized") {
107
+ console.log(` initialized: ${state.id}, mode=${state.mode}, chunks=${p.total}`);
108
+ } else if (state.status === "queued") {
109
+ process.stdout.write(`\r queued chunks: ${p.queued}/${p.total}`);
110
+ } else {
111
+ process.stdout.write(`\r backend: ${state.status} ${p.uploaded || 0}/${p.total || 0}`);
112
+ }
113
+ }
114
+ });
115
+
116
+ allResults.push(result);
117
+ if (!args.json) {
118
+ process.stdout.write("\n");
119
+ console.log(`Done: ${result.fullUrl}`);
120
+ }
121
+ }
122
+
123
+ if (args.json) {
124
+ console.log(JSON.stringify(allResults.length === 1 ? allResults[0] : allResults, null, 2));
125
+ }
126
+ } catch (err) {
127
+ console.error("Upload failed:", err.message || err);
128
+ if (err.data) console.error(JSON.stringify(err.data, null, 2));
129
+ process.exit(1);
130
+ }
131
+ })();
package/lib/index.cjs ADDED
@@ -0,0 +1,286 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ const BASE_URL = "https://api.tmpbox.me";
5
+ const DEFAULT_CHUNK_SIZE = 5 * 1024 * 1024;
6
+ const DEFAULT_CHUNK_CONCURRENCY = 4;
7
+ const DEFAULT_POLL_INTERVAL_MS = 1000;
8
+ const DEFAULT_TIMEOUT_MS = 30 * 60 * 1000;
9
+ const GUEST_MAX_FILE_SIZE = 100 * 1024 * 1024;
10
+ const USER_MAX_FILE_SIZE = 500 * 1024 * 1024;
11
+
12
+ function sleep(ms) {
13
+ return new Promise((resolve) => setTimeout(resolve, ms));
14
+ }
15
+
16
+ function formatBytes(bytes) {
17
+ const mb = bytes / 1024 / 1024;
18
+ return `${mb % 1 === 0 ? mb.toFixed(0) : mb.toFixed(2)}MB`;
19
+ }
20
+
21
+ function guessMimeType(filePath) {
22
+ const ext = path.extname(filePath).toLowerCase();
23
+ const map = {
24
+ ".txt": "text/plain",
25
+ ".json": "application/json",
26
+ ".pdf": "application/pdf",
27
+ ".png": "image/png",
28
+ ".jpg": "image/jpeg",
29
+ ".jpeg": "image/jpeg",
30
+ ".gif": "image/gif",
31
+ ".webp": "image/webp",
32
+ ".mp4": "video/mp4",
33
+ ".mov": "video/quicktime",
34
+ ".zip": "application/zip",
35
+ ".rar": "application/vnd.rar",
36
+ ".7z": "application/x-7z-compressed"
37
+ };
38
+ return map[ext] || "application/octet-stream";
39
+ }
40
+
41
+ function authHeader(token) {
42
+ if (!token) return {};
43
+ return { Authorization: token.startsWith("Bearer ") ? token : `Bearer ${token}` };
44
+ }
45
+
46
+ async function parseJsonResponse(res) {
47
+ const text = await res.text();
48
+ let data;
49
+ try {
50
+ data = text ? JSON.parse(text) : {};
51
+ } catch {
52
+ data = { raw: text };
53
+ }
54
+
55
+ if (!res.ok) {
56
+ const error = new Error(data.msg || data.message || `HTTP ${res.status}`);
57
+ error.status = res.status;
58
+ error.data = data;
59
+ throw error;
60
+ }
61
+
62
+ return data;
63
+ }
64
+
65
+ async function login(username, password) {
66
+ if (!username || !password) {
67
+ throw new Error("username and password are required");
68
+ }
69
+
70
+ const res = await fetch(`${BASE_URL}/auth/login`, {
71
+ method: "POST",
72
+ headers: { "Content-Type": "application/json" },
73
+ body: JSON.stringify({ username, password })
74
+ });
75
+
76
+ return parseJsonResponse(res);
77
+ }
78
+
79
+ async function resolveToken(options = {}) {
80
+ if (options.token) return options.token;
81
+
82
+ const envToken = process.env.TMPBOX_TOKEN || process.env.FILESTORAGE_TOKEN || process.env.UPLOAD_TOKEN;
83
+ if (envToken) return envToken;
84
+
85
+ const username = options.username || process.env.TMPBOX_USERNAME;
86
+ const password = options.password || process.env.TMPBOX_PASSWORD;
87
+
88
+ if (username && password) {
89
+ const auth = await login(username, password);
90
+ return auth.token;
91
+ }
92
+
93
+ return undefined;
94
+ }
95
+
96
+ async function initUpload({ token, filename, mimetype, size, ttl }) {
97
+ const res = await fetch(`${BASE_URL}/upload/init`, {
98
+ method: "POST",
99
+ headers: {
100
+ "Content-Type": "application/json",
101
+ ...authHeader(token)
102
+ },
103
+ body: JSON.stringify({ filename, mimetype, size, ttl })
104
+ });
105
+
106
+ return parseJsonResponse(res);
107
+ }
108
+
109
+ async function uploadChunk({ token, uploadId, index, buffer }) {
110
+ const form = new FormData();
111
+ form.append("chunk", new Blob([buffer], { type: "application/octet-stream" }), "chunk.bin");
112
+
113
+ const res = await fetch(`${BASE_URL}/upload/chunk/${uploadId}/${index}`, {
114
+ method: "POST",
115
+ headers: authHeader(token),
116
+ body: form
117
+ });
118
+
119
+ return parseJsonResponse(res);
120
+ }
121
+
122
+ async function checkUpload(uploadId) {
123
+ const res = await fetch(`${BASE_URL}/check/${uploadId}`);
124
+ return parseJsonResponse(res);
125
+ }
126
+
127
+ async function waitForDone(uploadId, options = {}) {
128
+ const timeoutMs = options.timeoutMs || DEFAULT_TIMEOUT_MS;
129
+ const pollIntervalMs = options.pollIntervalMs || DEFAULT_POLL_INTERVAL_MS;
130
+ const onProgress = options.onProgress;
131
+ const startedAt = Date.now();
132
+ let lastUploaded = -1;
133
+ let lastStatus = "";
134
+
135
+ while (true) {
136
+ const check = await checkUpload(uploadId);
137
+ const progress = check.progress || {};
138
+
139
+ if (onProgress && (progress.uploaded !== lastUploaded || check.status !== lastStatus)) {
140
+ lastUploaded = progress.uploaded;
141
+ lastStatus = check.status;
142
+ onProgress(check);
143
+ }
144
+
145
+ if (check.status === "done") return check;
146
+ if (check.status === "failed") {
147
+ const error = new Error(check.error || "Upload failed on backend");
148
+ error.data = check;
149
+ throw error;
150
+ }
151
+
152
+ if (Date.now() - startedAt > timeoutMs) {
153
+ const error = new Error(`Upload timeout after ${timeoutMs}ms`);
154
+ error.data = check;
155
+ throw error;
156
+ }
157
+
158
+ await sleep(pollIntervalMs);
159
+ }
160
+ }
161
+
162
+ async function mapLimit(items, limit, task) {
163
+ const results = new Array(items.length);
164
+ let nextIndex = 0;
165
+
166
+ async function worker() {
167
+ while (nextIndex < items.length) {
168
+ const currentIndex = nextIndex++;
169
+ results[currentIndex] = await task(items[currentIndex], currentIndex);
170
+ }
171
+ }
172
+
173
+ const workers = Array.from(
174
+ { length: Math.min(Math.max(1, limit), items.length) },
175
+ () => worker()
176
+ );
177
+
178
+ await Promise.all(workers);
179
+ return results;
180
+ }
181
+
182
+ async function uploadFile(filePath, options = {}) {
183
+ const resolvedPath = path.resolve(filePath);
184
+ const stat = fs.statSync(resolvedPath);
185
+ if (!stat.isFile()) throw new Error(`${resolvedPath} is not a file`);
186
+
187
+ const token = await resolveToken(options);
188
+ const isGuest = !token;
189
+ const maxFileSize = isGuest ? GUEST_MAX_FILE_SIZE : USER_MAX_FILE_SIZE;
190
+
191
+ if (stat.size > maxFileSize) {
192
+ throw new Error(
193
+ `File is too large for ${isGuest ? "guest" : "user"} upload. ` +
194
+ `Limit is ${formatBytes(maxFileSize)}, file size is ${formatBytes(stat.size)}.`
195
+ );
196
+ }
197
+
198
+ const chunkSize = options.chunkSize || DEFAULT_CHUNK_SIZE;
199
+ const chunkConcurrency = options.chunkConcurrency || DEFAULT_CHUNK_CONCURRENCY;
200
+ const ttl = options.ttl || "30d";
201
+ const filename = options.filename || path.basename(resolvedPath);
202
+ const mimetype = options.mimetype || guessMimeType(resolvedPath);
203
+ const onProgress = options.onProgress;
204
+
205
+ const init = await initUpload({ token, filename, mimetype, size: stat.size, ttl });
206
+ const totalChunks = init.totalChunks || Math.ceil(stat.size / chunkSize);
207
+ let queuedChunks = 0;
208
+
209
+ if (onProgress) {
210
+ onProgress({
211
+ success: true,
212
+ status: "initialized",
213
+ id: init.uploadId,
214
+ url: init.url,
215
+ mode: isGuest ? "guest" : "user",
216
+ limit: maxFileSize,
217
+ progress: { percent: 0, uploaded: 0, queued: 0, failed: 0, total: totalChunks }
218
+ });
219
+ }
220
+
221
+ const fd = fs.openSync(resolvedPath, "r");
222
+ try {
223
+ const indexes = Array.from({ length: totalChunks }, (_, index) => index);
224
+
225
+ await mapLimit(indexes, chunkConcurrency, async (index) => {
226
+ const start = index * chunkSize;
227
+ const size = Math.min(chunkSize, stat.size - start);
228
+ const buffer = Buffer.alloc(size);
229
+ fs.readSync(fd, buffer, 0, size, start);
230
+
231
+ await uploadChunk({ token, uploadId: init.uploadId, index, buffer });
232
+
233
+ queuedChunks += 1;
234
+ if (onProgress) {
235
+ onProgress({
236
+ success: true,
237
+ status: "queued",
238
+ id: init.uploadId,
239
+ url: init.url,
240
+ mode: isGuest ? "guest" : "user",
241
+ limit: maxFileSize,
242
+ progress: {
243
+ percent: Math.floor((queuedChunks / totalChunks) * 100),
244
+ queued: queuedChunks,
245
+ total: totalChunks
246
+ }
247
+ });
248
+ }
249
+ });
250
+ } finally {
251
+ fs.closeSync(fd);
252
+ }
253
+
254
+ const final = options.wait === false
255
+ ? await checkUpload(init.uploadId)
256
+ : await waitForDone(init.uploadId, options);
257
+
258
+ return {
259
+ ...final,
260
+ id: init.uploadId,
261
+ url: final.url || init.url,
262
+ fullUrl: `${BASE_URL}${final.url || init.url}`,
263
+ mode: isGuest ? "guest" : "user",
264
+ limit: maxFileSize
265
+ };
266
+ }
267
+
268
+ async function uploadFiles(filePaths, options = {}) {
269
+ const results = [];
270
+ for (const filePath of filePaths) {
271
+ results.push(await uploadFile(filePath, options));
272
+ }
273
+ return results;
274
+ }
275
+
276
+ module.exports = {
277
+ DEFAULT_CHUNK_SIZE,
278
+ DEFAULT_CHUNK_CONCURRENCY,
279
+ GUEST_MAX_FILE_SIZE,
280
+ USER_MAX_FILE_SIZE,
281
+ login,
282
+ uploadFile,
283
+ uploadFiles,
284
+ checkUpload,
285
+ waitForDone
286
+ };
package/lib/index.d.ts ADDED
@@ -0,0 +1,89 @@
1
+ export const BASE_URL: "https://api.tmpbox.me";
2
+ export const DEFAULT_CHUNK_SIZE: number;
3
+ export const DEFAULT_CHUNK_CONCURRENCY: number;
4
+ export const GUEST_MAX_FILE_SIZE: number;
5
+ export const USER_MAX_FILE_SIZE: number;
6
+
7
+ export interface TmpBoxUser {
8
+ username: string;
9
+ role: string;
10
+ }
11
+
12
+ export interface LoginResult {
13
+ success: boolean;
14
+ token: string;
15
+ user?: TmpBoxUser;
16
+ [key: string]: unknown;
17
+ }
18
+
19
+ export interface UploadProgress {
20
+ percent?: number;
21
+ uploaded?: number;
22
+ queued?: number;
23
+ failed?: number;
24
+ total?: number;
25
+ [key: string]: unknown;
26
+ }
27
+
28
+ export interface UploadState {
29
+ success?: boolean;
30
+ status?: string;
31
+ id?: string;
32
+ url?: string;
33
+ mode?: "guest" | "user";
34
+ limit?: number;
35
+ progress?: UploadProgress;
36
+ [key: string]: unknown;
37
+ }
38
+
39
+ export interface UploadOptions {
40
+ token?: string;
41
+ username?: string;
42
+ password?: string;
43
+ ttl?: string;
44
+ filename?: string;
45
+ mimetype?: string;
46
+ chunkSize?: number;
47
+ chunkConcurrency?: number;
48
+ wait?: boolean;
49
+ timeoutMs?: number;
50
+ pollIntervalMs?: number;
51
+ onProgress?: (state: UploadState) => void;
52
+ }
53
+
54
+ export interface UploadResult extends UploadState {
55
+ id: string;
56
+ url: string;
57
+ fullUrl: string;
58
+ mode: "guest" | "user";
59
+ limit: number;
60
+ }
61
+
62
+ export function login(username: string, password: string): Promise<LoginResult>;
63
+ export function uploadFile(
64
+ filePath: string,
65
+ options?: UploadOptions,
66
+ ): Promise<UploadResult>;
67
+ export function uploadFiles(
68
+ filePaths: string[],
69
+ options?: UploadOptions,
70
+ ): Promise<UploadResult[]>;
71
+ export function checkUpload(uploadId: string): Promise<UploadState>;
72
+ export function waitForDone(
73
+ uploadId: string,
74
+ options?: Pick<UploadOptions, "timeoutMs" | "pollIntervalMs" | "onProgress">,
75
+ ): Promise<UploadState>;
76
+
77
+ declare const _default: {
78
+ DEFAULT_CHUNK_SIZE: typeof DEFAULT_CHUNK_SIZE;
79
+ DEFAULT_CHUNK_CONCURRENCY: typeof DEFAULT_CHUNK_CONCURRENCY;
80
+ GUEST_MAX_FILE_SIZE: typeof GUEST_MAX_FILE_SIZE;
81
+ USER_MAX_FILE_SIZE: typeof USER_MAX_FILE_SIZE;
82
+ login: typeof login;
83
+ uploadFile: typeof uploadFile;
84
+ uploadFiles: typeof uploadFiles;
85
+ checkUpload: typeof checkUpload;
86
+ waitForDone: typeof waitForDone;
87
+ };
88
+
89
+ export default _default;
package/lib/index.mjs ADDED
@@ -0,0 +1,14 @@
1
+ import cjs from "./index.cjs";
2
+
3
+ export const BASE_URL = cjs.BASE_URL;
4
+ export const DEFAULT_CHUNK_SIZE = cjs.DEFAULT_CHUNK_SIZE;
5
+ export const DEFAULT_CHUNK_CONCURRENCY = cjs.DEFAULT_CHUNK_CONCURRENCY;
6
+ export const GUEST_MAX_FILE_SIZE = cjs.GUEST_MAX_FILE_SIZE;
7
+ export const USER_MAX_FILE_SIZE = cjs.USER_MAX_FILE_SIZE;
8
+ export const login = cjs.login;
9
+ export const uploadFile = cjs.uploadFile;
10
+ export const uploadFiles = cjs.uploadFiles;
11
+ export const checkUpload = cjs.checkUpload;
12
+ export const waitForDone = cjs.waitForDone;
13
+
14
+ export default cjs;
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "tmpbox.me",
3
+ "author": "bangvn71",
4
+ "version": "1.0.2",
5
+ "description": "Official TmpBox.me uploader SDK and CLI for Node.js.",
6
+ "type": "module",
7
+ "main": "./lib/index.cjs",
8
+ "module": "./lib/index.mjs",
9
+ "types": "./lib/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./lib/index.d.ts",
13
+ "import": "./lib/index.mjs",
14
+ "require": "./lib/index.cjs"
15
+ }
16
+ },
17
+ "bin": {
18
+ "tmpbox-upload": "./bin/tmpbox-upload.cjs"
19
+ },
20
+ "files": [
21
+ "bin",
22
+ "lib",
23
+ "README.md",
24
+ "LICENSE"
25
+ ],
26
+ "scripts": {
27
+ "test": "node --check lib/index.cjs && node --check lib/index.mjs && node --check bin/tmpbox.cjs",
28
+ "pack:local": "npm pack"
29
+ },
30
+ "keywords": [
31
+ "tmpbox.me",
32
+ "tmpbox",
33
+ "upload",
34
+ "file-upload",
35
+ "storage",
36
+ "cli"
37
+ ],
38
+ "license": "MIT",
39
+ "engines": {
40
+ "node": ">=18"
41
+ },
42
+ "publishConfig": {
43
+ "access": "public"
44
+ }
45
+ }