Skip to content

Commit dd77d89

Browse files
committed
feat(sdk): expose requestUploadUrl, confirmUpload and uploadToPresignedUrl in storage module
1 parent 26d59d5 commit dd77d89

1 file changed

Lines changed: 68 additions & 7 deletions

File tree

‎sdks/urbackend-sdk/src/modules/storage.ts‎

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,7 @@ export class StorageModule {
105105
}
106106

107107
// step 1 — ask server for a signed URL
108-
const { signedUrl, filePath } = await this.client.request<{ signedUrl: string; filePath: string }>(
109-
"POST",
110-
"/api/storage/upload-request",
111-
{ body: { filename: resolvedName, contentType, size: fileSize } }
112-
);
108+
const { signedUrl, filePath } = await this.requestUploadUrl(resolvedName, contentType, fileSize);
113109

114110
// step 2 — upload directly to cloud, server not involved
115111
const putResponse = await fetch(signedUrl, {
@@ -123,12 +119,77 @@ export class StorageModule {
123119
}
124120

125121
// step 3 — tell server we're done so it can verify + update quota
122+
return this.confirmUpload(filePath, fileSize);
123+
}
124+
125+
/**
126+
* Requests a pre-signed upload URL for direct-to-cloud client uploads.
127+
* Useful when delegating uploads to a frontend client without exposing the secret key.
128+
*
129+
* @param {string} filename - The name of the file
130+
* @param {string} contentType - The MIME type of the file
131+
* @param {number} size - The size of the file in bytes
132+
* @returns {Promise<{ signedUrl: string; filePath: string; token?: string }>} The pre-signed URL and file path
133+
*/
134+
public async requestUploadUrl(filename: string, contentType: string, size: number): Promise<{ signedUrl: string; filePath: string; token?: string }> {
135+
return this.client.request<{ signedUrl: string; filePath: string; token?: string }>(
136+
"POST",
137+
"/api/storage/upload-request",
138+
{ body: { filename, contentType, size } }
139+
);
140+
}
141+
142+
/**
143+
* Confirms a direct-to-cloud upload to finalize it and update quotas.
144+
*
145+
* @param {string} filePath - The path returned by requestUploadUrl
146+
* @param {number} size - The size of the uploaded file
147+
* @returns {Promise<UploadResponse>} The upload confirmation details
148+
*/
149+
public async confirmUpload(filePath: string, size: number): Promise<UploadResponse> {
126150
return this.client.request<UploadResponse>(
127151
"POST",
128152
"/api/storage/upload-confirm",
129-
{ body: { filePath, size: fileSize } }
153+
{ body: { filePath, size } }
130154
);
131-
}
155+
}
156+
157+
/**
158+
* Uploads a file directly to a pre-signed URL.
159+
* Useful in client-side applications (like React) where the signed URL is provided by your secure backend.
160+
*
161+
* @param {unknown} file - The file to upload (File, Blob, or Buffer)
162+
* @param {string} signedUrl - The pre-signed URL obtained from your backend
163+
* @param {string} [contentType] - The MIME type (optional, auto-detected from File/Blob)
164+
* @returns {Promise<void>} Resolves when the upload completes successfully
165+
*/
166+
public static async uploadToPresignedUrl(file: unknown, signedUrl: string, contentType?: string): Promise<void> {
167+
let fileData: BodyInit;
168+
let type = contentType || "application/octet-stream";
169+
170+
if (typeof File !== "undefined" && file instanceof File) {
171+
type = contentType || file.type || type;
172+
fileData = file;
173+
} else if (file instanceof Blob) {
174+
type = contentType || file.type || type;
175+
fileData = file;
176+
} else if (typeof Buffer !== "undefined" && Buffer.isBuffer(file)) {
177+
fileData = file as unknown as BodyInit;
178+
} else {
179+
throw new Error("Unsupported file type. Pass a File, Blob, or Buffer.");
180+
}
181+
182+
const putResponse = await fetch(signedUrl, {
183+
method: "PUT",
184+
headers: { "Content-Type": type },
185+
body: fileData,
186+
});
187+
188+
if (!putResponse.ok) {
189+
throw new Error(`Direct upload to cloud failed: ${putResponse.status} ${putResponse.statusText}`);
190+
}
191+
}
192+
132193
/**
133194
* Deletes a file from storage by its path
134195
*

0 commit comments

Comments
 (0)