@russ-b/nestjs-common-tools 1.13.0 → 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 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,2 @@
1
+ export * from './to-string-array.decorator';
2
+ export * from './to-optional-boolean.decorator';
@@ -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,3 @@
1
+ import { TransformFnParams } from 'class-transformer';
2
+ export declare function ToOptionalBoolean(): PropertyDecorator;
3
+ export declare const parseOptionalBooleanTransformer: ({ value, }: TransformFnParams) => unknown;
@@ -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"}
@@ -1,2 +1,3 @@
1
1
  export * from './s3.module';
2
2
  export * from './s3.service';
3
+ export * from './s3.interface';
@@ -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: string;
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 UploadParams {
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
- return new client_s3_1.S3Client({
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,6CAAyC;AACzC,iDAA8D;AAC9D,kDAA8C;AAIvC,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,OAAO,IAAI,oBAAQ,CAAC;4BAClB,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,WAAW;4BAClC,QAAQ,EAAE,IAAI,CAAC,QAAQ;4BACvB,WAAW,EAAE;gCACX,WAAW,EAAE,IAAI,CAAC,WAAW;gCAC7B,eAAe,EAAE,IAAI,CAAC,eAAe;6BACtC;4BACD,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,IAAI;yBAC5C,CAAC,CAAC;oBACL,CAAC;iBACF;gBACD,sBAAS;aACV;YACD,OAAO,EAAE,CAAC,sBAAS,CAAC;SACrB,CAAC;IACJ,CAAC;CACF,CAAA;AAhCY,4BAAQ;mBAAR,QAAQ;IADpB,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,QAAQ,CAgCpB"}
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 { Readable } from 'stream';
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
- private readonly bucket;
10
- constructor(options: Record<string, string>, s3Client: S3Client);
11
- upload(key: string, body: StreamingBlobPayloadInputTypes, contentType?: string, params?: UploadParams): Promise<void>;
12
- uploadObject(key: string, body: StreamingBlobPayloadInputTypes, contentType?: string, params?: UploadParams): Promise<void>;
13
- deleteObject(key: string, bucket?: string): Promise<void>;
14
- getObject(key: string, bucket?: string): Promise<Readable>;
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 s3_constants_1 = require("./s3.constants");
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
- let S3Service = class S3Service {
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 = new common_1.Logger(this.constructor.name);
25
- this.bucket = this.options.bucket;
27
+ this.logger =
28
+ options.logger === true ? new common_1.Logger(S3Service_1.name) : options.logger || undefined;
26
29
  }
27
- async upload(key, body, contentType = 'application/octet-stream', params) {
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 uploadObject(key, body, contentType = 'application/octet-stream', params) {
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.logger.log(`Uploaded object: ${key}`);
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.logger.error(`Failed to upload object: ${key}`, error);
47
+ this.logError(`Failed to upload object: ${key}`, error);
54
48
  throw error;
55
49
  }
56
50
  }
57
- async deleteObject(key, bucket) {
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: bucket || this.bucket,
56
+ Bucket: this.resolveBucket(options?.bucket),
60
57
  Key: key,
61
58
  });
62
59
  try {
63
- await this.s3Client.send(command);
64
- this.logger.log(`Deleted object: ${key}`);
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.logger.error(`Failed to delete object: ${key}`, error);
65
+ this.logError(`Failed to delete object: ${key}`, error);
68
66
  throw error;
69
67
  }
70
68
  }
71
- async getObject(key, bucket) {
69
+ async getObject(key, options) {
72
70
  const command = new client_s3_1.GetObjectCommand({
73
- Bucket: bucket || this.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.logger.log(`Fetched object: ${key}`);
79
- return response.Body;
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.logger.error(`Failed to get object: ${key}`, error);
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":"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"}
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.13.0",
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"
@@ -65,6 +69,34 @@
65
69
  },
66
70
  "./package.json": "./package.json"
67
71
  },
72
+ "typesVersions": {
73
+ "*": {
74
+ "validators": [
75
+ "dist/validators/index.d.ts"
76
+ ],
77
+ "typeorm": [
78
+ "dist/typeorm/index.d.ts"
79
+ ],
80
+ "common/util": [
81
+ "dist/common/util/index.d.ts"
82
+ ],
83
+ "common/pagination": [
84
+ "dist/common/pagination/index.d.ts"
85
+ ],
86
+ "common/filters": [
87
+ "dist/common/filters/index.d.ts"
88
+ ],
89
+ "class-transformer": [
90
+ "dist/class-transformer/index.d.ts"
91
+ ],
92
+ "modules": [
93
+ "dist/modules/index.d.ts"
94
+ ],
95
+ "logger": [
96
+ "dist/logger/index.d.ts"
97
+ ]
98
+ }
99
+ },
68
100
  "dependencies": {
69
101
  "class-transformer": "^0.5.1",
70
102
  "class-validator": "^0.14.1",
@@ -74,6 +106,7 @@
74
106
  "peerDependencies": {
75
107
  "@aws-sdk/client-s3": "^3.0.0",
76
108
  "@aws-sdk/lib-storage": "^3.0.0",
109
+ "@aws-sdk/s3-request-presigner": "^3.1019.0",
77
110
  "@nestjs/common": "^10.0.0 || ^11.0.0",
78
111
  "@nestjs/config": "^3.0.0 || ^4.0.0",
79
112
  "nest-winston": "^1.10.2",