nestjs-r2-storage 1.4.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -332,48 +332,6 @@ const result = await photoManager.deletePhotosFromObject(product, photoFields);
332
332
  // }
333
333
  ```
334
334
 
335
- ## Upload Detection (Update Operations)
336
-
337
- The `updateObjectWithPhotos()` method uses intelligent upload detection to prevent unnecessary uploads and file deletions.
338
-
339
- ### Dual-Mode Detection
340
-
341
- **Mode 1: Explicit Size Detection (when `sizeField` is defined)**
342
- - Only treats a field as a new upload if `sizeField > 0`
343
- - If `sizeField` is missing, null, or 0 → treats as existing file (no upload)
344
-
345
- **Mode 2: Filename Comparison (when `sizeField` is NOT defined)**
346
- - Compares base filenames between existing fileKey and incoming filename
347
- - Strips path, extension, and trailing timestamps before comparing
348
- - Only uploads if the base name differs
349
-
350
- ```typescript
351
- // Example: existing fileKey = "product_1776949996526.png"
352
- // Incoming filename = "product.png"
353
- // extractBaseFilename returns "product" for both → no upload
354
-
355
- // Example: existing fileKey = "product_1776949996526.png"
356
- // Incoming filename = "new-product.png"
357
- // extractBaseFilename returns "product" vs "new-product" → upload
358
- ```
359
-
360
- ### Detection Matrix
361
-
362
- | Scenario | `sizeField` defined | Result |
363
- |----------|---------------------|--------|
364
- | Existing file unchanged | yes (size=0) | No upload, no delete |
365
- | Existing file unchanged | no (same base) | No upload, no delete |
366
- | Same filename resent | yes (size=0) | No upload |
367
- | Same filename resent | no (same base) | No upload |
368
- | New file uploaded | yes (size > 0) | Upload + replace old |
369
- | New file (no sizeField) | no (different base) | Upload + replace old |
370
-
371
- ### Backward Compatibility
372
-
373
- - Existing clients that send `sizeField > 0` continue to work as before
374
- - Clients that don't send `sizeField` get automatic fallback to filename comparison
375
- - No changes to DTO structure or API required
376
-
377
335
  ## Field Path Syntax
378
336
 
379
337
  ### Simple Nested Fields
@@ -448,16 +406,7 @@ R2StorageModule.forRootAsync({
448
406
 
449
407
  ## Changelog
450
408
 
451
- ### v1.4.0 (2026-04-23)
452
-
453
- - **Dual-mode upload detection** for `updateObjectWithPhotos()`:
454
- - Mode 1: Explicit size detection when `sizeField` is defined (size > 0 = new upload)
455
- - Mode 2: Base filename comparison when `sizeField` is NOT defined
456
- - **Deterministic file replacement** using `extractBaseFilename()` helper
457
- - **Backward compatible**: Existing clients work unchanged, clients without `sizeField` get automatic fallback
458
- - Removed heuristic-based upload detection (no longer relies on filename patterns or "/" presence)
459
-
460
- ### v1.3.4 (2026-04-23)
409
+ ### v1.2.6 (2025-04-20)
461
410
 
462
411
  - Refactored getNestedValue: access key first, then handle array segments
463
412
  - Refactored setNestedValue: proper handling of empty brackets [] and indexed arrays [0]
@@ -1,55 +1,54 @@
1
- import { CloudflareService } from "./cloudflare.service";
2
- export interface PhotoField {
3
- field: string;
4
- urlField?: string;
5
- sizeField?: string;
6
- }
7
- export interface PhotoUploadRequest {
8
- field: string;
9
- filename: string;
10
- size: number;
11
- prefix?: string;
12
- }
13
- export interface PhotoUploadResponse {
14
- field: string;
15
- fileKey: string;
16
- uploadUrl: string;
17
- publicUrl: string | null;
18
- filename?: string;
19
- }
20
- export interface CreatePhotosResult<T extends Record<string, any>> {
21
- updatedPayload: T;
22
- uploadUrls: PhotoUploadResponse[];
23
- totalStorageUsed: number;
24
- }
25
- export interface UpdatePhotosResult<T extends Record<string, any>> {
26
- updatedPayload: T;
27
- uploadUrls: PhotoUploadResponse[];
28
- storageIncrease: number;
29
- storageDecrease: number;
30
- deletedFiles: string[];
31
- }
32
- export interface DeletePhotosResult {
33
- deletedFiles: string[];
34
- totalStorageFreed: number;
35
- }
36
- export interface AppendUrlsOptions {
37
- urlField?: (field: string) => string;
38
- }
39
- export declare class PhotoManagerService {
40
- private readonly cloudflareService;
41
- constructor(cloudflareService: CloudflareService);
42
- appendPhotoUrls<T extends Record<string, any>>(payload: T[], photoFields: PhotoField[]): Promise<T[]>;
43
- private handleSingleFieldUrl;
44
- private handleArrayFieldUrls;
45
- createObjectWithPhotos<T extends Record<string, any>>(payload: T, photoFields: PhotoField[], filePrefix?: string): Promise<CreatePhotosResult<T>>;
46
- updateObjectWithPhotos<T extends Record<string, any>>(payload: T, existingObject: T, photoFields: PhotoField[], filePrefix?: string): Promise<UpdatePhotosResult<T>>;
47
- deletePhotosFromObject<T extends Record<string, any>>(object: T, photoFields: PhotoField[]): Promise<DeletePhotosResult>;
48
- private extractPhotoUploadRequests;
49
- private extractArrayFieldUploadRequests;
50
- private extractExistingFiles;
51
- extractBaseFilename(fileKey: string): string;
52
- private filterNewPhotoRequests;
53
- private determineFilesToDelete;
54
- private updateArrayFieldWithNewFileKey;
55
- }
1
+ import { CloudflareService } from "./cloudflare.service";
2
+ export interface PhotoField {
3
+ field: string;
4
+ urlField?: string;
5
+ sizeField?: string;
6
+ }
7
+ export interface PhotoUploadRequest {
8
+ field: string;
9
+ filename: string;
10
+ size: number;
11
+ prefix?: string;
12
+ }
13
+ export interface PhotoUploadResponse {
14
+ field: string;
15
+ fileKey: string;
16
+ uploadUrl: string;
17
+ publicUrl: string | null;
18
+ filename?: string;
19
+ }
20
+ export interface CreatePhotosResult<T extends Record<string, any>> {
21
+ updatedPayload: T;
22
+ uploadUrls: PhotoUploadResponse[];
23
+ totalStorageUsed: number;
24
+ }
25
+ export interface UpdatePhotosResult<T extends Record<string, any>> {
26
+ updatedPayload: T;
27
+ uploadUrls: PhotoUploadResponse[];
28
+ storageIncrease: number;
29
+ storageDecrease: number;
30
+ deletedFiles: string[];
31
+ }
32
+ export interface DeletePhotosResult {
33
+ deletedFiles: string[];
34
+ totalStorageFreed: number;
35
+ }
36
+ export interface AppendUrlsOptions {
37
+ urlField?: (field: string) => string;
38
+ }
39
+ export declare class PhotoManagerService {
40
+ private readonly cloudflareService;
41
+ constructor(cloudflareService: CloudflareService);
42
+ appendPhotoUrls<T extends Record<string, any>>(payload: T[], photoFields: PhotoField[]): Promise<T[]>;
43
+ private handleSingleFieldUrl;
44
+ private handleArrayFieldUrls;
45
+ createObjectWithPhotos<T extends Record<string, any>>(payload: T, photoFields: PhotoField[], filePrefix?: string): Promise<CreatePhotosResult<T>>;
46
+ updateObjectWithPhotos<T extends Record<string, any>>(payload: T, existingObject: T, photoFields: PhotoField[], filePrefix?: string): Promise<UpdatePhotosResult<T>>;
47
+ deletePhotosFromObject<T extends Record<string, any>>(object: T, photoFields: PhotoField[]): Promise<DeletePhotosResult>;
48
+ private extractPhotoUploadRequests;
49
+ private extractArrayFieldUploadRequests;
50
+ private extractExistingFiles;
51
+ private determineFilesToDelete;
52
+ private normalizeFilename;
53
+ private updateArrayFieldWithNewFileKey;
54
+ }