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.
@@ -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
- _prepareRetryAttempt(attempt) {
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.startUpload(handle, options);
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.startUpload(handle, options);
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._prepareRetryAttempt(attempt);
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.customMetadata ? { customMetadata: options.customMetadata } : void 0;
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-PBO3CMOD.js.map
766
- //# sourceMappingURL=chunk-PBO3CMOD.js.map
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"]}
@@ -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, StorageManager as S, type UploadBatch as U, type BatchHandleEvents as a, type BatchHandleInit as b, type BatchOptions as c, type ProviderUploadTask as d, type StorageState as e, type UploadControlHooks as f, UploadHandle as g, type UploadHandleEvents as h, type UploadItem as i, type UploadOptions as j, type UploadRetryBackoffDetails as k, type UploadRetryEvent as l, type UploadStatus as m };
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-DT6lxmUD.js';
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 StorageManager, e as StorageState, U as UploadBatch, f as UploadControlHooks, g as UploadHandle, h as UploadHandleEvents, i as UploadItem, j as UploadOptions, k as UploadRetryBackoffDetails, l as UploadRetryEvent, m as UploadStatus } from './firebase-storage-manager-DT6lxmUD.js';
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
- export { DEFAULT_RETRY_OPTIONS, RetryOptions, computeRetryDelay, getStorageErrorCode, isRetryableStorageError, resolveRetryOptions };
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-PBO3CMOD.js';
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
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
- import { S as StorageManager, B as BatchHandle, U as UploadBatch, e as StorageState, g as UploadHandle, i as UploadItem } from '../firebase-storage-manager-DT6lxmUD.js';
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 {
@@ -1,4 +1,4 @@
1
- import { StorageManager } from '../chunk-PBO3CMOD.js';
1
+ import { StorageManager } from '../chunk-PTKP7RWS.js';
2
2
  import { createContext, useContext, useMemo, useSyncExternalStore, useState, useEffect } from 'react';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-storage-kit",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "Storage manager for Firebase Storage with uploads, progress tracking, batch uploads, and file query helpers.",
5
5
  "keywords": [
6
6
  "browser",
@@ -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":"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","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"]}