nestjs-r2-storage 1.4.2 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -406,6 +406,17 @@ R2StorageModule.forRootAsync({
406
406
 
407
407
  ## Changelog
408
408
 
409
+ ### v1.5.0 (2026-04-25)
410
+
411
+ - **Refactored photo update logic** - Diff-based (state reconciliation) instead of request-driven
412
+ - **No unnecessary uploads** - Files are only uploaded when the value actually changes
413
+ - **No accidental deletions** - Files are only deleted when removed from the payload
414
+ - **Index-based array handling** - Array fields use path-based comparison (`gallery[0].photo`) instead of filename matching
415
+ - **Reusable `extractExistingFileMap()`** - Public method for extracting `fieldPath → fileKey` maps
416
+ - **Optimized traversal** - Single-pass map extraction, O(1) lookups via Map
417
+ - **Size is optional** - Size field does not affect diff logic, only used for storage tracking
418
+ - **Deterministic behavior** - Backend-driven, no assumptions about frontend behavior
419
+
409
420
  ### v1.2.6 (2025-04-20)
410
421
 
411
422
  - Refactored getNestedValue: access key first, then handle array segments
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
- export { StorageOptions, FileFieldConfig, PhotoFieldConfig, StorageModuleOptions, AccessMode, } from './r2-storage/interfaces/storage-options.interface';
2
- export { CloudflareService, UploadUrlResult, DownloadUrlResult, FileInfo, AccessModeError, } from './r2-storage/cloudflare.service';
3
- export { PhotoManagerService, PhotoField, PhotoUploadRequest, PhotoUploadResponse, CreatePhotosResult, UpdatePhotosResult, DeletePhotosResult, AppendUrlsOptions, } from './r2-storage/photo-manager.service';
4
- export { R2StorageModule, } from './r2-storage/r2-storage.module';
5
- export { PhotoFields, UploadUrls, StorageInfo, } from './r2-storage/decorators/photo-fields.decorator';
6
- export { parseFieldPath, getNestedValue, setNestedValue, collectNestedValues, isArrayPath, getArrayBasePath, getArrayElementPath, getAllArrayItemPaths, ParsedPath, PathSegment, } from './r2-storage/utils/nested-value.util';
1
+ export { StorageOptions, FileFieldConfig, PhotoFieldConfig, StorageModuleOptions, AccessMode, } from "./r2-storage/interfaces/storage-options.interface";
2
+ export { CloudflareService, AccessModeError, } from "./r2-storage/cloudflare.service";
3
+ export { UploadUrlResult, DownloadUrlResult, FileInfo, } from "./r2-storage/interfaces/cloudflare-service.interface";
4
+ export { PhotoManagerService } from "./r2-storage/photo-manager.service";
5
+ export { PhotoField, AppendUrlsOptions, PhotoUploadRequest, PhotoUploadResponse, CreatePhotosResult, UpdatePhotosResult, DeletePhotosResult, } from "./r2-storage/interfaces/photo-manager.interface";
6
+ export { R2StorageModule } from "./r2-storage/r2-storage.module";
7
+ export { PhotoFields, UploadUrls, StorageInfo, } from "./r2-storage/decorators/photo-fields.decorator";
8
+ export { parseFieldPath, getNestedValue, setNestedValue, collectNestedValues, isArrayPath, getArrayBasePath, getArrayElementPath, getAllArrayItemPaths, ParsedPath, PathSegment, } from "./r2-storage/utils/nested-value.util";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAQA,sEAMyC;AALvC,uHAAA,iBAAiB,OAAA;AAIjB,qHAAA,eAAe,OAAA;AAGjB,4EAS4C;AAR1C,4HAAA,mBAAmB,OAAA;AAUrB,oEAEwC;AADtC,oHAAA,eAAe,OAAA;AAGjB,yFAIwD;AAHtD,qHAAA,WAAW,OAAA;AACX,oHAAA,UAAU,OAAA;AACV,qHAAA,WAAW,OAAA;AAGb,0EAW8C;AAV5C,mHAAA,cAAc,OAAA;AACd,mHAAA,cAAc,OAAA;AACd,mHAAA,cAAc,OAAA;AACd,wHAAA,mBAAmB,OAAA;AACnB,gHAAA,WAAW,OAAA;AACX,qHAAA,gBAAgB,OAAA;AAChB,wHAAA,mBAAmB,OAAA;AACnB,yHAAA,oBAAoB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAQA,sEAGyC;AAFvC,uHAAA,iBAAiB,OAAA;AACjB,qHAAA,eAAe,OAAA;AASjB,4EAAyE;AAAhE,4HAAA,mBAAmB,OAAA;AAY5B,oEAAiE;AAAxD,oHAAA,eAAe,OAAA;AAExB,yFAIwD;AAHtD,qHAAA,WAAW,OAAA;AACX,oHAAA,UAAU,OAAA;AACV,qHAAA,WAAW,OAAA;AAGb,0EAW8C;AAV5C,mHAAA,cAAc,OAAA;AACd,mHAAA,cAAc,OAAA;AACd,mHAAA,cAAc,OAAA;AACd,wHAAA,mBAAmB,OAAA;AACnB,gHAAA,WAAW,OAAA;AACX,qHAAA,gBAAgB,OAAA;AAChB,wHAAA,mBAAmB,OAAA;AACnB,yHAAA,oBAAoB,OAAA"}
@@ -1,24 +1,9 @@
1
- import { OnModuleInit, OnModuleDestroy, BadRequestException } from '@nestjs/common';
2
- import { StorageOptions } from './interfaces/storage-options.interface';
1
+ import { OnModuleInit, OnModuleDestroy, BadRequestException } from "@nestjs/common";
2
+ import { StorageOptions } from "./interfaces/storage-options.interface";
3
+ import { DownloadUrlResult, FileInfo, UploadUrlResult } from "./interfaces/cloudflare-service.interface";
3
4
  export declare class AccessModeError extends BadRequestException {
4
5
  constructor(message: string);
5
6
  }
6
- export interface UploadUrlResult {
7
- uploadUrl: string;
8
- fileKey: string;
9
- publicUrl: string | null;
10
- mimeType: string;
11
- sizeField?: number;
12
- }
13
- export interface DownloadUrlResult {
14
- downloadUrl: string;
15
- publicUrl: string | null;
16
- }
17
- export interface FileInfo {
18
- size: number;
19
- lastModified?: Date;
20
- contentType?: string;
21
- }
22
7
  export declare class CloudflareService implements OnModuleInit, OnModuleDestroy {
23
8
  private readonly storageOptions;
24
9
  private s3Client;
@@ -28,11 +13,9 @@ export declare class CloudflareService implements OnModuleInit, OnModuleDestroy
28
13
  constructor(storageOptions: StorageOptions);
29
14
  private get accessMode();
30
15
  private isPublicAccessAllowed;
31
- private ensurePublicAccessAllowed;
32
16
  onModuleInit(): void;
33
17
  onModuleDestroy(): void;
34
18
  private initializeClient;
35
- setOptions(options: StorageOptions): void;
36
19
  getOptions(): StorageOptions;
37
20
  private sanitizeFilename;
38
21
  private detectMimeType;
@@ -52,10 +52,11 @@ const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
52
52
  const path = __importStar(require("path"));
53
53
  const mime = __importStar(require("mime-types"));
54
54
  const constants_1 = require("./constants");
55
+ const validate_options_utils_1 = require("./utils/validate-options.utils");
55
56
  class AccessModeError extends common_1.BadRequestException {
56
57
  constructor(message) {
57
58
  super(message);
58
- this.name = 'AccessModeError';
59
+ this.name = "AccessModeError";
59
60
  }
60
61
  }
61
62
  exports.AccessModeError = AccessModeError;
@@ -63,21 +64,17 @@ let CloudflareService = class CloudflareService {
63
64
  constructor(storageOptions) {
64
65
  this.storageOptions = storageOptions;
65
66
  this.defaultExpiry = 3600;
66
- this.defaultAccessMode = 'hybrid';
67
- this.options = storageOptions;
67
+ this.defaultAccessMode = "hybrid";
68
+ this.options = this.storageOptions;
68
69
  }
69
70
  get accessMode() {
70
71
  return this.options.accessMode || this.defaultAccessMode;
71
72
  }
72
73
  isPublicAccessAllowed() {
73
- return this.accessMode === 'public-read' || this.accessMode === 'hybrid';
74
- }
75
- ensurePublicAccessAllowed() {
76
- if (this.accessMode === 'private') {
77
- throw new AccessModeError('Public URL generation is not allowed in "private" access mode. Use presigned URLs for file access.');
78
- }
74
+ return this.accessMode === "public-read" || this.accessMode === "hybrid";
79
75
  }
80
76
  onModuleInit() {
77
+ (0, validate_options_utils_1.validateOptions)(this.options);
81
78
  this.initializeClient();
82
79
  }
83
80
  onModuleDestroy() {
@@ -88,37 +85,35 @@ let CloudflareService = class CloudflareService {
88
85
  initializeClient() {
89
86
  this.s3Client = new client_s3_1.S3Client({
90
87
  endpoint: this.options.endpoint,
91
- region: this.options.region || 'auto',
88
+ region: this.options.region || "auto",
92
89
  credentials: {
93
90
  accessKeyId: this.options.accessKeyId,
94
91
  secretAccessKey: this.options.secretAccessKey,
95
92
  },
96
93
  forcePathStyle: true,
97
- requestChecksumCalculation: 'WHEN_REQUIRED',
94
+ requestChecksumCalculation: "WHEN_REQUIRED",
98
95
  });
99
96
  }
100
- setOptions(options) {
101
- this.options = options;
102
- this.initializeClient();
103
- }
104
97
  getOptions() {
105
98
  return this.options;
106
99
  }
107
- sanitizeFilename(filename) {
108
- const sanitized = filename.replace(/[^a-zA-Z0-9._-]/g, '_');
109
- const timestamp = Date.now();
100
+ sanitizeFilename(filename, unique = true) {
101
+ const sanitized = filename.replace(/[^a-zA-Z0-9._-]/g, "_");
102
+ if (!unique)
103
+ return sanitized;
104
+ const uniqueSuffix = `${Date.now()}`;
110
105
  const ext = path.extname(sanitized);
111
106
  const basename = path.basename(sanitized, ext);
112
- return `${basename}_${timestamp}${ext}`;
107
+ return `${basename}_${uniqueSuffix}${ext}`;
113
108
  }
114
- detectMimeType(filename, fallbackContentType = 'application/octet-stream') {
109
+ detectMimeType(filename, fallbackContentType = "application/octet-stream") {
115
110
  const mimeType = mime.lookup(filename);
116
111
  return mimeType || fallbackContentType;
117
112
  }
118
113
  async getUploadUrl(fileKey, fileSize, customFilename, contentType) {
119
114
  const filename = customFilename || path.basename(fileKey);
120
115
  const sanitizedFilename = this.sanitizeFilename(filename);
121
- const finalFileKey = fileKey.includes('/')
116
+ const finalFileKey = fileKey.includes("/")
122
117
  ? `${path.dirname(fileKey)}/${sanitizedFilename}`
123
118
  : sanitizedFilename;
124
119
  const mimeType = contentType || this.detectMimeType(sanitizedFilename);
@@ -130,7 +125,7 @@ let CloudflareService = class CloudflareService {
130
125
  const expiry = this.options.signedUrlExpiry || this.defaultExpiry;
131
126
  const uploadUrl = await (0, s3_request_presigner_1.getSignedUrl)(this.s3Client, command, {
132
127
  expiresIn: expiry,
133
- signableHeaders: new Set(['host', 'content-type']),
128
+ signableHeaders: new Set(["host", "content-type"]),
134
129
  });
135
130
  let publicUrl = null;
136
131
  if (this.options.publicUrlBase && this.isPublicAccessAllowed()) {
@@ -150,7 +145,9 @@ let CloudflareService = class CloudflareService {
150
145
  Key: fileKey,
151
146
  });
152
147
  const expiry = this.options.signedUrlExpiry || this.defaultExpiry;
153
- const downloadUrl = await (0, s3_request_presigner_1.getSignedUrl)(this.s3Client, command, { expiresIn: expiry });
148
+ const downloadUrl = await (0, s3_request_presigner_1.getSignedUrl)(this.s3Client, command, {
149
+ expiresIn: expiry,
150
+ });
154
151
  let publicUrl = null;
155
152
  if (this.options.publicUrlBase && this.isPublicAccessAllowed()) {
156
153
  publicUrl = `${this.options.publicUrlBase}/${fileKey}`;
@@ -198,7 +195,10 @@ let CloudflareService = class CloudflareService {
198
195
  };
199
196
  }
200
197
  catch (error) {
201
- return null;
198
+ if (error?.$metadata?.httpStatusCode === 404) {
199
+ return null;
200
+ }
201
+ throw error;
202
202
  }
203
203
  }
204
204
  async fileExists(fileKey) {
@@ -206,9 +206,7 @@ let CloudflareService = class CloudflareService {
206
206
  return fileInfo !== null;
207
207
  }
208
208
  generateFileKey(prefix, filename) {
209
- const timestamp = Date.now();
210
- const sanitizedFilename = this.sanitizeFilename(filename);
211
- return `${prefix}/${timestamp}_${sanitizedFilename}`;
209
+ return `${prefix}/${this.sanitizeFilename(filename)}`;
212
210
  }
213
211
  };
214
212
  exports.CloudflareService = CloudflareService;
@@ -1 +1 @@
1
- {"version":3,"file":"cloudflare.service.js","sourceRoot":"","sources":["../../src/r2-storage/cloudflare.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cloudflare.service.js","sourceRoot":"","sources":["../../src/r2-storage/cloudflare.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export interface UploadUrlResult {
2
+ uploadUrl: string;
3
+ fileKey: string;
4
+ publicUrl: string | null;
5
+ mimeType: string;
6
+ sizeField?: number;
7
+ }
8
+ export interface DownloadUrlResult {
9
+ downloadUrl: string;
10
+ publicUrl: string | null;
11
+ }
12
+ export interface FileInfo {
13
+ size: number;
14
+ lastModified?: Date;
15
+ contentType?: string;
16
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=cloudflare-service.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-service.interface.js","sourceRoot":"","sources":["../../../src/r2-storage/interfaces/cloudflare-service.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ export interface PhotoField {
2
+ field: string;
3
+ urlField?: string;
4
+ sizeField?: string;
5
+ }
6
+ export interface PhotoUploadRequest {
7
+ field: string;
8
+ filename: string;
9
+ size: number;
10
+ prefix?: string;
11
+ }
12
+ export interface PhotoUploadResponse {
13
+ field: string;
14
+ fileKey: string;
15
+ uploadUrl: string;
16
+ publicUrl: string | null;
17
+ filename?: string;
18
+ }
19
+ export interface CreatePhotosResult<T extends Record<string, any>> {
20
+ updatedPayload: T;
21
+ uploadUrls: PhotoUploadResponse[];
22
+ totalStorageUsed: number;
23
+ }
24
+ export interface UpdatePhotosResult<T extends Record<string, any>> {
25
+ updatedPayload: T;
26
+ uploadUrls: PhotoUploadResponse[];
27
+ storageIncrease: number;
28
+ storageDecrease: number;
29
+ deletedFiles: string[];
30
+ }
31
+ export interface DeletePhotosResult {
32
+ deletedFiles: string[];
33
+ totalStorageFreed: number;
34
+ }
35
+ export interface AppendUrlsOptions {
36
+ urlField?: (field: string) => string;
37
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=photo-manager.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"photo-manager.interface.js","sourceRoot":"","sources":["../../../src/r2-storage/interfaces/photo-manager.interface.ts"],"names":[],"mappings":""}
@@ -1,23 +1,23 @@
1
- export type AccessMode = 'private' | 'public-read' | 'hybrid';
2
- export interface StorageOptions {
3
- endpoint: string;
4
- accessKeyId: string;
5
- secretAccessKey: string;
6
- bucketName: string;
7
- region?: string;
8
- publicUrlBase?: string;
9
- signedUrlExpiry?: number;
10
- accessMode?: AccessMode;
11
- }
12
- export interface FileFieldConfig {
13
- field: string;
14
- sizeField?: string;
15
- }
16
- export interface PhotoFieldConfig {
17
- field: string;
18
- urlField?: string;
19
- sizeField?: string;
20
- }
21
- export interface StorageModuleOptions {
22
- isGlobal?: boolean;
23
- }
1
+ export type AccessMode = "private" | "public-read" | "hybrid";
2
+ export interface StorageOptions {
3
+ endpoint: string;
4
+ accessKeyId: string;
5
+ secretAccessKey: string;
6
+ bucketName: string;
7
+ region?: string;
8
+ publicUrlBase?: string;
9
+ signedUrlExpiry?: number;
10
+ accessMode?: AccessMode;
11
+ }
12
+ export interface FileFieldConfig {
13
+ field: string;
14
+ sizeField?: string;
15
+ }
16
+ export interface PhotoFieldConfig {
17
+ field: string;
18
+ urlField?: string;
19
+ sizeField?: string;
20
+ }
21
+ export interface StorageModuleOptions {
22
+ isGlobal?: boolean;
23
+ }
@@ -1,54 +1,23 @@
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
- }
1
+ import { CloudflareService } from "./cloudflare.service";
2
+ import { CreatePhotosResult, DeletePhotosResult, PhotoField, UpdatePhotosResult } from "./interfaces/photo-manager.interface";
3
+ type FileMap = Map<string, string>;
4
+ export declare class PhotoManagerService {
5
+ private readonly cloudflareService;
6
+ constructor(cloudflareService: CloudflareService);
7
+ appendPhotoUrls<T extends Record<string, any>>(payload: T, photoFields: PhotoField[]): Promise<T>;
8
+ appendPhotoUrls<T extends Record<string, any>>(payload: T[], photoFields: PhotoField[]): Promise<T[]>;
9
+ private handleSingleFieldUrl;
10
+ private handleArrayFieldUrls;
11
+ createObjectWithPhotos<T extends Record<string, any>>(payload: T, photoFields: PhotoField[], filePrefix?: string): Promise<CreatePhotosResult<T>>;
12
+ updateObjectWithPhotos<T extends Record<string, any>>(payload: T, existingObject: T, photoFields: PhotoField[], filePrefix?: string): Promise<UpdatePhotosResult<T>>;
13
+ deletePhotosFromObject<T extends Record<string, any>>(object: T, photoFields: PhotoField[]): Promise<DeletePhotosResult>;
14
+ extractExistingFileMap<T extends Record<string, any>>(object: T, photoFields: PhotoField[]): FileMap;
15
+ private extractPayloadFileMap;
16
+ private getArrayFieldPaths;
17
+ private calculatePhotoDiffs;
18
+ private getSizeForField;
19
+ private updateFieldWithFileKey;
20
+ private extractPhotoUploadRequests;
21
+ private extractExistingFiles;
22
+ }
23
+ export {};