@ustorage/sdk 0.1.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.
@@ -0,0 +1,397 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/core/index.ts
21
+ var core_exports = {};
22
+ __export(core_exports, {
23
+ FetchHttpClient: () => FetchHttpClient,
24
+ MemoryResumeStore: () => MemoryResumeStore,
25
+ UStorageCoreClient: () => UStorageCoreClient,
26
+ UStorageError: () => UStorageError,
27
+ UploadApi: () => UploadApi,
28
+ Uploader: () => Uploader,
29
+ resolveToken: () => resolveToken,
30
+ toUStorageError: () => toUStorageError
31
+ });
32
+ module.exports = __toCommonJS(core_exports);
33
+
34
+ // src/core/auth/index.ts
35
+ async function resolveToken(value) {
36
+ return typeof value === "function" ? value() : value;
37
+ }
38
+
39
+ // src/core/errors/index.ts
40
+ var UStorageError = class extends Error {
41
+ code;
42
+ status;
43
+ requestId;
44
+ details;
45
+ constructor(message, options) {
46
+ super(message);
47
+ this.name = "UStorageError";
48
+ this.code = options.code;
49
+ this.status = options.status;
50
+ this.requestId = options.requestId;
51
+ this.details = options.details;
52
+ }
53
+ };
54
+ function toUStorageError(status, body) {
55
+ const parsed = body;
56
+ if (parsed?.error?.code && parsed.error.message) {
57
+ return new UStorageError(parsed.error.message, {
58
+ code: parsed.error.code,
59
+ status,
60
+ requestId: parsed.request_id,
61
+ details: parsed.error.details
62
+ });
63
+ }
64
+ return new UStorageError(`UStorage request failed with status ${status}`, { code: "REQUEST_FAILED", status });
65
+ }
66
+
67
+ // src/core/http/index.ts
68
+ var FetchHttpClient = class {
69
+ baseUrl;
70
+ authHeaders;
71
+ fetchImpl;
72
+ constructor(options) {
73
+ this.baseUrl = options.baseUrl.replace(/\/$/, "");
74
+ this.authHeaders = options.authHeaders;
75
+ this.fetchImpl = options.fetchImpl ?? fetch;
76
+ }
77
+ async request(options) {
78
+ const headers = new Headers();
79
+ for (const [key, value] of Object.entries(options.headers ?? {})) {
80
+ if (value !== void 0 && value !== null) headers.set(key, value);
81
+ }
82
+ let body;
83
+ if (options.body !== void 0) {
84
+ if (isBodyInit(options.body)) {
85
+ body = options.body;
86
+ } else {
87
+ headers.set("content-type", headers.get("content-type") ?? "application/json");
88
+ body = JSON.stringify(options.body);
89
+ }
90
+ }
91
+ const path = this.pathWithQuery(options.path, options.query);
92
+ const authHeaders = this.authHeaders ? await this.authHeaders({ method: options.method, path, body }) : {};
93
+ for (const [key, value] of Object.entries(authHeaders)) headers.set(key, value);
94
+ const response = await this.fetchImpl(this.url(path), {
95
+ method: options.method,
96
+ headers,
97
+ body,
98
+ signal: options.signal
99
+ });
100
+ if (response.status === 204) return void 0;
101
+ const text = await response.text();
102
+ const parsed = text ? parseJson(text) : void 0;
103
+ if (!response.ok) throw toUStorageError(response.status, parsed);
104
+ return parsed;
105
+ }
106
+ url(path) {
107
+ return new URL(path.startsWith("/") ? path : `/${path}`, `${this.baseUrl}/`).toString();
108
+ }
109
+ pathWithQuery(path, query) {
110
+ const url = new URL(path.startsWith("/") ? path : `/${path}`, "http://sdk.local");
111
+ for (const [key, value] of Object.entries(query ?? {})) {
112
+ if (value !== void 0 && value !== null) url.searchParams.set(key, String(value));
113
+ }
114
+ return `${url.pathname}${url.search}`;
115
+ }
116
+ };
117
+ function parseJson(value) {
118
+ try {
119
+ return JSON.parse(value);
120
+ } catch {
121
+ return value;
122
+ }
123
+ }
124
+ function isBodyInit(value) {
125
+ return typeof Blob !== "undefined" && value instanceof Blob || typeof FormData !== "undefined" && value instanceof FormData || typeof URLSearchParams !== "undefined" && value instanceof URLSearchParams || typeof ArrayBuffer !== "undefined" && value instanceof ArrayBuffer || ArrayBuffer.isView(value) || typeof ReadableStream !== "undefined" && value instanceof ReadableStream;
126
+ }
127
+
128
+ // src/core/upload/api.ts
129
+ var UploadApi = class {
130
+ constructor(http) {
131
+ this.http = http;
132
+ }
133
+ http;
134
+ createUploadToken(request) {
135
+ return this.http.request({ method: "POST", path: "/uploads/tokens", body: request });
136
+ }
137
+ createSession(request) {
138
+ return this.http.request({ method: "POST", path: "/uploads/sessions", body: request });
139
+ }
140
+ createFileUrl(request) {
141
+ return this.http.request({ method: "POST", path: "/files/url", body: request });
142
+ }
143
+ uploadChunk(uploadId, index, body, checksum, signal) {
144
+ return this.http.request({ method: "PUT", path: `/uploads/${uploadId}/chunks/${index}`, headers: { "x-chunk-checksum": checksum }, body, signal });
145
+ }
146
+ getStatus(uploadId) {
147
+ return this.http.request({ method: "GET", path: `/uploads/${uploadId}/status` });
148
+ }
149
+ complete(uploadId, request = {}) {
150
+ return this.http.request({ method: "POST", path: `/uploads/${uploadId}/complete`, body: request });
151
+ }
152
+ cancel(uploadId) {
153
+ return this.http.request({ method: "DELETE", path: `/uploads/${uploadId}` });
154
+ }
155
+ };
156
+
157
+ // src/core/upload/checksum.ts
158
+ async function sha256Hex(data) {
159
+ const bytes = await toBytes(data);
160
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
161
+ return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
162
+ }
163
+ async function toBytes(data) {
164
+ if (data instanceof ArrayBuffer) return data;
165
+ if (ArrayBuffer.isView(data)) return new Uint8Array(data.buffer, data.byteOffset, data.byteLength).slice().buffer;
166
+ if (typeof Blob !== "undefined" && data instanceof Blob) return data.arrayBuffer();
167
+ if (typeof data === "string") return new TextEncoder().encode(data).buffer;
168
+ return new Response(data).arrayBuffer();
169
+ }
170
+
171
+ // src/core/upload/file-metadata.ts
172
+ var mimeTypesByExtension = {
173
+ jpg: "image/jpeg",
174
+ jpeg: "image/jpeg",
175
+ png: "image/png",
176
+ gif: "image/gif",
177
+ webp: "image/webp",
178
+ bmp: "image/bmp",
179
+ svg: "image/svg+xml",
180
+ heic: "image/heic",
181
+ mp4: "video/mp4",
182
+ mpeg: "video/mpeg",
183
+ mov: "video/quicktime",
184
+ avi: "video/x-msvideo",
185
+ webm: "video/webm",
186
+ ogg: "video/ogg",
187
+ "3gp": "video/3gpp",
188
+ flv: "video/x-flv",
189
+ mp3: "audio/mpeg",
190
+ wav: "audio/wav",
191
+ aac: "audio/aac",
192
+ m4a: "audio/x-m4a",
193
+ flac: "audio/flac",
194
+ amr: "audio/amr",
195
+ pdf: "application/pdf",
196
+ txt: "text/plain",
197
+ json: "application/json",
198
+ zip: "application/zip",
199
+ tar: "application/x-tar",
200
+ rar: "application/vnd.rar",
201
+ doc: "application/msword",
202
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
203
+ xls: "application/vnd.ms-excel",
204
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
205
+ ppt: "application/vnd.ms-powerpoint",
206
+ pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation"
207
+ };
208
+ function extensionFromName(nameOrKey) {
209
+ const filename = nameOrKey.split(/[\\/]/).filter(Boolean).at(-1) ?? nameOrKey;
210
+ const dot = filename.lastIndexOf(".");
211
+ if (dot <= 0 || dot === filename.length - 1) {
212
+ return null;
213
+ }
214
+ return filename.slice(dot + 1).toLowerCase();
215
+ }
216
+ function mimeTypeFromExtension(extension) {
217
+ return extension ? mimeTypesByExtension[extension.toLowerCase()] ?? null : null;
218
+ }
219
+ function resolveUploadContentType(explicit, sourceType, ...names) {
220
+ const normalizedExplicit = normalizeContentType(explicit);
221
+ if (normalizedExplicit) {
222
+ return normalizedExplicit;
223
+ }
224
+ const normalizedSourceType = normalizeContentType(sourceType);
225
+ if (normalizedSourceType) {
226
+ return normalizedSourceType;
227
+ }
228
+ for (const name of names) {
229
+ if (!name) continue;
230
+ const inferred = mimeTypeFromExtension(extensionFromName(name));
231
+ if (inferred) {
232
+ return inferred;
233
+ }
234
+ }
235
+ return null;
236
+ }
237
+ function normalizeContentType(value) {
238
+ const normalized = value?.trim();
239
+ return normalized ? normalized : null;
240
+ }
241
+
242
+ // src/core/upload/uploader.ts
243
+ var Uploader = class {
244
+ constructor(uploads, resumeStore) {
245
+ this.uploads = uploads;
246
+ this.resumeStore = resumeStore;
247
+ }
248
+ uploads;
249
+ resumeStore;
250
+ async putObject(source, options) {
251
+ const chunkSize = options.chunkSize ?? 8 * 1024 * 1024;
252
+ if (chunkSize <= 0) throw new Error("chunkSize must be positive");
253
+ const totalChunks = source.size === 0 ? 1 : Math.ceil(source.size / chunkSize);
254
+ const useResume = options.resume === true || Boolean(options.resumeKey);
255
+ const resumeKey = useResume ? options.resumeKey ?? await source.fingerprint(options.key) : void 0;
256
+ let uploadId = resumeKey && this.resumeStore ? await this.resumeStore.get(resumeKey) : void 0;
257
+ let missingChunks;
258
+ if (uploadId) {
259
+ try {
260
+ const status = await this.uploads.getStatus(uploadId);
261
+ missingChunks = status.missing_chunks;
262
+ options.onProgress?.(statusToProgress(status));
263
+ } catch {
264
+ uploadId = void 0;
265
+ if (resumeKey) await this.resumeStore?.delete(resumeKey);
266
+ }
267
+ }
268
+ if (!uploadId) {
269
+ const session = await this.uploads.createSession({
270
+ bucket_name: options.bucketName,
271
+ key: options.key,
272
+ workspace_name: options.workspaceName ?? null,
273
+ mime_type: resolveUploadContentType(
274
+ options.contentType,
275
+ source.type,
276
+ options.key,
277
+ source.name
278
+ ),
279
+ file_size: source.size,
280
+ chunk_size: chunkSize,
281
+ total_chunks: totalChunks,
282
+ checksum: typeof options.checksum === "object" ? options.checksum.file ?? null : null,
283
+ metadata: options.metadata,
284
+ overwrite: options.overwrite ?? true,
285
+ visibility: options.visibility ?? null
286
+ });
287
+ uploadId = session.upload_id;
288
+ missingChunks = Array.from({ length: totalChunks }, (_, index) => index);
289
+ if (resumeKey) await this.resumeStore?.set(resumeKey, uploadId);
290
+ }
291
+ for (const index of missingChunks ?? []) {
292
+ const start = index * chunkSize;
293
+ const end = source.size === 0 ? 0 : Math.min(source.size, start + chunkSize);
294
+ const chunk = await source.slice(start, end);
295
+ const checksum = await this.chunkChecksum(options.checksum, index, chunk.body);
296
+ const response = await this.uploads.uploadChunk(uploadId, index, chunk.body, checksum, options.signal);
297
+ options.onProgress?.(chunkResponseToProgress(response));
298
+ }
299
+ const complete = await this.uploads.complete(uploadId, { checksum: typeof options.checksum === "object" ? options.checksum.file : void 0 });
300
+ if (resumeKey) await this.resumeStore?.delete(resumeKey);
301
+ return {
302
+ ...complete,
303
+ uploadId: complete.upload_id,
304
+ fileId: complete.file_id,
305
+ publicId: complete.public_id,
306
+ visibility: complete.visibility,
307
+ url: complete.url,
308
+ expiresAt: complete.expires_at ?? null
309
+ };
310
+ }
311
+ async chunkChecksum(checksum, index, body) {
312
+ if (!checksum) return void 0;
313
+ if (checksum === "sha256") return sha256Hex(body);
314
+ return checksum.chunks?.[index];
315
+ }
316
+ };
317
+ function chunkResponseToProgress(response) {
318
+ return {
319
+ uploadId: response.upload_id,
320
+ chunkIndex: response.chunk_index,
321
+ uploadedChunks: response.uploaded_chunks,
322
+ totalChunks: response.total_chunks,
323
+ uploadedSize: response.uploaded_size,
324
+ fileSize: response.file_size,
325
+ progress: response.progress
326
+ };
327
+ }
328
+ function statusToProgress(response) {
329
+ return {
330
+ uploadId: response.upload_id,
331
+ uploadedChunks: response.uploaded_chunks.length,
332
+ totalChunks: response.total_chunks,
333
+ uploadedSize: response.uploaded_size,
334
+ fileSize: response.file_size,
335
+ progress: response.progress
336
+ };
337
+ }
338
+
339
+ // src/core/client/index.ts
340
+ var UStorageCoreClient = class {
341
+ uploads;
342
+ uploader;
343
+ constructor(options) {
344
+ const uploadHttp = options.uploadHttpClient ?? new FetchHttpClient({ baseUrl: options.uploadBaseUrl, authHeaders: options.authHeaders });
345
+ this.uploads = new UploadApi(uploadHttp);
346
+ this.uploader = new Uploader(this.uploads, options.resumeStore);
347
+ }
348
+ async getObjectUrl(input) {
349
+ const response = await this.uploads.createFileUrl({
350
+ file_id: input.fileId ?? null,
351
+ bucket: input.bucket ?? null,
352
+ bucket_id: input.bucketId ?? null,
353
+ key: input.key ?? null,
354
+ path: input.path ?? null,
355
+ expires_in: input.expiresIn ?? null
356
+ });
357
+ return {
358
+ fileId: response.file_id,
359
+ publicId: response.public_id,
360
+ visibility: response.visibility,
361
+ url: response.url,
362
+ expiresAt: response.expires_at
363
+ };
364
+ }
365
+ getSignedUrl(input) {
366
+ return this.getObjectUrl(input);
367
+ }
368
+ uploadSource(source, options) {
369
+ return this.uploader.putObject(source, options);
370
+ }
371
+ };
372
+
373
+ // src/core/upload/source.ts
374
+ var MemoryResumeStore = class {
375
+ values = /* @__PURE__ */ new Map();
376
+ get(key) {
377
+ return this.values.get(key);
378
+ }
379
+ set(key, uploadId) {
380
+ this.values.set(key, uploadId);
381
+ }
382
+ delete(key) {
383
+ this.values.delete(key);
384
+ }
385
+ };
386
+ // Annotate the CommonJS export names for ESM import in node:
387
+ 0 && (module.exports = {
388
+ FetchHttpClient,
389
+ MemoryResumeStore,
390
+ UStorageCoreClient,
391
+ UStorageError,
392
+ UploadApi,
393
+ Uploader,
394
+ resolveToken,
395
+ toUStorageError
396
+ });
397
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/index.ts","../../src/core/auth/index.ts","../../src/core/errors/index.ts","../../src/core/http/index.ts","../../src/core/upload/api.ts","../../src/core/upload/checksum.ts","../../src/core/upload/file-metadata.ts","../../src/core/upload/uploader.ts","../../src/core/client/index.ts","../../src/core/upload/source.ts"],"sourcesContent":["export * from './auth';\nexport * from './client';\nexport * from './errors';\nexport * from './http';\nexport * from './types';\nexport * from './upload/api';\nexport * from './upload/source';\nexport * from './upload/uploader';\n","export type BrowserAuth =\n | { bearerToken: string | (() => string | Promise<string>); uploadToken?: never }\n | { uploadToken: string | (() => string | Promise<string>); bearerToken?: never };\n\nexport interface NodeCredentialAuth {\n accessKey: string;\n secretKey: string;\n}\n\nexport interface BearerAuth {\n bearerToken: string | (() => string | Promise<string>);\n}\n\nexport async function resolveToken(value: string | (() => string | Promise<string>)): Promise<string> {\n return typeof value === 'function' ? value() : value;\n}\n","import type { ErrorResponse } from '../types';\n\nexport class UStorageError extends Error {\n readonly code: string;\n readonly status: number;\n readonly requestId?: string;\n readonly details?: unknown;\n\n constructor(message: string, options: { code: string; status: number; requestId?: string; details?: unknown }) {\n super(message);\n this.name = 'UStorageError';\n this.code = options.code;\n this.status = options.status;\n this.requestId = options.requestId;\n this.details = options.details;\n }\n}\n\nexport function toUStorageError(status: number, body: unknown): UStorageError {\n const parsed = body as Partial<ErrorResponse>;\n if (parsed?.error?.code && parsed.error.message) {\n return new UStorageError(parsed.error.message, {\n code: parsed.error.code,\n status,\n requestId: parsed.request_id,\n details: parsed.error.details,\n });\n }\n return new UStorageError(`UStorage request failed with status ${status}`, { code: 'REQUEST_FAILED', status });\n}\n","import { toUStorageError } from '../errors';\n\nexport type HeaderValue = string | undefined | null;\n\nexport interface HttpRequestOptions {\n method: string;\n path: string;\n headers?: Record<string, HeaderValue>;\n query?: Record<string, string | number | boolean | undefined | null>;\n body?: unknown;\n signal?: AbortSignal;\n}\n\nexport interface HttpClient {\n request<T>(options: HttpRequestOptions): Promise<T>;\n}\n\nexport type AuthHeadersProvider = (request?: { method: string; path: string; body?: BodyInit }) => Record<string, string> | Promise<Record<string, string>>;\n\nexport class FetchHttpClient implements HttpClient {\n private readonly baseUrl: string;\n private readonly authHeaders?: AuthHeadersProvider;\n private readonly fetchImpl: typeof fetch;\n\n constructor(options: { baseUrl: string; authHeaders?: AuthHeadersProvider; fetchImpl?: typeof fetch }) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, '');\n this.authHeaders = options.authHeaders;\n this.fetchImpl = options.fetchImpl ?? fetch;\n }\n\n async request<T>(options: HttpRequestOptions): Promise<T> {\n const headers = new Headers();\n for (const [key, value] of Object.entries(options.headers ?? {})) {\n if (value !== undefined && value !== null) headers.set(key, value);\n }\n let body: BodyInit | undefined;\n if (options.body !== undefined) {\n if (isBodyInit(options.body)) {\n body = options.body;\n } else {\n headers.set('content-type', headers.get('content-type') ?? 'application/json');\n body = JSON.stringify(options.body);\n }\n }\n const path = this.pathWithQuery(options.path, options.query);\n const authHeaders = this.authHeaders ? await this.authHeaders({ method: options.method, path, body }) : {};\n for (const [key, value] of Object.entries(authHeaders)) headers.set(key, value);\n const response = await this.fetchImpl(this.url(path), {\n method: options.method,\n headers,\n body,\n signal: options.signal,\n });\n if (response.status === 204) return undefined as T;\n const text = await response.text();\n const parsed = text ? parseJson(text) : undefined;\n if (!response.ok) throw toUStorageError(response.status, parsed);\n return parsed as T;\n }\n\n private url(path: string): string {\n return new URL(path.startsWith('/') ? path : `/${path}`, `${this.baseUrl}/`).toString();\n }\n\n private pathWithQuery(path: string, query?: HttpRequestOptions['query']): string {\n const url = new URL(path.startsWith('/') ? path : `/${path}`, 'http://sdk.local');\n for (const [key, value] of Object.entries(query ?? {})) {\n if (value !== undefined && value !== null) url.searchParams.set(key, String(value));\n }\n return `${url.pathname}${url.search}`;\n }\n}\n\nfunction parseJson(value: string): unknown {\n try {\n return JSON.parse(value);\n } catch {\n return value;\n }\n}\n\nfunction isBodyInit(value: unknown): value is BodyInit {\n return typeof Blob !== 'undefined' && value instanceof Blob ||\n typeof FormData !== 'undefined' && value instanceof FormData ||\n typeof URLSearchParams !== 'undefined' && value instanceof URLSearchParams ||\n typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer ||\n ArrayBuffer.isView(value) ||\n typeof ReadableStream !== 'undefined' && value instanceof ReadableStream;\n}\n","import type { HttpClient } from '../http';\nimport type { UploadBody } from './source';\nimport type {\n CompleteUploadRequest,\n CompleteUploadResponse,\n CreateFileUrlRequest,\n CreateFileUrlResponse,\n CreateUploadSessionRequest,\n CreateUploadSessionResponse,\n CreateUploadTokenRequest,\n CreateUploadTokenResponse,\n UploadChunkResponse,\n UploadStatusResponse,\n} from '../types';\n\nexport class UploadApi {\n constructor(private readonly http: HttpClient) {}\n\n createUploadToken(request: CreateUploadTokenRequest): Promise<CreateUploadTokenResponse> {\n return this.http.request({ method: 'POST', path: '/uploads/tokens', body: request });\n }\n\n createSession(request: CreateUploadSessionRequest): Promise<CreateUploadSessionResponse> {\n return this.http.request({ method: 'POST', path: '/uploads/sessions', body: request });\n }\n\n createFileUrl(request: CreateFileUrlRequest): Promise<CreateFileUrlResponse> {\n return this.http.request({ method: 'POST', path: '/files/url', body: request });\n }\n\n uploadChunk(uploadId: string, index: number, body: UploadBody, checksum?: string, signal?: AbortSignal): Promise<UploadChunkResponse> {\n return this.http.request({ method: 'PUT', path: `/uploads/${uploadId}/chunks/${index}`, headers: { 'x-chunk-checksum': checksum }, body, signal });\n }\n\n getStatus(uploadId: string): Promise<UploadStatusResponse> {\n return this.http.request({ method: 'GET', path: `/uploads/${uploadId}/status` });\n }\n\n complete(uploadId: string, request: CompleteUploadRequest = {}): Promise<CompleteUploadResponse> {\n return this.http.request({ method: 'POST', path: `/uploads/${uploadId}/complete`, body: request });\n }\n\n cancel(uploadId: string): Promise<void> {\n return this.http.request({ method: 'DELETE', path: `/uploads/${uploadId}` });\n }\n}\n","import type { UploadBody } from './source';\n\nexport async function sha256Hex(data: UploadBody): Promise<string> {\n const bytes = await toBytes(data);\n const digest = await crypto.subtle.digest('SHA-256', bytes);\n return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, '0')).join('');\n}\n\nasync function toBytes(data: UploadBody): Promise<ArrayBuffer> {\n if (data instanceof ArrayBuffer) return data;\n if (ArrayBuffer.isView(data)) return new Uint8Array(data.buffer, data.byteOffset, data.byteLength).slice().buffer;\n if (typeof Blob !== 'undefined' && data instanceof Blob) return data.arrayBuffer();\n if (typeof data === 'string') return new TextEncoder().encode(data).buffer;\n return new Response(data).arrayBuffer();\n}\n","const mimeTypesByExtension: Record<string, string> = {\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n bmp: 'image/bmp',\n svg: 'image/svg+xml',\n heic: 'image/heic',\n mp4: 'video/mp4',\n mpeg: 'video/mpeg',\n mov: 'video/quicktime',\n avi: 'video/x-msvideo',\n webm: 'video/webm',\n ogg: 'video/ogg',\n '3gp': 'video/3gpp',\n flv: 'video/x-flv',\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n aac: 'audio/aac',\n m4a: 'audio/x-m4a',\n flac: 'audio/flac',\n amr: 'audio/amr',\n pdf: 'application/pdf',\n txt: 'text/plain',\n json: 'application/json',\n zip: 'application/zip',\n tar: 'application/x-tar',\n rar: 'application/vnd.rar',\n doc: 'application/msword',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xls: 'application/vnd.ms-excel',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n ppt: 'application/vnd.ms-powerpoint',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n};\n\nexport function extensionFromName(nameOrKey: string): string | null {\n const filename = nameOrKey.split(/[\\\\/]/).filter(Boolean).at(-1) ?? nameOrKey;\n const dot = filename.lastIndexOf('.');\n if (dot <= 0 || dot === filename.length - 1) {\n return null;\n }\n return filename.slice(dot + 1).toLowerCase();\n}\n\nexport function mimeTypeFromExtension(extension: string | null): string | null {\n return extension ? mimeTypesByExtension[extension.toLowerCase()] ?? null : null;\n}\n\nexport function resolveUploadContentType(\n explicit: string | null | undefined,\n sourceType: string | null | undefined,\n ...names: Array<string | null | undefined>\n): string | null {\n const normalizedExplicit = normalizeContentType(explicit);\n if (normalizedExplicit) {\n return normalizedExplicit;\n }\n\n const normalizedSourceType = normalizeContentType(sourceType);\n if (normalizedSourceType) {\n return normalizedSourceType;\n }\n\n for (const name of names) {\n if (!name) continue;\n const inferred = mimeTypeFromExtension(extensionFromName(name));\n if (inferred) {\n return inferred;\n }\n }\n\n return null;\n}\n\nfunction normalizeContentType(value: string | null | undefined): string | null {\n const normalized = value?.trim();\n return normalized ? normalized : null;\n}\n","import { sha256Hex } from './checksum';\nimport { resolveUploadContentType } from './file-metadata';\nimport type { UploadApi } from './api';\nimport type { JsonValue, UploadChunkResponse, CompleteUploadResponse } from '../types';\nimport type { ResumeStore, UploadBody, UploadSource } from './source';\n\nexport interface PutObjectOptions {\n bucketName: string;\n key: string;\n workspaceName?: string;\n contentType?: string | null;\n metadata?: JsonValue;\n checksum?: false | 'sha256' | { file?: string; chunks?: Record<number, string> };\n resume?: boolean;\n resumeKey?: string;\n overwrite?: boolean;\n visibility?: 'public' | 'private';\n chunkSize?: number;\n signal?: AbortSignal;\n onProgress?: (event: UploadProgressEvent) => void;\n}\n\nexport interface UploadFileOptions extends Omit<PutObjectOptions, 'key'> {\n key?: string;\n}\n\nexport interface UploadProgressEvent {\n uploadId: string;\n chunkIndex?: number;\n uploadedChunks: number;\n totalChunks: number;\n uploadedSize: number;\n fileSize: number;\n progress: number;\n}\n\nexport interface UploadObjectResult extends CompleteUploadResponse {\n uploadId: string;\n fileId: string;\n publicId?: string;\n visibility?: 'public' | 'private' | string;\n url?: string;\n expiresAt?: string | null;\n}\n\nexport class Uploader {\n constructor(\n private readonly uploads: UploadApi,\n private readonly resumeStore?: ResumeStore,\n ) {}\n\n async putObject(source: UploadSource, options: PutObjectOptions): Promise<UploadObjectResult> {\n const chunkSize = options.chunkSize ?? 8 * 1024 * 1024;\n if (chunkSize <= 0) throw new Error('chunkSize must be positive');\n const totalChunks = source.size === 0 ? 1 : Math.ceil(source.size / chunkSize);\n const useResume = options.resume === true || Boolean(options.resumeKey);\n const resumeKey = useResume ? options.resumeKey ?? await source.fingerprint(options.key) : undefined;\n let uploadId = resumeKey && this.resumeStore ? await this.resumeStore.get(resumeKey) : undefined;\n let missingChunks: number[] | undefined;\n if (uploadId) {\n try {\n const status = await this.uploads.getStatus(uploadId);\n missingChunks = status.missing_chunks;\n options.onProgress?.(statusToProgress(status));\n } catch {\n uploadId = undefined;\n if (resumeKey) await this.resumeStore?.delete(resumeKey);\n }\n }\n if (!uploadId) {\n const session = await this.uploads.createSession({\n bucket_name: options.bucketName,\n key: options.key,\n workspace_name: options.workspaceName ?? null,\n mime_type: resolveUploadContentType(\n options.contentType,\n source.type,\n options.key,\n source.name,\n ),\n file_size: source.size,\n chunk_size: chunkSize,\n total_chunks: totalChunks,\n checksum: typeof options.checksum === 'object' ? options.checksum.file ?? null : null,\n metadata: options.metadata,\n overwrite: options.overwrite ?? true,\n visibility: options.visibility ?? null,\n });\n uploadId = session.upload_id;\n missingChunks = Array.from({ length: totalChunks }, (_, index) => index);\n if (resumeKey) await this.resumeStore?.set(resumeKey, uploadId);\n }\n for (const index of missingChunks ?? []) {\n const start = index * chunkSize;\n const end = source.size === 0 ? 0 : Math.min(source.size, start + chunkSize);\n const chunk = await source.slice(start, end);\n const checksum = await this.chunkChecksum(options.checksum, index, chunk.body);\n const response = await this.uploads.uploadChunk(uploadId, index, chunk.body, checksum, options.signal);\n options.onProgress?.(chunkResponseToProgress(response));\n }\n const complete = await this.uploads.complete(uploadId, { checksum: typeof options.checksum === 'object' ? options.checksum.file : undefined });\n if (resumeKey) await this.resumeStore?.delete(resumeKey);\n return {\n ...complete,\n uploadId: complete.upload_id,\n fileId: complete.file_id,\n publicId: complete.public_id,\n visibility: complete.visibility,\n url: complete.url,\n expiresAt: complete.expires_at ?? null,\n };\n }\n\n private async chunkChecksum(checksum: PutObjectOptions['checksum'], index: number, body: UploadBody): Promise<string | undefined> {\n if (!checksum) return undefined;\n if (checksum === 'sha256') return sha256Hex(body);\n return checksum.chunks?.[index];\n }\n}\n\nfunction chunkResponseToProgress(response: UploadChunkResponse): UploadProgressEvent {\n return {\n uploadId: response.upload_id,\n chunkIndex: response.chunk_index,\n uploadedChunks: response.uploaded_chunks,\n totalChunks: response.total_chunks,\n uploadedSize: response.uploaded_size,\n fileSize: response.file_size,\n progress: response.progress,\n };\n}\n\nfunction statusToProgress(response: { upload_id: string; uploaded_chunks: number[]; total_chunks: number; uploaded_size: number; file_size: number; progress: number }): UploadProgressEvent {\n return {\n uploadId: response.upload_id,\n uploadedChunks: response.uploaded_chunks.length,\n totalChunks: response.total_chunks,\n uploadedSize: response.uploaded_size,\n fileSize: response.file_size,\n progress: response.progress,\n };\n}\n","import { FetchHttpClient, type AuthHeadersProvider, type HttpClient } from '../http';\nimport { UploadApi } from '../upload/api';\nimport { Uploader } from '../upload/uploader';\nimport type { ResumeStore, UploadSource } from '../upload/source';\nimport type { GetObjectUrlInput, GetObjectUrlResult } from '../types';\nimport type { PutObjectOptions } from '../upload/uploader';\n\nexport interface UStorageClientOptions {\n uploadBaseUrl: string;\n authHeaders?: AuthHeadersProvider;\n uploadHttpClient?: HttpClient;\n resumeStore?: ResumeStore;\n}\n\nexport class UStorageCoreClient {\n readonly uploads: UploadApi;\n private readonly uploader: Uploader;\n\n constructor(options: UStorageClientOptions) {\n const uploadHttp = options.uploadHttpClient ?? new FetchHttpClient({ baseUrl: options.uploadBaseUrl, authHeaders: options.authHeaders });\n this.uploads = new UploadApi(uploadHttp);\n this.uploader = new Uploader(this.uploads, options.resumeStore);\n }\n\n async getObjectUrl(input: GetObjectUrlInput): Promise<GetObjectUrlResult> {\n const response = await this.uploads.createFileUrl({\n file_id: input.fileId ?? null,\n bucket: input.bucket ?? null,\n bucket_id: input.bucketId ?? null,\n key: input.key ?? null,\n path: input.path ?? null,\n expires_in: input.expiresIn ?? null,\n });\n return {\n fileId: response.file_id,\n publicId: response.public_id,\n visibility: response.visibility,\n url: response.url,\n expiresAt: response.expires_at,\n };\n }\n\n getSignedUrl(input: GetObjectUrlInput): Promise<GetObjectUrlResult> {\n return this.getObjectUrl(input);\n }\n\n protected uploadSource(source: UploadSource, options: PutObjectOptions) {\n return this.uploader.putObject(source, options);\n }\n}\n","export type UploadBody = BodyInit | ArrayBufferView;\n\nexport interface UploadChunk {\n body: UploadBody;\n size: number;\n}\n\nexport interface UploadSource {\n readonly name: string;\n readonly size: number;\n readonly type?: string;\n fingerprint(key?: string): string | Promise<string>;\n slice(start: number, end: number): UploadChunk | Promise<UploadChunk>;\n}\n\nexport interface ResumeStore {\n get(key: string): Promise<string | undefined> | string | undefined;\n set(key: string, uploadId: string): Promise<void> | void;\n delete(key: string): Promise<void> | void;\n}\n\nexport class MemoryResumeStore implements ResumeStore {\n private readonly values = new Map<string, string>();\n\n get(key: string): string | undefined {\n return this.values.get(key);\n }\n\n set(key: string, uploadId: string): void {\n this.values.set(key, uploadId);\n }\n\n delete(key: string): void {\n this.values.delete(key);\n }\n}\n"],"mappings":"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","names":[]}