deepspace 0.11.0 → 0.13.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/CHANGELOG.md +198 -0
- package/dist/{chunk-ZJ43EK3N.js → chunk-233GQU2H.js} +492 -365
- package/dist/chunk-233GQU2H.js.map +1 -0
- package/dist/cli.js +872 -256
- package/dist/cli.js.map +1 -1
- package/dist/documentation-client-core.d.ts +2 -2
- package/dist/documentation-client-core.js +1 -1
- package/dist/documentation-default-renderer.cjs +34 -34
- package/dist/documentation-react.d.ts +1 -1
- package/dist/documentation-react.js +1 -1
- package/dist/documentation-runtime.js +10 -10
- package/dist/documentation-server-core.d.ts +2 -2
- package/dist/documentation-server-core.js +1 -1
- package/dist/documentation.js +2 -2
- package/dist/documentation.js.map +1 -1
- package/dist/index.d.ts +28 -3
- package/dist/index.js +131 -5
- package/dist/index.js.map +1 -1
- package/dist/{public-BGRX_Cjd.d.ts → public-BtArwbVM.d.ts} +8 -0
- package/dist/server.d.ts +104 -5
- package/dist/server.js +355 -77
- package/dist/server.js.map +1 -1
- package/dist/worker.d.ts +104 -5
- package/dist/worker.js +360 -77
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-ZJ43EK3N.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -3636,6 +3636,12 @@ declare function toConnectionStatus(queryStatus: string): ConnectionStatus;
|
|
|
3636
3636
|
*
|
|
3637
3637
|
* Provides upload, download, list, and delete for files in R2.
|
|
3638
3638
|
*
|
|
3639
|
+
* Uploads pick their own transport. A small file goes in one request; a large
|
|
3640
|
+
* one is chunked into parts with `Blob.slice`, so peak memory is bounded by
|
|
3641
|
+
* the PART SIZE rather than by the file — a 1 GiB video costs one part, not a
|
|
3642
|
+
* gibibyte — and the file ceiling becomes a product decision rather than a
|
|
3643
|
+
* request-size accident. Callers do nothing differently either way.
|
|
3644
|
+
*
|
|
3639
3645
|
* Two scopes are supported via the `scope` option:
|
|
3640
3646
|
* - `'self'` (default): per-user storage. Reads require auth.
|
|
3641
3647
|
* - `'app'`: app-wide storage. Reads are public — the upload URL works
|
|
@@ -3668,10 +3674,29 @@ interface R2FileInfo {
|
|
|
3668
3674
|
originalName?: string;
|
|
3669
3675
|
uploadedBy?: string;
|
|
3670
3676
|
}
|
|
3677
|
+
/** Told after each part lands, so a long upload can drive a progress bar. */
|
|
3678
|
+
type UploadProgress = (sent: number, total: number) => void;
|
|
3679
|
+
interface UploadOptions {
|
|
3680
|
+
onProgress?: UploadProgress;
|
|
3681
|
+
}
|
|
3671
3682
|
interface UseR2FilesReturn {
|
|
3672
|
-
/**
|
|
3673
|
-
|
|
3674
|
-
|
|
3683
|
+
/**
|
|
3684
|
+
* Upload a File or Blob. Optionally provide a display name.
|
|
3685
|
+
*
|
|
3686
|
+
* A file above the single-request bound is chunked automatically and sent as
|
|
3687
|
+
* parts — nothing to opt into, and nothing held in memory beyond one part.
|
|
3688
|
+
* Pass `onProgress` to follow a large one.
|
|
3689
|
+
*/
|
|
3690
|
+
upload: (file: File | Blob, name?: string, options?: UploadOptions) => Promise<R2UploadResult>;
|
|
3691
|
+
/**
|
|
3692
|
+
* Upload raw base64 data.
|
|
3693
|
+
*
|
|
3694
|
+
* Single-request only: base64 has to be materialized whole to be decoded, so
|
|
3695
|
+
* this path keeps the one-request bound rather than the file ceiling — and
|
|
3696
|
+
* because the request carries the ENCODED string, its real budget is
|
|
3697
|
+
* `MAX_BASE64_UPLOAD_BYTES` (~18.75 MiB decoded), not the full 25 MiB. Send a
|
|
3698
|
+
* Blob through `upload` for anything larger; it chunks.
|
|
3699
|
+
*/
|
|
3675
3700
|
uploadBase64: (base64Data: string, name: string, mimeType?: string) => Promise<R2UploadResult>;
|
|
3676
3701
|
/**
|
|
3677
3702
|
* Delete a file. Accepts an R2FileInfo from `list()` or a raw key string.
|
package/dist/index.js
CHANGED
|
@@ -3519,14 +3519,128 @@ function toConnectionStatus(queryStatus) {
|
|
|
3519
3519
|
|
|
3520
3520
|
// src/client/storage/useR2Files.ts
|
|
3521
3521
|
import { useCallback as useCallback15, useState as useState13, useMemo as useMemo11 } from "react";
|
|
3522
|
+
|
|
3523
|
+
// src/shared/app-files.ts
|
|
3524
|
+
var MAX_APP_FILE_BYTES = 1024 * 1024 * 1024;
|
|
3525
|
+
var MAX_UPLOAD_REQUEST_BYTES = 25 * 1024 * 1024;
|
|
3526
|
+
var UPLOAD_PART_BYTES = 20 * 1024 * 1024;
|
|
3527
|
+
var MAX_UPLOAD_PARTS = Math.ceil(MAX_APP_FILE_BYTES / UPLOAD_PART_BYTES);
|
|
3528
|
+
var MAX_BASE64_UPLOAD_BYTES = Math.floor(MAX_UPLOAD_REQUEST_BYTES * 3 / 4);
|
|
3529
|
+
function planUploadParts(totalBytes, partSize) {
|
|
3530
|
+
const parts = [];
|
|
3531
|
+
for (let start = 0; start < totalBytes; start += partSize) {
|
|
3532
|
+
parts.push({
|
|
3533
|
+
partNumber: parts.length + 1,
|
|
3534
|
+
start,
|
|
3535
|
+
end: Math.min(start + partSize, totalBytes)
|
|
3536
|
+
});
|
|
3537
|
+
}
|
|
3538
|
+
return parts;
|
|
3539
|
+
}
|
|
3540
|
+
var MAX_DEPLOY_ASSET_FILE_BYTES = 25 * 1024 * 1024;
|
|
3541
|
+
function formatBytes(bytes) {
|
|
3542
|
+
if (bytes >= 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GiB`;
|
|
3543
|
+
if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MiB`;
|
|
3544
|
+
if (bytes >= 1024) return `${Math.round(bytes / 1024)} KiB`;
|
|
3545
|
+
return `${bytes} B`;
|
|
3546
|
+
}
|
|
3547
|
+
function encodeKeyPath(key) {
|
|
3548
|
+
return key.split("/").map(encodeURIComponent).join("/");
|
|
3549
|
+
}
|
|
3550
|
+
function oversizeMessage(bytes, limit = MAX_APP_FILE_BYTES) {
|
|
3551
|
+
return `That file is ${formatBytes(bytes)}; the limit is ${formatBytes(limit)} per file.`;
|
|
3552
|
+
}
|
|
3553
|
+
function describeFilesFailure(status, body) {
|
|
3554
|
+
const trimmed = body.trim();
|
|
3555
|
+
if (trimmed.startsWith("{")) {
|
|
3556
|
+
try {
|
|
3557
|
+
const parsed = JSON.parse(trimmed);
|
|
3558
|
+
if (parsed.error) return parsed.error;
|
|
3559
|
+
} catch {
|
|
3560
|
+
}
|
|
3561
|
+
}
|
|
3562
|
+
if (status === 413) {
|
|
3563
|
+
return `The upload is too large. Files are limited to ${formatBytes(MAX_APP_FILE_BYTES)}, and one request may carry ${formatBytes(MAX_UPLOAD_REQUEST_BYTES)} \u2014 a larger request is rejected by the network before the app receives it.`;
|
|
3564
|
+
}
|
|
3565
|
+
if (status === 411) return "The upload did not declare its length.";
|
|
3566
|
+
if (status === 401 || status === 403) return "Not authorized to write these files.";
|
|
3567
|
+
if (status === 415) return "That file type is not accepted.";
|
|
3568
|
+
if (status >= 500) return `The files service failed (HTTP ${status}). Retry shortly.`;
|
|
3569
|
+
return `Upload failed (HTTP ${status}).`;
|
|
3570
|
+
}
|
|
3571
|
+
|
|
3572
|
+
// src/client/storage/useR2Files.ts
|
|
3573
|
+
function oversize(bytes, limit = MAX_APP_FILE_BYTES) {
|
|
3574
|
+
return bytes > limit ? { success: false, error: oversizeMessage(bytes, limit) } : null;
|
|
3575
|
+
}
|
|
3576
|
+
async function readUploadResult(response) {
|
|
3577
|
+
const text = await response.text();
|
|
3578
|
+
if (response.ok) {
|
|
3579
|
+
try {
|
|
3580
|
+
return JSON.parse(text);
|
|
3581
|
+
} catch {
|
|
3582
|
+
return { success: false, error: "The files service returned a malformed response." };
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3585
|
+
return { success: false, error: describeFilesFailure(response.status, text) };
|
|
3586
|
+
}
|
|
3522
3587
|
function resolveFile(fileOrKey) {
|
|
3523
3588
|
if (typeof fileOrKey === "string") {
|
|
3524
3589
|
return { key: fileOrKey, name: void 0 };
|
|
3525
3590
|
}
|
|
3526
3591
|
return { key: fileOrKey.key, name: fileOrKey.originalName };
|
|
3527
3592
|
}
|
|
3528
|
-
function
|
|
3529
|
-
|
|
3593
|
+
async function uploadInParts(file, name, scopeParams, authHeaders, onProgress) {
|
|
3594
|
+
const headers = await authHeaders();
|
|
3595
|
+
const json = { ...headers, "Content-Type": "application/json" };
|
|
3596
|
+
const initResponse = await fetch(`/api/files/multipart?${scopeParams}`, {
|
|
3597
|
+
method: "POST",
|
|
3598
|
+
headers: json,
|
|
3599
|
+
body: JSON.stringify({ name, mimeType: file.type || "application/octet-stream", size: file.size })
|
|
3600
|
+
});
|
|
3601
|
+
if (!initResponse.ok) return await readUploadResult(initResponse);
|
|
3602
|
+
const session = await initResponse.json();
|
|
3603
|
+
if (!Number.isSafeInteger(session.partSize) || session.partSize < 1) {
|
|
3604
|
+
return {
|
|
3605
|
+
success: false,
|
|
3606
|
+
error: `The files service advertised an unusable part size (${session.partSize}).`
|
|
3607
|
+
};
|
|
3608
|
+
}
|
|
3609
|
+
const query = `${scopeParams}&uploadKey=${encodeKeyPath(session.uploadKey)}&uploadId=${encodeURIComponent(session.uploadId)}`;
|
|
3610
|
+
const plan = planUploadParts(file.size, session.partSize);
|
|
3611
|
+
const parts = [];
|
|
3612
|
+
let assembled = false;
|
|
3613
|
+
try {
|
|
3614
|
+
for (const part of plan) {
|
|
3615
|
+
const send = () => fetch(`/api/files/multipart/part?${query}&partNumber=${part.partNumber}`, {
|
|
3616
|
+
method: "PUT",
|
|
3617
|
+
headers,
|
|
3618
|
+
body: file.slice(part.start, part.end)
|
|
3619
|
+
});
|
|
3620
|
+
let response = await send().catch(() => null);
|
|
3621
|
+
if (!response || response.status === 429 || response.status >= 500) {
|
|
3622
|
+
const retried = await send().catch(() => null);
|
|
3623
|
+
if (retried) response = retried;
|
|
3624
|
+
}
|
|
3625
|
+
if (!response) return { success: false, error: "The files service could not be reached." };
|
|
3626
|
+
if (!response.ok) return await readUploadResult(response);
|
|
3627
|
+
parts.push(await response.json());
|
|
3628
|
+
onProgress?.(part.end, file.size);
|
|
3629
|
+
}
|
|
3630
|
+
const completed = await fetch(`/api/files/multipart/complete?${query}`, {
|
|
3631
|
+
method: "POST",
|
|
3632
|
+
headers: json,
|
|
3633
|
+
body: JSON.stringify({ parts })
|
|
3634
|
+
});
|
|
3635
|
+
assembled = completed.ok;
|
|
3636
|
+
return await readUploadResult(completed);
|
|
3637
|
+
} finally {
|
|
3638
|
+
if (!assembled) {
|
|
3639
|
+
await fetch(`/api/files/multipart?${query}`, { method: "DELETE", headers }).catch(
|
|
3640
|
+
() => void 0
|
|
3641
|
+
);
|
|
3642
|
+
}
|
|
3643
|
+
}
|
|
3530
3644
|
}
|
|
3531
3645
|
function useR2Files(options) {
|
|
3532
3646
|
const [isUploading, setIsUploading] = useState13(false);
|
|
@@ -3544,9 +3658,15 @@ function useR2Files(options) {
|
|
|
3544
3658
|
return {};
|
|
3545
3659
|
}, []);
|
|
3546
3660
|
const upload = useCallback15(
|
|
3547
|
-
async (file, name) => {
|
|
3661
|
+
async (file, name, options2) => {
|
|
3548
3662
|
setIsUploading(true);
|
|
3549
3663
|
try {
|
|
3664
|
+
const tooBig = oversize(file.size);
|
|
3665
|
+
if (tooBig) return tooBig;
|
|
3666
|
+
const fileName = name ?? (file instanceof File ? file.name : "upload");
|
|
3667
|
+
if (file.size > UPLOAD_PART_BYTES) {
|
|
3668
|
+
return await uploadInParts(file, fileName, scopeParams, authHeaders, options2?.onProgress);
|
|
3669
|
+
}
|
|
3550
3670
|
const headers = await authHeaders();
|
|
3551
3671
|
const formData = new FormData();
|
|
3552
3672
|
formData.append("file", file);
|
|
@@ -3556,7 +3676,8 @@ function useR2Files(options) {
|
|
|
3556
3676
|
headers,
|
|
3557
3677
|
body: formData
|
|
3558
3678
|
});
|
|
3559
|
-
|
|
3679
|
+
options2?.onProgress?.(file.size, file.size);
|
|
3680
|
+
return await readUploadResult(response);
|
|
3560
3681
|
} catch (err) {
|
|
3561
3682
|
return { success: false, error: err instanceof Error ? err.message : "Upload failed" };
|
|
3562
3683
|
} finally {
|
|
@@ -3569,13 +3690,18 @@ function useR2Files(options) {
|
|
|
3569
3690
|
async (base64Data, name, mimeType) => {
|
|
3570
3691
|
setIsUploading(true);
|
|
3571
3692
|
try {
|
|
3693
|
+
const tooBig = oversize(
|
|
3694
|
+
Math.floor(base64Data.length * 3 / 4),
|
|
3695
|
+
MAX_BASE64_UPLOAD_BYTES
|
|
3696
|
+
);
|
|
3697
|
+
if (tooBig) return tooBig;
|
|
3572
3698
|
const headers = await authHeaders();
|
|
3573
3699
|
const response = await fetch(`/api/files/upload?${scopeParams}`, {
|
|
3574
3700
|
method: "POST",
|
|
3575
3701
|
headers: { ...headers, "Content-Type": "application/json" },
|
|
3576
3702
|
body: JSON.stringify({ data: base64Data, name, mimeType })
|
|
3577
3703
|
});
|
|
3578
|
-
return await response
|
|
3704
|
+
return await readUploadResult(response);
|
|
3579
3705
|
} catch (err) {
|
|
3580
3706
|
return { success: false, error: err instanceof Error ? err.message : "Upload failed" };
|
|
3581
3707
|
} finally {
|