@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,59 @@
1
+ import { NodeCredentialAuth, BearerAuth, UStorageCoreClient, ResumeStore, PutObjectOptions, UploadObjectResult, UploadFileOptions, MemoryResumeStore, UploadSource, UploadChunk } from '../core/index.cjs';
2
+ export { AuthHeadersProvider, BrowserAuth, CompleteUploadRequest, CompleteUploadResponse, CreateFileUrlRequest, CreateFileUrlResponse, CreateUploadSessionRequest, CreateUploadSessionResponse, CreateUploadTokenRequest, CreateUploadTokenResponse, ErrorResponse, FetchHttpClient, GetObjectUrlInput, GetObjectUrlResult, HeaderValue, HttpClient, HttpRequestOptions, JsonValue, FetchHttpClient as NodeHttpClient, UStorageClientOptions, UStorageError, UploadApi, UploadBody, UploadChunkResponse, UploadProgressEvent, UploadStatus, UploadStatusResponse, Uploader, resolveToken, toUStorageError } from '../core/index.cjs';
3
+
4
+ type UStorageNodeAuth = NodeCredentialAuth | BearerAuth;
5
+ interface UStorageNodeClientOptions {
6
+ uploadBaseUrl: string;
7
+ auth: UStorageNodeAuth;
8
+ resumeStore?: ResumeStore;
9
+ }
10
+ declare class UStorageNodeClient extends UStorageCoreClient {
11
+ constructor(options: UStorageNodeClientOptions);
12
+ putObject(options: PutObjectOptions & {
13
+ body: Buffer | string;
14
+ }): Promise<UploadObjectResult>;
15
+ uploadFile(path: string, options: UploadFileOptions): Promise<UploadObjectResult>;
16
+ }
17
+
18
+ declare class NodeMemoryResumeStore extends MemoryResumeStore {
19
+ }
20
+ declare class NodeFileResumeStore implements ResumeStore {
21
+ private readonly path;
22
+ constructor(path: string);
23
+ get(key: string): Promise<string | undefined>;
24
+ set(key: string, uploadId: string): Promise<void>;
25
+ delete(key: string): Promise<void>;
26
+ private read;
27
+ private write;
28
+ clear(): Promise<void>;
29
+ }
30
+
31
+ interface SignedRequestPlaceholder {
32
+ readonly supported: false;
33
+ }
34
+ declare const nodeSigner: SignedRequestPlaceholder;
35
+
36
+ declare class NodeFileUploadSource implements UploadSource {
37
+ private readonly path;
38
+ readonly name: string;
39
+ readonly size: number;
40
+ readonly type?: string;
41
+ private constructor();
42
+ static fromPath(path: string, options?: {
43
+ name?: string;
44
+ type?: string;
45
+ }): Promise<NodeFileUploadSource>;
46
+ fingerprint(key?: string): string;
47
+ slice(start: number, end: number): Promise<UploadChunk>;
48
+ }
49
+ declare class NodeBufferUploadSource implements UploadSource {
50
+ private readonly buffer;
51
+ readonly name: string;
52
+ readonly size: number;
53
+ readonly type?: string;
54
+ constructor(buffer: Buffer, name: string, type?: string);
55
+ fingerprint(key?: string): string;
56
+ slice(start: number, end: number): UploadChunk;
57
+ }
58
+
59
+ export { BearerAuth, MemoryResumeStore, NodeBufferUploadSource, NodeCredentialAuth, NodeFileResumeStore, NodeFileUploadSource, NodeMemoryResumeStore, PutObjectOptions, ResumeStore, type SignedRequestPlaceholder, UStorageCoreClient, type UStorageNodeAuth, UStorageNodeClient, type UStorageNodeClientOptions, UploadChunk, UploadFileOptions, UploadObjectResult, UploadSource, nodeSigner };
@@ -0,0 +1,59 @@
1
+ import { NodeCredentialAuth, BearerAuth, UStorageCoreClient, ResumeStore, PutObjectOptions, UploadObjectResult, UploadFileOptions, MemoryResumeStore, UploadSource, UploadChunk } from '../core/index.js';
2
+ export { AuthHeadersProvider, BrowserAuth, CompleteUploadRequest, CompleteUploadResponse, CreateFileUrlRequest, CreateFileUrlResponse, CreateUploadSessionRequest, CreateUploadSessionResponse, CreateUploadTokenRequest, CreateUploadTokenResponse, ErrorResponse, FetchHttpClient, GetObjectUrlInput, GetObjectUrlResult, HeaderValue, HttpClient, HttpRequestOptions, JsonValue, FetchHttpClient as NodeHttpClient, UStorageClientOptions, UStorageError, UploadApi, UploadBody, UploadChunkResponse, UploadProgressEvent, UploadStatus, UploadStatusResponse, Uploader, resolveToken, toUStorageError } from '../core/index.js';
3
+
4
+ type UStorageNodeAuth = NodeCredentialAuth | BearerAuth;
5
+ interface UStorageNodeClientOptions {
6
+ uploadBaseUrl: string;
7
+ auth: UStorageNodeAuth;
8
+ resumeStore?: ResumeStore;
9
+ }
10
+ declare class UStorageNodeClient extends UStorageCoreClient {
11
+ constructor(options: UStorageNodeClientOptions);
12
+ putObject(options: PutObjectOptions & {
13
+ body: Buffer | string;
14
+ }): Promise<UploadObjectResult>;
15
+ uploadFile(path: string, options: UploadFileOptions): Promise<UploadObjectResult>;
16
+ }
17
+
18
+ declare class NodeMemoryResumeStore extends MemoryResumeStore {
19
+ }
20
+ declare class NodeFileResumeStore implements ResumeStore {
21
+ private readonly path;
22
+ constructor(path: string);
23
+ get(key: string): Promise<string | undefined>;
24
+ set(key: string, uploadId: string): Promise<void>;
25
+ delete(key: string): Promise<void>;
26
+ private read;
27
+ private write;
28
+ clear(): Promise<void>;
29
+ }
30
+
31
+ interface SignedRequestPlaceholder {
32
+ readonly supported: false;
33
+ }
34
+ declare const nodeSigner: SignedRequestPlaceholder;
35
+
36
+ declare class NodeFileUploadSource implements UploadSource {
37
+ private readonly path;
38
+ readonly name: string;
39
+ readonly size: number;
40
+ readonly type?: string;
41
+ private constructor();
42
+ static fromPath(path: string, options?: {
43
+ name?: string;
44
+ type?: string;
45
+ }): Promise<NodeFileUploadSource>;
46
+ fingerprint(key?: string): string;
47
+ slice(start: number, end: number): Promise<UploadChunk>;
48
+ }
49
+ declare class NodeBufferUploadSource implements UploadSource {
50
+ private readonly buffer;
51
+ readonly name: string;
52
+ readonly size: number;
53
+ readonly type?: string;
54
+ constructor(buffer: Buffer, name: string, type?: string);
55
+ fingerprint(key?: string): string;
56
+ slice(start: number, end: number): UploadChunk;
57
+ }
58
+
59
+ export { BearerAuth, MemoryResumeStore, NodeBufferUploadSource, NodeCredentialAuth, NodeFileResumeStore, NodeFileUploadSource, NodeMemoryResumeStore, PutObjectOptions, ResumeStore, type SignedRequestPlaceholder, UStorageCoreClient, type UStorageNodeAuth, UStorageNodeClient, type UStorageNodeClientOptions, UploadChunk, UploadFileOptions, UploadObjectResult, UploadSource, nodeSigner };
@@ -0,0 +1,514 @@
1
+ // src/core/auth/index.ts
2
+ async function resolveToken(value) {
3
+ return typeof value === "function" ? value() : value;
4
+ }
5
+
6
+ // src/core/errors/index.ts
7
+ var UStorageError = class extends Error {
8
+ code;
9
+ status;
10
+ requestId;
11
+ details;
12
+ constructor(message, options) {
13
+ super(message);
14
+ this.name = "UStorageError";
15
+ this.code = options.code;
16
+ this.status = options.status;
17
+ this.requestId = options.requestId;
18
+ this.details = options.details;
19
+ }
20
+ };
21
+ function toUStorageError(status, body) {
22
+ const parsed = body;
23
+ if (parsed?.error?.code && parsed.error.message) {
24
+ return new UStorageError(parsed.error.message, {
25
+ code: parsed.error.code,
26
+ status,
27
+ requestId: parsed.request_id,
28
+ details: parsed.error.details
29
+ });
30
+ }
31
+ return new UStorageError(`UStorage request failed with status ${status}`, { code: "REQUEST_FAILED", status });
32
+ }
33
+
34
+ // src/core/http/index.ts
35
+ var FetchHttpClient = class {
36
+ baseUrl;
37
+ authHeaders;
38
+ fetchImpl;
39
+ constructor(options) {
40
+ this.baseUrl = options.baseUrl.replace(/\/$/, "");
41
+ this.authHeaders = options.authHeaders;
42
+ this.fetchImpl = options.fetchImpl ?? fetch;
43
+ }
44
+ async request(options) {
45
+ const headers = new Headers();
46
+ for (const [key, value] of Object.entries(options.headers ?? {})) {
47
+ if (value !== void 0 && value !== null) headers.set(key, value);
48
+ }
49
+ let body;
50
+ if (options.body !== void 0) {
51
+ if (isBodyInit(options.body)) {
52
+ body = options.body;
53
+ } else {
54
+ headers.set("content-type", headers.get("content-type") ?? "application/json");
55
+ body = JSON.stringify(options.body);
56
+ }
57
+ }
58
+ const path = this.pathWithQuery(options.path, options.query);
59
+ const authHeaders = this.authHeaders ? await this.authHeaders({ method: options.method, path, body }) : {};
60
+ for (const [key, value] of Object.entries(authHeaders)) headers.set(key, value);
61
+ const response = await this.fetchImpl(this.url(path), {
62
+ method: options.method,
63
+ headers,
64
+ body,
65
+ signal: options.signal
66
+ });
67
+ if (response.status === 204) return void 0;
68
+ const text = await response.text();
69
+ const parsed = text ? parseJson(text) : void 0;
70
+ if (!response.ok) throw toUStorageError(response.status, parsed);
71
+ return parsed;
72
+ }
73
+ url(path) {
74
+ return new URL(path.startsWith("/") ? path : `/${path}`, `${this.baseUrl}/`).toString();
75
+ }
76
+ pathWithQuery(path, query) {
77
+ const url = new URL(path.startsWith("/") ? path : `/${path}`, "http://sdk.local");
78
+ for (const [key, value] of Object.entries(query ?? {})) {
79
+ if (value !== void 0 && value !== null) url.searchParams.set(key, String(value));
80
+ }
81
+ return `${url.pathname}${url.search}`;
82
+ }
83
+ };
84
+ function parseJson(value) {
85
+ try {
86
+ return JSON.parse(value);
87
+ } catch {
88
+ return value;
89
+ }
90
+ }
91
+ function isBodyInit(value) {
92
+ 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;
93
+ }
94
+
95
+ // src/core/upload/api.ts
96
+ var UploadApi = class {
97
+ constructor(http) {
98
+ this.http = http;
99
+ }
100
+ http;
101
+ createUploadToken(request) {
102
+ return this.http.request({ method: "POST", path: "/uploads/tokens", body: request });
103
+ }
104
+ createSession(request) {
105
+ return this.http.request({ method: "POST", path: "/uploads/sessions", body: request });
106
+ }
107
+ createFileUrl(request) {
108
+ return this.http.request({ method: "POST", path: "/files/url", body: request });
109
+ }
110
+ uploadChunk(uploadId, index, body, checksum, signal) {
111
+ return this.http.request({ method: "PUT", path: `/uploads/${uploadId}/chunks/${index}`, headers: { "x-chunk-checksum": checksum }, body, signal });
112
+ }
113
+ getStatus(uploadId) {
114
+ return this.http.request({ method: "GET", path: `/uploads/${uploadId}/status` });
115
+ }
116
+ complete(uploadId, request = {}) {
117
+ return this.http.request({ method: "POST", path: `/uploads/${uploadId}/complete`, body: request });
118
+ }
119
+ cancel(uploadId) {
120
+ return this.http.request({ method: "DELETE", path: `/uploads/${uploadId}` });
121
+ }
122
+ };
123
+
124
+ // src/core/upload/checksum.ts
125
+ async function sha256Hex(data) {
126
+ const bytes = await toBytes(data);
127
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
128
+ return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
129
+ }
130
+ async function toBytes(data) {
131
+ if (data instanceof ArrayBuffer) return data;
132
+ if (ArrayBuffer.isView(data)) return new Uint8Array(data.buffer, data.byteOffset, data.byteLength).slice().buffer;
133
+ if (typeof Blob !== "undefined" && data instanceof Blob) return data.arrayBuffer();
134
+ if (typeof data === "string") return new TextEncoder().encode(data).buffer;
135
+ return new Response(data).arrayBuffer();
136
+ }
137
+
138
+ // src/core/upload/file-metadata.ts
139
+ var mimeTypesByExtension = {
140
+ jpg: "image/jpeg",
141
+ jpeg: "image/jpeg",
142
+ png: "image/png",
143
+ gif: "image/gif",
144
+ webp: "image/webp",
145
+ bmp: "image/bmp",
146
+ svg: "image/svg+xml",
147
+ heic: "image/heic",
148
+ mp4: "video/mp4",
149
+ mpeg: "video/mpeg",
150
+ mov: "video/quicktime",
151
+ avi: "video/x-msvideo",
152
+ webm: "video/webm",
153
+ ogg: "video/ogg",
154
+ "3gp": "video/3gpp",
155
+ flv: "video/x-flv",
156
+ mp3: "audio/mpeg",
157
+ wav: "audio/wav",
158
+ aac: "audio/aac",
159
+ m4a: "audio/x-m4a",
160
+ flac: "audio/flac",
161
+ amr: "audio/amr",
162
+ pdf: "application/pdf",
163
+ txt: "text/plain",
164
+ json: "application/json",
165
+ zip: "application/zip",
166
+ tar: "application/x-tar",
167
+ rar: "application/vnd.rar",
168
+ doc: "application/msword",
169
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
170
+ xls: "application/vnd.ms-excel",
171
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
172
+ ppt: "application/vnd.ms-powerpoint",
173
+ pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation"
174
+ };
175
+ function extensionFromName(nameOrKey) {
176
+ const filename = nameOrKey.split(/[\\/]/).filter(Boolean).at(-1) ?? nameOrKey;
177
+ const dot = filename.lastIndexOf(".");
178
+ if (dot <= 0 || dot === filename.length - 1) {
179
+ return null;
180
+ }
181
+ return filename.slice(dot + 1).toLowerCase();
182
+ }
183
+ function mimeTypeFromExtension(extension) {
184
+ return extension ? mimeTypesByExtension[extension.toLowerCase()] ?? null : null;
185
+ }
186
+ function resolveUploadContentType(explicit, sourceType, ...names) {
187
+ const normalizedExplicit = normalizeContentType(explicit);
188
+ if (normalizedExplicit) {
189
+ return normalizedExplicit;
190
+ }
191
+ const normalizedSourceType = normalizeContentType(sourceType);
192
+ if (normalizedSourceType) {
193
+ return normalizedSourceType;
194
+ }
195
+ for (const name of names) {
196
+ if (!name) continue;
197
+ const inferred = mimeTypeFromExtension(extensionFromName(name));
198
+ if (inferred) {
199
+ return inferred;
200
+ }
201
+ }
202
+ return null;
203
+ }
204
+ function normalizeContentType(value) {
205
+ const normalized = value?.trim();
206
+ return normalized ? normalized : null;
207
+ }
208
+
209
+ // src/core/upload/uploader.ts
210
+ var Uploader = class {
211
+ constructor(uploads, resumeStore) {
212
+ this.uploads = uploads;
213
+ this.resumeStore = resumeStore;
214
+ }
215
+ uploads;
216
+ resumeStore;
217
+ async putObject(source, options) {
218
+ const chunkSize = options.chunkSize ?? 8 * 1024 * 1024;
219
+ if (chunkSize <= 0) throw new Error("chunkSize must be positive");
220
+ const totalChunks = source.size === 0 ? 1 : Math.ceil(source.size / chunkSize);
221
+ const useResume = options.resume === true || Boolean(options.resumeKey);
222
+ const resumeKey = useResume ? options.resumeKey ?? await source.fingerprint(options.key) : void 0;
223
+ let uploadId = resumeKey && this.resumeStore ? await this.resumeStore.get(resumeKey) : void 0;
224
+ let missingChunks;
225
+ if (uploadId) {
226
+ try {
227
+ const status = await this.uploads.getStatus(uploadId);
228
+ missingChunks = status.missing_chunks;
229
+ options.onProgress?.(statusToProgress(status));
230
+ } catch {
231
+ uploadId = void 0;
232
+ if (resumeKey) await this.resumeStore?.delete(resumeKey);
233
+ }
234
+ }
235
+ if (!uploadId) {
236
+ const session = await this.uploads.createSession({
237
+ bucket_name: options.bucketName,
238
+ key: options.key,
239
+ workspace_name: options.workspaceName ?? null,
240
+ mime_type: resolveUploadContentType(
241
+ options.contentType,
242
+ source.type,
243
+ options.key,
244
+ source.name
245
+ ),
246
+ file_size: source.size,
247
+ chunk_size: chunkSize,
248
+ total_chunks: totalChunks,
249
+ checksum: typeof options.checksum === "object" ? options.checksum.file ?? null : null,
250
+ metadata: options.metadata,
251
+ overwrite: options.overwrite ?? true,
252
+ visibility: options.visibility ?? null
253
+ });
254
+ uploadId = session.upload_id;
255
+ missingChunks = Array.from({ length: totalChunks }, (_, index) => index);
256
+ if (resumeKey) await this.resumeStore?.set(resumeKey, uploadId);
257
+ }
258
+ for (const index of missingChunks ?? []) {
259
+ const start = index * chunkSize;
260
+ const end = source.size === 0 ? 0 : Math.min(source.size, start + chunkSize);
261
+ const chunk = await source.slice(start, end);
262
+ const checksum = await this.chunkChecksum(options.checksum, index, chunk.body);
263
+ const response = await this.uploads.uploadChunk(uploadId, index, chunk.body, checksum, options.signal);
264
+ options.onProgress?.(chunkResponseToProgress(response));
265
+ }
266
+ const complete = await this.uploads.complete(uploadId, { checksum: typeof options.checksum === "object" ? options.checksum.file : void 0 });
267
+ if (resumeKey) await this.resumeStore?.delete(resumeKey);
268
+ return {
269
+ ...complete,
270
+ uploadId: complete.upload_id,
271
+ fileId: complete.file_id,
272
+ publicId: complete.public_id,
273
+ visibility: complete.visibility,
274
+ url: complete.url,
275
+ expiresAt: complete.expires_at ?? null
276
+ };
277
+ }
278
+ async chunkChecksum(checksum, index, body) {
279
+ if (!checksum) return void 0;
280
+ if (checksum === "sha256") return sha256Hex(body);
281
+ return checksum.chunks?.[index];
282
+ }
283
+ };
284
+ function chunkResponseToProgress(response) {
285
+ return {
286
+ uploadId: response.upload_id,
287
+ chunkIndex: response.chunk_index,
288
+ uploadedChunks: response.uploaded_chunks,
289
+ totalChunks: response.total_chunks,
290
+ uploadedSize: response.uploaded_size,
291
+ fileSize: response.file_size,
292
+ progress: response.progress
293
+ };
294
+ }
295
+ function statusToProgress(response) {
296
+ return {
297
+ uploadId: response.upload_id,
298
+ uploadedChunks: response.uploaded_chunks.length,
299
+ totalChunks: response.total_chunks,
300
+ uploadedSize: response.uploaded_size,
301
+ fileSize: response.file_size,
302
+ progress: response.progress
303
+ };
304
+ }
305
+
306
+ // src/core/client/index.ts
307
+ var UStorageCoreClient = class {
308
+ uploads;
309
+ uploader;
310
+ constructor(options) {
311
+ const uploadHttp = options.uploadHttpClient ?? new FetchHttpClient({ baseUrl: options.uploadBaseUrl, authHeaders: options.authHeaders });
312
+ this.uploads = new UploadApi(uploadHttp);
313
+ this.uploader = new Uploader(this.uploads, options.resumeStore);
314
+ }
315
+ async getObjectUrl(input) {
316
+ const response = await this.uploads.createFileUrl({
317
+ file_id: input.fileId ?? null,
318
+ bucket: input.bucket ?? null,
319
+ bucket_id: input.bucketId ?? null,
320
+ key: input.key ?? null,
321
+ path: input.path ?? null,
322
+ expires_in: input.expiresIn ?? null
323
+ });
324
+ return {
325
+ fileId: response.file_id,
326
+ publicId: response.public_id,
327
+ visibility: response.visibility,
328
+ url: response.url,
329
+ expiresAt: response.expires_at
330
+ };
331
+ }
332
+ getSignedUrl(input) {
333
+ return this.getObjectUrl(input);
334
+ }
335
+ uploadSource(source, options) {
336
+ return this.uploader.putObject(source, options);
337
+ }
338
+ };
339
+
340
+ // src/core/upload/source.ts
341
+ var MemoryResumeStore = class {
342
+ values = /* @__PURE__ */ new Map();
343
+ get(key) {
344
+ return this.values.get(key);
345
+ }
346
+ set(key, uploadId) {
347
+ this.values.set(key, uploadId);
348
+ }
349
+ delete(key) {
350
+ this.values.delete(key);
351
+ }
352
+ };
353
+
354
+ // src/node/node-client.ts
355
+ import { basename as basename2 } from "path";
356
+
357
+ // src/node/node-upload-source.ts
358
+ import { basename } from "path";
359
+ import { open, stat } from "fs/promises";
360
+ var NodeFileUploadSource = class _NodeFileUploadSource {
361
+ constructor(path, size, name, type) {
362
+ this.path = path;
363
+ this.name = name ?? basename(path);
364
+ this.size = size;
365
+ this.type = type;
366
+ }
367
+ path;
368
+ name;
369
+ size;
370
+ type;
371
+ static async fromPath(path, options = {}) {
372
+ const info = await stat(path);
373
+ const name = options.name ?? basename(path);
374
+ return new _NodeFileUploadSource(
375
+ path,
376
+ info.size,
377
+ name,
378
+ resolveUploadContentType(options.type, void 0, name, path) ?? void 0
379
+ );
380
+ }
381
+ fingerprint(key) {
382
+ return ["node-file", key ?? "", this.path, this.name, this.size, this.type ?? ""].join(":");
383
+ }
384
+ async slice(start, end) {
385
+ const length = end - start;
386
+ if (length === 0) return { body: new Uint8Array(), size: 0 };
387
+ const file = await open(this.path, "r");
388
+ try {
389
+ const buffer = Buffer.alloc(length);
390
+ await file.read(buffer, 0, length, start);
391
+ const body = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength).slice().buffer;
392
+ return { body, size: buffer.byteLength };
393
+ } finally {
394
+ await closeFile(file);
395
+ }
396
+ }
397
+ };
398
+ var NodeBufferUploadSource = class {
399
+ constructor(buffer, name, type) {
400
+ this.buffer = buffer;
401
+ this.name = name;
402
+ this.type = resolveUploadContentType(type, void 0, name) ?? void 0;
403
+ this.size = buffer.byteLength;
404
+ }
405
+ buffer;
406
+ name;
407
+ size;
408
+ type;
409
+ fingerprint(key) {
410
+ return ["node-buffer", key ?? "", this.name, this.size, this.type ?? ""].join(":");
411
+ }
412
+ slice(start, end) {
413
+ const buffer = this.buffer.subarray(start, end);
414
+ const body = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength).slice().buffer;
415
+ return { body, size: buffer.byteLength };
416
+ }
417
+ };
418
+ async function closeFile(file) {
419
+ await file.close();
420
+ }
421
+
422
+ // src/node/node-client.ts
423
+ var UStorageNodeClient = class extends UStorageCoreClient {
424
+ constructor(options) {
425
+ super({
426
+ uploadBaseUrl: options.uploadBaseUrl,
427
+ resumeStore: options.resumeStore,
428
+ authHeaders: async () => {
429
+ if ("accessKey" in options.auth) {
430
+ return {
431
+ "x-access-key": options.auth.accessKey,
432
+ "x-secret-key": options.auth.secretKey
433
+ };
434
+ }
435
+ return { Authorization: `Bearer ${await resolveToken(options.auth.bearerToken)}` };
436
+ }
437
+ });
438
+ }
439
+ async putObject(options) {
440
+ if (typeof options.body === "string") {
441
+ return this.uploadSource(await NodeFileUploadSource.fromPath(options.body, { name: objectName(options.key), type: options.contentType ?? void 0 }), options);
442
+ }
443
+ return this.uploadSource(new NodeBufferUploadSource(options.body, objectName(options.key), options.contentType ?? void 0), options);
444
+ }
445
+ async uploadFile(path, options) {
446
+ const key = options.key ?? basename2(path);
447
+ return this.uploadSource(await NodeFileUploadSource.fromPath(path, { name: objectName(key), type: options.contentType ?? void 0 }), { ...options, key });
448
+ }
449
+ };
450
+ function objectName(key) {
451
+ return key.split("/").filter(Boolean).at(-1) ?? key;
452
+ }
453
+
454
+ // src/node/node-resume-store.ts
455
+ import { readFile, writeFile, rm } from "fs/promises";
456
+ import { dirname } from "path";
457
+ import { mkdir } from "fs/promises";
458
+ var NodeMemoryResumeStore = class extends MemoryResumeStore {
459
+ };
460
+ var NodeFileResumeStore = class {
461
+ constructor(path) {
462
+ this.path = path;
463
+ }
464
+ path;
465
+ async get(key) {
466
+ const values = await this.read();
467
+ return values[key];
468
+ }
469
+ async set(key, uploadId) {
470
+ const values = await this.read();
471
+ values[key] = uploadId;
472
+ await this.write(values);
473
+ }
474
+ async delete(key) {
475
+ const values = await this.read();
476
+ delete values[key];
477
+ await this.write(values);
478
+ }
479
+ async read() {
480
+ try {
481
+ return JSON.parse(await readFile(this.path, "utf8"));
482
+ } catch {
483
+ return {};
484
+ }
485
+ }
486
+ async write(values) {
487
+ await mkdir(dirname(this.path), { recursive: true });
488
+ await writeFile(this.path, JSON.stringify(values, null, 2));
489
+ }
490
+ async clear() {
491
+ await rm(this.path, { force: true });
492
+ }
493
+ };
494
+
495
+ // src/node/node-signer.ts
496
+ var nodeSigner = { supported: false };
497
+ export {
498
+ FetchHttpClient,
499
+ MemoryResumeStore,
500
+ NodeBufferUploadSource,
501
+ NodeFileResumeStore,
502
+ NodeFileUploadSource,
503
+ FetchHttpClient as NodeHttpClient,
504
+ NodeMemoryResumeStore,
505
+ UStorageCoreClient,
506
+ UStorageError,
507
+ UStorageNodeClient,
508
+ UploadApi,
509
+ Uploader,
510
+ nodeSigner,
511
+ resolveToken,
512
+ toUStorageError
513
+ };
514
+ //# sourceMappingURL=index.js.map