@russ-b/nestjs-common-tools 1.13.1 → 1.14.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 +214 -0
- package/dist/class-transformer/index.d.ts +2 -0
- package/dist/class-transformer/index.js +19 -0
- package/dist/class-transformer/index.js.map +1 -0
- package/dist/class-transformer/to-optional-boolean.decorator.d.ts +3 -0
- package/dist/class-transformer/to-optional-boolean.decorator.js +29 -0
- package/dist/class-transformer/to-optional-boolean.decorator.js.map +1 -0
- package/dist/class-transformer/to-string-array.decorator.d.ts +1 -0
- package/dist/class-transformer/to-string-array.decorator.js +23 -0
- package/dist/class-transformer/to-string-array.decorator.js.map +1 -0
- package/dist/modules/s3/index.d.ts +1 -0
- package/dist/modules/s3/index.js +1 -0
- package/dist/modules/s3/index.js.map +1 -1
- package/dist/modules/s3/s3.interface.d.ts +31 -6
- package/dist/modules/s3/s3.module.js +5 -8
- package/dist/modules/s3/s3.module.js.map +1 -1
- package/dist/modules/s3/s3.service.d.ts +13 -10
- package/dist/modules/s3/s3.service.js +91 -35
- package/dist/modules/s3/s3.service.js.map +1 -1
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -15,6 +15,220 @@ npm install @russ-b/nestjs-common-tools
|
|
|
15
15
|
|
|
16
16
|
Depending on which features you use, make sure the relevant peer dependencies are also installed in your project.
|
|
17
17
|
|
|
18
|
+
## Class Transformer Helpers
|
|
19
|
+
|
|
20
|
+
This package can also expose small reusable decorators for `class-transformer`.
|
|
21
|
+
|
|
22
|
+
### `ToStringArray`
|
|
23
|
+
|
|
24
|
+
`ToStringArray()` is useful for DTO query fields that may arrive as a comma-separated string such as `"cars, bikes, boats"` or as an array.
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { ToStringArray } from '@russ-b/nestjs-common-tools/class-transformer';
|
|
28
|
+
|
|
29
|
+
export class SearchDto {
|
|
30
|
+
@ToStringArray()
|
|
31
|
+
tags?: string[];
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
It will:
|
|
36
|
+
|
|
37
|
+
- split string values by comma
|
|
38
|
+
- trim extra spaces around items
|
|
39
|
+
- remove empty values
|
|
40
|
+
- flatten array inputs like `['cars, bikes', 'boats']` into `['cars', 'bikes', 'boats']`
|
|
41
|
+
|
|
42
|
+
### `ToOptionalBoolean`
|
|
43
|
+
|
|
44
|
+
`ToOptionalBoolean()` is useful for DTO fields that may arrive as `'true'` or `'false'` strings and should become real booleans.
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { ToOptionalBoolean } from '@russ-b/nestjs-common-tools/class-transformer';
|
|
48
|
+
|
|
49
|
+
export class SearchDto {
|
|
50
|
+
@ToOptionalBoolean()
|
|
51
|
+
archived?: boolean;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
It will:
|
|
56
|
+
|
|
57
|
+
- convert `'true'` to `true`
|
|
58
|
+
- convert `'false'` to `false`
|
|
59
|
+
- trim extra spaces and ignore case
|
|
60
|
+
- leave unsupported values unchanged
|
|
61
|
+
|
|
62
|
+
## S3 Module
|
|
63
|
+
|
|
64
|
+
`S3Module` is a small NestJS wrapper around the AWS SDK v3 S3 client. It gives you a reusable `S3Service` with a simple Nest-friendly setup for uploads, downloads, deletes, and signed URLs.
|
|
65
|
+
|
|
66
|
+
### Install S3 peer dependencies
|
|
67
|
+
|
|
68
|
+
If you want to use the S3 module, install the required AWS peer dependencies in your application:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npm install @aws-sdk/client-s3 @aws-sdk/lib-storage @aws-sdk/s3-request-presigner
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Register the module
|
|
75
|
+
|
|
76
|
+
Import the module from `@russ-b/nestjs-common-tools/modules` and configure it with `forRootAsync`.
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// app.module.ts
|
|
80
|
+
import { Module } from '@nestjs/common';
|
|
81
|
+
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
82
|
+
import { S3Module } from '@russ-b/nestjs-common-tools/modules';
|
|
83
|
+
|
|
84
|
+
@Module({
|
|
85
|
+
imports: [
|
|
86
|
+
ConfigModule.forRoot({
|
|
87
|
+
isGlobal: true,
|
|
88
|
+
}),
|
|
89
|
+
S3Module.forRootAsync({
|
|
90
|
+
global: true,
|
|
91
|
+
imports: [ConfigModule],
|
|
92
|
+
inject: [ConfigService],
|
|
93
|
+
useFactory: (config: ConfigService) => ({
|
|
94
|
+
region: config.get<string>('AWS_REGION') ?? 'eu-central-1',
|
|
95
|
+
bucket: config.get<string>('S3_BUCKET'),
|
|
96
|
+
endpoint: config.get<string>('S3_ENDPOINT'),
|
|
97
|
+
forcePathStyle: config.get<string>('S3_FORCE_PATH_STYLE') === 'true',
|
|
98
|
+
logger: config.get<string>('S3_DEBUG') === 'true',
|
|
99
|
+
}),
|
|
100
|
+
}),
|
|
101
|
+
],
|
|
102
|
+
})
|
|
103
|
+
export class AppModule {}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Credentials
|
|
107
|
+
|
|
108
|
+
The module does not accept `accessKeyId` or `secretAccessKey` directly. It relies on the AWS SDK default credential chain instead, which means credentials can come from:
|
|
109
|
+
|
|
110
|
+
- `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`
|
|
111
|
+
- local AWS profiles and shared config
|
|
112
|
+
- IAM roles in AWS environments
|
|
113
|
+
|
|
114
|
+
Example environment variables:
|
|
115
|
+
|
|
116
|
+
```env
|
|
117
|
+
AWS_REGION=eu-central-1
|
|
118
|
+
AWS_ACCESS_KEY_ID=your-access-key
|
|
119
|
+
AWS_SECRET_ACCESS_KEY=your-secret-key
|
|
120
|
+
S3_BUCKET=my-app-bucket
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`endpoint` is optional and is mostly useful for S3-compatible providers such as MinIO or LocalStack.
|
|
124
|
+
|
|
125
|
+
### Optional logging
|
|
126
|
+
|
|
127
|
+
By default, the module stays silent and does not write S3 operation logs.
|
|
128
|
+
|
|
129
|
+
If you want extra visibility while testing connectivity with S3 or MinIO, set `logger: true` in the module options. That enables the standard Nest logger for this service.
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
S3Module.forRootAsync({
|
|
133
|
+
useFactory: () => ({
|
|
134
|
+
bucket: 'my-app-bucket',
|
|
135
|
+
endpoint: 'http://localhost:9000',
|
|
136
|
+
forcePathStyle: true,
|
|
137
|
+
logger: true,
|
|
138
|
+
}),
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
You can also pass your own Nest-compatible logger object if you want to redirect those logs elsewhere.
|
|
143
|
+
|
|
144
|
+
### Inject and use the service
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
// files.service.ts
|
|
148
|
+
import { Injectable } from '@nestjs/common';
|
|
149
|
+
import { Readable } from 'stream';
|
|
150
|
+
import { S3Service } from '@russ-b/nestjs-common-tools/modules';
|
|
151
|
+
|
|
152
|
+
@Injectable()
|
|
153
|
+
export class FilesService {
|
|
154
|
+
constructor(private readonly s3Service: S3Service) {}
|
|
155
|
+
|
|
156
|
+
async putAvatar(key: string, file: Buffer) {
|
|
157
|
+
return this.s3Service.putObject(key, file, {
|
|
158
|
+
contentType: 'image/png',
|
|
159
|
+
cacheControl: 'public, max-age=31536000, immutable',
|
|
160
|
+
metadata: {
|
|
161
|
+
source: 'avatar-service',
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async uploadLargeFile(key: string, stream: Readable) {
|
|
167
|
+
return this.s3Service.upload(key, stream, {
|
|
168
|
+
contentType: 'application/pdf',
|
|
169
|
+
metadata: {
|
|
170
|
+
source: 'document-service',
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async getAvatar(key: string) {
|
|
176
|
+
const object = await this.s3Service.getObject(key);
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
stream: object.body,
|
|
180
|
+
contentType: object.contentType,
|
|
181
|
+
cacheControl: object.cacheControl,
|
|
182
|
+
metadata: object.metadata,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async deleteAvatar(key: string) {
|
|
187
|
+
return this.s3Service.deleteObject(key);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Signed URLs
|
|
193
|
+
|
|
194
|
+
Use `getSignedUrl` when the client should upload or download directly from S3.
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
// files.service.ts
|
|
198
|
+
async getAvatarUploadUrl(key: string) {
|
|
199
|
+
return this.s3Service.getSignedUrl(key, {
|
|
200
|
+
operation: 'putObject',
|
|
201
|
+
expiresIn: 300,
|
|
202
|
+
contentType: 'image/png',
|
|
203
|
+
cacheControl: 'public, max-age=31536000, immutable',
|
|
204
|
+
metadata: {
|
|
205
|
+
source: 'avatar-upload',
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async getAvatarDownloadUrl(key: string) {
|
|
211
|
+
return this.s3Service.getSignedUrl(key, {
|
|
212
|
+
operation: 'getObject',
|
|
213
|
+
expiresIn: 300,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
When generating a signed `putObject` URL, make sure the client sends the same headers you used during signing, especially `Content-Type` and any custom metadata headers.
|
|
219
|
+
|
|
220
|
+
### Available methods
|
|
221
|
+
|
|
222
|
+
| Method | Description |
|
|
223
|
+
|--------|-------------|
|
|
224
|
+
| `putObject(key, body, options)` | Simple upload using `PutObjectCommand` |
|
|
225
|
+
| `upload(key, body, options)` | Managed upload using `@aws-sdk/lib-storage`, useful for larger or streaming payloads |
|
|
226
|
+
| `getObject(key, options)` | Returns the readable stream together with object metadata |
|
|
227
|
+
| `deleteObject(key, options)` | Deletes an object from the configured bucket |
|
|
228
|
+
| `getSignedUrl(key, options)` | Creates a presigned URL for `getObject` or `putObject` |
|
|
229
|
+
|
|
230
|
+
`uploadObject` is still available as a compatibility alias, but `putObject` is the preferred method name going forward.
|
|
231
|
+
|
|
18
232
|
## Entity Validator
|
|
19
233
|
|
|
20
234
|
A custom validator for NestJS that validates if an entity exists in the database using TypeORM.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./to-string-array.decorator"), exports);
|
|
18
|
+
__exportStar(require("./to-optional-boolean.decorator"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/class-transformer/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8DAA4C;AAC5C,kEAAgD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseOptionalBooleanTransformer = void 0;
|
|
4
|
+
exports.ToOptionalBoolean = ToOptionalBoolean;
|
|
5
|
+
const class_transformer_1 = require("class-transformer");
|
|
6
|
+
function ToOptionalBoolean() {
|
|
7
|
+
return (0, class_transformer_1.Transform)(exports.parseOptionalBooleanTransformer);
|
|
8
|
+
}
|
|
9
|
+
const parseOptionalBooleanTransformer = ({ value, }) => normalizeOptionalBoolean(value);
|
|
10
|
+
exports.parseOptionalBooleanTransformer = parseOptionalBooleanTransformer;
|
|
11
|
+
function normalizeOptionalBoolean(value) {
|
|
12
|
+
if (value === undefined) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
if (typeof value === 'boolean') {
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
if (typeof value === 'string') {
|
|
19
|
+
const normalizedValue = value.trim().toLowerCase();
|
|
20
|
+
if (normalizedValue === 'true') {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
if (normalizedValue === 'false') {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=to-optional-boolean.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"to-optional-boolean.decorator.js","sourceRoot":"","sources":["../../src/class-transformer/to-optional-boolean.decorator.ts"],"names":[],"mappings":";;;AAEA,8CAEC;AAJD,yDAAiE;AAEjE,SAAgB,iBAAiB;IAC/B,OAAO,IAAA,6BAAS,EAAC,uCAA+B,CAAC,CAAC;AACpD,CAAC;AAEM,MAAM,+BAA+B,GAAG,CAAC,EAC9C,KAAK,GACa,EAAW,EAAE,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC;AAFrD,QAAA,+BAA+B,mCAEsB;AAElE,SAAS,wBAAwB,CAAC,KAAc;IAC9C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,eAAe,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAEnD,IAAI,eAAe,KAAK,MAAM,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,eAAe,KAAK,OAAO,EAAE,CAAC;YAChC,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function ToStringArray(): PropertyDecorator;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ToStringArray = ToStringArray;
|
|
4
|
+
const class_transformer_1 = require("class-transformer");
|
|
5
|
+
function ToStringArray() {
|
|
6
|
+
return (0, class_transformer_1.Transform)(({ value }) => normalizeToStringArray(value));
|
|
7
|
+
}
|
|
8
|
+
function normalizeToStringArray(value) {
|
|
9
|
+
if (typeof value === 'string') {
|
|
10
|
+
return splitAndTrim(value);
|
|
11
|
+
}
|
|
12
|
+
if (Array.isArray(value)) {
|
|
13
|
+
return value.flatMap((item) => typeof item === 'string' ? splitAndTrim(item) : []);
|
|
14
|
+
}
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
function splitAndTrim(value) {
|
|
18
|
+
return value
|
|
19
|
+
.split(',')
|
|
20
|
+
.map((item) => item.trim())
|
|
21
|
+
.filter(Boolean);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=to-string-array.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"to-string-array.decorator.js","sourceRoot":"","sources":["../../src/class-transformer/to-string-array.decorator.ts"],"names":[],"mappings":";;AAEA,sCAEC;AAJD,yDAAiE;AAEjE,SAAgB,aAAa;IAC3B,OAAO,IAAA,6BAAS,EAAC,CAAC,EAAE,KAAK,EAAqB,EAAE,EAAE,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC,CAAC;AACpF,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAc;IAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAC5B,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CACnD,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,OAAO,KAAK;SACT,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,OAAO,CAAC,CAAC;AACrB,CAAC"}
|
package/dist/modules/s3/index.js
CHANGED
|
@@ -16,4 +16,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./s3.module"), exports);
|
|
18
18
|
__exportStar(require("./s3.service"), exports);
|
|
19
|
+
__exportStar(require("./s3.interface"), exports);
|
|
19
20
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/modules/s3/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA4B;AAC5B,+CAA6B"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/modules/s3/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA4B;AAC5B,+CAA6B;AAC7B,iDAA+B"}
|
|
@@ -1,19 +1,44 @@
|
|
|
1
|
-
import { ModuleMetadata } from '@nestjs/common';
|
|
2
|
-
import { ObjectCannedACL } from '@aws-sdk/client-s3';
|
|
1
|
+
import type { LoggerService, ModuleMetadata } from '@nestjs/common';
|
|
2
|
+
import type { DeleteObjectCommandOutput, GetObjectCommandOutput, ObjectCannedACL, PutObjectCommandInput, PutObjectCommandOutput } from '@aws-sdk/client-s3';
|
|
3
|
+
import type { CompleteMultipartUploadCommandOutput } from '@aws-sdk/client-s3';
|
|
4
|
+
import type { Readable } from 'stream';
|
|
5
|
+
export type S3ModuleLogger = Pick<LoggerService, 'log' | 'error'>;
|
|
3
6
|
export interface S3ModuleOptions {
|
|
4
7
|
region?: string;
|
|
5
|
-
endpoint
|
|
6
|
-
accessKeyId: string;
|
|
7
|
-
secretAccessKey: string;
|
|
8
|
+
endpoint?: string;
|
|
8
9
|
forcePathStyle?: boolean;
|
|
9
10
|
bucket?: string;
|
|
11
|
+
logger?: boolean | S3ModuleLogger;
|
|
10
12
|
}
|
|
11
13
|
export interface S3ModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
|
|
12
14
|
useFactory: (...args: any[]) => Promise<S3ModuleOptions> | S3ModuleOptions;
|
|
13
15
|
global?: boolean;
|
|
14
16
|
inject?: any[];
|
|
15
17
|
}
|
|
16
|
-
export interface
|
|
18
|
+
export interface S3ObjectOptions {
|
|
17
19
|
bucket?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface S3UploadOptions extends S3ObjectOptions {
|
|
18
22
|
acl?: ObjectCannedACL;
|
|
23
|
+
cacheControl?: PutObjectCommandInput['CacheControl'];
|
|
24
|
+
contentType?: NonNullable<PutObjectCommandInput['ContentType']>;
|
|
25
|
+
metadata?: PutObjectCommandInput['Metadata'];
|
|
26
|
+
}
|
|
27
|
+
export interface S3SignedUrlOptions extends S3UploadOptions {
|
|
28
|
+
expiresIn?: number;
|
|
29
|
+
operation?: 'getObject' | 'putObject';
|
|
30
|
+
}
|
|
31
|
+
export interface S3GetObjectResult {
|
|
32
|
+
body: Readable;
|
|
33
|
+
cacheControl?: GetObjectCommandOutput['CacheControl'];
|
|
34
|
+
contentLength?: GetObjectCommandOutput['ContentLength'];
|
|
35
|
+
contentType?: GetObjectCommandOutput['ContentType'];
|
|
36
|
+
eTag?: GetObjectCommandOutput['ETag'];
|
|
37
|
+
lastModified?: GetObjectCommandOutput['LastModified'];
|
|
38
|
+
metadata?: GetObjectCommandOutput['Metadata'];
|
|
19
39
|
}
|
|
40
|
+
export type S3UploadResult = CompleteMultipartUploadCommandOutput;
|
|
41
|
+
export type S3PutObjectResult = PutObjectCommandOutput;
|
|
42
|
+
export type S3DeleteObjectResult = DeleteObjectCommandOutput;
|
|
43
|
+
export type S3Body = NonNullable<PutObjectCommandInput['Body']>;
|
|
44
|
+
export type UploadParams = S3UploadOptions;
|
|
@@ -9,9 +9,9 @@ var S3Module_1;
|
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.S3Module = void 0;
|
|
11
11
|
const common_1 = require("@nestjs/common");
|
|
12
|
-
const s3_service_1 = require("./s3.service");
|
|
13
|
-
const s3_constants_1 = require("./s3.constants");
|
|
14
12
|
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
13
|
+
const s3_constants_1 = require("./s3.constants");
|
|
14
|
+
const s3_service_1 = require("./s3.service");
|
|
15
15
|
let S3Module = S3Module_1 = class S3Module {
|
|
16
16
|
static forRootAsync(options) {
|
|
17
17
|
return {
|
|
@@ -28,15 +28,12 @@ let S3Module = S3Module_1 = class S3Module {
|
|
|
28
28
|
provide: s3_constants_1.S3_CLIENT,
|
|
29
29
|
inject: [s3_constants_1.S3_MODULE_OPTIONS],
|
|
30
30
|
useFactory: (opts) => {
|
|
31
|
-
|
|
31
|
+
const clientConfig = {
|
|
32
32
|
region: opts.region || 'us-east-1',
|
|
33
33
|
endpoint: opts.endpoint,
|
|
34
|
-
credentials: {
|
|
35
|
-
accessKeyId: opts.accessKeyId,
|
|
36
|
-
secretAccessKey: opts.secretAccessKey,
|
|
37
|
-
},
|
|
38
34
|
forcePathStyle: opts.forcePathStyle ?? true,
|
|
39
|
-
}
|
|
35
|
+
};
|
|
36
|
+
return new client_s3_1.S3Client(clientConfig);
|
|
40
37
|
},
|
|
41
38
|
},
|
|
42
39
|
s3_service_1.S3Service,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"s3.module.js","sourceRoot":"","sources":["../../../src/modules/s3/s3.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAAuD;AACvD,
|
|
1
|
+
{"version":3,"file":"s3.module.js","sourceRoot":"","sources":["../../../src/modules/s3/s3.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAAuD;AACvD,kDAA8D;AAE9D,iDAA8D;AAC9D,6CAAyC;AAGlC,IAAM,QAAQ,gBAAd,MAAM,QAAQ;IACnB,MAAM,CAAC,YAAY,CAAC,OAA6B;QAC/C,OAAO;YACL,MAAM,EAAE,UAAQ;YAChB,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;YAC9B,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,SAAS,EAAE;gBACT;oBACE,OAAO,EAAE,gCAAiB;oBAC1B,UAAU,EAAE,OAAO,CAAC,UAAU;oBAC9B,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;iBAC7B;gBACD;oBACE,OAAO,EAAE,wBAAS;oBAClB,MAAM,EAAE,CAAC,gCAAiB,CAAC;oBAC3B,UAAU,EAAE,CAAC,IAAqB,EAAE,EAAE;wBACpC,MAAM,YAAY,GAAmB;4BACnC,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,WAAW;4BAClC,QAAQ,EAAE,IAAI,CAAC,QAAQ;4BACvB,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,IAAI;yBAC5C,CAAC;wBAEF,OAAO,IAAI,oBAAQ,CAAC,YAAY,CAAC,CAAC;oBACpC,CAAC;iBACF;gBACD,sBAAS;aACV;YACD,OAAO,EAAE,CAAC,sBAAS,CAAC;SACrB,CAAC;IACJ,CAAC;CACF,CAAA;AA9BY,4BAAQ;mBAAR,QAAQ;IADpB,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,QAAQ,CA8BpB"}
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { S3Client } from '@aws-sdk/client-s3';
|
|
2
|
-
import {
|
|
3
|
-
import { StreamingBlobPayloadInputTypes } from '@smithy/types/dist-types/streaming-payload/streaming-blob-payload-input-types';
|
|
4
|
-
import { UploadParams } from './s3.interface';
|
|
2
|
+
import { S3Body, S3DeleteObjectResult, S3GetObjectResult, S3ModuleOptions, S3ObjectOptions, S3PutObjectResult, S3SignedUrlOptions, S3UploadOptions, S3UploadResult } from './s3.interface';
|
|
5
3
|
export declare class S3Service {
|
|
6
4
|
private readonly options;
|
|
7
5
|
private readonly s3Client;
|
|
8
|
-
private readonly logger
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
uploadObject(key: string, body:
|
|
13
|
-
deleteObject(key: string,
|
|
14
|
-
getObject(key: string,
|
|
6
|
+
private readonly logger?;
|
|
7
|
+
constructor(options: S3ModuleOptions, s3Client: S3Client);
|
|
8
|
+
upload(key: string, body: S3Body, options?: S3UploadOptions): Promise<S3UploadResult>;
|
|
9
|
+
putObject(key: string, body: S3Body, options?: S3UploadOptions): Promise<S3PutObjectResult>;
|
|
10
|
+
uploadObject(key: string, body: S3Body, options?: S3UploadOptions): Promise<S3PutObjectResult>;
|
|
11
|
+
deleteObject(key: string, options?: S3ObjectOptions): Promise<S3DeleteObjectResult>;
|
|
12
|
+
getObject(key: string, options?: S3ObjectOptions): Promise<S3GetObjectResult>;
|
|
13
|
+
getSignedUrl(key: string, options?: S3SignedUrlOptions): Promise<string>;
|
|
14
|
+
private createPutObjectParams;
|
|
15
|
+
private resolveBucket;
|
|
16
|
+
private log;
|
|
17
|
+
private logError;
|
|
15
18
|
}
|
|
@@ -11,81 +11,137 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
11
11
|
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
12
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
13
|
};
|
|
14
|
+
var S3Service_1;
|
|
14
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
16
|
exports.S3Service = void 0;
|
|
16
17
|
const common_1 = require("@nestjs/common");
|
|
17
18
|
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
18
|
-
const
|
|
19
|
+
const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
|
|
20
|
+
const stream_1 = require("stream");
|
|
19
21
|
const lib_storage_1 = require("@aws-sdk/lib-storage");
|
|
20
|
-
|
|
22
|
+
const s3_constants_1 = require("./s3.constants");
|
|
23
|
+
let S3Service = S3Service_1 = class S3Service {
|
|
21
24
|
constructor(options, s3Client) {
|
|
22
25
|
this.options = options;
|
|
23
26
|
this.s3Client = s3Client;
|
|
24
|
-
this.logger =
|
|
25
|
-
|
|
27
|
+
this.logger =
|
|
28
|
+
options.logger === true ? new common_1.Logger(S3Service_1.name) : options.logger || undefined;
|
|
26
29
|
}
|
|
27
|
-
async upload(key, body,
|
|
30
|
+
async upload(key, body, options) {
|
|
28
31
|
const upload = new lib_storage_1.Upload({
|
|
29
32
|
client: this.s3Client,
|
|
30
|
-
params:
|
|
31
|
-
Bucket: params?.bucket || this.bucket,
|
|
32
|
-
Key: key,
|
|
33
|
-
Body: body,
|
|
34
|
-
ContentType: contentType,
|
|
35
|
-
ACL: params?.acl || 'public-read',
|
|
36
|
-
},
|
|
33
|
+
params: this.createPutObjectParams(key, body, options, true),
|
|
37
34
|
});
|
|
38
|
-
await upload.done();
|
|
35
|
+
const response = await upload.done();
|
|
36
|
+
this.log(`Uploaded object with multipart upload: ${key}`);
|
|
37
|
+
return response;
|
|
39
38
|
}
|
|
40
|
-
async
|
|
41
|
-
const command = new client_s3_1.PutObjectCommand(
|
|
42
|
-
Bucket: params?.bucket || this.bucket,
|
|
43
|
-
Key: key,
|
|
44
|
-
Body: body,
|
|
45
|
-
ContentType: contentType,
|
|
46
|
-
ACL: params?.acl || 'public-read',
|
|
47
|
-
});
|
|
39
|
+
async putObject(key, body, options) {
|
|
40
|
+
const command = new client_s3_1.PutObjectCommand(this.createPutObjectParams(key, body, options, true));
|
|
48
41
|
try {
|
|
49
|
-
await this.s3Client.send(command);
|
|
50
|
-
this.
|
|
42
|
+
const response = await this.s3Client.send(command);
|
|
43
|
+
this.log(`Uploaded object: ${key}`);
|
|
44
|
+
return response;
|
|
51
45
|
}
|
|
52
46
|
catch (error) {
|
|
53
|
-
this.
|
|
47
|
+
this.logError(`Failed to upload object: ${key}`, error);
|
|
54
48
|
throw error;
|
|
55
49
|
}
|
|
56
50
|
}
|
|
57
|
-
async
|
|
51
|
+
async uploadObject(key, body, options) {
|
|
52
|
+
return this.putObject(key, body, options);
|
|
53
|
+
}
|
|
54
|
+
async deleteObject(key, options) {
|
|
58
55
|
const command = new client_s3_1.DeleteObjectCommand({
|
|
59
|
-
Bucket:
|
|
56
|
+
Bucket: this.resolveBucket(options?.bucket),
|
|
60
57
|
Key: key,
|
|
61
58
|
});
|
|
62
59
|
try {
|
|
63
|
-
await this.s3Client.send(command);
|
|
64
|
-
this.
|
|
60
|
+
const response = await this.s3Client.send(command);
|
|
61
|
+
this.log(`Deleted object: ${key}`);
|
|
62
|
+
return response;
|
|
65
63
|
}
|
|
66
64
|
catch (error) {
|
|
67
|
-
this.
|
|
65
|
+
this.logError(`Failed to delete object: ${key}`, error);
|
|
68
66
|
throw error;
|
|
69
67
|
}
|
|
70
68
|
}
|
|
71
|
-
async getObject(key,
|
|
69
|
+
async getObject(key, options) {
|
|
72
70
|
const command = new client_s3_1.GetObjectCommand({
|
|
73
|
-
Bucket:
|
|
71
|
+
Bucket: this.resolveBucket(options?.bucket),
|
|
74
72
|
Key: key,
|
|
75
73
|
});
|
|
76
74
|
try {
|
|
77
75
|
const response = await this.s3Client.send(command);
|
|
78
|
-
this.
|
|
79
|
-
|
|
76
|
+
this.log(`Fetched object: ${key}`);
|
|
77
|
+
if (!response.Body) {
|
|
78
|
+
throw new Error(`S3 object "${key}" returned an empty body.`);
|
|
79
|
+
}
|
|
80
|
+
if (!(response.Body instanceof stream_1.Readable)) {
|
|
81
|
+
throw new Error(`S3 object "${key}" did not return a Node.js readable stream.`);
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
body: response.Body,
|
|
85
|
+
cacheControl: response.CacheControl,
|
|
86
|
+
contentLength: response.ContentLength,
|
|
87
|
+
contentType: response.ContentType,
|
|
88
|
+
eTag: response.ETag,
|
|
89
|
+
lastModified: response.LastModified,
|
|
90
|
+
metadata: response.Metadata,
|
|
91
|
+
};
|
|
80
92
|
}
|
|
81
93
|
catch (error) {
|
|
82
|
-
this.
|
|
94
|
+
this.logError(`Failed to get object: ${key}`, error);
|
|
83
95
|
throw error;
|
|
84
96
|
}
|
|
85
97
|
}
|
|
98
|
+
async getSignedUrl(key, options) {
|
|
99
|
+
const expiresIn = options?.expiresIn ?? 900;
|
|
100
|
+
const operation = options?.operation ?? 'getObject';
|
|
101
|
+
const command = operation === 'putObject'
|
|
102
|
+
? new client_s3_1.PutObjectCommand(this.createPutObjectParams(key, undefined, options))
|
|
103
|
+
: new client_s3_1.GetObjectCommand({
|
|
104
|
+
Bucket: this.resolveBucket(options?.bucket),
|
|
105
|
+
Key: key,
|
|
106
|
+
});
|
|
107
|
+
return (0, s3_request_presigner_1.getSignedUrl)(this.s3Client, command, { expiresIn });
|
|
108
|
+
}
|
|
109
|
+
createPutObjectParams(key, body, options, useDefaultContentType = false) {
|
|
110
|
+
const contentType = options?.contentType ??
|
|
111
|
+
(useDefaultContentType ? 'application/octet-stream' : undefined);
|
|
112
|
+
return {
|
|
113
|
+
Bucket: this.resolveBucket(options?.bucket),
|
|
114
|
+
Key: key,
|
|
115
|
+
...(body !== undefined ? { Body: body } : {}),
|
|
116
|
+
...(contentType ? { ContentType: contentType } : {}),
|
|
117
|
+
...(options?.acl ? { ACL: options.acl } : {}),
|
|
118
|
+
...(options?.cacheControl ? { CacheControl: options.cacheControl } : {}),
|
|
119
|
+
...(options?.metadata ? { Metadata: options.metadata } : {}),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
resolveBucket(bucket) {
|
|
123
|
+
const resolvedBucket = bucket ?? this.options.bucket;
|
|
124
|
+
if (!resolvedBucket) {
|
|
125
|
+
throw new Error('S3 bucket is not configured. Pass a bucket to the method call or set S3ModuleOptions.bucket.');
|
|
126
|
+
}
|
|
127
|
+
return resolvedBucket;
|
|
128
|
+
}
|
|
129
|
+
log(message) {
|
|
130
|
+
this.logger?.log(message);
|
|
131
|
+
}
|
|
132
|
+
logError(message, error) {
|
|
133
|
+
if (!this.logger) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (error instanceof Error) {
|
|
137
|
+
this.logger.error(message, error.stack ?? error.message);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
this.logger.error(message, error);
|
|
141
|
+
}
|
|
86
142
|
};
|
|
87
143
|
exports.S3Service = S3Service;
|
|
88
|
-
exports.S3Service = S3Service = __decorate([
|
|
144
|
+
exports.S3Service = S3Service = S3Service_1 = __decorate([
|
|
89
145
|
(0, common_1.Injectable)(),
|
|
90
146
|
__param(0, (0, common_1.Inject)(s3_constants_1.S3_MODULE_OPTIONS)),
|
|
91
147
|
__param(1, (0, common_1.Inject)(s3_constants_1.S3_CLIENT)),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"s3.service.js","sourceRoot":"","sources":["../../../src/modules/s3/s3.service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"s3.service.js","sourceRoot":"","sources":["../../../src/modules/s3/s3.service.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@russ-b/nestjs-common-tools",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"description": "NestJS utility tools",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -47,6 +47,10 @@
|
|
|
47
47
|
"types": "./dist/common/filters/index.d.ts",
|
|
48
48
|
"default": "./dist/common/filters/index.js"
|
|
49
49
|
},
|
|
50
|
+
"./class-transformer": {
|
|
51
|
+
"types": "./dist/class-transformer/index.d.ts",
|
|
52
|
+
"default": "./dist/class-transformer/index.js"
|
|
53
|
+
},
|
|
50
54
|
"./validators": {
|
|
51
55
|
"types": "./dist/validators/index.d.ts",
|
|
52
56
|
"default": "./dist/validators/index.js"
|
|
@@ -82,6 +86,9 @@
|
|
|
82
86
|
"common/filters": [
|
|
83
87
|
"dist/common/filters/index.d.ts"
|
|
84
88
|
],
|
|
89
|
+
"class-transformer": [
|
|
90
|
+
"dist/class-transformer/index.d.ts"
|
|
91
|
+
],
|
|
85
92
|
"modules": [
|
|
86
93
|
"dist/modules/index.d.ts"
|
|
87
94
|
],
|
|
@@ -99,6 +106,7 @@
|
|
|
99
106
|
"peerDependencies": {
|
|
100
107
|
"@aws-sdk/client-s3": "^3.0.0",
|
|
101
108
|
"@aws-sdk/lib-storage": "^3.0.0",
|
|
109
|
+
"@aws-sdk/s3-request-presigner": "^3.1019.0",
|
|
102
110
|
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
|
103
111
|
"@nestjs/config": "^3.0.0 || ^4.0.0",
|
|
104
112
|
"nest-winston": "^1.10.2",
|