firebase-storage-kit 1.4.0 → 1.6.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/dist/{chunk-PBO3CMOD.js → chunk-PTKP7RWS.js} +217 -9
- package/dist/chunk-PTKP7RWS.js.map +1 -0
- package/dist/{firebase-storage-manager-DT6lxmUD.d.ts → firebase-storage-manager-6BfTfmyy.d.ts} +44 -1
- package/dist/index.d.ts +33 -3
- package/dist/index.js +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-PBO3CMOD.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ref, uploadBytesResumable, getDownloadURL, getMetadata, deleteObject } from 'firebase/storage';
|
|
1
|
+
import { ref, uploadBytesResumable, getDownloadURL, getMetadata, deleteObject, list, listAll } from 'firebase/storage';
|
|
2
2
|
|
|
3
3
|
// src/core/emitter.ts
|
|
4
4
|
var Emitter = class {
|
|
@@ -320,6 +320,137 @@ var computeRetryDelay = (failedAttempt, options) => {
|
|
|
320
320
|
return Math.round(base * (0.5 + Math.random() * 0.5));
|
|
321
321
|
};
|
|
322
322
|
|
|
323
|
+
// src/core/validation.ts
|
|
324
|
+
var VALIDATION_ERROR_CODES = {
|
|
325
|
+
extensionNotAllowed: "validation/extension-not-allowed",
|
|
326
|
+
fileTooLarge: "validation/file-too-large",
|
|
327
|
+
imageDimensionUnavailable: "validation/image-dimension-unavailable",
|
|
328
|
+
imageDimensionsUnreadable: "validation/image-dimensions-unreadable",
|
|
329
|
+
imageHeightTooLarge: "validation/image-height-too-large",
|
|
330
|
+
imageWidthTooLarge: "validation/image-width-too-large",
|
|
331
|
+
mimeTypeNotAllowed: "validation/mime-type-not-allowed"
|
|
332
|
+
};
|
|
333
|
+
var ValidationError = class extends Error {
|
|
334
|
+
name = "ValidationError";
|
|
335
|
+
code;
|
|
336
|
+
constructor(message, code) {
|
|
337
|
+
super(message);
|
|
338
|
+
this.code = code;
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
var normalizeExtension = (extension) => {
|
|
342
|
+
const lower = extension.toLowerCase();
|
|
343
|
+
return lower.startsWith(".") ? lower : `.${lower}`;
|
|
344
|
+
};
|
|
345
|
+
var getFileExtension = (fileName) => {
|
|
346
|
+
const dot = fileName.lastIndexOf(".");
|
|
347
|
+
if (dot === -1) {
|
|
348
|
+
return "";
|
|
349
|
+
}
|
|
350
|
+
return fileName.slice(dot).toLowerCase();
|
|
351
|
+
};
|
|
352
|
+
var formatBytes = (bytes) => {
|
|
353
|
+
if (bytes < 1024) {
|
|
354
|
+
return `${bytes} B`;
|
|
355
|
+
}
|
|
356
|
+
if (bytes < 1024 * 1024) {
|
|
357
|
+
return `${Math.round(bytes / 1024)} KB`;
|
|
358
|
+
}
|
|
359
|
+
return `${Math.round(bytes / (1024 * 1024))} MB`;
|
|
360
|
+
};
|
|
361
|
+
var isImageFile = (file) => file.type.startsWith("image/");
|
|
362
|
+
var needsImageDimensionValidation = (options) => options.maxImageWidth !== void 0 || options.maxImageHeight !== void 0;
|
|
363
|
+
var validateUploadSync = (file, options) => {
|
|
364
|
+
if (options.maxSizeBytes !== void 0 && file.size > options.maxSizeBytes) {
|
|
365
|
+
return new ValidationError(
|
|
366
|
+
`File size ${formatBytes(file.size)} exceeds maximum of ${formatBytes(options.maxSizeBytes)}`,
|
|
367
|
+
VALIDATION_ERROR_CODES.fileTooLarge
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
if (options.allowedMimeTypes !== void 0) {
|
|
371
|
+
const allowed = options.allowedMimeTypes.map((type) => type.toLowerCase());
|
|
372
|
+
const mime = file.type.toLowerCase();
|
|
373
|
+
if (!allowed.includes(mime)) {
|
|
374
|
+
return new ValidationError(
|
|
375
|
+
`File type ${file.type || "(unknown)"} is not allowed`,
|
|
376
|
+
VALIDATION_ERROR_CODES.mimeTypeNotAllowed
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
if (options.allowedExtensions !== void 0) {
|
|
381
|
+
const extension = getFileExtension(file.name);
|
|
382
|
+
const allowed = options.allowedExtensions.map(normalizeExtension);
|
|
383
|
+
if (!allowed.includes(extension)) {
|
|
384
|
+
return new ValidationError(
|
|
385
|
+
`File extension ${extension || "(none)"} is not allowed`,
|
|
386
|
+
VALIDATION_ERROR_CODES.extensionNotAllowed
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return null;
|
|
391
|
+
};
|
|
392
|
+
var readImageDimensions = async (file) => {
|
|
393
|
+
if (typeof createImageBitmap === "undefined") {
|
|
394
|
+
throw new ValidationError(
|
|
395
|
+
"Image dimension validation is not available",
|
|
396
|
+
VALIDATION_ERROR_CODES.imageDimensionUnavailable
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
const bitmap = await createImageBitmap(file);
|
|
400
|
+
const dimensions = {
|
|
401
|
+
height: bitmap.height,
|
|
402
|
+
width: bitmap.width
|
|
403
|
+
};
|
|
404
|
+
bitmap.close();
|
|
405
|
+
return dimensions;
|
|
406
|
+
};
|
|
407
|
+
var validateImageDimensionLimits = (dimensions, options) => {
|
|
408
|
+
if (options.maxImageWidth !== void 0 && dimensions.width > options.maxImageWidth) {
|
|
409
|
+
return new ValidationError(
|
|
410
|
+
`Image width ${dimensions.width}px exceeds maximum of ${options.maxImageWidth}px`,
|
|
411
|
+
VALIDATION_ERROR_CODES.imageWidthTooLarge
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
if (options.maxImageHeight !== void 0 && dimensions.height > options.maxImageHeight) {
|
|
415
|
+
return new ValidationError(
|
|
416
|
+
`Image height ${dimensions.height}px exceeds maximum of ${options.maxImageHeight}px`,
|
|
417
|
+
VALIDATION_ERROR_CODES.imageHeightTooLarge
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
return null;
|
|
421
|
+
};
|
|
422
|
+
var validateImageDimensions = async (file, options) => {
|
|
423
|
+
if (!needsImageDimensionValidation(options)) {
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
if (!isImageFile(file)) {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
let dimensions;
|
|
430
|
+
try {
|
|
431
|
+
dimensions = await readImageDimensions(file);
|
|
432
|
+
} catch (error) {
|
|
433
|
+
if (error instanceof ValidationError) {
|
|
434
|
+
return error;
|
|
435
|
+
}
|
|
436
|
+
return new ValidationError(
|
|
437
|
+
"Unable to read image dimensions",
|
|
438
|
+
VALIDATION_ERROR_CODES.imageDimensionsUnreadable
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
return validateImageDimensionLimits(dimensions, options);
|
|
442
|
+
};
|
|
443
|
+
var validateUpload = async (file, options) => {
|
|
444
|
+
if (!options) {
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
const syncError = validateUploadSync(file, options);
|
|
448
|
+
if (syncError) {
|
|
449
|
+
return syncError;
|
|
450
|
+
}
|
|
451
|
+
return await validateImageDimensions(file, options);
|
|
452
|
+
};
|
|
453
|
+
|
|
323
454
|
// src/core/upload-handle.ts
|
|
324
455
|
var UploadHandle = class extends Emitter {
|
|
325
456
|
upload;
|
|
@@ -368,10 +499,11 @@ var UploadHandle = class extends Emitter {
|
|
|
368
499
|
this.onChange();
|
|
369
500
|
}
|
|
370
501
|
/** @internal */
|
|
371
|
-
|
|
502
|
+
_prepareAttempt(attempt) {
|
|
372
503
|
if (this.terminated) {
|
|
373
504
|
return;
|
|
374
505
|
}
|
|
506
|
+
this.upload.attempt = attempt;
|
|
375
507
|
this.upload.retryAttempt = attempt;
|
|
376
508
|
this.upload.bytesTransferred = 0;
|
|
377
509
|
this.upload.progress = 0;
|
|
@@ -385,6 +517,7 @@ var UploadHandle = class extends Emitter {
|
|
|
385
517
|
if (this.terminated) {
|
|
386
518
|
return;
|
|
387
519
|
}
|
|
520
|
+
this.upload.attempt = details.attempt;
|
|
388
521
|
this.upload.retryAttempt = details.attempt;
|
|
389
522
|
this.upload.error = details.error;
|
|
390
523
|
this.task = null;
|
|
@@ -513,6 +646,14 @@ var StorageManager = class {
|
|
|
513
646
|
async delete(path) {
|
|
514
647
|
await this.provider.delete(path);
|
|
515
648
|
}
|
|
649
|
+
/** Lists folders and files at `prefix` with optional pagination. */
|
|
650
|
+
async list(prefix, options) {
|
|
651
|
+
return await this.provider.list(prefix, options);
|
|
652
|
+
}
|
|
653
|
+
/** Lists all folders and files at `prefix` (auto-paginates internally). */
|
|
654
|
+
async listAll(prefix) {
|
|
655
|
+
return await this.provider.listAll(prefix);
|
|
656
|
+
}
|
|
516
657
|
/** Starts the file upload.`options.path` is the object path in storage (see {@link UploadOptions}).
|
|
517
658
|
*
|
|
518
659
|
* @returns An {@link UploadHandle} to control the upload: `pause`, `resume`, `cancel`, and listen for progress with `.on`.
|
|
@@ -522,7 +663,7 @@ var StorageManager = class {
|
|
|
522
663
|
this.uploadOptionsByHandleId.set(handle.upload.id, options);
|
|
523
664
|
this.uploadHandles.push(handle);
|
|
524
665
|
this.notifyChange();
|
|
525
|
-
this.
|
|
666
|
+
this.validateAndStartUpload(handle, options);
|
|
526
667
|
return handle;
|
|
527
668
|
}
|
|
528
669
|
/**
|
|
@@ -556,7 +697,7 @@ var StorageManager = class {
|
|
|
556
697
|
const options = this.uploadOptionsByHandleId.get(handle.upload.id) ?? {
|
|
557
698
|
path: handle.upload.path
|
|
558
699
|
};
|
|
559
|
-
this.
|
|
700
|
+
this.validateAndStartUpload(handle, options);
|
|
560
701
|
},
|
|
561
702
|
uploads: handles
|
|
562
703
|
});
|
|
@@ -580,6 +721,38 @@ var StorageManager = class {
|
|
|
580
721
|
this.notifyChange();
|
|
581
722
|
});
|
|
582
723
|
}
|
|
724
|
+
validateAndStartUpload(handle, options) {
|
|
725
|
+
if (options.validate) {
|
|
726
|
+
const syncError = validateUploadSync(
|
|
727
|
+
handle.upload.file,
|
|
728
|
+
options.validate
|
|
729
|
+
);
|
|
730
|
+
if (syncError) {
|
|
731
|
+
queueMicrotask(() => {
|
|
732
|
+
handle._reportError(syncError);
|
|
733
|
+
});
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
if (needsImageDimensionValidation(options.validate)) {
|
|
737
|
+
void this.runImageValidation(handle, options);
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
this.startUpload(handle, options);
|
|
742
|
+
}
|
|
743
|
+
async runImageValidation(handle, options) {
|
|
744
|
+
const { validate } = options;
|
|
745
|
+
if (!validate) {
|
|
746
|
+
this.startUpload(handle, options);
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
const error = await validateImageDimensions(handle.upload.file, validate);
|
|
750
|
+
if (error) {
|
|
751
|
+
handle._reportError(error);
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
this.startUpload(handle, options);
|
|
755
|
+
}
|
|
583
756
|
startUpload(handle, options) {
|
|
584
757
|
const retryOptions = resolveRetryOptions(options.retry);
|
|
585
758
|
const maxAttempts = retryOptions ? retryOptions.maxRetries + 1 : 1;
|
|
@@ -608,7 +781,7 @@ var StorageManager = class {
|
|
|
608
781
|
return;
|
|
609
782
|
}
|
|
610
783
|
attempt += 1;
|
|
611
|
-
handle.
|
|
784
|
+
handle._prepareAttempt(attempt);
|
|
612
785
|
currentTask = this.provider.upload(handle.upload.file, options, {
|
|
613
786
|
onError: (error) => {
|
|
614
787
|
currentTask = null;
|
|
@@ -691,7 +864,14 @@ var FirebaseStorageProvider = class {
|
|
|
691
864
|
}
|
|
692
865
|
upload(file, options, callbacks) {
|
|
693
866
|
const storageRef = ref(this.storage, options.path);
|
|
694
|
-
const metadata = options.
|
|
867
|
+
const metadata = options.contentType !== void 0 || options.customMetadata !== void 0 ? {
|
|
868
|
+
...options.contentType !== void 0 && {
|
|
869
|
+
contentType: options.contentType
|
|
870
|
+
},
|
|
871
|
+
...options.customMetadata !== void 0 && {
|
|
872
|
+
customMetadata: options.customMetadata
|
|
873
|
+
}
|
|
874
|
+
} : void 0;
|
|
695
875
|
const task = uploadBytesResumable(storageRef, file, metadata);
|
|
696
876
|
task.on(
|
|
697
877
|
"state_changed",
|
|
@@ -752,6 +932,34 @@ var FirebaseStorageProvider = class {
|
|
|
752
932
|
async delete(path) {
|
|
753
933
|
await deleteObject(ref(this.storage, path));
|
|
754
934
|
}
|
|
935
|
+
async list(prefix, options) {
|
|
936
|
+
const result = await list(ref(this.storage, prefix), {
|
|
937
|
+
...options?.maxResults !== void 0 && {
|
|
938
|
+
maxResults: options.maxResults
|
|
939
|
+
},
|
|
940
|
+
...options?.pageToken !== void 0 && { pageToken: options.pageToken }
|
|
941
|
+
});
|
|
942
|
+
return {
|
|
943
|
+
items: result.items.map((item) => ({
|
|
944
|
+
name: item.name,
|
|
945
|
+
path: item.fullPath
|
|
946
|
+
})),
|
|
947
|
+
...result.nextPageToken !== void 0 && {
|
|
948
|
+
nextPageToken: result.nextPageToken
|
|
949
|
+
},
|
|
950
|
+
prefixes: result.prefixes.map((folderRef) => folderRef.fullPath)
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
async listAll(prefix) {
|
|
954
|
+
const result = await listAll(ref(this.storage, prefix));
|
|
955
|
+
return {
|
|
956
|
+
items: result.items.map((item) => ({
|
|
957
|
+
name: item.name,
|
|
958
|
+
path: item.fullPath
|
|
959
|
+
})),
|
|
960
|
+
prefixes: result.prefixes.map((folderRef) => folderRef.fullPath)
|
|
961
|
+
};
|
|
962
|
+
}
|
|
755
963
|
};
|
|
756
964
|
|
|
757
965
|
// src/firebase-storage-manager.ts
|
|
@@ -761,6 +969,6 @@ var StorageManager2 = class extends StorageManager {
|
|
|
761
969
|
}
|
|
762
970
|
};
|
|
763
971
|
|
|
764
|
-
export { BatchHandle, DEFAULT_RETRY_OPTIONS, StorageManager2 as StorageManager, UploadHandle, computeRetryDelay, getStorageErrorCode, isRetryableStorageError, resolveRetryOptions };
|
|
765
|
-
//# sourceMappingURL=chunk-
|
|
766
|
-
//# sourceMappingURL=chunk-
|
|
972
|
+
export { BatchHandle, DEFAULT_RETRY_OPTIONS, StorageManager2 as StorageManager, UploadHandle, VALIDATION_ERROR_CODES, ValidationError, computeRetryDelay, getFileExtension, getStorageErrorCode, isRetryableStorageError, readImageDimensions, resolveRetryOptions, validateImageDimensionLimits, validateImageDimensions, validateUpload, validateUploadSync };
|
|
973
|
+
//# sourceMappingURL=chunk-PTKP7RWS.js.map
|
|
974
|
+
//# sourceMappingURL=chunk-PTKP7RWS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/emitter.ts","../src/core/batch-handle.ts","../src/core/retry.ts","../src/core/validation.ts","../src/core/upload-handle.ts","../src/core/storage-manager.ts","../src/providers/firebase-provider.ts","../src/firebase-storage-manager.ts"],"names":["StorageManager"],"mappings":"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","file":"chunk-PTKP7RWS.js","sourcesContent":["type Listener<TPayload> = (payload: TPayload) => void;\n\nexport class Emitter<TEvents extends Record<string, unknown>> {\n private listeners: { [K in keyof TEvents]?: Set<Listener<TEvents[K]>> } = {};\n\n /**\n * @param event The event to listen for.\n * @param listener The function to call when the event is emitted.\n * @returns A function to unsubscribe from the event.\n */\n on<K extends keyof TEvents>(event: K, listener: Listener<TEvents[K]>) {\n let listeners = this.listeners[event];\n if (!listeners) {\n listeners = new Set();\n this.listeners[event] = listeners;\n }\n\n listeners.add(listener);\n\n return () => {\n this.listeners[event]?.delete(listener);\n };\n }\n\n /**\n * @param event The event to emit.\n * @param payload The payload to emit.\n */\n protected emit<K extends keyof TEvents>(event: K, payload: TEvents[K]) {\n const listeners = this.listeners[event];\n\n if (!listeners) {\n return;\n }\n\n for (const listener of listeners) {\n listener(payload);\n }\n }\n}\n","import type { UploadBatch, UploadItem } from \"../types/upload\";\nimport { Emitter } from \"./emitter\";\nimport type { UploadHandle, UploadRetryEvent } from \"./upload-handle\";\n\n/**\n * Events on a batch from {@link StorageManager.uploadFiles}. `progress` / `change` carry a {@link UploadBatch} snapshot.\n * `uploadSuccess`, `uploadError`, and `uploadRetry` fire once per child (retry can fire multiple times per child). When all children are done: `success` (normal end) or `error` (only if `continueOnError` was `false` and one failed).\n */\nexport interface BatchHandleEvents extends Record<string, unknown> {\n progress: UploadBatch;\n uploadSuccess: UploadItem;\n uploadError: UploadItem;\n uploadRetry: UploadRetryEvent;\n success: UploadBatch;\n error: UploadBatch;\n change: UploadBatch;\n}\n\n/** Settings for {@link StorageManager.uploadFiles} (third argument). */\nexport interface BatchOptions {\n /** How many files upload at the same time. Default is 3. */\n concurrency?: number;\n /**\n * `true` (default): if one file fails, the others keep going. When every file has finished, the batch fires `success` — look at each upload for errors.\n *\n * `false`: the first failure stops the other files and the batch fires `error`.\n */\n continueOnError?: boolean;\n}\n\nexport interface BatchHandleInit {\n id: string;\n uploads: UploadHandle[];\n options: BatchOptions;\n startNext: (handle: UploadHandle) => void;\n onChange: () => void;\n}\n\n/**\n * A group of files from {@link StorageManager.uploadFiles}. Use `.on(...)` like a single {@link UploadHandle}, plus `snapshot()` for totals.\n */\nexport class BatchHandle extends Emitter<BatchHandleEvents> {\n public readonly id: string;\n public readonly uploads: UploadHandle[];\n\n private readonly concurrency: number;\n private readonly continueOnError: boolean;\n private readonly startNext: (handle: UploadHandle) => void;\n private readonly onChange: () => void;\n\n private running = 0;\n private nextIdx = 0;\n /** Indices that were started via {@link fillSlots} and still hold a concurrency slot. */\n private readonly activeSlots = new Set<number>();\n private settledCount = 0;\n private succeededCount = 0;\n private failedCount = 0;\n private failedFast = false;\n private canceled = false;\n private paused = false;\n private terminalEmitted = false;\n\n // Stable view of UploadItems; the items themselves mutate in place, but the\n // array reference never changes, so we allocate it once instead of rebuilding\n // it on every snapshot.\n private readonly uploadsView: UploadItem[];\n\n // Running aggregates updated incrementally on each child event so snapshot()\n // is O(1) instead of O(n) per progress tick.\n private aggregateBytesTransferred = 0;\n private aggregateTotalBytes = 0;\n private readonly lastBytes: number[];\n private readonly lastTotal: number[];\n\n constructor(init: BatchHandleInit) {\n super();\n this.id = init.id;\n this.uploads = init.uploads;\n this.concurrency = Math.max(1, init.options.concurrency ?? 3);\n this.continueOnError = init.options.continueOnError ?? true;\n this.startNext = init.startNext;\n this.onChange = init.onChange;\n\n this.uploadsView = init.uploads.map((h) => h.upload);\n this.lastBytes = Array.from(\n { length: init.uploads.length },\n (): number => 0\n );\n this.lastTotal = Array.from(\n { length: init.uploads.length },\n (): number => 0\n );\n for (let i = 0; i < this.uploadsView.length; i += 1) {\n const u = this.uploadsView[i];\n if (!u) {\n continue;\n }\n this.lastBytes[i] = u.bytesTransferred;\n this.lastTotal[i] = u.totalBytes;\n this.aggregateBytesTransferred += u.bytesTransferred;\n this.aggregateTotalBytes += u.totalBytes;\n }\n\n for (let idx = 0; idx < this.uploads.length; idx += 1) {\n const child = this.uploads[idx];\n if (!child) {\n continue;\n }\n child.on(\"progress\", (upload) => {\n this.handleChildProgress(idx, upload);\n });\n child.on(\"retry\", (retryEvent) => {\n this.handleChildRetry(idx, retryEvent);\n });\n child.on(\"success\", (upload) => {\n this.handleChildSettled(idx, upload, \"success\");\n });\n child.on(\"error\", (upload) => {\n this.handleChildSettled(idx, upload, \"error\");\n });\n child.on(\"canceled\", (upload) => {\n this.handleChildSettled(idx, upload, \"canceled\");\n });\n }\n }\n\n /** @internal */\n _start(): void {\n this.fillSlots();\n }\n\n cancel(): void {\n if (this.canceled || this.terminalEmitted) {\n return;\n }\n this.canceled = true;\n for (const h of this.uploads) {\n const s = h.upload.status;\n if (\n s === \"queued\" ||\n s === \"uploading\" ||\n s === \"retrying\" ||\n s === \"paused\"\n ) {\n h.cancel();\n }\n }\n this.onChange();\n }\n\n pause(): void {\n if (this.paused || this.canceled || this.terminalEmitted) {\n return;\n }\n this.paused = true;\n for (const h of this.uploads) {\n if (h.upload.status === \"uploading\" || h.upload.status === \"retrying\") {\n h.pause();\n }\n }\n this.onChange();\n }\n\n resume(): void {\n if (!this.paused || this.canceled || this.terminalEmitted) {\n return;\n }\n this.paused = false;\n for (const h of this.uploads) {\n if (h.upload.status === \"paused\") {\n h.resume();\n }\n }\n this.fillSlots();\n this.onChange();\n }\n\n snapshot(): UploadBatch {\n const totalProgress =\n this.aggregateTotalBytes > 0\n ? (this.aggregateBytesTransferred / this.aggregateTotalBytes) * 100\n : 0;\n return {\n completedCount: this.succeededCount,\n failedCount: this.failedCount,\n id: this.id,\n totalProgress,\n uploads: this.uploadsView,\n };\n }\n\n private updateAggregate(idx: number, u: UploadItem): void {\n const prevBytes = this.lastBytes[idx] ?? 0;\n const prevTotal = this.lastTotal[idx] ?? 0;\n this.aggregateBytesTransferred += u.bytesTransferred - prevBytes;\n this.aggregateTotalBytes += u.totalBytes - prevTotal;\n this.lastBytes[idx] = u.bytesTransferred;\n this.lastTotal[idx] = u.totalBytes;\n }\n\n private fillSlots(): void {\n while (\n !this.canceled &&\n !this.paused &&\n !this.failedFast &&\n this.running < this.concurrency &&\n this.nextIdx < this.uploads.length\n ) {\n const idx = this.nextIdx;\n this.nextIdx += 1;\n const handle = this.uploads[idx];\n if (!handle || handle.upload.status !== \"queued\") {\n continue;\n }\n this.activeSlots.add(idx);\n this.running += 1;\n this.startNext(handle);\n }\n }\n\n private handleChildProgress(idx: number, upload: UploadItem): void {\n this.updateAggregate(idx, upload);\n const snap = this.snapshot();\n this.emit(\"progress\", snap);\n this.emit(\"change\", snap);\n }\n\n private handleChildRetry(idx: number, event: UploadRetryEvent): void {\n this.updateAggregate(idx, event.upload);\n this.emit(\"uploadRetry\", event);\n const snap = this.snapshot();\n this.emit(\"change\", snap);\n }\n\n private handleChildSettled(\n idx: number,\n upload: UploadItem,\n kind: \"success\" | \"error\" | \"canceled\"\n ): void {\n this.updateAggregate(idx, upload);\n if (this.activeSlots.delete(idx)) {\n this.running = Math.max(0, this.running - 1);\n }\n this.settledCount += 1;\n\n if (kind === \"success\") {\n this.succeededCount += 1;\n this.emit(\"uploadSuccess\", upload);\n } else if (kind === \"error\") {\n this.failedCount += 1;\n this.emit(\"uploadError\", upload);\n }\n\n const snap = this.snapshot();\n this.emit(\"change\", snap);\n\n if (\n kind === \"error\" &&\n !this.continueOnError &&\n !this.failedFast &&\n !this.canceled\n ) {\n this.failedFast = true;\n for (const h of this.uploads) {\n if (h.upload.id === upload.id) {\n continue;\n }\n const s = h.upload.status;\n if (\n s === \"queued\" ||\n s === \"uploading\" ||\n s === \"retrying\" ||\n s === \"paused\"\n ) {\n h.cancel();\n }\n }\n this.terminalEmitted = true;\n this.emit(\"error\", snap);\n this.onChange();\n return;\n }\n\n if (this.failedFast || this.canceled) {\n // we call this because a task can canceled as seen above\n // by h.cancel(). Which then triggers the handelchildSettled call above.\n this.onChange();\n return;\n }\n\n this.fillSlots();\n\n if (this.settledCount >= this.uploads.length && !this.terminalEmitted) {\n this.terminalEmitted = true;\n this.emit(\"success\", snap);\n }\n\n this.onChange();\n }\n}\n","import type { RetryOptions } from \"../types/provider\";\n\nexport interface ResolvedRetryOptions {\n maxRetries: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n isRetryable?: (error: Error) => boolean;\n}\n\nexport const DEFAULT_RETRY_OPTIONS: ResolvedRetryOptions = {\n initialDelayMs: 1000,\n jitter: true,\n maxDelayMs: 30_000,\n maxRetries: 3,\n};\n\nconst NON_RETRYABLE_CODES = new Set([\n \"storage/canceled\",\n \"storage/unauthorized\",\n \"storage/unauthenticated\",\n \"storage/quota-exceeded\",\n \"storage/invalid-argument\",\n \"storage/invalid-argument-count\",\n \"storage/invalid-url\",\n \"storage/invalid-default-bucket\",\n \"storage/no-default-bucket\",\n \"storage/bucket-not-found\",\n \"storage/project-not-found\",\n \"storage/invalid-root-operation\",\n \"storage/invalid-event-name\",\n \"storage/invalid-format\",\n \"storage/no-download-url\",\n \"storage/unauthorized-app\",\n \"storage/unsupported-environment\",\n]);\n\nconst RETRYABLE_CODES = new Set([\n \"storage/retry-limit-exceeded\",\n \"storage/unknown\",\n \"storage/invalid-checksum\",\n \"storage/cannot-slice-blob\",\n \"storage/server-file-wrong-size\",\n]);\n\n/** Resolves upload retry settings. Returns `null` when retries are disabled. */\nexport const resolveRetryOptions = (\n retry?: RetryOptions | false\n): ResolvedRetryOptions | null => {\n if (retry === false) {\n return null;\n }\n return {\n ...DEFAULT_RETRY_OPTIONS,\n ...retry,\n };\n};\n\nconst hasStorageErrorCode = (error: Error): error is Error & { code: string } =>\n \"code\" in error && typeof error.code === \"string\";\n\n/** Reads a Firebase-style `code` from an error without importing Firebase types. */\nexport const getStorageErrorCode = (error: Error): string | undefined => {\n if (!hasStorageErrorCode(error)) {\n return undefined;\n }\n return error.code;\n};\n\n/** Whether an upload error should trigger another attempt. */\nexport const isRetryableStorageError = (\n error: Error,\n options: ResolvedRetryOptions | null\n): boolean => {\n if (!options) {\n return false;\n }\n\n if (options.isRetryable) {\n return options.isRetryable(error);\n }\n\n const code = getStorageErrorCode(error);\n if (code !== undefined) {\n if (NON_RETRYABLE_CODES.has(code)) {\n return false;\n }\n if (RETRYABLE_CODES.has(code)) {\n return true;\n }\n return false;\n }\n\n return true;\n};\n\n/** Computes backoff delay after a failed attempt (1-based). */\nexport const computeRetryDelay = (\n failedAttempt: number,\n options: ResolvedRetryOptions\n): number => {\n const base = Math.min(\n options.maxDelayMs,\n options.initialDelayMs * 2 ** (failedAttempt - 1)\n );\n if (!options.jitter) {\n return base;\n }\n return Math.round(base * (0.5 + Math.random() * 0.5));\n};\n","import type { UploadValidationOptions } from \"../types/provider\";\n\nexport const VALIDATION_ERROR_CODES = {\n extensionNotAllowed: \"validation/extension-not-allowed\",\n fileTooLarge: \"validation/file-too-large\",\n imageDimensionUnavailable: \"validation/image-dimension-unavailable\",\n imageDimensionsUnreadable: \"validation/image-dimensions-unreadable\",\n imageHeightTooLarge: \"validation/image-height-too-large\",\n imageWidthTooLarge: \"validation/image-width-too-large\",\n mimeTypeNotAllowed: \"validation/mime-type-not-allowed\",\n} as const;\n\nexport type ValidationErrorCode =\n (typeof VALIDATION_ERROR_CODES)[keyof typeof VALIDATION_ERROR_CODES];\n\nexport class ValidationError extends Error {\n override readonly name = \"ValidationError\";\n readonly code: ValidationErrorCode;\n\n constructor(message: string, code: ValidationErrorCode) {\n super(message);\n this.code = code;\n }\n}\n\nexport interface ImageDimensions {\n width: number;\n height: number;\n}\n\nconst normalizeExtension = (extension: string): string => {\n const lower = extension.toLowerCase();\n return lower.startsWith(\".\") ? lower : `.${lower}`;\n};\n\nexport const getFileExtension = (fileName: string): string => {\n const dot = fileName.lastIndexOf(\".\");\n if (dot === -1) {\n return \"\";\n }\n return fileName.slice(dot).toLowerCase();\n};\n\nconst formatBytes = (bytes: number): string => {\n if (bytes < 1024) {\n return `${bytes} B`;\n }\n if (bytes < 1024 * 1024) {\n return `${Math.round(bytes / 1024)} KB`;\n }\n return `${Math.round(bytes / (1024 * 1024))} MB`;\n};\n\nconst isImageFile = (file: File): boolean => file.type.startsWith(\"image/\");\n\nexport const needsImageDimensionValidation = (\n options: UploadValidationOptions\n): boolean =>\n options.maxImageWidth !== undefined || options.maxImageHeight !== undefined;\n\n/** Synchronous checks: size, MIME type, and extension. */\nexport const validateUploadSync = (\n file: File,\n options: UploadValidationOptions\n): ValidationError | null => {\n if (options.maxSizeBytes !== undefined && file.size > options.maxSizeBytes) {\n return new ValidationError(\n `File size ${formatBytes(file.size)} exceeds maximum of ${formatBytes(options.maxSizeBytes)}`,\n VALIDATION_ERROR_CODES.fileTooLarge\n );\n }\n\n if (options.allowedMimeTypes !== undefined) {\n const allowed = options.allowedMimeTypes.map((type) => type.toLowerCase());\n const mime = file.type.toLowerCase();\n if (!allowed.includes(mime)) {\n return new ValidationError(\n `File type ${file.type || \"(unknown)\"} is not allowed`,\n VALIDATION_ERROR_CODES.mimeTypeNotAllowed\n );\n }\n }\n\n if (options.allowedExtensions !== undefined) {\n const extension = getFileExtension(file.name);\n const allowed = options.allowedExtensions.map(normalizeExtension);\n if (!allowed.includes(extension)) {\n return new ValidationError(\n `File extension ${extension || \"(none)\"} is not allowed`,\n VALIDATION_ERROR_CODES.extensionNotAllowed\n );\n }\n }\n\n return null;\n};\n\nexport const readImageDimensions = async (\n file: File\n): Promise<ImageDimensions> => {\n if (typeof createImageBitmap === \"undefined\") {\n throw new ValidationError(\n \"Image dimension validation is not available\",\n VALIDATION_ERROR_CODES.imageDimensionUnavailable\n );\n }\n\n const bitmap = await createImageBitmap(file);\n const dimensions = {\n height: bitmap.height,\n width: bitmap.width,\n };\n bitmap.close();\n return dimensions;\n};\n\n/** Checks width/height against configured limits. */\nexport const validateImageDimensionLimits = (\n dimensions: ImageDimensions,\n options: UploadValidationOptions\n): ValidationError | null => {\n if (\n options.maxImageWidth !== undefined &&\n dimensions.width > options.maxImageWidth\n ) {\n return new ValidationError(\n `Image width ${dimensions.width}px exceeds maximum of ${options.maxImageWidth}px`,\n VALIDATION_ERROR_CODES.imageWidthTooLarge\n );\n }\n\n if (\n options.maxImageHeight !== undefined &&\n dimensions.height > options.maxImageHeight\n ) {\n return new ValidationError(\n `Image height ${dimensions.height}px exceeds maximum of ${options.maxImageHeight}px`,\n VALIDATION_ERROR_CODES.imageHeightTooLarge\n );\n }\n\n return null;\n};\n\n/** Async image dimension checks. Skipped for non-image files. */\nexport const validateImageDimensions = async (\n file: File,\n options: UploadValidationOptions\n): Promise<ValidationError | null> => {\n if (!needsImageDimensionValidation(options)) {\n return null;\n }\n\n if (!isImageFile(file)) {\n return null;\n }\n\n let dimensions: ImageDimensions;\n try {\n dimensions = await readImageDimensions(file);\n } catch (error) {\n if (error instanceof ValidationError) {\n return error;\n }\n return new ValidationError(\n \"Unable to read image dimensions\",\n VALIDATION_ERROR_CODES.imageDimensionsUnreadable\n );\n }\n\n return validateImageDimensionLimits(dimensions, options);\n};\n\n/** Runs all upload validation rules. Returns the first error, if any. */\nexport const validateUpload = async (\n file: File,\n options: UploadValidationOptions | undefined\n): Promise<ValidationError | null> => {\n if (!options) {\n return null;\n }\n\n const syncError = validateUploadSync(file, options);\n if (syncError) {\n return syncError;\n }\n\n return await validateImageDimensions(file, options);\n};\n","import type { ProviderUploadTask } from \"../types/provider\";\nimport type { UploadItem, UploadStatus } from \"../types/upload\";\nimport { Emitter } from \"./emitter\";\n\nexport interface UploadRetryEvent {\n upload: UploadItem;\n error: Error;\n attempt: number;\n maxAttempts: number;\n delayMs: number;\n}\n\nexport interface UploadRetryBackoffDetails {\n attempt: number;\n maxAttempts: number;\n delayMs: number;\n error: Error;\n}\n\nexport interface UploadControlHooks {\n abort: () => void;\n pauseDuringRetry?: () => void;\n resumeDuringRetry?: () => void;\n}\n\nexport interface UploadHandleEvents extends Record<string, unknown> {\n progress: UploadItem;\n success: UploadItem;\n error: UploadItem;\n canceled: UploadItem;\n statusChange: UploadItem;\n retry: UploadRetryEvent;\n}\n\n/** Controls file upload and tracks its progress.\n *\n * @param upload The upload item to control.\n * @param onChange A function to call when the upload status changes.\n * @returns An {@link UploadHandle} to control the upload: `pause`, `resume`, `cancel`, and listen for progress with `.on`.\n */\nexport class UploadHandle extends Emitter<UploadHandleEvents> {\n public readonly upload: UploadItem;\n\n private task: ProviderUploadTask | null = null;\n private readonly onChange: () => void;\n private terminated = false;\n private controlHooks: UploadControlHooks | null = null;\n private pausedDuringRetry = false;\n\n constructor(upload: UploadItem, onChange: () => void) {\n super();\n this.upload = upload;\n this.onChange = onChange;\n }\n\n /** @internal */\n _attachTask(task: ProviderUploadTask): void {\n this.task = task;\n }\n\n /** @internal */\n _registerControlHooks(hooks: UploadControlHooks): void {\n this.controlHooks = hooks;\n }\n\n /** @internal */\n _clearControlHooks(): void {\n this.controlHooks = null;\n }\n\n /** @internal */\n _setStatus(status: UploadStatus): void {\n if (this.upload.status === status) {\n return;\n }\n this.upload.status = status;\n this.emit(\"statusChange\", this.upload);\n }\n\n /** @internal */\n _reportProgress(bytesTransferred: number, totalBytes: number): void {\n if (this.terminated) {\n return;\n }\n this.upload.bytesTransferred = bytesTransferred;\n this.upload.totalBytes = totalBytes;\n this.upload.progress =\n totalBytes > 0 ? (bytesTransferred / totalBytes) * 100 : 0;\n if (this.upload.status !== \"uploading\") {\n this._setStatus(\"uploading\");\n }\n this.emit(\"progress\", this.upload);\n this.onChange();\n }\n\n /** @internal */\n _prepareAttempt(attempt: number): void {\n if (this.terminated) {\n return;\n }\n this.upload.attempt = attempt;\n // oxlint-disable-next-line typescript/no-deprecated -- intentionally mirroring the deprecated alias\n this.upload.retryAttempt = attempt;\n this.upload.bytesTransferred = 0;\n this.upload.progress = 0;\n this.upload.error = undefined;\n this.pausedDuringRetry = false;\n this._setStatus(\"uploading\");\n this.onChange();\n }\n\n /** @internal */\n _enterRetryBackoff(details: UploadRetryBackoffDetails): void {\n if (this.terminated) {\n return;\n }\n this.upload.attempt = details.attempt;\n // oxlint-disable-next-line typescript/no-deprecated -- intentionally mirroring the deprecated alias\n this.upload.retryAttempt = details.attempt;\n this.upload.error = details.error;\n this.task = null;\n this._setStatus(\"retrying\");\n this.emit(\"retry\", {\n attempt: details.attempt,\n delayMs: details.delayMs,\n error: details.error,\n maxAttempts: details.maxAttempts,\n upload: this.upload,\n });\n this.onChange();\n }\n\n /** @internal */\n _reportSuccess(downloadURL: string): void {\n if (this.terminated) {\n return;\n }\n this.terminated = true;\n this.upload.downloadURL = downloadURL;\n this.upload.progress = 100;\n this._clearControlHooks();\n this._setStatus(\"success\");\n this.emit(\"success\", this.upload);\n this.onChange();\n }\n\n /** @internal */\n _reportError(error: Error): void {\n if (this.terminated) {\n return;\n }\n this.terminated = true;\n this.upload.error = error;\n this._clearControlHooks();\n this._setStatus(\"error\");\n this.emit(\"error\", this.upload);\n this.onChange();\n }\n\n cancel(): void {\n if (this.terminated) {\n return;\n }\n this.terminated = true;\n this.controlHooks?.abort();\n this.task?.cancel();\n this._clearControlHooks();\n this._setStatus(\"canceled\");\n this.emit(\"canceled\", this.upload);\n this.onChange();\n }\n\n pause(): void {\n if (this.terminated) {\n return;\n }\n if (this.upload.status === \"uploading\") {\n this.task?.pause?.();\n this._setStatus(\"paused\");\n this.onChange();\n return;\n }\n if (this.upload.status === \"retrying\") {\n this.pausedDuringRetry = true;\n this.controlHooks?.pauseDuringRetry?.();\n this._setStatus(\"paused\");\n this.onChange();\n }\n }\n\n resume(): void {\n if (this.terminated) {\n return;\n }\n if (this.upload.status !== \"paused\") {\n return;\n }\n\n if (this.pausedDuringRetry) {\n this.pausedDuringRetry = false;\n this.controlHooks?.resumeDuringRetry?.();\n this.onChange();\n return;\n }\n\n this.task?.resume?.();\n this._setStatus(\"uploading\");\n this.onChange();\n }\n}\n","import type { StorageProvider } from \"../providers/provider\";\nimport type { ListOptions, StorageListResult } from \"../types/list\";\nimport type { FileMetadata } from \"../types/metadata\";\nimport type { ProviderUploadTask, UploadOptions } from \"../types/provider\";\nimport type { StorageState, UploadItem } from \"../types/upload\";\nimport type { BatchOptions } from \"./batch-handle\";\nimport { BatchHandle } from \"./batch-handle\";\nimport {\n computeRetryDelay,\n isRetryableStorageError,\n resolveRetryOptions,\n} from \"./retry\";\nimport { UploadHandle } from \"./upload-handle\";\nimport {\n needsImageDimensionValidation,\n validateImageDimensions,\n validateUploadSync,\n} from \"./validation\";\n\n/**\n * Manages file uploads and storage queries.\n *\n * You can react in two ways: call `.on(...)` on each {@link UploadHandle} / {@link BatchHandle}, **or** call `subscribe` to get the same lists\n * that {@link StorageManager.getState} returns whenever anything changes (call the returned function to stop listening).\n *\n */\nexport class StorageManager {\n private readonly provider: StorageProvider;\n private readonly uploadHandles: UploadHandle[] = [];\n private readonly batches: BatchHandle[] = [];\n private readonly changeListeners = new Set<(state: StorageState) => void>();\n private cachedState: StorageState | null = null;\n private readonly uploadOptionsByHandleId = new Map<string, UploadOptions>();\n\n constructor(provider: StorageProvider) {\n this.provider = provider;\n }\n\n /** Current `uploads` and `batches` state. */\n getState = (): StorageState => {\n this.cachedState ??= {\n batches: this.batches.map((b) => b.snapshot()),\n uploads: this.uploadHandles.map((h) => h.upload),\n };\n return this.cachedState;\n };\n\n /** Runs `listener` after each change; returns a function — call it to unsubscribe. */\n subscribe = (listener: (state: StorageState) => void): (() => void) => {\n this.changeListeners.add(listener);\n return () => {\n this.changeListeners.delete(listener);\n };\n };\n\n /** Returns `true` if the object exists. Returns `false` only for not-found; other errors are thrown. */\n async exists(path: string): Promise<boolean> {\n return await this.provider.exists(path);\n }\n\n /** Returns metadata for the object at `path`. Throws if the object does not exist. */\n async getMetadata(path: string): Promise<FileMetadata> {\n return await this.provider.getMetadata(path);\n }\n\n /** Returns a download URL for the object at `path`. */\n async getDownloadURL(path: string): Promise<string> {\n return await this.provider.getDownloadURL(path);\n }\n\n /** Deletes the object at `path`. */\n async delete(path: string): Promise<void> {\n await this.provider.delete(path);\n }\n\n /** Lists folders and files at `prefix` with optional pagination. */\n async list(\n prefix: string,\n options?: ListOptions\n ): Promise<StorageListResult> {\n return await this.provider.list(prefix, options);\n }\n\n /** Lists all folders and files at `prefix` (auto-paginates internally). */\n async listAll(prefix: string): Promise<StorageListResult> {\n return await this.provider.listAll(prefix);\n }\n\n /** Starts the file upload.`options.path` is the object path in storage (see {@link UploadOptions}).\n *\n * @returns An {@link UploadHandle} to control the upload: `pause`, `resume`, `cancel`, and listen for progress with `.on`.\n */\n uploadFile(file: File, options: UploadOptions): UploadHandle {\n const handle = this.createHandle(file, { path: options.path });\n this.uploadOptionsByHandleId.set(handle.upload.id, options);\n this.uploadHandles.push(handle);\n this.notifyChange();\n this.validateAndStartUpload(handle, options);\n return handle;\n }\n\n /**\n * Upload several files as one batch. The optional third argument sets how many run at once\n * and what happens when one file fails — see {@link BatchOptions}.\n *\n * `optionsFor` picks storage options per file (same as `uploadFile`); index matches `files` order.\n * If `continueOnError` is `false`, the first failure cancels the other files and the batch fires `error`.\n * If it stays `true` (default), other files keep going; when every file has finished, the batch fires `success`.\n *\n */\n uploadFiles(\n files: File[],\n optionsFor: (file: File, index: number) => UploadOptions,\n batchOptions: BatchOptions = {}\n ): BatchHandle {\n const id = crypto.randomUUID();\n const handles = files.map((file, i) => {\n const options = optionsFor(file, i);\n const handle = this.createHandle(file, {\n batchId: id,\n path: options.path,\n });\n this.uploadOptionsByHandleId.set(handle.upload.id, options);\n return handle;\n });\n\n this.uploadHandles.push(...handles);\n\n const batch = new BatchHandle({\n id,\n onChange: () => {\n this.notifyChange();\n },\n options: batchOptions,\n startNext: (handle) => {\n const options = this.uploadOptionsByHandleId.get(handle.upload.id) ?? {\n path: handle.upload.path,\n };\n this.validateAndStartUpload(handle, options);\n },\n uploads: handles,\n });\n\n this.batches.push(batch);\n this.notifyChange();\n batch._start();\n return batch;\n }\n\n private createHandle(\n file: File,\n options: { path: string; batchId?: string }\n ): UploadHandle {\n const upload: UploadItem = {\n bytesTransferred: 0,\n file,\n id: crypto.randomUUID(),\n path: options.path,\n progress: 0,\n status: \"queued\",\n totalBytes: file.size,\n ...(options.batchId === undefined ? {} : { batchId: options.batchId }),\n };\n return new UploadHandle(upload, () => {\n this.notifyChange();\n });\n }\n\n private validateAndStartUpload(\n handle: UploadHandle,\n options: UploadOptions\n ): void {\n if (options.validate) {\n const syncError = validateUploadSync(\n handle.upload.file,\n options.validate\n );\n if (syncError) {\n queueMicrotask(() => {\n handle._reportError(syncError);\n });\n return;\n }\n\n if (needsImageDimensionValidation(options.validate)) {\n void this.runImageValidation(handle, options);\n return;\n }\n }\n\n this.startUpload(handle, options);\n }\n\n private async runImageValidation(\n handle: UploadHandle,\n options: UploadOptions\n ): Promise<void> {\n const { validate } = options;\n if (!validate) {\n this.startUpload(handle, options);\n return;\n }\n\n const error = await validateImageDimensions(handle.upload.file, validate);\n if (error) {\n handle._reportError(error);\n return;\n }\n this.startUpload(handle, options);\n }\n\n private startUpload(handle: UploadHandle, options: UploadOptions): void {\n const retryOptions = resolveRetryOptions(options.retry);\n const maxAttempts = retryOptions ? retryOptions.maxRetries + 1 : 1;\n\n let attempt = 0;\n let retryTimeout: ReturnType<typeof setTimeout> | null = null;\n let currentTask: ProviderUploadTask | null = null;\n let aborted = false;\n let pausedDuringRetry = false;\n let pendingRetryError: Error | null = null;\n\n const clearRetryTimeout = (): void => {\n if (retryTimeout !== null) {\n clearTimeout(retryTimeout);\n retryTimeout = null;\n }\n };\n\n const abort = (): void => {\n aborted = true;\n clearRetryTimeout();\n currentTask?.cancel();\n currentTask = null;\n pendingRetryError = null;\n };\n\n const retryController = {\n runAttempt: (): void => {\n if (aborted) {\n return;\n }\n\n attempt += 1;\n handle._prepareAttempt(attempt);\n\n currentTask = this.provider.upload(handle.upload.file, options, {\n onError: (error) => {\n currentTask = null;\n if (aborted) {\n return;\n }\n\n if (\n attempt < maxAttempts &&\n isRetryableStorageError(error, retryOptions)\n ) {\n const delayMs = retryOptions\n ? computeRetryDelay(attempt, retryOptions)\n : 0;\n retryController.scheduleRetry(error, delayMs);\n return;\n }\n\n handle._reportError(error);\n },\n onProgress: (bytesTransferred, totalBytes) => {\n handle._reportProgress(bytesTransferred, totalBytes);\n },\n onSuccess: (downloadURL) => {\n currentTask = null;\n if (aborted) {\n return;\n }\n handle._reportSuccess(downloadURL);\n },\n });\n handle._attachTask(currentTask);\n },\n scheduleRetry: (error: Error, delayMs: number): void => {\n if (aborted) {\n return;\n }\n\n pendingRetryError = error;\n handle._enterRetryBackoff({\n attempt: attempt + 1,\n delayMs,\n error,\n maxAttempts,\n });\n\n retryTimeout = setTimeout(() => {\n retryTimeout = null;\n if (aborted || pausedDuringRetry) {\n return;\n }\n pendingRetryError = null;\n retryController.runAttempt();\n }, delayMs);\n },\n };\n\n handle._registerControlHooks({\n abort,\n pauseDuringRetry: () => {\n pausedDuringRetry = true;\n clearRetryTimeout();\n },\n resumeDuringRetry: () => {\n if (aborted) {\n return;\n }\n pausedDuringRetry = false;\n if (pendingRetryError) {\n retryController.scheduleRetry(pendingRetryError, 0);\n }\n },\n });\n\n retryController.runAttempt();\n }\n\n private notifyChange(): void {\n this.cachedState = null;\n const state = this.getState();\n for (const listener of this.changeListeners) {\n listener(state);\n }\n }\n}\n","import {\n deleteObject,\n getDownloadURL,\n getMetadata,\n list,\n listAll,\n ref,\n uploadBytesResumable,\n} from \"firebase/storage\";\nimport type { FirebaseStorage, StorageError } from \"firebase/storage\";\n\nimport type { ListOptions, StorageListResult } from \"../types/list\";\nimport type { FileMetadata } from \"../types/metadata\";\nimport type {\n ProviderUploadCallbacks,\n ProviderUploadTask,\n UploadOptions,\n} from \"../types/provider\";\nimport type { StorageProvider } from \"./provider\";\n\nconst isStorageError = (error: unknown): error is StorageError =>\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n typeof (error as { code: unknown }).code === \"string\";\n\nconst toError = (error: unknown): Error =>\n error instanceof Error ? error : new Error(String(error));\n\nexport class FirebaseStorageProvider implements StorageProvider {\n private readonly storage: FirebaseStorage;\n\n constructor(storage: FirebaseStorage) {\n this.storage = storage;\n }\n\n upload(\n file: File,\n options: UploadOptions,\n callbacks: ProviderUploadCallbacks\n ): ProviderUploadTask {\n const storageRef = ref(this.storage, options.path);\n\n const metadata =\n options.contentType !== undefined || options.customMetadata !== undefined\n ? {\n ...(options.contentType !== undefined && {\n contentType: options.contentType,\n }),\n ...(options.customMetadata !== undefined && {\n customMetadata: options.customMetadata,\n }),\n }\n : undefined;\n\n const task = uploadBytesResumable(storageRef, file, metadata);\n\n task.on(\n \"state_changed\",\n (snapshot) => {\n callbacks.onProgress(snapshot.bytesTransferred, snapshot.totalBytes);\n },\n (error) => {\n callbacks.onError(error);\n },\n () => {\n void (async () => {\n try {\n const downloadURL = await getDownloadURL(storageRef);\n callbacks.onSuccess(downloadURL);\n } catch (error) {\n callbacks.onError(toError(error));\n }\n })();\n }\n );\n\n return {\n cancel: () => {\n task.cancel();\n },\n pause: () => {\n task.pause();\n },\n resume: () => {\n task.resume();\n },\n };\n }\n\n async exists(path: string): Promise<boolean> {\n try {\n await getMetadata(ref(this.storage, path));\n return true;\n } catch (error) {\n if (isStorageError(error) && error.code === \"storage/object-not-found\") {\n return false;\n }\n throw error;\n }\n }\n\n async getMetadata(path: string): Promise<FileMetadata> {\n const meta = await getMetadata(ref(this.storage, path));\n return {\n contentType: meta.contentType,\n createdAt: new Date(meta.timeCreated),\n customMetadata: meta.customMetadata,\n path,\n size: meta.size,\n updatedAt: new Date(meta.updated),\n };\n }\n\n async getDownloadURL(path: string): Promise<string> {\n return await getDownloadURL(ref(this.storage, path));\n }\n\n async delete(path: string): Promise<void> {\n await deleteObject(ref(this.storage, path));\n }\n\n async list(\n prefix: string,\n options?: ListOptions\n ): Promise<StorageListResult> {\n const result = await list(ref(this.storage, prefix), {\n ...(options?.maxResults !== undefined && {\n maxResults: options.maxResults,\n }),\n ...(options?.pageToken !== undefined && { pageToken: options.pageToken }),\n });\n\n return {\n items: result.items.map((item) => ({\n name: item.name,\n path: item.fullPath,\n })),\n ...(result.nextPageToken !== undefined && {\n nextPageToken: result.nextPageToken,\n }),\n prefixes: result.prefixes.map((folderRef) => folderRef.fullPath),\n };\n }\n\n async listAll(prefix: string): Promise<StorageListResult> {\n const result = await listAll(ref(this.storage, prefix));\n\n return {\n items: result.items.map((item) => ({\n name: item.name,\n path: item.fullPath,\n })),\n prefixes: result.prefixes.map((folderRef) => folderRef.fullPath),\n };\n }\n}\n","import type { FirebaseStorage } from \"firebase/storage\";\n\nimport { StorageManager as BaseStorageManager } from \"./core/storage-manager\";\nimport { FirebaseStorageProvider } from \"./providers/firebase-provider\";\n\n/** Firebase Storage uploads and file helpers. Pass a `FirebaseStorage` instance from `getStorage(app)`. */\nexport class StorageManager extends BaseStorageManager {\n constructor(storage: FirebaseStorage) {\n super(new FirebaseStorageProvider(storage));\n }\n}\n"]}
|
package/dist/{firebase-storage-manager-DT6lxmUD.d.ts → firebase-storage-manager-6BfTfmyy.d.ts}
RENAMED
|
@@ -16,6 +16,11 @@ interface UploadItem {
|
|
|
16
16
|
status: UploadStatus;
|
|
17
17
|
downloadURL?: string;
|
|
18
18
|
error?: Error;
|
|
19
|
+
/** The current attempt number (1-based). The initial upload is attempt `1`; each retry increments it. */
|
|
20
|
+
attempt?: number;
|
|
21
|
+
/**
|
|
22
|
+
* @deprecated Use {@link UploadItem.attempt} instead. Kept as an alias for backward compatibility and always mirrors `attempt`.
|
|
23
|
+
*/
|
|
19
24
|
retryAttempt?: number;
|
|
20
25
|
batchId?: string;
|
|
21
26
|
}
|
|
@@ -167,6 +172,18 @@ interface ProviderUploadCallbacks {
|
|
|
167
172
|
onError: (error: Error) => void;
|
|
168
173
|
onSuccess: (downloadURL: string) => void;
|
|
169
174
|
}
|
|
175
|
+
interface UploadValidationOptions {
|
|
176
|
+
/** Maximum file size in bytes. */
|
|
177
|
+
maxSizeBytes?: number;
|
|
178
|
+
/** Allowed MIME types, e.g. `image/jpeg`. */
|
|
179
|
+
allowedMimeTypes?: string[];
|
|
180
|
+
/** Allowed file extensions including the dot, e.g. `.jpg`. */
|
|
181
|
+
allowedExtensions?: string[];
|
|
182
|
+
/** Maximum image width in pixels (checked for image files only). */
|
|
183
|
+
maxImageWidth?: number;
|
|
184
|
+
/** Maximum image height in pixels (checked for image files only). */
|
|
185
|
+
maxImageHeight?: number;
|
|
186
|
+
}
|
|
170
187
|
interface RetryOptions {
|
|
171
188
|
/** Extra attempts after the first failure. Default: 3 (4 total tries). */
|
|
172
189
|
maxRetries?: number;
|
|
@@ -182,12 +199,30 @@ interface RetryOptions {
|
|
|
182
199
|
interface UploadOptions {
|
|
183
200
|
/** Object path in the bucket (Firebase), e.g. `uploads/photo.jpg`. */
|
|
184
201
|
path: string;
|
|
202
|
+
/** Optional pre-upload validation. Rejects before the provider upload starts. */
|
|
203
|
+
validate?: UploadValidationOptions;
|
|
185
204
|
/** Retries are enabled by default. Pass `false` to disable, or an object to customize. */
|
|
186
205
|
retry?: RetryOptions | false;
|
|
206
|
+
/** MIME type stored on the object (e.g. `image/jpeg`). */
|
|
207
|
+
contentType?: string;
|
|
187
208
|
/** App-specific string key/value pairs stored on the object.*/
|
|
188
209
|
customMetadata?: Record<string, string>;
|
|
189
210
|
}
|
|
190
211
|
|
|
212
|
+
interface StorageListItem {
|
|
213
|
+
path: string;
|
|
214
|
+
name: string;
|
|
215
|
+
}
|
|
216
|
+
interface StorageListResult {
|
|
217
|
+
prefixes: string[];
|
|
218
|
+
items: StorageListItem[];
|
|
219
|
+
nextPageToken?: string;
|
|
220
|
+
}
|
|
221
|
+
interface ListOptions {
|
|
222
|
+
maxResults?: number;
|
|
223
|
+
pageToken?: string;
|
|
224
|
+
}
|
|
225
|
+
|
|
191
226
|
interface FileMetadata {
|
|
192
227
|
path: string;
|
|
193
228
|
size: number;
|
|
@@ -203,6 +238,8 @@ interface StorageProvider {
|
|
|
203
238
|
getMetadata(path: string): Promise<FileMetadata>;
|
|
204
239
|
getDownloadURL(path: string): Promise<string>;
|
|
205
240
|
delete(path: string): Promise<void>;
|
|
241
|
+
list(prefix: string, options?: ListOptions): Promise<StorageListResult>;
|
|
242
|
+
listAll(prefix: string): Promise<StorageListResult>;
|
|
206
243
|
}
|
|
207
244
|
|
|
208
245
|
/**
|
|
@@ -232,6 +269,10 @@ declare class StorageManager$1 {
|
|
|
232
269
|
getDownloadURL(path: string): Promise<string>;
|
|
233
270
|
/** Deletes the object at `path`. */
|
|
234
271
|
delete(path: string): Promise<void>;
|
|
272
|
+
/** Lists folders and files at `prefix` with optional pagination. */
|
|
273
|
+
list(prefix: string, options?: ListOptions): Promise<StorageListResult>;
|
|
274
|
+
/** Lists all folders and files at `prefix` (auto-paginates internally). */
|
|
275
|
+
listAll(prefix: string): Promise<StorageListResult>;
|
|
235
276
|
/** Starts the file upload.`options.path` is the object path in storage (see {@link UploadOptions}).
|
|
236
277
|
*
|
|
237
278
|
* @returns An {@link UploadHandle} to control the upload: `pause`, `resume`, `cancel`, and listen for progress with `.on`.
|
|
@@ -248,6 +289,8 @@ declare class StorageManager$1 {
|
|
|
248
289
|
*/
|
|
249
290
|
uploadFiles(files: File[], optionsFor: (file: File, index: number) => UploadOptions, batchOptions?: BatchOptions): BatchHandle;
|
|
250
291
|
private createHandle;
|
|
292
|
+
private validateAndStartUpload;
|
|
293
|
+
private runImageValidation;
|
|
251
294
|
private startUpload;
|
|
252
295
|
private notifyChange;
|
|
253
296
|
}
|
|
@@ -257,4 +300,4 @@ declare class StorageManager extends StorageManager$1 {
|
|
|
257
300
|
constructor(storage: FirebaseStorage);
|
|
258
301
|
}
|
|
259
302
|
|
|
260
|
-
export { BatchHandle as B, type FileMetadata as F, type ProviderUploadCallbacks as P, type RetryOptions as R,
|
|
303
|
+
export { BatchHandle as B, type FileMetadata as F, type ListOptions as L, type ProviderUploadCallbacks as P, type RetryOptions as R, type StorageListItem as S, type UploadValidationOptions as U, type BatchHandleEvents as a, type BatchHandleInit as b, type BatchOptions as c, type ProviderUploadTask as d, type StorageListResult as e, StorageManager as f, type StorageState as g, type UploadBatch as h, type UploadControlHooks as i, UploadHandle as j, type UploadHandleEvents as k, type UploadItem as l, type UploadOptions as m, type UploadRetryBackoffDetails as n, type UploadRetryEvent as o, type UploadStatus as p };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { R as RetryOptions } from './firebase-storage-manager-
|
|
2
|
-
export { B as BatchHandle, a as BatchHandleEvents, b as BatchHandleInit, c as BatchOptions, F as FileMetadata, P as ProviderUploadCallbacks, d as ProviderUploadTask, S as
|
|
1
|
+
import { R as RetryOptions, U as UploadValidationOptions } from './firebase-storage-manager-6BfTfmyy.js';
|
|
2
|
+
export { B as BatchHandle, a as BatchHandleEvents, b as BatchHandleInit, c as BatchOptions, F as FileMetadata, L as ListOptions, P as ProviderUploadCallbacks, d as ProviderUploadTask, S as StorageListItem, e as StorageListResult, f as StorageManager, g as StorageState, h as UploadBatch, i as UploadControlHooks, j as UploadHandle, k as UploadHandleEvents, l as UploadItem, m as UploadOptions, n as UploadRetryBackoffDetails, o as UploadRetryEvent, p as UploadStatus } from './firebase-storage-manager-6BfTfmyy.js';
|
|
3
3
|
import 'firebase/storage';
|
|
4
4
|
|
|
5
5
|
interface ResolvedRetryOptions {
|
|
@@ -19,4 +19,34 @@ declare const isRetryableStorageError: (error: Error, options: ResolvedRetryOpti
|
|
|
19
19
|
/** Computes backoff delay after a failed attempt (1-based). */
|
|
20
20
|
declare const computeRetryDelay: (failedAttempt: number, options: ResolvedRetryOptions) => number;
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
declare const VALIDATION_ERROR_CODES: {
|
|
23
|
+
readonly extensionNotAllowed: "validation/extension-not-allowed";
|
|
24
|
+
readonly fileTooLarge: "validation/file-too-large";
|
|
25
|
+
readonly imageDimensionUnavailable: "validation/image-dimension-unavailable";
|
|
26
|
+
readonly imageDimensionsUnreadable: "validation/image-dimensions-unreadable";
|
|
27
|
+
readonly imageHeightTooLarge: "validation/image-height-too-large";
|
|
28
|
+
readonly imageWidthTooLarge: "validation/image-width-too-large";
|
|
29
|
+
readonly mimeTypeNotAllowed: "validation/mime-type-not-allowed";
|
|
30
|
+
};
|
|
31
|
+
type ValidationErrorCode = (typeof VALIDATION_ERROR_CODES)[keyof typeof VALIDATION_ERROR_CODES];
|
|
32
|
+
declare class ValidationError extends Error {
|
|
33
|
+
readonly name = "ValidationError";
|
|
34
|
+
readonly code: ValidationErrorCode;
|
|
35
|
+
constructor(message: string, code: ValidationErrorCode);
|
|
36
|
+
}
|
|
37
|
+
interface ImageDimensions {
|
|
38
|
+
width: number;
|
|
39
|
+
height: number;
|
|
40
|
+
}
|
|
41
|
+
declare const getFileExtension: (fileName: string) => string;
|
|
42
|
+
/** Synchronous checks: size, MIME type, and extension. */
|
|
43
|
+
declare const validateUploadSync: (file: File, options: UploadValidationOptions) => ValidationError | null;
|
|
44
|
+
declare const readImageDimensions: (file: File) => Promise<ImageDimensions>;
|
|
45
|
+
/** Checks width/height against configured limits. */
|
|
46
|
+
declare const validateImageDimensionLimits: (dimensions: ImageDimensions, options: UploadValidationOptions) => ValidationError | null;
|
|
47
|
+
/** Async image dimension checks. Skipped for non-image files. */
|
|
48
|
+
declare const validateImageDimensions: (file: File, options: UploadValidationOptions) => Promise<ValidationError | null>;
|
|
49
|
+
/** Runs all upload validation rules. Returns the first error, if any. */
|
|
50
|
+
declare const validateUpload: (file: File, options: UploadValidationOptions | undefined) => Promise<ValidationError | null>;
|
|
51
|
+
|
|
52
|
+
export { DEFAULT_RETRY_OPTIONS, RetryOptions, UploadValidationOptions, VALIDATION_ERROR_CODES, ValidationError, type ValidationErrorCode, computeRetryDelay, getFileExtension, getStorageErrorCode, isRetryableStorageError, readImageDimensions, resolveRetryOptions, validateImageDimensionLimits, validateImageDimensions, validateUpload, validateUploadSync };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { BatchHandle, DEFAULT_RETRY_OPTIONS, StorageManager, UploadHandle, computeRetryDelay, getStorageErrorCode, isRetryableStorageError, resolveRetryOptions } from './chunk-
|
|
1
|
+
export { BatchHandle, DEFAULT_RETRY_OPTIONS, StorageManager, UploadHandle, VALIDATION_ERROR_CODES, ValidationError, computeRetryDelay, getFileExtension, getStorageErrorCode, isRetryableStorageError, readImageDimensions, resolveRetryOptions, validateImageDimensionLimits, validateImageDimensions, validateUpload, validateUploadSync } from './chunk-PTKP7RWS.js';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { f as StorageManager, B as BatchHandle, h as UploadBatch, g as StorageState, j as UploadHandle, l as UploadItem } from '../firebase-storage-manager-6BfTfmyy.js';
|
|
4
4
|
import { FirebaseStorage } from 'firebase/storage';
|
|
5
5
|
|
|
6
6
|
interface StorageManagerProviderProps {
|
package/dist/react/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/emitter.ts","../src/core/batch-handle.ts","../src/core/retry.ts","../src/core/upload-handle.ts","../src/core/storage-manager.ts","../src/providers/firebase-provider.ts","../src/firebase-storage-manager.ts"],"names":["StorageManager"],"mappings":";;;AAEO,IAAM,UAAN,MAAuD;AAAA,EACpD,YAAkE,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO3E,EAAA,CAA4B,OAAU,QAAA,EAAgC;AACpE,IAAA,IAAI,SAAA,GAAY,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA;AACpC,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,SAAA,uBAAgB,GAAA,EAAI;AACpB,MAAA,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,GAAI,SAAA;AAAA,IAC1B;AAEA,IAAA,SAAA,CAAU,IAAI,QAAQ,CAAA;AAEtB,IAAA,OAAO,MAAM;AACX,MAAA,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,EAAG,MAAA,CAAO,QAAQ,CAAA;AAAA,IACxC,CAAA;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,IAAA,CAA8B,OAAU,OAAA,EAAqB;AACrE,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA;AAEtC,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA;AAAA,IACF;AAEA,IAAA,KAAA,MAAW,YAAY,SAAA,EAAW;AAChC,MAAA,QAAA,CAAS,OAAO,CAAA;AAAA,IAClB;AAAA,EACF;AACF,CAAA;;;ACEO,IAAM,WAAA,GAAN,cAA0B,OAAA,CAA2B;AAAA,EAC1C,EAAA;AAAA,EACA,OAAA;AAAA,EAEC,WAAA;AAAA,EACA,eAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EAET,OAAA,GAAU,CAAA;AAAA,EACV,OAAA,GAAU,CAAA;AAAA;AAAA,EAED,WAAA,uBAAkB,GAAA,EAAY;AAAA,EACvC,YAAA,GAAe,CAAA;AAAA,EACf,cAAA,GAAiB,CAAA;AAAA,EACjB,WAAA,GAAc,CAAA;AAAA,EACd,UAAA,GAAa,KAAA;AAAA,EACb,QAAA,GAAW,KAAA;AAAA,EACX,MAAA,GAAS,KAAA;AAAA,EACT,eAAA,GAAkB,KAAA;AAAA;AAAA;AAAA;AAAA,EAKT,WAAA;AAAA;AAAA;AAAA,EAIT,yBAAA,GAA4B,CAAA;AAAA,EAC5B,mBAAA,GAAsB,CAAA;AAAA,EACb,SAAA;AAAA,EACA,SAAA;AAAA,EAEjB,YAAY,IAAA,EAAuB;AACjC,IAAA,KAAA,EAAM;AACN,IAAA,IAAA,CAAK,KAAK,IAAA,CAAK,EAAA;AACf,IAAA,IAAA,CAAK,UAAU,IAAA,CAAK,OAAA;AACpB,IAAA,IAAA,CAAK,cAAc,IAAA,CAAK,GAAA,CAAI,GAAG,IAAA,CAAK,OAAA,CAAQ,eAAe,CAAC,CAAA;AAC5D,IAAA,IAAA,CAAK,eAAA,GAAkB,IAAA,CAAK,OAAA,CAAQ,eAAA,IAAmB,IAAA;AACvD,IAAA,IAAA,CAAK,YAAY,IAAA,CAAK,SAAA;AACtB,IAAA,IAAA,CAAK,WAAW,IAAA,CAAK,QAAA;AAErB,IAAA,IAAA,CAAK,cAAc,IAAA,CAAK,OAAA,CAAQ,IAAI,CAAC,CAAA,KAAM,EAAE,MAAM,CAAA;AACnD,IAAA,IAAA,CAAK,YAAY,KAAA,CAAM,IAAA;AAAA,MACrB,EAAE,MAAA,EAAQ,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAO;AAAA,MAC9B,MAAc;AAAA,KAChB;AACA,IAAA,IAAA,CAAK,YAAY,KAAA,CAAM,IAAA;AAAA,MACrB,EAAE,MAAA,EAAQ,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAO;AAAA,MAC9B,MAAc;AAAA,KAChB;AACA,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,KAAK,WAAA,CAAY,MAAA,EAAQ,KAAK,CAAA,EAAG;AACnD,MAAA,MAAM,CAAA,GAAI,IAAA,CAAK,WAAA,CAAY,CAAC,CAAA;AAC5B,MAAA,IAAI,CAAC,CAAA,EAAG;AACN,QAAA;AAAA,MACF;AACA,MAAA,IAAA,CAAK,SAAA,CAAU,CAAC,CAAA,GAAI,CAAA,CAAE,gBAAA;AACtB,MAAA,IAAA,CAAK,SAAA,CAAU,CAAC,CAAA,GAAI,CAAA,CAAE,UAAA;AACtB,MAAA,IAAA,CAAK,6BAA6B,CAAA,CAAE,gBAAA;AACpC,MAAA,IAAA,CAAK,uBAAuB,CAAA,CAAE,UAAA;AAAA,IAChC;AAEA,IAAA,KAAA,IAAS,MAAM,CAAA,EAAG,GAAA,GAAM,KAAK,OAAA,CAAQ,MAAA,EAAQ,OAAO,CAAA,EAAG;AACrD,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AAC9B,MAAA,IAAI,CAAC,KAAA,EAAO;AACV,QAAA;AAAA,MACF;AACA,MAAA,KAAA,CAAM,EAAA,CAAG,UAAA,EAAY,CAAC,MAAA,KAAW;AAC/B,QAAA,IAAA,CAAK,mBAAA,CAAoB,KAAK,MAAM,CAAA;AAAA,MACtC,CAAC,CAAA;AACD,MAAA,KAAA,CAAM,EAAA,CAAG,OAAA,EAAS,CAAC,UAAA,KAAe;AAChC,QAAA,IAAA,CAAK,gBAAA,CAAiB,KAAK,UAAU,CAAA;AAAA,MACvC,CAAC,CAAA;AACD,MAAA,KAAA,CAAM,EAAA,CAAG,SAAA,EAAW,CAAC,MAAA,KAAW;AAC9B,QAAA,IAAA,CAAK,kBAAA,CAAmB,GAAA,EAAK,MAAA,EAAQ,SAAS,CAAA;AAAA,MAChD,CAAC,CAAA;AACD,MAAA,KAAA,CAAM,EAAA,CAAG,OAAA,EAAS,CAAC,MAAA,KAAW;AAC5B,QAAA,IAAA,CAAK,kBAAA,CAAmB,GAAA,EAAK,MAAA,EAAQ,OAAO,CAAA;AAAA,MAC9C,CAAC,CAAA;AACD,MAAA,KAAA,CAAM,EAAA,CAAG,UAAA,EAAY,CAAC,MAAA,KAAW;AAC/B,QAAA,IAAA,CAAK,kBAAA,CAAmB,GAAA,EAAK,MAAA,EAAQ,UAAU,CAAA;AAAA,MACjD,CAAC,CAAA;AAAA,IACH;AAAA,EACF;AAAA;AAAA,EAGA,MAAA,GAAe;AACb,IAAA,IAAA,CAAK,SAAA,EAAU;AAAA,EACjB;AAAA,EAEA,MAAA,GAAe;AACb,IAAA,IAAI,IAAA,CAAK,QAAA,IAAY,IAAA,CAAK,eAAA,EAAiB;AACzC,MAAA;AAAA,IACF;AACA,IAAA,IAAA,CAAK,QAAA,GAAW,IAAA;AAChB,IAAA,KAAA,MAAW,CAAA,IAAK,KAAK,OAAA,EAAS;AAC5B,MAAA,MAAM,CAAA,GAAI,EAAE,MAAA,CAAO,MAAA;AACnB,MAAA,IACE,MAAM,QAAA,IACN,CAAA,KAAM,eACN,CAAA,KAAM,UAAA,IACN,MAAM,QAAA,EACN;AACA,QAAA,CAAA,CAAE,MAAA,EAAO;AAAA,MACX;AAAA,IACF;AACA,IAAA,IAAA,CAAK,QAAA,EAAS;AAAA,EAChB;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAI,IAAA,CAAK,MAAA,IAAU,IAAA,CAAK,QAAA,IAAY,KAAK,eAAA,EAAiB;AACxD,MAAA;AAAA,IACF;AACA,IAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AACd,IAAA,KAAA,MAAW,CAAA,IAAK,KAAK,OAAA,EAAS;AAC5B,MAAA,IAAI,EAAE,MAAA,CAAO,MAAA,KAAW,eAAe,CAAA,CAAE,MAAA,CAAO,WAAW,UAAA,EAAY;AACrE,QAAA,CAAA,CAAE,KAAA,EAAM;AAAA,MACV;AAAA,IACF;AACA,IAAA,IAAA,CAAK,QAAA,EAAS;AAAA,EAChB;AAAA,EAEA,MAAA,GAAe;AACb,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,IAAU,IAAA,CAAK,QAAA,IAAY,KAAK,eAAA,EAAiB;AACzD,MAAA;AAAA,IACF;AACA,IAAA,IAAA,CAAK,MAAA,GAAS,KAAA;AACd,IAAA,KAAA,MAAW,CAAA,IAAK,KAAK,OAAA,EAAS;AAC5B,MAAA,IAAI,CAAA,CAAE,MAAA,CAAO,MAAA,KAAW,QAAA,EAAU;AAChC,QAAA,CAAA,CAAE,MAAA,EAAO;AAAA,MACX;AAAA,IACF;AACA,IAAA,IAAA,CAAK,SAAA,EAAU;AACf,IAAA,IAAA,CAAK,QAAA,EAAS;AAAA,EAChB;AAAA,EAEA,QAAA,GAAwB;AACtB,IAAA,MAAM,aAAA,GACJ,KAAK,mBAAA,GAAsB,CAAA,GACtB,KAAK,yBAAA,GAA4B,IAAA,CAAK,sBAAuB,GAAA,GAC9D,CAAA;AACN,IAAA,OAAO;AAAA,MACL,gBAAgB,IAAA,CAAK,cAAA;AAAA,MACrB,aAAa,IAAA,CAAK,WAAA;AAAA,MAClB,IAAI,IAAA,CAAK,EAAA;AAAA,MACT,aAAA;AAAA,MACA,SAAS,IAAA,CAAK;AAAA,KAChB;AAAA,EACF;AAAA,EAEQ,eAAA,CAAgB,KAAa,CAAA,EAAqB;AACxD,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,SAAA,CAAU,GAAG,CAAA,IAAK,CAAA;AACzC,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,SAAA,CAAU,GAAG,CAAA,IAAK,CAAA;AACzC,IAAA,IAAA,CAAK,yBAAA,IAA6B,EAAE,gBAAA,GAAmB,SAAA;AACvD,IAAA,IAAA,CAAK,mBAAA,IAAuB,EAAE,UAAA,GAAa,SAAA;AAC3C,IAAA,IAAA,CAAK,SAAA,CAAU,GAAG,CAAA,GAAI,CAAA,CAAE,gBAAA;AACxB,IAAA,IAAA,CAAK,SAAA,CAAU,GAAG,CAAA,GAAI,CAAA,CAAE,UAAA;AAAA,EAC1B;AAAA,EAEQ,SAAA,GAAkB;AACxB,IAAA,OACE,CAAC,IAAA,CAAK,QAAA,IACN,CAAC,IAAA,CAAK,UACN,CAAC,IAAA,CAAK,UAAA,IACN,IAAA,CAAK,UAAU,IAAA,CAAK,WAAA,IACpB,KAAK,OAAA,GAAU,IAAA,CAAK,QAAQ,MAAA,EAC5B;AACA,MAAA,MAAM,MAAM,IAAA,CAAK,OAAA;AACjB,MAAA,IAAA,CAAK,OAAA,IAAW,CAAA;AAChB,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AAC/B,MAAA,IAAI,CAAC,MAAA,IAAU,MAAA,CAAO,MAAA,CAAO,WAAW,QAAA,EAAU;AAChD,QAAA;AAAA,MACF;AACA,MAAA,IAAA,CAAK,WAAA,CAAY,IAAI,GAAG,CAAA;AACxB,MAAA,IAAA,CAAK,OAAA,IAAW,CAAA;AAChB,MAAA,IAAA,CAAK,UAAU,MAAM,CAAA;AAAA,IACvB;AAAA,EACF;AAAA,EAEQ,mBAAA,CAAoB,KAAa,MAAA,EAA0B;AACjE,IAAA,IAAA,CAAK,eAAA,CAAgB,KAAK,MAAM,CAAA;AAChC,IAAA,MAAM,IAAA,GAAO,KAAK,QAAA,EAAS;AAC3B,IAAA,IAAA,CAAK,IAAA,CAAK,YAAY,IAAI,CAAA;AAC1B,IAAA,IAAA,CAAK,IAAA,CAAK,UAAU,IAAI,CAAA;AAAA,EAC1B;AAAA,EAEQ,gBAAA,CAAiB,KAAa,KAAA,EAA+B;AACnE,IAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,EAAK,KAAA,CAAM,MAAM,CAAA;AACtC,IAAA,IAAA,CAAK,IAAA,CAAK,eAAe,KAAK,CAAA;AAC9B,IAAA,MAAM,IAAA,GAAO,KAAK,QAAA,EAAS;AAC3B,IAAA,IAAA,CAAK,IAAA,CAAK,UAAU,IAAI,CAAA;AAAA,EAC1B;AAAA,EAEQ,kBAAA,CACN,GAAA,EACA,MAAA,EACA,IAAA,EACM;AACN,IAAA,IAAA,CAAK,eAAA,CAAgB,KAAK,MAAM,CAAA;AAChC,IAAA,IAAI,IAAA,CAAK,WAAA,CAAY,MAAA,CAAO,GAAG,CAAA,EAAG;AAChC,MAAA,IAAA,CAAK,UAAU,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,UAAU,CAAC,CAAA;AAAA,IAC7C;AACA,IAAA,IAAA,CAAK,YAAA,IAAgB,CAAA;AAErB,IAAA,IAAI,SAAS,SAAA,EAAW;AACtB,MAAA,IAAA,CAAK,cAAA,IAAkB,CAAA;AACvB,MAAA,IAAA,CAAK,IAAA,CAAK,iBAAiB,MAAM,CAAA;AAAA,IACnC,CAAA,MAAA,IAAW,SAAS,OAAA,EAAS;AAC3B,MAAA,IAAA,CAAK,WAAA,IAAe,CAAA;AACpB,MAAA,IAAA,CAAK,IAAA,CAAK,eAAe,MAAM,CAAA;AAAA,IACjC;AAEA,IAAA,MAAM,IAAA,GAAO,KAAK,QAAA,EAAS;AAC3B,IAAA,IAAA,CAAK,IAAA,CAAK,UAAU,IAAI,CAAA;AAExB,IAAA,IACE,IAAA,KAAS,OAAA,IACT,CAAC,IAAA,CAAK,eAAA,IACN,CAAC,IAAA,CAAK,UAAA,IACN,CAAC,IAAA,CAAK,QAAA,EACN;AACA,MAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAClB,MAAA,KAAA,MAAW,CAAA,IAAK,KAAK,OAAA,EAAS;AAC5B,QAAA,IAAI,CAAA,CAAE,MAAA,CAAO,EAAA,KAAO,MAAA,CAAO,EAAA,EAAI;AAC7B,UAAA;AAAA,QACF;AACA,QAAA,MAAM,CAAA,GAAI,EAAE,MAAA,CAAO,MAAA;AACnB,QAAA,IACE,MAAM,QAAA,IACN,CAAA,KAAM,eACN,CAAA,KAAM,UAAA,IACN,MAAM,QAAA,EACN;AACA,UAAA,CAAA,CAAE,MAAA,EAAO;AAAA,QACX;AAAA,MACF;AACA,MAAA,IAAA,CAAK,eAAA,GAAkB,IAAA;AACvB,MAAA,IAAA,CAAK,IAAA,CAAK,SAAS,IAAI,CAAA;AACvB,MAAA,IAAA,CAAK,QAAA,EAAS;AACd,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,IAAA,CAAK,UAAA,IAAc,IAAA,CAAK,QAAA,EAAU;AAGpC,MAAA,IAAA,CAAK,QAAA,EAAS;AACd,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,SAAA,EAAU;AAEf,IAAA,IAAI,KAAK,YAAA,IAAgB,IAAA,CAAK,QAAQ,MAAA,IAAU,CAAC,KAAK,eAAA,EAAiB;AACrE,MAAA,IAAA,CAAK,eAAA,GAAkB,IAAA;AACvB,MAAA,IAAA,CAAK,IAAA,CAAK,WAAW,IAAI,CAAA;AAAA,IAC3B;AAEA,IAAA,IAAA,CAAK,QAAA,EAAS;AAAA,EAChB;AACF;;;ACjSO,IAAM,qBAAA,GAA8C;AAAA,EACzD,cAAA,EAAgB,GAAA;AAAA,EAChB,MAAA,EAAQ,IAAA;AAAA,EACR,UAAA,EAAY,GAAA;AAAA,EACZ,UAAA,EAAY;AACd;AAEA,IAAM,mBAAA,uBAA0B,GAAA,CAAI;AAAA,EAClC,kBAAA;AAAA,EACA,sBAAA;AAAA,EACA,yBAAA;AAAA,EACA,wBAAA;AAAA,EACA,0BAAA;AAAA,EACA,gCAAA;AAAA,EACA,qBAAA;AAAA,EACA,gCAAA;AAAA,EACA,2BAAA;AAAA,EACA,0BAAA;AAAA,EACA,2BAAA;AAAA,EACA,gCAAA;AAAA,EACA,4BAAA;AAAA,EACA,wBAAA;AAAA,EACA,yBAAA;AAAA,EACA,0BAAA;AAAA,EACA;AACF,CAAC,CAAA;AAED,IAAM,eAAA,uBAAsB,GAAA,CAAI;AAAA,EAC9B,8BAAA;AAAA,EACA,iBAAA;AAAA,EACA,0BAAA;AAAA,EACA,2BAAA;AAAA,EACA;AACF,CAAC,CAAA;AAGM,IAAM,mBAAA,GAAsB,CACjC,KAAA,KACgC;AAChC,EAAA,IAAI,UAAU,KAAA,EAAO;AACnB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO;AAAA,IACL,GAAG,qBAAA;AAAA,IACH,GAAG;AAAA,GACL;AACF;AAEA,IAAM,sBAAsB,CAAC,KAAA,KAC3B,UAAU,KAAA,IAAS,OAAO,MAAM,IAAA,KAAS,QAAA;AAGpC,IAAM,mBAAA,GAAsB,CAAC,KAAA,KAAqC;AACvE,EAAA,IAAI,CAAC,mBAAA,CAAoB,KAAK,CAAA,EAAG;AAC/B,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,KAAA,CAAM,IAAA;AACf;AAGO,IAAM,uBAAA,GAA0B,CACrC,KAAA,EACA,OAAA,KACY;AACZ,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,QAAQ,WAAA,EAAa;AACvB,IAAA,OAAO,OAAA,CAAQ,YAAY,KAAK,CAAA;AAAA,EAClC;AAEA,EAAA,MAAM,IAAA,GAAO,oBAAoB,KAAK,CAAA;AACtC,EAAA,IAAI,SAAS,MAAA,EAAW;AACtB,IAAA,IAAI,mBAAA,CAAoB,GAAA,CAAI,IAAI,CAAA,EAAG;AACjC,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,IAAI,eAAA,CAAgB,GAAA,CAAI,IAAI,CAAA,EAAG;AAC7B,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,OAAO,IAAA;AACT;AAGO,IAAM,iBAAA,GAAoB,CAC/B,aAAA,EACA,OAAA,KACW;AACX,EAAA,MAAM,OAAO,IAAA,CAAK,GAAA;AAAA,IAChB,OAAA,CAAQ,UAAA;AAAA,IACR,OAAA,CAAQ,cAAA,GAAiB,CAAA,KAAM,aAAA,GAAgB,CAAA;AAAA,GACjD;AACA,EAAA,IAAI,CAAC,QAAQ,MAAA,EAAQ;AACnB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,KAAK,KAAA,CAAM,IAAA,IAAQ,MAAM,IAAA,CAAK,MAAA,KAAW,GAAA,CAAI,CAAA;AACtD;;;ACrEO,IAAM,YAAA,GAAN,cAA2B,OAAA,CAA4B;AAAA,EAC5C,MAAA;AAAA,EAER,IAAA,GAAkC,IAAA;AAAA,EACzB,QAAA;AAAA,EACT,UAAA,GAAa,KAAA;AAAA,EACb,YAAA,GAA0C,IAAA;AAAA,EAC1C,iBAAA,GAAoB,KAAA;AAAA,EAE5B,WAAA,CAAY,QAAoB,QAAA,EAAsB;AACpD,IAAA,KAAA,EAAM;AACN,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAAA,EAClB;AAAA;AAAA,EAGA,YAAY,IAAA,EAAgC;AAC1C,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AAAA;AAAA,EAGA,sBAAsB,KAAA,EAAiC;AACrD,IAAA,IAAA,CAAK,YAAA,GAAe,KAAA;AAAA,EACtB;AAAA;AAAA,EAGA,kBAAA,GAA2B;AACzB,IAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AAAA,EACtB;AAAA;AAAA,EAGA,WAAW,MAAA,EAA4B;AACrC,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,MAAA,KAAW,MAAA,EAAQ;AACjC,MAAA;AAAA,IACF;AACA,IAAA,IAAA,CAAK,OAAO,MAAA,GAAS,MAAA;AACrB,IAAA,IAAA,CAAK,IAAA,CAAK,cAAA,EAAgB,IAAA,CAAK,MAAM,CAAA;AAAA,EACvC;AAAA;AAAA,EAGA,eAAA,CAAgB,kBAA0B,UAAA,EAA0B;AAClE,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA;AAAA,IACF;AACA,IAAA,IAAA,CAAK,OAAO,gBAAA,GAAmB,gBAAA;AAC/B,IAAA,IAAA,CAAK,OAAO,UAAA,GAAa,UAAA;AACzB,IAAA,IAAA,CAAK,OAAO,QAAA,GACV,UAAA,GAAa,CAAA,GAAK,gBAAA,GAAmB,aAAc,GAAA,GAAM,CAAA;AAC3D,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,MAAA,KAAW,WAAA,EAAa;AACtC,MAAA,IAAA,CAAK,WAAW,WAAW,CAAA;AAAA,IAC7B;AACA,IAAA,IAAA,CAAK,IAAA,CAAK,UAAA,EAAY,IAAA,CAAK,MAAM,CAAA;AACjC,IAAA,IAAA,CAAK,QAAA,EAAS;AAAA,EAChB;AAAA;AAAA,EAGA,qBAAqB,OAAA,EAAuB;AAC1C,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA;AAAA,IACF;AACA,IAAA,IAAA,CAAK,OAAO,YAAA,GAAe,OAAA;AAC3B,IAAA,IAAA,CAAK,OAAO,gBAAA,GAAmB,CAAA;AAC/B,IAAA,IAAA,CAAK,OAAO,QAAA,GAAW,CAAA;AACvB,IAAA,IAAA,CAAK,OAAO,KAAA,GAAQ,MAAA;AACpB,IAAA,IAAA,CAAK,iBAAA,GAAoB,KAAA;AACzB,IAAA,IAAA,CAAK,WAAW,WAAW,CAAA;AAC3B,IAAA,IAAA,CAAK,QAAA,EAAS;AAAA,EAChB;AAAA;AAAA,EAGA,mBAAmB,OAAA,EAA0C;AAC3D,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA;AAAA,IACF;AACA,IAAA,IAAA,CAAK,MAAA,CAAO,eAAe,OAAA,CAAQ,OAAA;AACnC,IAAA,IAAA,CAAK,MAAA,CAAO,QAAQ,OAAA,CAAQ,KAAA;AAC5B,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,WAAW,UAAU,CAAA;AAC1B,IAAA,IAAA,CAAK,KAAK,OAAA,EAAS;AAAA,MACjB,SAAS,OAAA,CAAQ,OAAA;AAAA,MACjB,SAAS,OAAA,CAAQ,OAAA;AAAA,MACjB,OAAO,OAAA,CAAQ,KAAA;AAAA,MACf,aAAa,OAAA,CAAQ,WAAA;AAAA,MACrB,QAAQ,IAAA,CAAK;AAAA,KACd,CAAA;AACD,IAAA,IAAA,CAAK,QAAA,EAAS;AAAA,EAChB;AAAA;AAAA,EAGA,eAAe,WAAA,EAA2B;AACxC,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA;AAAA,IACF;AACA,IAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAClB,IAAA,IAAA,CAAK,OAAO,WAAA,GAAc,WAAA;AAC1B,IAAA,IAAA,CAAK,OAAO,QAAA,GAAW,GAAA;AACvB,IAAA,IAAA,CAAK,kBAAA,EAAmB;AACxB,IAAA,IAAA,CAAK,WAAW,SAAS,CAAA;AACzB,IAAA,IAAA,CAAK,IAAA,CAAK,SAAA,EAAW,IAAA,CAAK,MAAM,CAAA;AAChC,IAAA,IAAA,CAAK,QAAA,EAAS;AAAA,EAChB;AAAA;AAAA,EAGA,aAAa,KAAA,EAAoB;AAC/B,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA;AAAA,IACF;AACA,IAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAClB,IAAA,IAAA,CAAK,OAAO,KAAA,GAAQ,KAAA;AACpB,IAAA,IAAA,CAAK,kBAAA,EAAmB;AACxB,IAAA,IAAA,CAAK,WAAW,OAAO,CAAA;AACvB,IAAA,IAAA,CAAK,IAAA,CAAK,OAAA,EAAS,IAAA,CAAK,MAAM,CAAA;AAC9B,IAAA,IAAA,CAAK,QAAA,EAAS;AAAA,EAChB;AAAA,EAEA,MAAA,GAAe;AACb,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA;AAAA,IACF;AACA,IAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAClB,IAAA,IAAA,CAAK,cAAc,KAAA,EAAM;AACzB,IAAA,IAAA,CAAK,MAAM,MAAA,EAAO;AAClB,IAAA,IAAA,CAAK,kBAAA,EAAmB;AACxB,IAAA,IAAA,CAAK,WAAW,UAAU,CAAA;AAC1B,IAAA,IAAA,CAAK,IAAA,CAAK,UAAA,EAAY,IAAA,CAAK,MAAM,CAAA;AACjC,IAAA,IAAA,CAAK,QAAA,EAAS;AAAA,EAChB;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA;AAAA,IACF;AACA,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,MAAA,KAAW,WAAA,EAAa;AACtC,MAAA,IAAA,CAAK,MAAM,KAAA,IAAQ;AACnB,MAAA,IAAA,CAAK,WAAW,QAAQ,CAAA;AACxB,MAAA,IAAA,CAAK,QAAA,EAAS;AACd,MAAA;AAAA,IACF;AACA,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,MAAA,KAAW,UAAA,EAAY;AACrC,MAAA,IAAA,CAAK,iBAAA,GAAoB,IAAA;AACzB,MAAA,IAAA,CAAK,cAAc,gBAAA,IAAmB;AACtC,MAAA,IAAA,CAAK,WAAW,QAAQ,CAAA;AACxB,MAAA,IAAA,CAAK,QAAA,EAAS;AAAA,IAChB;AAAA,EACF;AAAA,EAEA,MAAA,GAAe;AACb,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA;AAAA,IACF;AACA,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,MAAA,KAAW,QAAA,EAAU;AACnC,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,KAAK,iBAAA,EAAmB;AAC1B,MAAA,IAAA,CAAK,iBAAA,GAAoB,KAAA;AACzB,MAAA,IAAA,CAAK,cAAc,iBAAA,IAAoB;AACvC,MAAA,IAAA,CAAK,QAAA,EAAS;AACd,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,MAAM,MAAA,IAAS;AACpB,IAAA,IAAA,CAAK,WAAW,WAAW,CAAA;AAC3B,IAAA,IAAA,CAAK,QAAA,EAAS;AAAA,EAChB;AACF;;;ACzLO,IAAM,iBAAN,MAAqB;AAAA,EACT,QAAA;AAAA,EACA,gBAAgC,EAAC;AAAA,EACjC,UAAyB,EAAC;AAAA,EAC1B,eAAA,uBAAsB,GAAA,EAAmC;AAAA,EAClE,WAAA,GAAmC,IAAA;AAAA,EAC1B,uBAAA,uBAA8B,GAAA,EAA2B;AAAA,EAE1E,YAAY,QAAA,EAA2B;AACrC,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAAA,EAClB;AAAA;AAAA,EAGA,WAAW,MAAoB;AAC7B,IAAA,IAAA,CAAK,WAAA,KAAgB;AAAA,MACnB,OAAA,EAAS,KAAK,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,CAAA;AAAA,MAC7C,SAAS,IAAA,CAAK,aAAA,CAAc,IAAI,CAAC,CAAA,KAAM,EAAE,MAAM;AAAA,KACjD;AACA,IAAA,OAAO,IAAA,CAAK,WAAA;AAAA,EACd,CAAA;AAAA;AAAA,EAGA,SAAA,GAAY,CAAC,QAAA,KAA0D;AACrE,IAAA,IAAA,CAAK,eAAA,CAAgB,IAAI,QAAQ,CAAA;AACjC,IAAA,OAAO,MAAM;AACX,MAAA,IAAA,CAAK,eAAA,CAAgB,OAAO,QAAQ,CAAA;AAAA,IACtC,CAAA;AAAA,EACF,CAAA;AAAA;AAAA,EAGA,MAAM,OAAO,IAAA,EAAgC;AAC3C,IAAA,OAAO,MAAM,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,IAAI,CAAA;AAAA,EACxC;AAAA;AAAA,EAGA,MAAM,YAAY,IAAA,EAAqC;AACrD,IAAA,OAAO,MAAM,IAAA,CAAK,QAAA,CAAS,WAAA,CAAY,IAAI,CAAA;AAAA,EAC7C;AAAA;AAAA,EAGA,MAAM,eAAe,IAAA,EAA+B;AAClD,IAAA,OAAO,MAAM,IAAA,CAAK,QAAA,CAAS,cAAA,CAAe,IAAI,CAAA;AAAA,EAChD;AAAA;AAAA,EAGA,MAAM,OAAO,IAAA,EAA6B;AACxC,IAAA,MAAM,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,IAAI,CAAA;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAA,CAAW,MAAY,OAAA,EAAsC;AAC3D,IAAA,MAAM,MAAA,GAAS,KAAK,YAAA,CAAa,IAAA,EAAM,EAAE,IAAA,EAAM,OAAA,CAAQ,MAAM,CAAA;AAC7D,IAAA,IAAA,CAAK,uBAAA,CAAwB,GAAA,CAAI,MAAA,CAAO,MAAA,CAAO,IAAI,OAAO,CAAA;AAC1D,IAAA,IAAA,CAAK,aAAA,CAAc,KAAK,MAAM,CAAA;AAC9B,IAAA,IAAA,CAAK,YAAA,EAAa;AAClB,IAAA,IAAA,CAAK,WAAA,CAAY,QAAQ,OAAO,CAAA;AAChC,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,WAAA,CACE,KAAA,EACA,UAAA,EACA,YAAA,GAA6B,EAAC,EACjB;AACb,IAAA,MAAM,EAAA,GAAK,OAAO,UAAA,EAAW;AAC7B,IAAA,MAAM,OAAA,GAAU,KAAA,CAAM,GAAA,CAAI,CAAC,MAAM,CAAA,KAAM;AACrC,MAAA,MAAM,OAAA,GAAU,UAAA,CAAW,IAAA,EAAM,CAAC,CAAA;AAClC,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,YAAA,CAAa,IAAA,EAAM;AAAA,QACrC,OAAA,EAAS,EAAA;AAAA,QACT,MAAM,OAAA,CAAQ;AAAA,OACf,CAAA;AACD,MAAA,IAAA,CAAK,uBAAA,CAAwB,GAAA,CAAI,MAAA,CAAO,MAAA,CAAO,IAAI,OAAO,CAAA;AAC1D,MAAA,OAAO,MAAA;AAAA,IACT,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,aAAA,CAAc,IAAA,CAAK,GAAG,OAAO,CAAA;AAElC,IAAA,MAAM,KAAA,GAAQ,IAAI,WAAA,CAAY;AAAA,MAC5B,EAAA;AAAA,MACA,UAAU,MAAM;AACd,QAAA,IAAA,CAAK,YAAA,EAAa;AAAA,MACpB,CAAA;AAAA,MACA,OAAA,EAAS,YAAA;AAAA,MACT,SAAA,EAAW,CAAC,MAAA,KAAW;AACrB,QAAA,MAAM,UAAU,IAAA,CAAK,uBAAA,CAAwB,IAAI,MAAA,CAAO,MAAA,CAAO,EAAE,CAAA,IAAK;AAAA,UACpE,IAAA,EAAM,OAAO,MAAA,CAAO;AAAA,SACtB;AACA,QAAA,IAAA,CAAK,WAAA,CAAY,QAAQ,OAAO,CAAA;AAAA,MAClC,CAAA;AAAA,MACA,OAAA,EAAS;AAAA,KACV,CAAA;AAED,IAAA,IAAA,CAAK,OAAA,CAAQ,KAAK,KAAK,CAAA;AACvB,IAAA,IAAA,CAAK,YAAA,EAAa;AAClB,IAAA,KAAA,CAAM,MAAA,EAAO;AACb,IAAA,OAAO,KAAA;AAAA,EACT;AAAA,EAEQ,YAAA,CACN,MACA,OAAA,EACc;AACd,IAAA,MAAM,MAAA,GAAqB;AAAA,MACzB,gBAAA,EAAkB,CAAA;AAAA,MAClB,IAAA;AAAA,MACA,EAAA,EAAI,OAAO,UAAA,EAAW;AAAA,MACtB,MAAM,OAAA,CAAQ,IAAA;AAAA,MACd,QAAA,EAAU,CAAA;AAAA,MACV,MAAA,EAAQ,QAAA;AAAA,MACR,YAAY,IAAA,CAAK,IAAA;AAAA,MACjB,GAAI,QAAQ,OAAA,KAAY,MAAA,GAAY,EAAC,GAAI,EAAE,OAAA,EAAS,OAAA,CAAQ,OAAA;AAAQ,KACtE;AACA,IAAA,OAAO,IAAI,YAAA,CAAa,MAAA,EAAQ,MAAM;AACpC,MAAA,IAAA,CAAK,YAAA,EAAa;AAAA,IACpB,CAAC,CAAA;AAAA,EACH;AAAA,EAEQ,WAAA,CAAY,QAAsB,OAAA,EAA8B;AACtE,IAAA,MAAM,YAAA,GAAe,mBAAA,CAAoB,OAAA,CAAQ,KAAK,CAAA;AACtD,IAAA,MAAM,WAAA,GAAc,YAAA,GAAe,YAAA,CAAa,UAAA,GAAa,CAAA,GAAI,CAAA;AAEjE,IAAA,IAAI,OAAA,GAAU,CAAA;AACd,IAAA,IAAI,YAAA,GAAqD,IAAA;AACzD,IAAA,IAAI,WAAA,GAAyC,IAAA;AAC7C,IAAA,IAAI,OAAA,GAAU,KAAA;AACd,IAAA,IAAI,iBAAA,GAAoB,KAAA;AACxB,IAAA,IAAI,iBAAA,GAAkC,IAAA;AAEtC,IAAA,MAAM,oBAAoB,MAAY;AACpC,MAAA,IAAI,iBAAiB,IAAA,EAAM;AACzB,QAAA,YAAA,CAAa,YAAY,CAAA;AACzB,QAAA,YAAA,GAAe,IAAA;AAAA,MACjB;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,QAAQ,MAAY;AACxB,MAAA,OAAA,GAAU,IAAA;AACV,MAAA,iBAAA,EAAkB;AAClB,MAAA,WAAA,EAAa,MAAA,EAAO;AACpB,MAAA,WAAA,GAAc,IAAA;AACd,MAAA,iBAAA,GAAoB,IAAA;AAAA,IACtB,CAAA;AAEA,IAAA,MAAM,eAAA,GAAkB;AAAA,MACtB,YAAY,MAAY;AACtB,QAAA,IAAI,OAAA,EAAS;AACX,UAAA;AAAA,QACF;AAEA,QAAA,OAAA,IAAW,CAAA;AACX,QAAA,MAAA,CAAO,qBAAqB,OAAO,CAAA;AAEnC,QAAA,WAAA,GAAc,KAAK,QAAA,CAAS,MAAA,CAAO,MAAA,CAAO,MAAA,CAAO,MAAM,OAAA,EAAS;AAAA,UAC9D,OAAA,EAAS,CAAC,KAAA,KAAU;AAClB,YAAA,WAAA,GAAc,IAAA;AACd,YAAA,IAAI,OAAA,EAAS;AACX,cAAA;AAAA,YACF;AAEA,YAAA,IACE,OAAA,GAAU,WAAA,IACV,uBAAA,CAAwB,KAAA,EAAO,YAAY,CAAA,EAC3C;AACA,cAAA,MAAM,OAAA,GAAU,YAAA,GACZ,iBAAA,CAAkB,OAAA,EAAS,YAAY,CAAA,GACvC,CAAA;AACJ,cAAA,eAAA,CAAgB,aAAA,CAAc,OAAO,OAAO,CAAA;AAC5C,cAAA;AAAA,YACF;AAEA,YAAA,MAAA,CAAO,aAAa,KAAK,CAAA;AAAA,UAC3B,CAAA;AAAA,UACA,UAAA,EAAY,CAAC,gBAAA,EAAkB,UAAA,KAAe;AAC5C,YAAA,MAAA,CAAO,eAAA,CAAgB,kBAAkB,UAAU,CAAA;AAAA,UACrD,CAAA;AAAA,UACA,SAAA,EAAW,CAAC,WAAA,KAAgB;AAC1B,YAAA,WAAA,GAAc,IAAA;AACd,YAAA,IAAI,OAAA,EAAS;AACX,cAAA;AAAA,YACF;AACA,YAAA,MAAA,CAAO,eAAe,WAAW,CAAA;AAAA,UACnC;AAAA,SACD,CAAA;AACD,QAAA,MAAA,CAAO,YAAY,WAAW,CAAA;AAAA,MAChC,CAAA;AAAA,MACA,aAAA,EAAe,CAAC,KAAA,EAAc,OAAA,KAA0B;AACtD,QAAA,IAAI,OAAA,EAAS;AACX,UAAA;AAAA,QACF;AAEA,QAAA,iBAAA,GAAoB,KAAA;AACpB,QAAA,MAAA,CAAO,kBAAA,CAAmB;AAAA,UACxB,SAAS,OAAA,GAAU,CAAA;AAAA,UACnB,OAAA;AAAA,UACA,KAAA;AAAA,UACA;AAAA,SACD,CAAA;AAED,QAAA,YAAA,GAAe,WAAW,MAAM;AAC9B,UAAA,YAAA,GAAe,IAAA;AACf,UAAA,IAAI,WAAW,iBAAA,EAAmB;AAChC,YAAA;AAAA,UACF;AACA,UAAA,iBAAA,GAAoB,IAAA;AACpB,UAAA,eAAA,CAAgB,UAAA,EAAW;AAAA,QAC7B,GAAG,OAAO,CAAA;AAAA,MACZ;AAAA,KACF;AAEA,IAAA,MAAA,CAAO,qBAAA,CAAsB;AAAA,MAC3B,KAAA;AAAA,MACA,kBAAkB,MAAM;AACtB,QAAA,iBAAA,GAAoB,IAAA;AACpB,QAAA,iBAAA,EAAkB;AAAA,MACpB,CAAA;AAAA,MACA,mBAAmB,MAAM;AACvB,QAAA,IAAI,OAAA,EAAS;AACX,UAAA;AAAA,QACF;AACA,QAAA,iBAAA,GAAoB,KAAA;AACpB,QAAA,IAAI,iBAAA,EAAmB;AACrB,UAAA,eAAA,CAAgB,aAAA,CAAc,mBAAmB,CAAC,CAAA;AAAA,QACpD;AAAA,MACF;AAAA,KACD,CAAA;AAED,IAAA,eAAA,CAAgB,UAAA,EAAW;AAAA,EAC7B;AAAA,EAEQ,YAAA,GAAqB;AAC3B,IAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AACnB,IAAA,MAAM,KAAA,GAAQ,KAAK,QAAA,EAAS;AAC5B,IAAA,KAAA,MAAW,QAAA,IAAY,KAAK,eAAA,EAAiB;AAC3C,MAAA,QAAA,CAAS,KAAK,CAAA;AAAA,IAChB;AAAA,EACF;AACF,CAAA;AC3PA,IAAM,cAAA,GAAiB,CAAC,KAAA,KACtB,OAAO,KAAA,KAAU,QAAA,IACjB,KAAA,KAAU,IAAA,IACV,MAAA,IAAU,KAAA,IACV,OAAQ,KAAA,CAA4B,IAAA,KAAS,QAAA;AAE/C,IAAM,OAAA,GAAU,CAAC,KAAA,KACf,KAAA,YAAiB,KAAA,GAAQ,QAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AAEnD,IAAM,0BAAN,MAAyD;AAAA,EAC7C,OAAA;AAAA,EAEjB,YAAY,OAAA,EAA0B;AACpC,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAAA,EACjB;AAAA,EAEA,MAAA,CACE,IAAA,EACA,OAAA,EACA,SAAA,EACoB;AACpB,IAAA,MAAM,UAAA,GAAa,GAAA,CAAI,IAAA,CAAK,OAAA,EAAS,QAAQ,IAAI,CAAA;AAEjD,IAAA,MAAM,WAAW,OAAA,CAAQ,cAAA,GACrB,EAAE,cAAA,EAAgB,OAAA,CAAQ,gBAAe,GACzC,MAAA;AAEJ,IAAA,MAAM,IAAA,GAAO,oBAAA,CAAqB,UAAA,EAAY,IAAA,EAAM,QAAQ,CAAA;AAE5D,IAAA,IAAA,CAAK,EAAA;AAAA,MACH,eAAA;AAAA,MACA,CAAC,QAAA,KAAa;AACZ,QAAA,SAAA,CAAU,UAAA,CAAW,QAAA,CAAS,gBAAA,EAAkB,QAAA,CAAS,UAAU,CAAA;AAAA,MACrE,CAAA;AAAA,MACA,CAAC,KAAA,KAAU;AACT,QAAA,SAAA,CAAU,QAAQ,KAAK,CAAA;AAAA,MACzB,CAAA;AAAA,MACA,MAAM;AACJ,QAAA,KAAA,CAAM,YAAY;AAChB,UAAA,IAAI;AACF,YAAA,MAAM,WAAA,GAAc,MAAM,cAAA,CAAe,UAAU,CAAA;AACnD,YAAA,SAAA,CAAU,UAAU,WAAW,CAAA;AAAA,UACjC,SAAS,KAAA,EAAO;AACd,YAAA,SAAA,CAAU,OAAA,CAAQ,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,UAClC;AAAA,QACF,CAAA,GAAG;AAAA,MACL;AAAA,KACF;AAEA,IAAA,OAAO;AAAA,MACL,QAAQ,MAAM;AACZ,QAAA,IAAA,CAAK,MAAA,EAAO;AAAA,MACd,CAAA;AAAA,MACA,OAAO,MAAM;AACX,QAAA,IAAA,CAAK,KAAA,EAAM;AAAA,MACb,CAAA;AAAA,MACA,QAAQ,MAAM;AACZ,QAAA,IAAA,CAAK,MAAA,EAAO;AAAA,MACd;AAAA,KACF;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,IAAA,EAAgC;AAC3C,IAAA,IAAI;AACF,MAAA,MAAM,WAAA,CAAY,GAAA,CAAI,IAAA,CAAK,OAAA,EAAS,IAAI,CAAC,CAAA;AACzC,MAAA,OAAO,IAAA;AAAA,IACT,SAAS,KAAA,EAAO;AACd,MAAA,IAAI,cAAA,CAAe,KAAK,CAAA,IAAK,KAAA,CAAM,SAAS,0BAAA,EAA4B;AACtE,QAAA,OAAO,KAAA;AAAA,MACT;AACA,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,IAAA,EAAqC;AACrD,IAAA,MAAM,OAAO,MAAM,WAAA,CAAY,IAAI,IAAA,CAAK,OAAA,EAAS,IAAI,CAAC,CAAA;AACtD,IAAA,OAAO;AAAA,MACL,aAAa,IAAA,CAAK,WAAA;AAAA,MAClB,SAAA,EAAW,IAAI,IAAA,CAAK,IAAA,CAAK,WAAW,CAAA;AAAA,MACpC,gBAAgB,IAAA,CAAK,cAAA;AAAA,MACrB,IAAA;AAAA,MACA,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,SAAA,EAAW,IAAI,IAAA,CAAK,IAAA,CAAK,OAAO;AAAA,KAClC;AAAA,EACF;AAAA,EAEA,MAAM,eAAe,IAAA,EAA+B;AAClD,IAAA,OAAO,MAAM,cAAA,CAAe,GAAA,CAAI,IAAA,CAAK,OAAA,EAAS,IAAI,CAAC,CAAA;AAAA,EACrD;AAAA,EAEA,MAAM,OAAO,IAAA,EAA6B;AACxC,IAAA,MAAM,YAAA,CAAa,GAAA,CAAI,IAAA,CAAK,OAAA,EAAS,IAAI,CAAC,CAAA;AAAA,EAC5C;AACF,CAAA;;;ACxGO,IAAMA,eAAAA,GAAN,cAA6B,cAAA,CAAmB;AAAA,EACrD,YAAY,OAAA,EAA0B;AACpC,IAAA,KAAA,CAAM,IAAI,uBAAA,CAAwB,OAAO,CAAC,CAAA;AAAA,EAC5C;AACF","file":"chunk-PBO3CMOD.js","sourcesContent":["type Listener<TPayload> = (payload: TPayload) => void;\n\nexport class Emitter<TEvents extends Record<string, unknown>> {\n private listeners: { [K in keyof TEvents]?: Set<Listener<TEvents[K]>> } = {};\n\n /**\n * @param event The event to listen for.\n * @param listener The function to call when the event is emitted.\n * @returns A function to unsubscribe from the event.\n */\n on<K extends keyof TEvents>(event: K, listener: Listener<TEvents[K]>) {\n let listeners = this.listeners[event];\n if (!listeners) {\n listeners = new Set();\n this.listeners[event] = listeners;\n }\n\n listeners.add(listener);\n\n return () => {\n this.listeners[event]?.delete(listener);\n };\n }\n\n /**\n * @param event The event to emit.\n * @param payload The payload to emit.\n */\n protected emit<K extends keyof TEvents>(event: K, payload: TEvents[K]) {\n const listeners = this.listeners[event];\n\n if (!listeners) {\n return;\n }\n\n for (const listener of listeners) {\n listener(payload);\n }\n }\n}\n","import type { UploadBatch, UploadItem } from \"../types/upload\";\nimport { Emitter } from \"./emitter\";\nimport type { UploadHandle, UploadRetryEvent } from \"./upload-handle\";\n\n/**\n * Events on a batch from {@link StorageManager.uploadFiles}. `progress` / `change` carry a {@link UploadBatch} snapshot.\n * `uploadSuccess`, `uploadError`, and `uploadRetry` fire once per child (retry can fire multiple times per child). When all children are done: `success` (normal end) or `error` (only if `continueOnError` was `false` and one failed).\n */\nexport interface BatchHandleEvents extends Record<string, unknown> {\n progress: UploadBatch;\n uploadSuccess: UploadItem;\n uploadError: UploadItem;\n uploadRetry: UploadRetryEvent;\n success: UploadBatch;\n error: UploadBatch;\n change: UploadBatch;\n}\n\n/** Settings for {@link StorageManager.uploadFiles} (third argument). */\nexport interface BatchOptions {\n /** How many files upload at the same time. Default is 3. */\n concurrency?: number;\n /**\n * `true` (default): if one file fails, the others keep going. When every file has finished, the batch fires `success` — look at each upload for errors.\n *\n * `false`: the first failure stops the other files and the batch fires `error`.\n */\n continueOnError?: boolean;\n}\n\nexport interface BatchHandleInit {\n id: string;\n uploads: UploadHandle[];\n options: BatchOptions;\n startNext: (handle: UploadHandle) => void;\n onChange: () => void;\n}\n\n/**\n * A group of files from {@link StorageManager.uploadFiles}. Use `.on(...)` like a single {@link UploadHandle}, plus `snapshot()` for totals.\n */\nexport class BatchHandle extends Emitter<BatchHandleEvents> {\n public readonly id: string;\n public readonly uploads: UploadHandle[];\n\n private readonly concurrency: number;\n private readonly continueOnError: boolean;\n private readonly startNext: (handle: UploadHandle) => void;\n private readonly onChange: () => void;\n\n private running = 0;\n private nextIdx = 0;\n /** Indices that were started via {@link fillSlots} and still hold a concurrency slot. */\n private readonly activeSlots = new Set<number>();\n private settledCount = 0;\n private succeededCount = 0;\n private failedCount = 0;\n private failedFast = false;\n private canceled = false;\n private paused = false;\n private terminalEmitted = false;\n\n // Stable view of UploadItems; the items themselves mutate in place, but the\n // array reference never changes, so we allocate it once instead of rebuilding\n // it on every snapshot.\n private readonly uploadsView: UploadItem[];\n\n // Running aggregates updated incrementally on each child event so snapshot()\n // is O(1) instead of O(n) per progress tick.\n private aggregateBytesTransferred = 0;\n private aggregateTotalBytes = 0;\n private readonly lastBytes: number[];\n private readonly lastTotal: number[];\n\n constructor(init: BatchHandleInit) {\n super();\n this.id = init.id;\n this.uploads = init.uploads;\n this.concurrency = Math.max(1, init.options.concurrency ?? 3);\n this.continueOnError = init.options.continueOnError ?? true;\n this.startNext = init.startNext;\n this.onChange = init.onChange;\n\n this.uploadsView = init.uploads.map((h) => h.upload);\n this.lastBytes = Array.from(\n { length: init.uploads.length },\n (): number => 0\n );\n this.lastTotal = Array.from(\n { length: init.uploads.length },\n (): number => 0\n );\n for (let i = 0; i < this.uploadsView.length; i += 1) {\n const u = this.uploadsView[i];\n if (!u) {\n continue;\n }\n this.lastBytes[i] = u.bytesTransferred;\n this.lastTotal[i] = u.totalBytes;\n this.aggregateBytesTransferred += u.bytesTransferred;\n this.aggregateTotalBytes += u.totalBytes;\n }\n\n for (let idx = 0; idx < this.uploads.length; idx += 1) {\n const child = this.uploads[idx];\n if (!child) {\n continue;\n }\n child.on(\"progress\", (upload) => {\n this.handleChildProgress(idx, upload);\n });\n child.on(\"retry\", (retryEvent) => {\n this.handleChildRetry(idx, retryEvent);\n });\n child.on(\"success\", (upload) => {\n this.handleChildSettled(idx, upload, \"success\");\n });\n child.on(\"error\", (upload) => {\n this.handleChildSettled(idx, upload, \"error\");\n });\n child.on(\"canceled\", (upload) => {\n this.handleChildSettled(idx, upload, \"canceled\");\n });\n }\n }\n\n /** @internal */\n _start(): void {\n this.fillSlots();\n }\n\n cancel(): void {\n if (this.canceled || this.terminalEmitted) {\n return;\n }\n this.canceled = true;\n for (const h of this.uploads) {\n const s = h.upload.status;\n if (\n s === \"queued\" ||\n s === \"uploading\" ||\n s === \"retrying\" ||\n s === \"paused\"\n ) {\n h.cancel();\n }\n }\n this.onChange();\n }\n\n pause(): void {\n if (this.paused || this.canceled || this.terminalEmitted) {\n return;\n }\n this.paused = true;\n for (const h of this.uploads) {\n if (h.upload.status === \"uploading\" || h.upload.status === \"retrying\") {\n h.pause();\n }\n }\n this.onChange();\n }\n\n resume(): void {\n if (!this.paused || this.canceled || this.terminalEmitted) {\n return;\n }\n this.paused = false;\n for (const h of this.uploads) {\n if (h.upload.status === \"paused\") {\n h.resume();\n }\n }\n this.fillSlots();\n this.onChange();\n }\n\n snapshot(): UploadBatch {\n const totalProgress =\n this.aggregateTotalBytes > 0\n ? (this.aggregateBytesTransferred / this.aggregateTotalBytes) * 100\n : 0;\n return {\n completedCount: this.succeededCount,\n failedCount: this.failedCount,\n id: this.id,\n totalProgress,\n uploads: this.uploadsView,\n };\n }\n\n private updateAggregate(idx: number, u: UploadItem): void {\n const prevBytes = this.lastBytes[idx] ?? 0;\n const prevTotal = this.lastTotal[idx] ?? 0;\n this.aggregateBytesTransferred += u.bytesTransferred - prevBytes;\n this.aggregateTotalBytes += u.totalBytes - prevTotal;\n this.lastBytes[idx] = u.bytesTransferred;\n this.lastTotal[idx] = u.totalBytes;\n }\n\n private fillSlots(): void {\n while (\n !this.canceled &&\n !this.paused &&\n !this.failedFast &&\n this.running < this.concurrency &&\n this.nextIdx < this.uploads.length\n ) {\n const idx = this.nextIdx;\n this.nextIdx += 1;\n const handle = this.uploads[idx];\n if (!handle || handle.upload.status !== \"queued\") {\n continue;\n }\n this.activeSlots.add(idx);\n this.running += 1;\n this.startNext(handle);\n }\n }\n\n private handleChildProgress(idx: number, upload: UploadItem): void {\n this.updateAggregate(idx, upload);\n const snap = this.snapshot();\n this.emit(\"progress\", snap);\n this.emit(\"change\", snap);\n }\n\n private handleChildRetry(idx: number, event: UploadRetryEvent): void {\n this.updateAggregate(idx, event.upload);\n this.emit(\"uploadRetry\", event);\n const snap = this.snapshot();\n this.emit(\"change\", snap);\n }\n\n private handleChildSettled(\n idx: number,\n upload: UploadItem,\n kind: \"success\" | \"error\" | \"canceled\"\n ): void {\n this.updateAggregate(idx, upload);\n if (this.activeSlots.delete(idx)) {\n this.running = Math.max(0, this.running - 1);\n }\n this.settledCount += 1;\n\n if (kind === \"success\") {\n this.succeededCount += 1;\n this.emit(\"uploadSuccess\", upload);\n } else if (kind === \"error\") {\n this.failedCount += 1;\n this.emit(\"uploadError\", upload);\n }\n\n const snap = this.snapshot();\n this.emit(\"change\", snap);\n\n if (\n kind === \"error\" &&\n !this.continueOnError &&\n !this.failedFast &&\n !this.canceled\n ) {\n this.failedFast = true;\n for (const h of this.uploads) {\n if (h.upload.id === upload.id) {\n continue;\n }\n const s = h.upload.status;\n if (\n s === \"queued\" ||\n s === \"uploading\" ||\n s === \"retrying\" ||\n s === \"paused\"\n ) {\n h.cancel();\n }\n }\n this.terminalEmitted = true;\n this.emit(\"error\", snap);\n this.onChange();\n return;\n }\n\n if (this.failedFast || this.canceled) {\n // we call this because a task can canceled as seen above\n // by h.cancel(). Which then triggers the handelchildSettled call above.\n this.onChange();\n return;\n }\n\n this.fillSlots();\n\n if (this.settledCount >= this.uploads.length && !this.terminalEmitted) {\n this.terminalEmitted = true;\n this.emit(\"success\", snap);\n }\n\n this.onChange();\n }\n}\n","import type { RetryOptions } from \"../types/provider\";\n\nexport interface ResolvedRetryOptions {\n maxRetries: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n isRetryable?: (error: Error) => boolean;\n}\n\nexport const DEFAULT_RETRY_OPTIONS: ResolvedRetryOptions = {\n initialDelayMs: 1000,\n jitter: true,\n maxDelayMs: 30_000,\n maxRetries: 3,\n};\n\nconst NON_RETRYABLE_CODES = new Set([\n \"storage/canceled\",\n \"storage/unauthorized\",\n \"storage/unauthenticated\",\n \"storage/quota-exceeded\",\n \"storage/invalid-argument\",\n \"storage/invalid-argument-count\",\n \"storage/invalid-url\",\n \"storage/invalid-default-bucket\",\n \"storage/no-default-bucket\",\n \"storage/bucket-not-found\",\n \"storage/project-not-found\",\n \"storage/invalid-root-operation\",\n \"storage/invalid-event-name\",\n \"storage/invalid-format\",\n \"storage/no-download-url\",\n \"storage/unauthorized-app\",\n \"storage/unsupported-environment\",\n]);\n\nconst RETRYABLE_CODES = new Set([\n \"storage/retry-limit-exceeded\",\n \"storage/unknown\",\n \"storage/invalid-checksum\",\n \"storage/cannot-slice-blob\",\n \"storage/server-file-wrong-size\",\n]);\n\n/** Resolves upload retry settings. Returns `null` when retries are disabled. */\nexport const resolveRetryOptions = (\n retry?: RetryOptions | false\n): ResolvedRetryOptions | null => {\n if (retry === false) {\n return null;\n }\n return {\n ...DEFAULT_RETRY_OPTIONS,\n ...retry,\n };\n};\n\nconst hasStorageErrorCode = (error: Error): error is Error & { code: string } =>\n \"code\" in error && typeof error.code === \"string\";\n\n/** Reads a Firebase-style `code` from an error without importing Firebase types. */\nexport const getStorageErrorCode = (error: Error): string | undefined => {\n if (!hasStorageErrorCode(error)) {\n return undefined;\n }\n return error.code;\n};\n\n/** Whether an upload error should trigger another attempt. */\nexport const isRetryableStorageError = (\n error: Error,\n options: ResolvedRetryOptions | null\n): boolean => {\n if (!options) {\n return false;\n }\n\n if (options.isRetryable) {\n return options.isRetryable(error);\n }\n\n const code = getStorageErrorCode(error);\n if (code !== undefined) {\n if (NON_RETRYABLE_CODES.has(code)) {\n return false;\n }\n if (RETRYABLE_CODES.has(code)) {\n return true;\n }\n return false;\n }\n\n return true;\n};\n\n/** Computes backoff delay after a failed attempt (1-based). */\nexport const computeRetryDelay = (\n failedAttempt: number,\n options: ResolvedRetryOptions\n): number => {\n const base = Math.min(\n options.maxDelayMs,\n options.initialDelayMs * 2 ** (failedAttempt - 1)\n );\n if (!options.jitter) {\n return base;\n }\n return Math.round(base * (0.5 + Math.random() * 0.5));\n};\n","import type { ProviderUploadTask } from \"../types/provider\";\nimport type { UploadItem, UploadStatus } from \"../types/upload\";\nimport { Emitter } from \"./emitter\";\n\nexport interface UploadRetryEvent {\n upload: UploadItem;\n error: Error;\n attempt: number;\n maxAttempts: number;\n delayMs: number;\n}\n\nexport interface UploadRetryBackoffDetails {\n attempt: number;\n maxAttempts: number;\n delayMs: number;\n error: Error;\n}\n\nexport interface UploadControlHooks {\n abort: () => void;\n pauseDuringRetry?: () => void;\n resumeDuringRetry?: () => void;\n}\n\nexport interface UploadHandleEvents extends Record<string, unknown> {\n progress: UploadItem;\n success: UploadItem;\n error: UploadItem;\n canceled: UploadItem;\n statusChange: UploadItem;\n retry: UploadRetryEvent;\n}\n\n/** Controls file upload and tracks its progress.\n *\n * @param upload The upload item to control.\n * @param onChange A function to call when the upload status changes.\n * @returns An {@link UploadHandle} to control the upload: `pause`, `resume`, `cancel`, and listen for progress with `.on`.\n */\nexport class UploadHandle extends Emitter<UploadHandleEvents> {\n public readonly upload: UploadItem;\n\n private task: ProviderUploadTask | null = null;\n private readonly onChange: () => void;\n private terminated = false;\n private controlHooks: UploadControlHooks | null = null;\n private pausedDuringRetry = false;\n\n constructor(upload: UploadItem, onChange: () => void) {\n super();\n this.upload = upload;\n this.onChange = onChange;\n }\n\n /** @internal */\n _attachTask(task: ProviderUploadTask): void {\n this.task = task;\n }\n\n /** @internal */\n _registerControlHooks(hooks: UploadControlHooks): void {\n this.controlHooks = hooks;\n }\n\n /** @internal */\n _clearControlHooks(): void {\n this.controlHooks = null;\n }\n\n /** @internal */\n _setStatus(status: UploadStatus): void {\n if (this.upload.status === status) {\n return;\n }\n this.upload.status = status;\n this.emit(\"statusChange\", this.upload);\n }\n\n /** @internal */\n _reportProgress(bytesTransferred: number, totalBytes: number): void {\n if (this.terminated) {\n return;\n }\n this.upload.bytesTransferred = bytesTransferred;\n this.upload.totalBytes = totalBytes;\n this.upload.progress =\n totalBytes > 0 ? (bytesTransferred / totalBytes) * 100 : 0;\n if (this.upload.status !== \"uploading\") {\n this._setStatus(\"uploading\");\n }\n this.emit(\"progress\", this.upload);\n this.onChange();\n }\n\n /** @internal */\n _prepareRetryAttempt(attempt: number): void {\n if (this.terminated) {\n return;\n }\n this.upload.retryAttempt = attempt;\n this.upload.bytesTransferred = 0;\n this.upload.progress = 0;\n this.upload.error = undefined;\n this.pausedDuringRetry = false;\n this._setStatus(\"uploading\");\n this.onChange();\n }\n\n /** @internal */\n _enterRetryBackoff(details: UploadRetryBackoffDetails): void {\n if (this.terminated) {\n return;\n }\n this.upload.retryAttempt = details.attempt;\n this.upload.error = details.error;\n this.task = null;\n this._setStatus(\"retrying\");\n this.emit(\"retry\", {\n attempt: details.attempt,\n delayMs: details.delayMs,\n error: details.error,\n maxAttempts: details.maxAttempts,\n upload: this.upload,\n });\n this.onChange();\n }\n\n /** @internal */\n _reportSuccess(downloadURL: string): void {\n if (this.terminated) {\n return;\n }\n this.terminated = true;\n this.upload.downloadURL = downloadURL;\n this.upload.progress = 100;\n this._clearControlHooks();\n this._setStatus(\"success\");\n this.emit(\"success\", this.upload);\n this.onChange();\n }\n\n /** @internal */\n _reportError(error: Error): void {\n if (this.terminated) {\n return;\n }\n this.terminated = true;\n this.upload.error = error;\n this._clearControlHooks();\n this._setStatus(\"error\");\n this.emit(\"error\", this.upload);\n this.onChange();\n }\n\n cancel(): void {\n if (this.terminated) {\n return;\n }\n this.terminated = true;\n this.controlHooks?.abort();\n this.task?.cancel();\n this._clearControlHooks();\n this._setStatus(\"canceled\");\n this.emit(\"canceled\", this.upload);\n this.onChange();\n }\n\n pause(): void {\n if (this.terminated) {\n return;\n }\n if (this.upload.status === \"uploading\") {\n this.task?.pause?.();\n this._setStatus(\"paused\");\n this.onChange();\n return;\n }\n if (this.upload.status === \"retrying\") {\n this.pausedDuringRetry = true;\n this.controlHooks?.pauseDuringRetry?.();\n this._setStatus(\"paused\");\n this.onChange();\n }\n }\n\n resume(): void {\n if (this.terminated) {\n return;\n }\n if (this.upload.status !== \"paused\") {\n return;\n }\n\n if (this.pausedDuringRetry) {\n this.pausedDuringRetry = false;\n this.controlHooks?.resumeDuringRetry?.();\n this.onChange();\n return;\n }\n\n this.task?.resume?.();\n this._setStatus(\"uploading\");\n this.onChange();\n }\n}\n","import type { StorageProvider } from \"../providers/provider\";\nimport type { FileMetadata } from \"../types/metadata\";\nimport type { ProviderUploadTask, UploadOptions } from \"../types/provider\";\nimport type { StorageState, UploadItem } from \"../types/upload\";\nimport type { BatchOptions } from \"./batch-handle\";\nimport { BatchHandle } from \"./batch-handle\";\nimport {\n computeRetryDelay,\n isRetryableStorageError,\n resolveRetryOptions,\n} from \"./retry\";\nimport { UploadHandle } from \"./upload-handle\";\n\n/**\n * Manages file uploads and storage queries.\n *\n * You can react in two ways: call `.on(...)` on each {@link UploadHandle} / {@link BatchHandle}, **or** call `subscribe` to get the same lists\n * that {@link StorageManager.getState} returns whenever anything changes (call the returned function to stop listening).\n *\n */\nexport class StorageManager {\n private readonly provider: StorageProvider;\n private readonly uploadHandles: UploadHandle[] = [];\n private readonly batches: BatchHandle[] = [];\n private readonly changeListeners = new Set<(state: StorageState) => void>();\n private cachedState: StorageState | null = null;\n private readonly uploadOptionsByHandleId = new Map<string, UploadOptions>();\n\n constructor(provider: StorageProvider) {\n this.provider = provider;\n }\n\n /** Current `uploads` and `batches` state. */\n getState = (): StorageState => {\n this.cachedState ??= {\n batches: this.batches.map((b) => b.snapshot()),\n uploads: this.uploadHandles.map((h) => h.upload),\n };\n return this.cachedState;\n };\n\n /** Runs `listener` after each change; returns a function — call it to unsubscribe. */\n subscribe = (listener: (state: StorageState) => void): (() => void) => {\n this.changeListeners.add(listener);\n return () => {\n this.changeListeners.delete(listener);\n };\n };\n\n /** Returns `true` if the object exists. Returns `false` only for not-found; other errors are thrown. */\n async exists(path: string): Promise<boolean> {\n return await this.provider.exists(path);\n }\n\n /** Returns metadata for the object at `path`. Throws if the object does not exist. */\n async getMetadata(path: string): Promise<FileMetadata> {\n return await this.provider.getMetadata(path);\n }\n\n /** Returns a download URL for the object at `path`. */\n async getDownloadURL(path: string): Promise<string> {\n return await this.provider.getDownloadURL(path);\n }\n\n /** Deletes the object at `path`. */\n async delete(path: string): Promise<void> {\n await this.provider.delete(path);\n }\n\n /** Starts the file upload.`options.path` is the object path in storage (see {@link UploadOptions}).\n *\n * @returns An {@link UploadHandle} to control the upload: `pause`, `resume`, `cancel`, and listen for progress with `.on`.\n */\n uploadFile(file: File, options: UploadOptions): UploadHandle {\n const handle = this.createHandle(file, { path: options.path });\n this.uploadOptionsByHandleId.set(handle.upload.id, options);\n this.uploadHandles.push(handle);\n this.notifyChange();\n this.startUpload(handle, options);\n return handle;\n }\n\n /**\n * Upload several files as one batch. The optional third argument sets how many run at once\n * and what happens when one file fails — see {@link BatchOptions}.\n *\n * `optionsFor` picks storage options per file (same as `uploadFile`); index matches `files` order.\n * If `continueOnError` is `false`, the first failure cancels the other files and the batch fires `error`.\n * If it stays `true` (default), other files keep going; when every file has finished, the batch fires `success`.\n *\n */\n uploadFiles(\n files: File[],\n optionsFor: (file: File, index: number) => UploadOptions,\n batchOptions: BatchOptions = {}\n ): BatchHandle {\n const id = crypto.randomUUID();\n const handles = files.map((file, i) => {\n const options = optionsFor(file, i);\n const handle = this.createHandle(file, {\n batchId: id,\n path: options.path,\n });\n this.uploadOptionsByHandleId.set(handle.upload.id, options);\n return handle;\n });\n\n this.uploadHandles.push(...handles);\n\n const batch = new BatchHandle({\n id,\n onChange: () => {\n this.notifyChange();\n },\n options: batchOptions,\n startNext: (handle) => {\n const options = this.uploadOptionsByHandleId.get(handle.upload.id) ?? {\n path: handle.upload.path,\n };\n this.startUpload(handle, options);\n },\n uploads: handles,\n });\n\n this.batches.push(batch);\n this.notifyChange();\n batch._start();\n return batch;\n }\n\n private createHandle(\n file: File,\n options: { path: string; batchId?: string }\n ): UploadHandle {\n const upload: UploadItem = {\n bytesTransferred: 0,\n file,\n id: crypto.randomUUID(),\n path: options.path,\n progress: 0,\n status: \"queued\",\n totalBytes: file.size,\n ...(options.batchId === undefined ? {} : { batchId: options.batchId }),\n };\n return new UploadHandle(upload, () => {\n this.notifyChange();\n });\n }\n\n private startUpload(handle: UploadHandle, options: UploadOptions): void {\n const retryOptions = resolveRetryOptions(options.retry);\n const maxAttempts = retryOptions ? retryOptions.maxRetries + 1 : 1;\n\n let attempt = 0;\n let retryTimeout: ReturnType<typeof setTimeout> | null = null;\n let currentTask: ProviderUploadTask | null = null;\n let aborted = false;\n let pausedDuringRetry = false;\n let pendingRetryError: Error | null = null;\n\n const clearRetryTimeout = (): void => {\n if (retryTimeout !== null) {\n clearTimeout(retryTimeout);\n retryTimeout = null;\n }\n };\n\n const abort = (): void => {\n aborted = true;\n clearRetryTimeout();\n currentTask?.cancel();\n currentTask = null;\n pendingRetryError = null;\n };\n\n const retryController = {\n runAttempt: (): void => {\n if (aborted) {\n return;\n }\n\n attempt += 1;\n handle._prepareRetryAttempt(attempt);\n\n currentTask = this.provider.upload(handle.upload.file, options, {\n onError: (error) => {\n currentTask = null;\n if (aborted) {\n return;\n }\n\n if (\n attempt < maxAttempts &&\n isRetryableStorageError(error, retryOptions)\n ) {\n const delayMs = retryOptions\n ? computeRetryDelay(attempt, retryOptions)\n : 0;\n retryController.scheduleRetry(error, delayMs);\n return;\n }\n\n handle._reportError(error);\n },\n onProgress: (bytesTransferred, totalBytes) => {\n handle._reportProgress(bytesTransferred, totalBytes);\n },\n onSuccess: (downloadURL) => {\n currentTask = null;\n if (aborted) {\n return;\n }\n handle._reportSuccess(downloadURL);\n },\n });\n handle._attachTask(currentTask);\n },\n scheduleRetry: (error: Error, delayMs: number): void => {\n if (aborted) {\n return;\n }\n\n pendingRetryError = error;\n handle._enterRetryBackoff({\n attempt: attempt + 1,\n delayMs,\n error,\n maxAttempts,\n });\n\n retryTimeout = setTimeout(() => {\n retryTimeout = null;\n if (aborted || pausedDuringRetry) {\n return;\n }\n pendingRetryError = null;\n retryController.runAttempt();\n }, delayMs);\n },\n };\n\n handle._registerControlHooks({\n abort,\n pauseDuringRetry: () => {\n pausedDuringRetry = true;\n clearRetryTimeout();\n },\n resumeDuringRetry: () => {\n if (aborted) {\n return;\n }\n pausedDuringRetry = false;\n if (pendingRetryError) {\n retryController.scheduleRetry(pendingRetryError, 0);\n }\n },\n });\n\n retryController.runAttempt();\n }\n\n private notifyChange(): void {\n this.cachedState = null;\n const state = this.getState();\n for (const listener of this.changeListeners) {\n listener(state);\n }\n }\n}\n","import {\n deleteObject,\n getDownloadURL,\n getMetadata,\n ref,\n uploadBytesResumable,\n} from \"firebase/storage\";\nimport type { FirebaseStorage, StorageError } from \"firebase/storage\";\n\nimport type { FileMetadata } from \"../types/metadata\";\nimport type {\n ProviderUploadCallbacks,\n ProviderUploadTask,\n UploadOptions,\n} from \"../types/provider\";\nimport type { StorageProvider } from \"./provider\";\n\nconst isStorageError = (error: unknown): error is StorageError =>\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n typeof (error as { code: unknown }).code === \"string\";\n\nconst toError = (error: unknown): Error =>\n error instanceof Error ? error : new Error(String(error));\n\nexport class FirebaseStorageProvider implements StorageProvider {\n private readonly storage: FirebaseStorage;\n\n constructor(storage: FirebaseStorage) {\n this.storage = storage;\n }\n\n upload(\n file: File,\n options: UploadOptions,\n callbacks: ProviderUploadCallbacks\n ): ProviderUploadTask {\n const storageRef = ref(this.storage, options.path);\n\n const metadata = options.customMetadata\n ? { customMetadata: options.customMetadata }\n : undefined;\n\n const task = uploadBytesResumable(storageRef, file, metadata);\n\n task.on(\n \"state_changed\",\n (snapshot) => {\n callbacks.onProgress(snapshot.bytesTransferred, snapshot.totalBytes);\n },\n (error) => {\n callbacks.onError(error);\n },\n () => {\n void (async () => {\n try {\n const downloadURL = await getDownloadURL(storageRef);\n callbacks.onSuccess(downloadURL);\n } catch (error) {\n callbacks.onError(toError(error));\n }\n })();\n }\n );\n\n return {\n cancel: () => {\n task.cancel();\n },\n pause: () => {\n task.pause();\n },\n resume: () => {\n task.resume();\n },\n };\n }\n\n async exists(path: string): Promise<boolean> {\n try {\n await getMetadata(ref(this.storage, path));\n return true;\n } catch (error) {\n if (isStorageError(error) && error.code === \"storage/object-not-found\") {\n return false;\n }\n throw error;\n }\n }\n\n async getMetadata(path: string): Promise<FileMetadata> {\n const meta = await getMetadata(ref(this.storage, path));\n return {\n contentType: meta.contentType,\n createdAt: new Date(meta.timeCreated),\n customMetadata: meta.customMetadata,\n path,\n size: meta.size,\n updatedAt: new Date(meta.updated),\n };\n }\n\n async getDownloadURL(path: string): Promise<string> {\n return await getDownloadURL(ref(this.storage, path));\n }\n\n async delete(path: string): Promise<void> {\n await deleteObject(ref(this.storage, path));\n }\n}\n","import type { FirebaseStorage } from \"firebase/storage\";\n\nimport { StorageManager as BaseStorageManager } from \"./core/storage-manager\";\nimport { FirebaseStorageProvider } from \"./providers/firebase-provider\";\n\n/** Firebase Storage uploads and file helpers. Pass a `FirebaseStorage` instance from `getStorage(app)`. */\nexport class StorageManager extends BaseStorageManager {\n constructor(storage: FirebaseStorage) {\n super(new FirebaseStorageProvider(storage));\n }\n}\n"]}
|