nestjs-r2-storage 1.1.1 → 1.2.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 +90 -6
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/r2-storage/cloudflare.service.d.ts +11 -3
- package/dist/r2-storage/cloudflare.service.js +30 -7
- package/dist/r2-storage/cloudflare.service.js.map +1 -1
- package/dist/r2-storage/interfaces/storage-options.interface.d.ts +2 -0
- package/dist/r2-storage/photo-manager.service.d.ts +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,16 +17,61 @@ Production-ready NestJS module for Cloudflare R2 object storage management.
|
|
|
17
17
|
- **Array Field Support** - Handle paths like `products[].image`, `gallery[].photo`
|
|
18
18
|
- **Storage Usage Tracking** - Track storage used, increased, and decreased
|
|
19
19
|
- **Full CRUD Lifecycle** - Create, Update, Delete file operations
|
|
20
|
+
- **Access Control Modes** - Control public vs signed URL access (`private`, `public-read`, `hybrid`)
|
|
20
21
|
|
|
21
|
-
##
|
|
22
|
+
## Access Control Modes
|
|
22
23
|
|
|
23
|
-
-
|
|
24
|
-
- NestJS >= 10.0.0 or >= 11.0.0
|
|
24
|
+
Cloudflare R2 does NOT enforce ACLs like AWS S3 - the R2 API ignores ACL headers. True security is achieved by controlling URL exposure.
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
### Modes
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
| Mode | Public URLs | Signed URLs | Use Case |
|
|
29
|
+
|------|-------------|-------------|----------|
|
|
30
|
+
| `private` | Not allowed | Required | Maximum security - only signed access |
|
|
31
|
+
| `public-read` | Allowed | Optional | Public files (e.g., static assets) |
|
|
32
|
+
| `hybrid` | Allowed | Allowed | Mixed content (default) |
|
|
33
|
+
|
|
34
|
+
### Private Mode
|
|
35
|
+
|
|
36
|
+
Only presigned URLs are allowed. Public URL generation throws `AccessModeError`.
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
R2StorageModule.forRoot({
|
|
40
|
+
// ... other options
|
|
41
|
+
accessMode: 'private',
|
|
42
|
+
publicUrlBase: 'https://cdn.example.com', // still configured but not used
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Response in private mode:
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"uploadUrl": "https://signed-url...",
|
|
50
|
+
"publicUrl": null
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Public-Read Mode
|
|
55
|
+
|
|
56
|
+
Public URLs are generated. Signed URLs are optional.
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
R2StorageModule.forRoot({
|
|
60
|
+
// ... other options
|
|
61
|
+
accessMode: 'public-read',
|
|
62
|
+
publicUrlBase: 'https://cdn.example.com',
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Hybrid Mode (Default)
|
|
67
|
+
|
|
68
|
+
Both public and signed access are allowed for backward compatibility.
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
R2StorageModule.forRoot({
|
|
72
|
+
// ... other options
|
|
73
|
+
accessMode: 'hybrid', // default
|
|
74
|
+
});
|
|
30
75
|
```
|
|
31
76
|
|
|
32
77
|
## Quick Start
|
|
@@ -144,6 +189,26 @@ await cloudflare.deleteFile('uploads/avatar.png');
|
|
|
144
189
|
const exists = await cloudflare.fileExists('uploads/avatar.png');
|
|
145
190
|
```
|
|
146
191
|
|
|
192
|
+
### Presigned URL Security
|
|
193
|
+
|
|
194
|
+
The module uses secure presigned URL generation:
|
|
195
|
+
|
|
196
|
+
- **Content-Length is NOT signed** - Prevents `SignatureDoesNotMatch` errors (browsers calculate it differently)
|
|
197
|
+
- **Checksum headers disabled** - Uses `requestChecksumCalculation: "WHEN_REQUIRED"` to avoid R2 compatibility issues
|
|
198
|
+
- **Minimal signing** - Only signs `host` and `content-type` headers
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
const result = await cloudflare.getUploadUrl('avatar.png', 1024000);
|
|
202
|
+
|
|
203
|
+
// result = {
|
|
204
|
+
// uploadUrl: "https://signed-url...",
|
|
205
|
+
// fileKey: "uploads/avatar_123.png",
|
|
206
|
+
// publicUrl: "https://cdn.example.com/uploads/avatar_123.png",
|
|
207
|
+
// mimeType: "image/png",
|
|
208
|
+
// sizeField: 1024000 // Use this for client-side validation before upload
|
|
209
|
+
// }
|
|
210
|
+
```
|
|
211
|
+
|
|
147
212
|
### PhotoManagerService
|
|
148
213
|
|
|
149
214
|
High-level photo management.
|
|
@@ -278,6 +343,25 @@ products[].images[] -> products[0].images[0], products[0].images[1], ...
|
|
|
278
343
|
| `region` | string | No | AWS region (default: 'auto') |
|
|
279
344
|
| `publicUrlBase` | string | No | Base URL for public access |
|
|
280
345
|
| `signedUrlExpiry` | number | No | Signed URL expiry in seconds (default: 3600) |
|
|
346
|
+
| `accessMode` | string | No | Access mode: `private`, `public-read`, `hybrid` (default: `hybrid`) |
|
|
347
|
+
|
|
348
|
+
## Error Handling
|
|
349
|
+
|
|
350
|
+
### AccessModeError
|
|
351
|
+
|
|
352
|
+
Thrown when attempting to generate public URLs in `private` access mode.
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
import { AccessModeError } from 'nestjs-r2-storage';
|
|
356
|
+
|
|
357
|
+
try {
|
|
358
|
+
const result = await cloudflare.getUploadUrl('file.png', 1024);
|
|
359
|
+
} catch (error) {
|
|
360
|
+
if (error instanceof AccessModeError) {
|
|
361
|
+
console.log(error.message); // "Public URL generation is not allowed in 'private' access mode..."
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
```
|
|
281
365
|
|
|
282
366
|
## Async Configuration
|
|
283
367
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { StorageOptions, FileFieldConfig, PhotoFieldConfig, StorageModuleOptions, } from './r2-storage/interfaces/storage-options.interface';
|
|
2
|
-
export { CloudflareService, UploadUrlResult, DownloadUrlResult, FileInfo, } from './r2-storage/cloudflare.service';
|
|
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
3
|
export { PhotoManagerService, PhotoField, PhotoUploadRequest, PhotoUploadResponse, CreatePhotosResult, UpdatePhotosResult, DeletePhotosResult, AppendUrlsOptions, } from './r2-storage/photo-manager.service';
|
|
4
4
|
export { R2StorageModule, } from './r2-storage/r2-storage.module';
|
|
5
5
|
export { PhotoFields, UploadUrls, StorageInfo, } from './r2-storage/decorators/photo-fields.decorator';
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getAllArrayItemPaths = exports.getArrayElementPath = exports.getArrayBasePath = exports.isArrayPath = exports.collectNestedValues = exports.setNestedValue = exports.getNestedValue = exports.parseFieldPath = exports.StorageInfo = exports.UploadUrls = exports.PhotoFields = exports.R2StorageModule = exports.PhotoManagerService = exports.CloudflareService = void 0;
|
|
3
|
+
exports.getAllArrayItemPaths = exports.getArrayElementPath = exports.getArrayBasePath = exports.isArrayPath = exports.collectNestedValues = exports.setNestedValue = exports.getNestedValue = exports.parseFieldPath = exports.StorageInfo = exports.UploadUrls = exports.PhotoFields = exports.R2StorageModule = exports.PhotoManagerService = exports.AccessModeError = exports.CloudflareService = void 0;
|
|
4
4
|
var cloudflare_service_1 = require("./r2-storage/cloudflare.service");
|
|
5
5
|
Object.defineProperty(exports, "CloudflareService", { enumerable: true, get: function () { return cloudflare_service_1.CloudflareService; } });
|
|
6
|
+
Object.defineProperty(exports, "AccessModeError", { enumerable: true, get: function () { return cloudflare_service_1.AccessModeError; } });
|
|
6
7
|
var photo_manager_service_1 = require("./r2-storage/photo-manager.service");
|
|
7
8
|
Object.defineProperty(exports, "PhotoManagerService", { enumerable: true, get: function () { return photo_manager_service_1.PhotoManagerService; } });
|
|
8
9
|
var r2_storage_module_1 = require("./r2-storage/r2-storage.module");
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;
|
|
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,14 +1,18 @@
|
|
|
1
|
-
import { OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
|
1
|
+
import { OnModuleInit, OnModuleDestroy, BadRequestException } from '@nestjs/common';
|
|
2
2
|
import { StorageOptions } from './interfaces/storage-options.interface';
|
|
3
|
+
export declare class AccessModeError extends BadRequestException {
|
|
4
|
+
constructor(message: string);
|
|
5
|
+
}
|
|
3
6
|
export interface UploadUrlResult {
|
|
4
7
|
uploadUrl: string;
|
|
5
8
|
fileKey: string;
|
|
6
|
-
publicUrl
|
|
9
|
+
publicUrl: string | null;
|
|
7
10
|
mimeType: string;
|
|
11
|
+
sizeField?: number;
|
|
8
12
|
}
|
|
9
13
|
export interface DownloadUrlResult {
|
|
10
14
|
downloadUrl: string;
|
|
11
|
-
publicUrl
|
|
15
|
+
publicUrl: string | null;
|
|
12
16
|
}
|
|
13
17
|
export interface FileInfo {
|
|
14
18
|
size: number;
|
|
@@ -20,7 +24,11 @@ export declare class CloudflareService implements OnModuleInit, OnModuleDestroy
|
|
|
20
24
|
private s3Client;
|
|
21
25
|
private options;
|
|
22
26
|
private readonly defaultExpiry;
|
|
27
|
+
private readonly defaultAccessMode;
|
|
23
28
|
constructor(storageOptions: StorageOptions);
|
|
29
|
+
private get accessMode();
|
|
30
|
+
private isPublicAccessAllowed;
|
|
31
|
+
private ensurePublicAccessAllowed;
|
|
24
32
|
onModuleInit(): void;
|
|
25
33
|
onModuleDestroy(): void;
|
|
26
34
|
private initializeClient;
|
|
@@ -45,19 +45,38 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
45
45
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
46
46
|
};
|
|
47
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
-
exports.CloudflareService = void 0;
|
|
48
|
+
exports.CloudflareService = exports.AccessModeError = void 0;
|
|
49
49
|
const common_1 = require("@nestjs/common");
|
|
50
50
|
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
51
51
|
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
|
+
class AccessModeError extends common_1.BadRequestException {
|
|
56
|
+
constructor(message) {
|
|
57
|
+
super(message);
|
|
58
|
+
this.name = 'AccessModeError';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.AccessModeError = AccessModeError;
|
|
55
62
|
let CloudflareService = class CloudflareService {
|
|
56
63
|
constructor(storageOptions) {
|
|
57
64
|
this.storageOptions = storageOptions;
|
|
58
65
|
this.defaultExpiry = 3600;
|
|
66
|
+
this.defaultAccessMode = 'hybrid';
|
|
59
67
|
this.options = storageOptions;
|
|
60
68
|
}
|
|
69
|
+
get accessMode() {
|
|
70
|
+
return this.options.accessMode || this.defaultAccessMode;
|
|
71
|
+
}
|
|
72
|
+
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
|
+
}
|
|
79
|
+
}
|
|
61
80
|
onModuleInit() {
|
|
62
81
|
this.initializeClient();
|
|
63
82
|
}
|
|
@@ -75,6 +94,7 @@ let CloudflareService = class CloudflareService {
|
|
|
75
94
|
secretAccessKey: this.options.secretAccessKey,
|
|
76
95
|
},
|
|
77
96
|
forcePathStyle: true,
|
|
97
|
+
requestChecksumCalculation: 'WHEN_REQUIRED',
|
|
78
98
|
});
|
|
79
99
|
}
|
|
80
100
|
setOptions(options) {
|
|
@@ -106,12 +126,14 @@ let CloudflareService = class CloudflareService {
|
|
|
106
126
|
Bucket: this.options.bucketName,
|
|
107
127
|
Key: finalFileKey,
|
|
108
128
|
ContentType: mimeType,
|
|
109
|
-
ContentLength: fileSize,
|
|
110
129
|
});
|
|
111
130
|
const expiry = this.options.signedUrlExpiry || this.defaultExpiry;
|
|
112
|
-
const uploadUrl = await (0, s3_request_presigner_1.getSignedUrl)(this.s3Client, command, {
|
|
113
|
-
|
|
114
|
-
|
|
131
|
+
const uploadUrl = await (0, s3_request_presigner_1.getSignedUrl)(this.s3Client, command, {
|
|
132
|
+
expiresIn: expiry,
|
|
133
|
+
signableHeaders: new Set(['host', 'content-type']),
|
|
134
|
+
});
|
|
135
|
+
let publicUrl = null;
|
|
136
|
+
if (this.options.publicUrlBase && this.isPublicAccessAllowed()) {
|
|
115
137
|
publicUrl = `${this.options.publicUrlBase}/${finalFileKey}`;
|
|
116
138
|
}
|
|
117
139
|
return {
|
|
@@ -119,6 +141,7 @@ let CloudflareService = class CloudflareService {
|
|
|
119
141
|
fileKey: finalFileKey,
|
|
120
142
|
publicUrl,
|
|
121
143
|
mimeType,
|
|
144
|
+
sizeField: fileSize,
|
|
122
145
|
};
|
|
123
146
|
}
|
|
124
147
|
async getDownloadUrl(fileKey) {
|
|
@@ -128,8 +151,8 @@ let CloudflareService = class CloudflareService {
|
|
|
128
151
|
});
|
|
129
152
|
const expiry = this.options.signedUrlExpiry || this.defaultExpiry;
|
|
130
153
|
const downloadUrl = await (0, s3_request_presigner_1.getSignedUrl)(this.s3Client, command, { expiresIn: expiry });
|
|
131
|
-
let publicUrl;
|
|
132
|
-
if (this.options.publicUrlBase) {
|
|
154
|
+
let publicUrl = null;
|
|
155
|
+
if (this.options.publicUrlBase && this.isPublicAccessAllowed()) {
|
|
133
156
|
publicUrl = `${this.options.publicUrlBase}/${fileKey}`;
|
|
134
157
|
}
|
|
135
158
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloudflare.service.js","sourceRoot":"","sources":["../../src/r2-storage/cloudflare.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"cloudflare.service.js","sourceRoot":"","sources":["../../src/r2-storage/cloudflare.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export type AccessMode = 'private' | 'public-read' | 'hybrid';
|
|
1
2
|
export interface StorageOptions {
|
|
2
3
|
endpoint: string;
|
|
3
4
|
accessKeyId: string;
|
|
@@ -6,6 +7,7 @@ export interface StorageOptions {
|
|
|
6
7
|
region?: string;
|
|
7
8
|
publicUrlBase?: string;
|
|
8
9
|
signedUrlExpiry?: number;
|
|
10
|
+
accessMode?: AccessMode;
|
|
9
11
|
}
|
|
10
12
|
export interface FileFieldConfig {
|
|
11
13
|
field: string;
|