@muhgholy/next-drive 4.23.24 → 4.23.26
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/dist/chunk-CLF77PSE.js +755 -0
- package/dist/chunk-CLF77PSE.js.map +1 -0
- package/dist/{chunk-IVSBLEMY.cjs → chunk-DUTHZ5HA.cjs} +201 -1027
- package/dist/chunk-DUTHZ5HA.cjs.map +1 -0
- package/dist/chunk-PSJYCISB.cjs +765 -0
- package/dist/chunk-PSJYCISB.cjs.map +1 -0
- package/dist/{chunk-CPMMHIQM.js → chunk-W7PHCOE6.js} +190 -1022
- package/dist/chunk-W7PHCOE6.js.map +1 -0
- package/dist/client/index.cjs +71 -140
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.js +70 -140
- package/dist/client/index.js.map +1 -1
- package/dist/client/upload.d.ts +9 -4
- package/dist/client/upload.d.ts.map +1 -1
- package/dist/server/actions/drive.d.ts.map +1 -1
- package/dist/server/config.d.ts.map +1 -1
- package/dist/server/controllers/drive.d.ts.map +1 -1
- package/dist/server/express.cjs +15 -14
- package/dist/server/express.cjs.map +1 -1
- package/dist/server/express.js +4 -2
- package/dist/server/express.js.map +1 -1
- package/dist/server/hono.cjs +15 -14
- package/dist/server/hono.cjs.map +1 -1
- package/dist/server/hono.js +4 -2
- package/dist/server/hono.js.map +1 -1
- package/dist/server/index.cjs +28 -27
- package/dist/server/index.js +2 -1
- package/dist/server/tus.d.ts +17 -0
- package/dist/server/tus.d.ts.map +1 -0
- package/dist/server/zod/schemas.d.ts +0 -53
- package/dist/server/zod/schemas.d.ts.map +1 -1
- package/dist/tus-JZQ3PKBS.cjs +16 -0
- package/dist/tus-JZQ3PKBS.cjs.map +1 -0
- package/dist/tus-MNPA66VL.js +3 -0
- package/dist/tus-MNPA66VL.js.map +1 -0
- package/dist/types/server/api.d.ts +1 -1
- package/dist/types/server/api.d.ts.map +1 -1
- package/package.json +4 -1
- package/dist/chunk-CPMMHIQM.js.map +0 -1
- package/dist/chunk-IVSBLEMY.cjs.map +0 -1
package/dist/client/index.cjs
CHANGED
|
@@ -4,6 +4,7 @@ var chunkHQTC3554_cjs = require('../chunk-HQTC3554.cjs');
|
|
|
4
4
|
var chunkA65ZAA2Z_cjs = require('../chunk-A65ZAA2Z.cjs');
|
|
5
5
|
var React3 = require('react');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
var tus = require('tus-js-client');
|
|
7
8
|
var reactSlot = require('@radix-ui/react-slot');
|
|
8
9
|
var classVarianceAuthority = require('class-variance-authority');
|
|
9
10
|
var ProgressPrimitive = require('@radix-ui/react-progress');
|
|
@@ -37,6 +38,7 @@ function _interopNamespace(e) {
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
var React3__namespace = /*#__PURE__*/_interopNamespace(React3);
|
|
41
|
+
var tus__namespace = /*#__PURE__*/_interopNamespace(tus);
|
|
40
42
|
var ProgressPrimitive__namespace = /*#__PURE__*/_interopNamespace(ProgressPrimitive);
|
|
41
43
|
var SheetPrimitive__namespace = /*#__PURE__*/_interopNamespace(SheetPrimitive);
|
|
42
44
|
var DropdownMenuPrimitive__namespace = /*#__PURE__*/_interopNamespace(DropdownMenuPrimitive);
|
|
@@ -332,8 +334,6 @@ var useDrive = () => {
|
|
|
332
334
|
if (!context) throw new Error("useDrive must be used within a DriveProvider");
|
|
333
335
|
return context;
|
|
334
336
|
};
|
|
335
|
-
|
|
336
|
-
// src/client/upload.ts
|
|
337
337
|
var MAX_CONCURRENT_UPLOADS = 2;
|
|
338
338
|
var getChunkSize = (fileSize) => {
|
|
339
339
|
if (fileSize < 50 * 1024 * 1024) return 2 * 1024 * 1024;
|
|
@@ -367,161 +367,92 @@ var uploadFile = (options) => {
|
|
|
367
367
|
onComplete
|
|
368
368
|
} = options;
|
|
369
369
|
const id = options.id ?? generateId();
|
|
370
|
-
const endpoint = apiEndpoint.replace(/\/$/, "")
|
|
371
|
-
const uploadUrl = `${endpoint}?action=upload`;
|
|
372
|
-
const controller = new AbortController();
|
|
373
|
-
let activeXhr = null;
|
|
374
|
-
let driveId;
|
|
375
|
-
let completedItem;
|
|
376
|
-
let cancelled = false;
|
|
377
|
-
const totalBytes = file.size;
|
|
370
|
+
const endpoint = `${apiEndpoint.replace(/\/$/, "")}?action=upload`;
|
|
378
371
|
const chunkSize = getChunkSize(file.size);
|
|
379
|
-
const totalChunks = Math.ceil(file.size / chunkSize);
|
|
372
|
+
const totalChunks = Math.max(1, Math.ceil(file.size / chunkSize));
|
|
380
373
|
const log = (type, message) => onLog?.({ id, type, message, timestamp: Date.now() });
|
|
381
|
-
|
|
382
|
-
const percent = totalBytes === 0 ? 100 : Math.min(100, Math.round(uploadedBytes / totalBytes * 100));
|
|
383
|
-
onProgress?.({ id, percent, uploadedBytes, totalBytes, currentChunk, totalChunks });
|
|
374
|
+
let settle = () => {
|
|
384
375
|
};
|
|
385
|
-
const
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
}
|
|
410
|
-
return;
|
|
376
|
+
const promise = new Promise((resolve) => {
|
|
377
|
+
settle = resolve;
|
|
378
|
+
});
|
|
379
|
+
let completedItem;
|
|
380
|
+
let cancelled = false;
|
|
381
|
+
const metadata = {
|
|
382
|
+
filename: file.name,
|
|
383
|
+
filetype: file.type || "application/octet-stream",
|
|
384
|
+
folderId: folderId || "root"
|
|
385
|
+
};
|
|
386
|
+
if (conflictAction) metadata.conflictAction = conflictAction;
|
|
387
|
+
const upload = new tus__namespace.Upload(file, {
|
|
388
|
+
endpoint,
|
|
389
|
+
chunkSize,
|
|
390
|
+
// ** Retry with backoff. On a dropped connection tus first re-checks the server offset (HEAD)
|
|
391
|
+
// ** and resumes from there — this is what prevents the "session expired" failures at ~100%.
|
|
392
|
+
retryDelays: [0, 1e3, 3e3, 5e3, 1e4],
|
|
393
|
+
removeFingerprintOnSuccess: true,
|
|
394
|
+
metadata,
|
|
395
|
+
headers: accountId ? { "x-drive-account": accountId } : {},
|
|
396
|
+
onBeforeRequest(req) {
|
|
397
|
+
if (withCredentials) {
|
|
398
|
+
const xhr = req.getUnderlyingObject();
|
|
399
|
+
if (xhr && "withCredentials" in xhr) xhr.withCredentials = true;
|
|
411
400
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
}
|
|
419
|
-
log("success", `Chunk uploaded successfully`);
|
|
420
|
-
resolve([true, data.data, false]);
|
|
421
|
-
} catch {
|
|
422
|
-
log("error", `Failed to parse response: ${text.slice(0, 100)}`);
|
|
423
|
-
resolve([false, "Invalid server response", true]);
|
|
401
|
+
},
|
|
402
|
+
onShouldRetry(err) {
|
|
403
|
+
const status = err?.originalResponse?.getStatus?.() ?? 0;
|
|
404
|
+
if ([400, 401, 403, 413].includes(status)) {
|
|
405
|
+
log("error", `Non-retryable error (status ${status})`);
|
|
406
|
+
return false;
|
|
424
407
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
for (let i = 0; i < totalChunks; i++) {
|
|
446
|
-
if (controller.signal.aborted) throw new Error("Cancelled");
|
|
447
|
-
log("info", `Processing chunk ${i + 1}/${totalChunks}`);
|
|
448
|
-
const start = i * chunkSize;
|
|
449
|
-
const end = Math.min(start + chunkSize, file.size);
|
|
450
|
-
const chunk = file.slice(start, end);
|
|
451
|
-
const formData = new FormData();
|
|
452
|
-
formData.append("chunk", chunk);
|
|
453
|
-
formData.append("chunkIndex", String(i));
|
|
454
|
-
formData.append("totalChunks", String(totalChunks));
|
|
455
|
-
formData.append("fileName", file.name);
|
|
456
|
-
formData.append("fileSize", String(file.size));
|
|
457
|
-
formData.append("fileType", file.type);
|
|
458
|
-
formData.append("folderId", folderId || "root");
|
|
459
|
-
if (conflictAction) formData.append("conflictAction", conflictAction);
|
|
460
|
-
if (driveId) formData.append("driveId", driveId);
|
|
461
|
-
let attempts = 0;
|
|
462
|
-
let success = false;
|
|
463
|
-
while (!success && attempts < 3 && !controller.signal.aborted) {
|
|
464
|
-
const [ok, result, canRetry] = await sendChunk(i, formData, start);
|
|
465
|
-
if (ok) {
|
|
466
|
-
success = true;
|
|
467
|
-
emitProgress(i + 1, end);
|
|
468
|
-
if (result.type === "UPLOAD_STARTED" && result.driveId) {
|
|
469
|
-
driveId = result.driveId;
|
|
470
|
-
log("success", `Upload session started with ID: ${driveId}`);
|
|
471
|
-
} else if (result.type === "UPLOAD_COMPLETE") {
|
|
472
|
-
if (result.driveId) driveId = result.driveId;
|
|
473
|
-
log("success", `Upload completed successfully`);
|
|
474
|
-
completedItem = result.item;
|
|
475
|
-
}
|
|
476
|
-
} else {
|
|
477
|
-
if (result === "Cancelled") throw new Error("Cancelled");
|
|
478
|
-
if (!canRetry) {
|
|
479
|
-
log("error", `Non-retryable error: ${result}`);
|
|
480
|
-
throw new Error(result);
|
|
481
|
-
}
|
|
482
|
-
attempts++;
|
|
483
|
-
log("warning", `Retry attempt ${attempts}/3 after error`);
|
|
484
|
-
if (attempts === 3) {
|
|
485
|
-
log("error", `Max retry attempts reached: ${result}`);
|
|
486
|
-
throw new Error(result);
|
|
487
|
-
}
|
|
488
|
-
await new Promise((r) => setTimeout(r, 1e3 * attempts));
|
|
489
|
-
}
|
|
408
|
+
log("warning", `Upload interrupted (status ${status}), retrying`);
|
|
409
|
+
return true;
|
|
410
|
+
},
|
|
411
|
+
onProgress(bytesUploaded, bytesTotal) {
|
|
412
|
+
const percent = bytesTotal === 0 ? 100 : Math.min(100, Math.round(bytesUploaded / bytesTotal * 100));
|
|
413
|
+
onProgress?.({
|
|
414
|
+
id,
|
|
415
|
+
percent,
|
|
416
|
+
uploadedBytes: bytesUploaded,
|
|
417
|
+
totalBytes: bytesTotal,
|
|
418
|
+
currentChunk: Math.min(totalChunks, Math.floor(bytesUploaded / chunkSize)),
|
|
419
|
+
totalChunks
|
|
420
|
+
});
|
|
421
|
+
},
|
|
422
|
+
onAfterResponse(_req, res) {
|
|
423
|
+
const header = res.getHeader("X-Drive-Item");
|
|
424
|
+
if (header) {
|
|
425
|
+
try {
|
|
426
|
+
completedItem = JSON.parse(decodeURIComponent(header));
|
|
427
|
+
} catch {
|
|
490
428
|
}
|
|
491
|
-
if (!success && controller.signal.aborted) throw new Error("Cancelled");
|
|
492
429
|
}
|
|
493
|
-
|
|
494
|
-
|
|
430
|
+
},
|
|
431
|
+
onSuccess() {
|
|
432
|
+
log("success", "Upload completed successfully");
|
|
495
433
|
if (completedItem !== void 0) onComplete?.(completedItem);
|
|
496
|
-
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
}
|
|
503
|
-
log("error", `Upload failed: ${errorMessage}`);
|
|
504
|
-
return { id, status: "error", driveId: driveId ?? null, error: errorMessage };
|
|
434
|
+
settle({ id, status: "complete", driveId: completedItem?.id ?? "", file: toDriveFile(completedItem), item: completedItem });
|
|
435
|
+
},
|
|
436
|
+
onError(error) {
|
|
437
|
+
const message = error instanceof Error ? error.message : "Upload failed";
|
|
438
|
+
log("error", `Upload failed: ${message}`);
|
|
439
|
+
settle({ id, status: "error", driveId: null, error: message });
|
|
505
440
|
}
|
|
506
|
-
};
|
|
441
|
+
});
|
|
507
442
|
const cancel = () => {
|
|
508
443
|
if (cancelled) return;
|
|
509
444
|
cancelled = true;
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
fetch(`${endpoint}?action=cancel&id=${driveId}`, {
|
|
514
|
-
method: "POST",
|
|
515
|
-
credentials: withCredentials ? "include" : "same-origin"
|
|
516
|
-
}).catch(() => {
|
|
517
|
-
});
|
|
518
|
-
}
|
|
445
|
+
upload.abort(true).catch(() => {
|
|
446
|
+
});
|
|
447
|
+
settle({ id, status: "cancelled", driveId: null });
|
|
519
448
|
};
|
|
520
449
|
if (signal) {
|
|
521
450
|
if (signal.aborted) cancel();
|
|
522
451
|
else signal.addEventListener("abort", cancel, { once: true });
|
|
523
452
|
}
|
|
524
|
-
|
|
453
|
+
log("info", `Starting upload: ${file.name} (${file.size} bytes)`);
|
|
454
|
+
upload.start();
|
|
455
|
+
return { id, promise, cancel };
|
|
525
456
|
};
|
|
526
457
|
var uploadFiles = (files, options) => {
|
|
527
458
|
const { concurrency = MAX_CONCURRENT_UPLOADS, onFileComplete, ...base } = options;
|