@edge-base/core 0.1.1
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/context.d.ts +36 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +60 -0
- package/dist/context.js.map +1 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +26 -0
- package/dist/errors.js.map +1 -0
- package/dist/field-ops.d.ts +43 -0
- package/dist/field-ops.d.ts.map +1 -0
- package/dist/field-ops.js +61 -0
- package/dist/field-ops.js.map +1 -0
- package/dist/functions.d.ts +50 -0
- package/dist/functions.d.ts.map +1 -0
- package/dist/functions.js +56 -0
- package/dist/functions.js.map +1 -0
- package/dist/generated/api-core.d.ts +503 -0
- package/dist/generated/api-core.d.ts.map +1 -0
- package/dist/generated/api-core.js +496 -0
- package/dist/generated/api-core.js.map +1 -0
- package/dist/generated/client-wrappers.d.ts +120 -0
- package/dist/generated/client-wrappers.d.ts.map +1 -0
- package/dist/generated/client-wrappers.js +219 -0
- package/dist/generated/client-wrappers.js.map +1 -0
- package/dist/http.d.ts +57 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +198 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/mime.d.ts +15 -0
- package/dist/mime.d.ts.map +1 -0
- package/dist/mime.js +84 -0
- package/dist/mime.js.map +1 -0
- package/dist/storage.d.ts +246 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +460 -0
- package/dist/storage.js.map +1 -0
- package/dist/table.d.ts +322 -0
- package/dist/table.d.ts.map +1 -0
- package/dist/table.js +734 -0
- package/dist/table.js.map +1 -0
- package/dist/transport-adapter.d.ts +37 -0
- package/dist/transport-adapter.d.ts.map +1 -0
- package/dist/transport-adapter.js +70 -0
- package/dist/transport-adapter.js.map +1 -0
- package/dist/types.d.ts +39 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/package.json +49 -0
package/dist/storage.js
ADDED
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage SDK — R2 File Storage client (M7, M17)
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* // Upload
|
|
6
|
+
* const meta = await client.storage.bucket('avatars').upload('user-123.jpg', file);
|
|
7
|
+
*
|
|
8
|
+
* // Download
|
|
9
|
+
* const blob = await client.storage.bucket('avatars').download('user-123.jpg');
|
|
10
|
+
*
|
|
11
|
+
* // Signed URL
|
|
12
|
+
* const url = await client.storage.bucket('documents').createSignedUrl('report.pdf', { expiresIn: '1h' });
|
|
13
|
+
*
|
|
14
|
+
* // Resume upload (M17)
|
|
15
|
+
* try { await bucket.upload('large.zip', file); }
|
|
16
|
+
* catch (e) { if (e instanceof ResumableUploadError) await bucket.resumeUpload(e.key, e.uploadId); }
|
|
17
|
+
*/
|
|
18
|
+
import { getMimeType } from './mime.js';
|
|
19
|
+
/**
|
|
20
|
+
* M17: Error thrown when a multipart upload fails but can be resumed.
|
|
21
|
+
* Contains the uploadId and key needed to call resumeUpload().
|
|
22
|
+
*/
|
|
23
|
+
export class ResumableUploadError extends Error {
|
|
24
|
+
key;
|
|
25
|
+
uploadId;
|
|
26
|
+
completedParts;
|
|
27
|
+
failedPartNumber;
|
|
28
|
+
constructor(key, uploadId, completedParts, failedPartNumber, message) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.key = key;
|
|
31
|
+
this.uploadId = uploadId;
|
|
32
|
+
this.completedParts = completedParts;
|
|
33
|
+
this.failedPartNumber = failedPartNumber;
|
|
34
|
+
this.name = 'ResumableUploadError';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// ─── StorageBucket ───
|
|
38
|
+
export class StorageBucket {
|
|
39
|
+
httpClient;
|
|
40
|
+
bucketName;
|
|
41
|
+
core;
|
|
42
|
+
constructor(httpClient, bucketName, core) {
|
|
43
|
+
this.httpClient = httpClient;
|
|
44
|
+
this.bucketName = bucketName;
|
|
45
|
+
this.core = core;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Upload a file (File, Blob, ArrayBuffer, or Uint8Array).
|
|
49
|
+
*
|
|
50
|
+
* Returns an `UploadTask` — awaitable like a regular Promise, but also
|
|
51
|
+
* exposes a `.cancel()` method to abort the upload mid-flight.
|
|
52
|
+
*
|
|
53
|
+
* `contentType` is auto-detected from the file extension when omitted.
|
|
54
|
+
*/
|
|
55
|
+
upload(key, data, options) {
|
|
56
|
+
const controller = new AbortController();
|
|
57
|
+
if (options?.signal) {
|
|
58
|
+
options.signal.addEventListener('abort', () => controller.abort(options.signal.reason), { once: true });
|
|
59
|
+
}
|
|
60
|
+
// Resolve contentType: explicit > File.type > extension > fallback
|
|
61
|
+
const contentType = options?.contentType
|
|
62
|
+
|| (data instanceof File && data.type ? data.type : null)
|
|
63
|
+
|| getMimeType(key);
|
|
64
|
+
const mergedOptions = { ...options, contentType, signal: controller.signal };
|
|
65
|
+
const promise = this._doUpload(key, data, mergedOptions);
|
|
66
|
+
return Object.assign(promise, { cancel: () => controller.abort() });
|
|
67
|
+
}
|
|
68
|
+
/** Internal upload logic (separated from upload() for UploadTask wrapping). */
|
|
69
|
+
async _doUpload(key, data, options) {
|
|
70
|
+
// For large files (>5MB), use multipart upload
|
|
71
|
+
const size = data instanceof Blob ? data.size : data.byteLength;
|
|
72
|
+
if (size > 5 * 1024 * 1024) {
|
|
73
|
+
return this.multipartUpload(key, data, options);
|
|
74
|
+
}
|
|
75
|
+
const formData = new FormData();
|
|
76
|
+
const blob = data instanceof Blob ? data : new Blob([data], { type: options.contentType });
|
|
77
|
+
formData.append('file', blob, key);
|
|
78
|
+
formData.append('key', key);
|
|
79
|
+
if (options.customMetadata) {
|
|
80
|
+
formData.append('customMetadata', JSON.stringify(options.customMetadata));
|
|
81
|
+
}
|
|
82
|
+
return this.uploadFormData(key, formData, options);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Upload a string in various formats.
|
|
86
|
+
* Returns an `UploadTask` with `.cancel()` support.
|
|
87
|
+
*
|
|
88
|
+
* Content type is auto-detected: data_url header > raw → text/plain > file extension.
|
|
89
|
+
*/
|
|
90
|
+
uploadString(key, value, format = 'raw', options) {
|
|
91
|
+
let data;
|
|
92
|
+
let contentType = options?.contentType;
|
|
93
|
+
switch (format) {
|
|
94
|
+
case 'raw':
|
|
95
|
+
data = new TextEncoder().encode(value);
|
|
96
|
+
if (!contentType)
|
|
97
|
+
contentType = 'text/plain';
|
|
98
|
+
break;
|
|
99
|
+
case 'base64':
|
|
100
|
+
data = this.base64ToBytes(value);
|
|
101
|
+
break;
|
|
102
|
+
case 'base64url':
|
|
103
|
+
data = this.base64ToBytes(value.replace(/-/g, '+').replace(/_/g, '/'));
|
|
104
|
+
break;
|
|
105
|
+
case 'data_url': {
|
|
106
|
+
const commaIndex = value.indexOf(',');
|
|
107
|
+
if (commaIndex === -1)
|
|
108
|
+
throw new Error('Invalid data URL format.');
|
|
109
|
+
const header = value.substring(0, commaIndex);
|
|
110
|
+
const mimeMatch = header.match(/data:([^;]+)/);
|
|
111
|
+
if (mimeMatch && !contentType)
|
|
112
|
+
contentType = mimeMatch[1];
|
|
113
|
+
const base64Data = value.substring(commaIndex + 1);
|
|
114
|
+
data = this.base64ToBytes(base64Data);
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
default:
|
|
118
|
+
throw new Error(`Unknown format: ${format}`);
|
|
119
|
+
}
|
|
120
|
+
// Delegates to upload() which handles UploadTask wrapping + remaining auto-detection
|
|
121
|
+
return this.upload(key, data, { ...options, contentType });
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Download a file.
|
|
125
|
+
*
|
|
126
|
+
* NOTE: Direct HTTP — requires raw Response for blob/arraybuffer/stream conversion.
|
|
127
|
+
* Generated core's downloadFile() returns parsed JSON via transport adapter,
|
|
128
|
+
* which cannot provide raw Response access needed here.
|
|
129
|
+
*/
|
|
130
|
+
async download(key, options) {
|
|
131
|
+
const encodedKey = key.split('/').map(encodeURIComponent).join('/');
|
|
132
|
+
const response = await this.httpClient.getRaw(`/api/storage/${this.bucketName}/${encodedKey}`);
|
|
133
|
+
const format = options?.as || 'blob';
|
|
134
|
+
switch (format) {
|
|
135
|
+
case 'blob':
|
|
136
|
+
return response.blob();
|
|
137
|
+
case 'arraybuffer':
|
|
138
|
+
return response.arrayBuffer();
|
|
139
|
+
case 'stream':
|
|
140
|
+
return response.body;
|
|
141
|
+
case 'text':
|
|
142
|
+
return response.text();
|
|
143
|
+
default:
|
|
144
|
+
return response.blob();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Get the public URL of a file (synchronous, just URL calculation).
|
|
149
|
+
*/
|
|
150
|
+
getUrl(key) {
|
|
151
|
+
const encodedKey = key.split('/').map(encodeURIComponent).join('/');
|
|
152
|
+
return this.httpClient.getBaseUrl() + `/api/storage/${this.bucketName}/${encodedKey}`;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Create a signed download URL with expiration.
|
|
156
|
+
*/
|
|
157
|
+
async createSignedUrl(key, options) {
|
|
158
|
+
const body = { key, expiresIn: options?.expiresIn || '1h' };
|
|
159
|
+
const result = this.core
|
|
160
|
+
? await this.core.createSignedDownloadUrl(this.bucketName, body)
|
|
161
|
+
: await this.httpClient.post(`/api/storage/${this.bucketName}/signed-url`, body);
|
|
162
|
+
return result.url;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Create signed download URLs for multiple files in a single request.
|
|
166
|
+
*/
|
|
167
|
+
async createSignedUrls(keys, options) {
|
|
168
|
+
const body = { keys, expiresIn: options?.expiresIn || '1h' };
|
|
169
|
+
const result = this.core
|
|
170
|
+
? await this.core.createSignedDownloadUrls(this.bucketName, body)
|
|
171
|
+
: await this.httpClient.post(`/api/storage/${this.bucketName}/signed-urls`, body);
|
|
172
|
+
return result.urls;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Create a signed upload URL for direct R2 upload.
|
|
176
|
+
*/
|
|
177
|
+
async createSignedUploadUrl(key, options) {
|
|
178
|
+
const body = { key, expiresIn: options?.expiresIn || '30m', maxFileSize: options?.maxFileSize };
|
|
179
|
+
return this.core
|
|
180
|
+
? await this.core.createSignedUploadUrl(this.bucketName, body)
|
|
181
|
+
: this.httpClient.post(`/api/storage/${this.bucketName}/signed-upload-url`, body);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Get file metadata.
|
|
185
|
+
*/
|
|
186
|
+
async getMetadata(key) {
|
|
187
|
+
const encodedKey = key.split('/').map(encodeURIComponent).join('/');
|
|
188
|
+
return this.core
|
|
189
|
+
? await this.core.getFileMetadata(this.bucketName, encodedKey)
|
|
190
|
+
: this.httpClient.get(`/api/storage/${this.bucketName}/${encodedKey}/metadata`);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Update file metadata (custom metadata, content type).
|
|
194
|
+
*/
|
|
195
|
+
async updateMetadata(key, metadata) {
|
|
196
|
+
const encodedKey = key.split('/').map(encodeURIComponent).join('/');
|
|
197
|
+
return this.core
|
|
198
|
+
? await this.core.updateFileMetadata(this.bucketName, encodedKey, metadata)
|
|
199
|
+
: this.httpClient.patch(`/api/storage/${this.bucketName}/${encodedKey}/metadata`, metadata);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Check if a file exists.
|
|
203
|
+
*
|
|
204
|
+
* NOTE: Direct HTTP — uses HEAD request. Generated core has no HEAD method support;
|
|
205
|
+
* headRaw() is the only way to check existence without downloading the file.
|
|
206
|
+
*/
|
|
207
|
+
async exists(key) {
|
|
208
|
+
const encodedKey = key.split('/').map(encodeURIComponent).join('/');
|
|
209
|
+
try {
|
|
210
|
+
await this.httpClient.headRaw(`/api/storage/${this.bucketName}/${encodedKey}`);
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Delete a file.
|
|
219
|
+
*/
|
|
220
|
+
async delete(key) {
|
|
221
|
+
const encodedKey = key.split('/').map(encodeURIComponent).join('/');
|
|
222
|
+
if (this.core) {
|
|
223
|
+
await this.core.deleteFile(this.bucketName, encodedKey);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
await this.httpClient.delete(`/api/storage/${this.bucketName}/${encodedKey}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Delete multiple files in a single request.
|
|
231
|
+
*/
|
|
232
|
+
async deleteMany(keys) {
|
|
233
|
+
const body = { keys };
|
|
234
|
+
return this.core
|
|
235
|
+
? await this.core.deleteBatch(this.bucketName, body)
|
|
236
|
+
: this.httpClient.post(`/api/storage/${this.bucketName}/delete-batch`, body);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* List files in the bucket.
|
|
240
|
+
*
|
|
241
|
+
* NOTE: Direct HTTP — generated listFiles(bucket) accepts no query params,
|
|
242
|
+
* but this method needs prefix/cursor/limit filtering. Codegen limitation.
|
|
243
|
+
*/
|
|
244
|
+
async list(options) {
|
|
245
|
+
const query = {};
|
|
246
|
+
if (options?.prefix)
|
|
247
|
+
query.prefix = options.prefix;
|
|
248
|
+
if (options?.cursor)
|
|
249
|
+
query.cursor = options.cursor;
|
|
250
|
+
if (options?.limit)
|
|
251
|
+
query.limit = String(options.limit);
|
|
252
|
+
return this.httpClient.get(`/api/storage/${this.bucketName}`, query);
|
|
253
|
+
}
|
|
254
|
+
// ─── Private helpers ───
|
|
255
|
+
base64ToBytes(base64) {
|
|
256
|
+
const binary = atob(base64);
|
|
257
|
+
const bytes = new Uint8Array(binary.length);
|
|
258
|
+
for (let i = 0; i < binary.length; i++) {
|
|
259
|
+
bytes[i] = binary.charCodeAt(i);
|
|
260
|
+
}
|
|
261
|
+
return bytes;
|
|
262
|
+
}
|
|
263
|
+
/** NOTE: Direct HTTP — FormData upload requires raw fetch for multipart/form-data boundary handling. */
|
|
264
|
+
async uploadFormData(key, formData, options) {
|
|
265
|
+
// Direct fetch with FormData (HttpClient doesn't support non-JSON bodies)
|
|
266
|
+
const headers = await this.httpClient.getAuthHeaders();
|
|
267
|
+
// Do NOT set Content-Type — browser sets it with boundary for FormData
|
|
268
|
+
delete headers['Content-Type'];
|
|
269
|
+
const fetchOptions = {
|
|
270
|
+
method: 'POST',
|
|
271
|
+
headers,
|
|
272
|
+
body: formData,
|
|
273
|
+
signal: options?.signal,
|
|
274
|
+
};
|
|
275
|
+
const response = await fetch(this.httpClient.getBaseUrl() + `/api/storage/${this.bucketName}/upload`, fetchOptions);
|
|
276
|
+
if (!response.ok) {
|
|
277
|
+
const body = await response.json().catch(() => null);
|
|
278
|
+
const msg = body?.message || `Upload failed: ${response.status}`;
|
|
279
|
+
throw new Error(String(msg));
|
|
280
|
+
}
|
|
281
|
+
return (await response.json());
|
|
282
|
+
}
|
|
283
|
+
async multipartUpload(key, data, options) {
|
|
284
|
+
const blob = data instanceof Blob ? data : new Blob([data]);
|
|
285
|
+
// contentType is already resolved by upload() → _doUpload() before reaching here
|
|
286
|
+
const contentType = options?.contentType || 'application/octet-stream';
|
|
287
|
+
// 1. Create multipart upload
|
|
288
|
+
const createBody = { key, contentType, customMetadata: options?.customMetadata };
|
|
289
|
+
const { uploadId } = this.core
|
|
290
|
+
? await this.core.createMultipartUpload(this.bucketName, createBody)
|
|
291
|
+
: await this.httpClient.post(`/api/storage/${this.bucketName}/multipart/create`, createBody);
|
|
292
|
+
// 2. Upload parts (5MB chunks)
|
|
293
|
+
const PART_SIZE = 5 * 1024 * 1024;
|
|
294
|
+
const totalSize = blob.size;
|
|
295
|
+
const parts = [];
|
|
296
|
+
let uploaded = 0;
|
|
297
|
+
// NOTE: Direct HTTP for part uploads — binary chunk body + progress tracking + abort signal
|
|
298
|
+
// require raw fetch. Generated uploadPart() only accepts JSON body via transport.
|
|
299
|
+
for (let partNumber = 1; uploaded < totalSize; partNumber++) {
|
|
300
|
+
const start = uploaded;
|
|
301
|
+
const end = Math.min(start + PART_SIZE, totalSize);
|
|
302
|
+
const chunk = blob.slice(start, end);
|
|
303
|
+
const headers = await this.httpClient.getAuthHeaders();
|
|
304
|
+
delete headers['Content-Type'];
|
|
305
|
+
const params = new URLSearchParams({
|
|
306
|
+
uploadId,
|
|
307
|
+
partNumber: String(partNumber),
|
|
308
|
+
key,
|
|
309
|
+
});
|
|
310
|
+
const response = await fetch(`${this.httpClient.getBaseUrl()}/api/storage/${this.bucketName}/multipart/upload-part?${params}`, { method: 'POST', headers, body: chunk, signal: options?.signal });
|
|
311
|
+
if (!response.ok) {
|
|
312
|
+
// M17: Throw resumable error instead of aborting
|
|
313
|
+
throw new ResumableUploadError(key, uploadId, parts, partNumber, `Multipart upload failed at part ${partNumber}`);
|
|
314
|
+
}
|
|
315
|
+
const part = (await response.json());
|
|
316
|
+
parts.push(part);
|
|
317
|
+
uploaded = end;
|
|
318
|
+
if (options?.onProgress) {
|
|
319
|
+
options.onProgress({
|
|
320
|
+
loaded: uploaded,
|
|
321
|
+
total: totalSize,
|
|
322
|
+
percent: Math.round((uploaded / totalSize) * 100),
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
// 3. Complete multipart upload
|
|
327
|
+
const completeBody = { uploadId, key, parts };
|
|
328
|
+
return this.core
|
|
329
|
+
? await this.core.completeMultipartUpload(this.bucketName, completeBody)
|
|
330
|
+
: this.httpClient.post(`/api/storage/${this.bucketName}/multipart/complete`, completeBody);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Start a multipart upload and return the upload ID so callers can resume it later.
|
|
334
|
+
*/
|
|
335
|
+
async initiateResumableUpload(key, contentType) {
|
|
336
|
+
const createBody = { key };
|
|
337
|
+
if (contentType) {
|
|
338
|
+
createBody.contentType = contentType;
|
|
339
|
+
}
|
|
340
|
+
const result = this.core
|
|
341
|
+
? await this.core.createMultipartUpload(this.bucketName, createBody)
|
|
342
|
+
: await this.httpClient.post(`/api/storage/${this.bucketName}/multipart/create`, createBody);
|
|
343
|
+
return result.uploadId;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* M17: Get uploaded parts for an in-progress multipart upload.
|
|
347
|
+
* Use this to check which parts have been uploaded before calling resumeUpload().
|
|
348
|
+
*
|
|
349
|
+
* NOTE: Direct HTTP — generated getUploadParts(bucket, uploadId) accepts no query params,
|
|
350
|
+
* but this method needs { key } query parameter. Codegen limitation.
|
|
351
|
+
*/
|
|
352
|
+
async getUploadParts(key, uploadId) {
|
|
353
|
+
return this.httpClient.get(`/api/storage/${this.bucketName}/uploads/${encodeURIComponent(uploadId)}/parts`, { key });
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* M17: Resume a previously failed multipart upload.
|
|
357
|
+
* Queries the server for completed parts, then uploads only the remaining chunks.
|
|
358
|
+
* Returns an `UploadTask` with `.cancel()` support.
|
|
359
|
+
*/
|
|
360
|
+
resumeUpload(key, uploadId, data, options) {
|
|
361
|
+
const controller = new AbortController();
|
|
362
|
+
if (options?.signal) {
|
|
363
|
+
options.signal.addEventListener('abort', () => controller.abort(options.signal.reason), { once: true });
|
|
364
|
+
}
|
|
365
|
+
const mergedOptions = { ...options, signal: controller.signal };
|
|
366
|
+
const promise = this._doResumeUpload(key, uploadId, data, mergedOptions);
|
|
367
|
+
return Object.assign(promise, { cancel: () => controller.abort() });
|
|
368
|
+
}
|
|
369
|
+
/** Internal resume upload logic. */
|
|
370
|
+
async _doResumeUpload(key, uploadId, data, options) {
|
|
371
|
+
const blob = data instanceof Blob ? data : new Blob([data]);
|
|
372
|
+
const totalSize = blob.size;
|
|
373
|
+
const PART_SIZE = 5 * 1024 * 1024;
|
|
374
|
+
// 1. Query server for already-uploaded parts
|
|
375
|
+
const { parts: completedParts } = await this.getUploadParts(key, uploadId);
|
|
376
|
+
const completedSet = new Set(completedParts.map(p => p.partNumber));
|
|
377
|
+
// 2. Upload remaining parts
|
|
378
|
+
const allParts = [...completedParts];
|
|
379
|
+
let uploaded = 0;
|
|
380
|
+
for (let partNumber = 1; uploaded < totalSize; partNumber++) {
|
|
381
|
+
const start = (partNumber - 1) * PART_SIZE;
|
|
382
|
+
const end = Math.min(start + PART_SIZE, totalSize);
|
|
383
|
+
if (completedSet.has(partNumber)) {
|
|
384
|
+
// Skip already-uploaded part
|
|
385
|
+
uploaded = end;
|
|
386
|
+
if (options.onProgress) {
|
|
387
|
+
options.onProgress({ loaded: uploaded, total: totalSize, percent: Math.round((uploaded / totalSize) * 100) });
|
|
388
|
+
}
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
// NOTE: Direct HTTP for part uploads — binary chunk body + abort signal
|
|
392
|
+
// require raw fetch. Generated uploadPart() only accepts JSON body via transport.
|
|
393
|
+
const chunk = blob.slice(start, end);
|
|
394
|
+
const headers = await this.httpClient.getAuthHeaders();
|
|
395
|
+
delete headers['Content-Type'];
|
|
396
|
+
const params = new URLSearchParams({
|
|
397
|
+
uploadId,
|
|
398
|
+
partNumber: String(partNumber),
|
|
399
|
+
key,
|
|
400
|
+
});
|
|
401
|
+
const response = await fetch(`${this.httpClient.getBaseUrl()}/api/storage/${this.bucketName}/multipart/upload-part?${params}`, { method: 'POST', headers, body: chunk, signal: options.signal });
|
|
402
|
+
if (!response.ok) {
|
|
403
|
+
throw new ResumableUploadError(key, uploadId, allParts, partNumber, `Resume upload failed at part ${partNumber}`);
|
|
404
|
+
}
|
|
405
|
+
const part = (await response.json());
|
|
406
|
+
allParts.push(part);
|
|
407
|
+
uploaded = end;
|
|
408
|
+
if (options.onProgress) {
|
|
409
|
+
options.onProgress({ loaded: uploaded, total: totalSize, percent: Math.round((uploaded / totalSize) * 100) });
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
// 3. Complete
|
|
413
|
+
// Sort parts by partNumber for R2
|
|
414
|
+
allParts.sort((a, b) => a.partNumber - b.partNumber);
|
|
415
|
+
const completeBody = { uploadId, key, parts: allParts };
|
|
416
|
+
return this.core
|
|
417
|
+
? await this.core.completeMultipartUpload(this.bucketName, completeBody)
|
|
418
|
+
: this.httpClient.post(`/api/storage/${this.bucketName}/multipart/complete`, completeBody);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
// ─── StorageClient ───
|
|
422
|
+
export class StorageClient {
|
|
423
|
+
httpClient;
|
|
424
|
+
core;
|
|
425
|
+
constructor(httpClient, core) {
|
|
426
|
+
this.httpClient = httpClient;
|
|
427
|
+
this.core = core;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Get a bucket reference.
|
|
431
|
+
* @example
|
|
432
|
+
* const avatarsBucket = client.storage.bucket('avatars');
|
|
433
|
+
*/
|
|
434
|
+
bucket(name) {
|
|
435
|
+
return new StorageBucket(this.httpClient, name, this.core);
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Convenience: get public URL for a file without creating a bucket reference.
|
|
439
|
+
* @example
|
|
440
|
+
* const url = admin.storage.getUrl('avatars', 'profile.png');
|
|
441
|
+
*/
|
|
442
|
+
getUrl(bucketName, key) {
|
|
443
|
+
return new StorageBucket(this.httpClient, bucketName, this.core).getUrl(key);
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Convenience: upload a file without creating a bucket reference.
|
|
447
|
+
* @example
|
|
448
|
+
* await admin.storage.upload('avatars', 'profile.png', blob);
|
|
449
|
+
*/
|
|
450
|
+
upload(bucketName, key, data, options) {
|
|
451
|
+
return new StorageBucket(this.httpClient, bucketName, this.core).upload(key, data, options);
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Convenience: delete a file without creating a bucket reference.
|
|
455
|
+
*/
|
|
456
|
+
delete(bucketName, key) {
|
|
457
|
+
return new StorageBucket(this.httpClient, bucketName, this.core).delete(key);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
|