nestjs-minio-s3 1.0.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/CHANGELOG.md ADDED
@@ -0,0 +1 @@
1
+ RELEASE 1.0.0
@@ -0,0 +1,31 @@
1
+ # Contributing
2
+
3
+ 1. [Fork it](https://help.github.com/articles/fork-a-repo/)
4
+ 2. Install dependencies (`npm install`)
5
+ 3. Create your feature branch (`git checkout -b my-new-feature`)
6
+ 4. Commit your changes (`git commit -am 'Added some feature'`)
7
+ 5. Test your changes (`npm test`)
8
+ 6. Push to the branch (`git push origin my-new-feature`)
9
+ 7. [Create new Pull Request](https://help.github.com/articles/creating-a-pull-request/)
10
+
11
+ ## Testing
12
+
13
+ We use [Jest](https://github.com/facebook/jest) to write tests. Run our test suite with this command:
14
+
15
+ ```
16
+ npm test
17
+ ```
18
+
19
+ ## Code Style
20
+
21
+ We use [Prettier](https://prettier.io/) and tslint to maintain code style and best practices.
22
+ Please make sure your PR adheres to the guides by running:
23
+
24
+ ```
25
+ npm run format
26
+ ```
27
+
28
+ and
29
+ ```
30
+ npm run lint
31
+ ```
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 John Biundo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,37 @@
1
+ <h1 align="center"></h1>
2
+
3
+ <div align="center">
4
+ <a href="http://nestjs.com/" target="_blank">
5
+ <img src="https://nestjs.com/img/logo_text.svg" width="150" alt="Nest Logo" />
6
+ </a>
7
+ </div>
8
+
9
+ <h3 align="center">NestJS npm Package Minio S3</h3>
10
+
11
+ <div align="center">
12
+ <a href="https://nestjs.com" target="_blank">
13
+ <img src="https://img.shields.io/badge/built%20with-NestJs-red.svg" alt="Built with NestJS">
14
+ </a>
15
+ </div>
16
+
17
+ ### Installation
18
+
19
+ ```bash
20
+ npm install nestjs-minio-s3
21
+ ```
22
+
23
+ ## Change Log
24
+
25
+ See [Changelog](CHANGELOG.md) for more information.
26
+
27
+ ## Contributing
28
+
29
+ Contributions welcome! See [Contributing](CONTRIBUTING.md).
30
+
31
+ ## Author
32
+
33
+ **Artem Kosyrev**
34
+
35
+ ## License
36
+
37
+ Licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1 @@
1
+ export declare const MINIO_MODULE_OPTIONS = "MINIO_MODULE_OPTIONS";
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MINIO_MODULE_OPTIONS = void 0;
4
+ exports.MINIO_MODULE_OPTIONS = 'MINIO_MODULE_OPTIONS';
@@ -0,0 +1,5 @@
1
+ export * from './minio.service';
2
+ export * from './minio.module';
3
+ export * from './interfaces/minio-options.interface';
4
+ export * from './interfaces/minio-bucket-config.interface';
5
+ export * from './constants';
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
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("./minio.service"), exports);
18
+ __exportStar(require("./minio.module"), exports);
19
+ __exportStar(require("./interfaces/minio-options.interface"), exports);
20
+ __exportStar(require("./interfaces/minio-bucket-config.interface"), exports);
21
+ __exportStar(require("./constants"), exports);
@@ -0,0 +1,13 @@
1
+ export interface MinioBucketConfig {
2
+ name: string;
3
+ policy?: 'public' | 'private' | 'custom';
4
+ customPolicy?: any;
5
+ }
6
+ export interface MinioBucketConfigPolicyStatement {
7
+ Effect: 'Allow' | 'Deny';
8
+ Principal: {
9
+ AWS: string[];
10
+ };
11
+ Action: string[];
12
+ Resource: string[];
13
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,21 @@
1
+ import { MinioBucketConfig } from './minio-bucket-config.interface';
2
+ import { Type } from '@nestjs/common';
3
+ import { ModuleMetadata } from '@nestjs/common/interfaces/modules/module-metadata.interface';
4
+ export interface MinioModuleOptions {
5
+ endpoint: string;
6
+ port?: number;
7
+ useSSL?: boolean;
8
+ accessKey: string;
9
+ secretKey: string;
10
+ region?: string;
11
+ buckets?: MinioBucketConfig[];
12
+ }
13
+ export interface MinioOptionsFactory {
14
+ createMinioOptions(): Promise<MinioModuleOptions> | MinioModuleOptions;
15
+ }
16
+ export interface MinioModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
17
+ useExisting?: Type<MinioOptionsFactory>;
18
+ useClass?: Type<MinioOptionsFactory>;
19
+ useFactory?: (...args: any[]) => Promise<MinioModuleOptions> | MinioModuleOptions;
20
+ inject?: any[];
21
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,8 @@
1
+ import { DynamicModule } from '@nestjs/common';
2
+ import { MinioModuleAsyncOptions, MinioModuleOptions } from './interfaces/minio-options.interface';
3
+ export declare class MinioModule {
4
+ static forRoot(options: MinioModuleOptions): DynamicModule;
5
+ static forRootAsync(options: MinioModuleAsyncOptions): DynamicModule;
6
+ private static createAsyncProviders;
7
+ private static createAsyncOptionsProvider;
8
+ }
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
9
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
10
+ return new (P || (P = Promise))(function (resolve, reject) {
11
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
12
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
13
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
14
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
15
+ });
16
+ };
17
+ var MinioModule_1;
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.MinioModule = void 0;
20
+ const common_1 = require("@nestjs/common");
21
+ const minio_service_1 = require("./minio.service");
22
+ const constants_1 = require("./constants");
23
+ let MinioModule = MinioModule_1 = class MinioModule {
24
+ static forRoot(options) {
25
+ return {
26
+ module: MinioModule_1,
27
+ providers: [
28
+ {
29
+ provide: constants_1.MINIO_MODULE_OPTIONS,
30
+ useValue: options,
31
+ },
32
+ minio_service_1.MinioService,
33
+ ],
34
+ exports: [minio_service_1.MinioService],
35
+ };
36
+ }
37
+ static forRootAsync(options) {
38
+ return {
39
+ module: MinioModule_1,
40
+ imports: options.imports || [],
41
+ providers: [...this.createAsyncProviders(options), minio_service_1.MinioService],
42
+ exports: [minio_service_1.MinioService],
43
+ };
44
+ }
45
+ static createAsyncProviders(options) {
46
+ if (options.useExisting || options.useFactory) {
47
+ return [this.createAsyncOptionsProvider(options)];
48
+ }
49
+ return [
50
+ this.createAsyncOptionsProvider(options),
51
+ {
52
+ provide: options.useClass,
53
+ useClass: options.useClass,
54
+ },
55
+ ];
56
+ }
57
+ static createAsyncOptionsProvider(options) {
58
+ if (options.useFactory) {
59
+ return {
60
+ provide: constants_1.MINIO_MODULE_OPTIONS,
61
+ useFactory: options.useFactory,
62
+ inject: options.inject || [],
63
+ };
64
+ }
65
+ return {
66
+ provide: constants_1.MINIO_MODULE_OPTIONS,
67
+ useFactory: (optionsFactory) => __awaiter(this, void 0, void 0, function* () { return yield optionsFactory.createMinioOptions(); }),
68
+ inject: [options.useExisting || options.useClass],
69
+ };
70
+ }
71
+ };
72
+ exports.MinioModule = MinioModule;
73
+ exports.MinioModule = MinioModule = MinioModule_1 = __decorate([
74
+ (0, common_1.Global)(),
75
+ (0, common_1.Module)({})
76
+ ], MinioModule);
@@ -0,0 +1,20 @@
1
+ import { OnModuleInit } from '@nestjs/common';
2
+ import { S3Client } from '@aws-sdk/client-s3';
3
+ import { MinioModuleOptions } from './interfaces/minio-options.interface';
4
+ export declare class MinioService implements OnModuleInit {
5
+ private readonly options;
6
+ private readonly logger;
7
+ private s3Client;
8
+ constructor(options: MinioModuleOptions);
9
+ onModuleInit(): Promise<void>;
10
+ private initializeBuckets;
11
+ private createBucketIfNotExists;
12
+ private setBucketPolicy;
13
+ upload(bucketName: string, key: string, body: Buffer, contentType?: string): Promise<string>;
14
+ delete(bucketName: string, key: string): Promise<void>;
15
+ get(bucketName: string, key: string): Promise<Buffer>;
16
+ list(bucketName: string, prefix?: string): Promise<string[]>;
17
+ getPublicUrl(bucketName: string, key: string): string;
18
+ getKeyFromUrl(url: string, bucketName: string): string | null;
19
+ getClient(): S3Client;
20
+ }
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
15
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
16
+ return new (P || (P = Promise))(function (resolve, reject) {
17
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
18
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
19
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
20
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
21
+ });
22
+ };
23
+ var MinioService_1;
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.MinioService = void 0;
26
+ const common_1 = require("@nestjs/common");
27
+ const client_s3_1 = require("@aws-sdk/client-s3");
28
+ const constants_1 = require("./constants");
29
+ let MinioService = MinioService_1 = class MinioService {
30
+ constructor(options) {
31
+ this.options = options;
32
+ this.logger = new common_1.Logger(MinioService_1.name);
33
+ this.s3Client = new client_s3_1.S3Client({
34
+ endpoint: this.options.endpoint,
35
+ region: this.options.region || 'us-east-1',
36
+ credentials: {
37
+ accessKeyId: this.options.accessKey,
38
+ secretAccessKey: this.options.secretKey,
39
+ },
40
+ forcePathStyle: true,
41
+ });
42
+ }
43
+ onModuleInit() {
44
+ return __awaiter(this, void 0, void 0, function* () {
45
+ if (this.options.buckets && this.options.buckets.length > 0) {
46
+ yield this.initializeBuckets(this.options.buckets);
47
+ }
48
+ });
49
+ }
50
+ initializeBuckets(buckets) {
51
+ return __awaiter(this, void 0, void 0, function* () {
52
+ for (const bucket of buckets) {
53
+ yield this.createBucketIfNotExists(bucket.name);
54
+ yield this.setBucketPolicy(bucket);
55
+ }
56
+ });
57
+ }
58
+ createBucketIfNotExists(bucketName) {
59
+ return __awaiter(this, void 0, void 0, function* () {
60
+ try {
61
+ yield this.s3Client.send(new client_s3_1.HeadBucketCommand({ Bucket: bucketName }));
62
+ this.logger.log(`Bucket "${bucketName}" already exists`);
63
+ }
64
+ catch (err) {
65
+ if (err.name === 'NotFound') {
66
+ try {
67
+ yield this.s3Client.send(new client_s3_1.CreateBucketCommand({ Bucket: bucketName }));
68
+ this.logger.log(`Bucket "${bucketName}" created successfully`);
69
+ }
70
+ catch (createErr) {
71
+ this.logger.error(`Error creating bucket "${bucketName}":`, createErr);
72
+ throw createErr;
73
+ }
74
+ }
75
+ else {
76
+ this.logger.error(`Error checking bucket "${bucketName}":`, err);
77
+ throw err;
78
+ }
79
+ }
80
+ });
81
+ }
82
+ setBucketPolicy(bucketConfig) {
83
+ return __awaiter(this, void 0, void 0, function* () {
84
+ let policy;
85
+ if (bucketConfig.customPolicy) {
86
+ policy = bucketConfig.customPolicy;
87
+ }
88
+ else if (bucketConfig.policy === 'public') {
89
+ policy = {
90
+ Version: '2012-10-17',
91
+ Statement: [
92
+ {
93
+ Effect: 'Allow',
94
+ Principal: { AWS: ['*'] },
95
+ Action: ['s3:GetObject'],
96
+ Resource: [`arn:aws:s3:::${bucketConfig.name}/*`],
97
+ },
98
+ ],
99
+ };
100
+ }
101
+ else if (bucketConfig.policy === 'private') {
102
+ return;
103
+ }
104
+ if (policy) {
105
+ try {
106
+ yield this.s3Client.send(new client_s3_1.PutBucketPolicyCommand({
107
+ Bucket: bucketConfig.name,
108
+ Policy: JSON.stringify(policy),
109
+ }));
110
+ this.logger.log(`Policy set for bucket "${bucketConfig.name}"`);
111
+ }
112
+ catch (err) {
113
+ this.logger.error(`Error setting policy for bucket "${bucketConfig.name}":`, err);
114
+ }
115
+ }
116
+ });
117
+ }
118
+ upload(bucketName, key, body, contentType) {
119
+ return __awaiter(this, void 0, void 0, function* () {
120
+ try {
121
+ yield this.s3Client.send(new client_s3_1.PutObjectCommand({
122
+ Bucket: bucketName,
123
+ Key: key,
124
+ Body: body,
125
+ ContentType: contentType,
126
+ }));
127
+ return this.getPublicUrl(bucketName, key);
128
+ }
129
+ catch (err) {
130
+ this.logger.error(`Error uploading file to ${bucketName}/${key}: `, err);
131
+ throw err;
132
+ }
133
+ });
134
+ }
135
+ delete(bucketName, key) {
136
+ return __awaiter(this, void 0, void 0, function* () {
137
+ try {
138
+ yield this.s3Client.send(new client_s3_1.DeleteObjectCommand({
139
+ Bucket: bucketName,
140
+ Key: key,
141
+ }));
142
+ this.logger.log(`Deleted ${bucketName}/${key}`);
143
+ }
144
+ catch (err) {
145
+ this.logger.error(`Error deleting file ${bucketName}/${key}: `, err);
146
+ throw err;
147
+ }
148
+ });
149
+ }
150
+ get(bucketName, key) {
151
+ return __awaiter(this, void 0, void 0, function* () {
152
+ try {
153
+ const response = yield this.s3Client.send(new client_s3_1.GetObjectCommand({
154
+ Bucket: bucketName,
155
+ Key: key,
156
+ }));
157
+ return Buffer.from(yield response.Body.transformToByteArray());
158
+ }
159
+ catch (err) {
160
+ this.logger.error(`Error getting file ${bucketName}/${key}: `, err);
161
+ throw err;
162
+ }
163
+ });
164
+ }
165
+ list(bucketName, prefix) {
166
+ return __awaiter(this, void 0, void 0, function* () {
167
+ try {
168
+ const response = yield this.s3Client.send(new client_s3_1.ListObjectsV2Command({
169
+ Bucket: bucketName,
170
+ Prefix: prefix,
171
+ }));
172
+ return response.Contents.map((item) => item.Key) || [];
173
+ }
174
+ catch (err) {
175
+ this.logger.error(`Error listing files in ${bucketName}: `, err);
176
+ throw err;
177
+ }
178
+ });
179
+ }
180
+ getPublicUrl(bucketName, key) {
181
+ const url = new URL(this.options.endpoint);
182
+ url.pathname = `/${bucketName}/${key}`;
183
+ return url.toString();
184
+ }
185
+ getKeyFromUrl(url, bucketName) {
186
+ const parts = url.split(`/${bucketName}/`);
187
+ return parts.length > 1 ? parts[1] : null;
188
+ }
189
+ getClient() {
190
+ return this.s3Client;
191
+ }
192
+ };
193
+ exports.MinioService = MinioService;
194
+ exports.MinioService = MinioService = MinioService_1 = __decorate([
195
+ (0, common_1.Injectable)(),
196
+ __param(0, (0, common_1.Inject)(constants_1.MINIO_MODULE_OPTIONS)),
197
+ __metadata("design:paramtypes", [Object])
198
+ ], MinioService);
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "nestjs-minio-s3",
3
+ "version": "1.0.0",
4
+ "description": "NestJS npm package starter",
5
+ "author": "Artem Kosyrev <cosinusgradusov90@gmail.com>",
6
+ "license": "MIT",
7
+ "readmeFilename": "README.md",
8
+ "main": "dist/index.js",
9
+ "files": [
10
+ "dist/**/*",
11
+ "*.md"
12
+ ],
13
+ "scripts": {
14
+ "start:dev": "tsc -w",
15
+ "build": "tsc",
16
+ "prepare": "npm run build",
17
+ "format": "prettier --write \"src/**/*.ts\"",
18
+ "lint": "tslint -p tsconfig.json -c tslint.json",
19
+ "test": "jest",
20
+ "test:watch": "jest --watch",
21
+ "test:cov": "jest --coverage",
22
+ "test:e2e": "jest --config ./test/jest-e2e.json"
23
+ },
24
+ "keywords": [
25
+ "nestjs"
26
+ ],
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/CurlyBattery/nestjs-minio-s3-repo"
33
+ },
34
+ "bugs": "https://github.com/CurlyBattery/nestjs-minio-s3-repo",
35
+ "peerDependencies": {
36
+ "@nestjs/common": "^6.0.0"
37
+ },
38
+ "dependencies": {
39
+ "@aws-sdk/client-s3": "^3.958.0",
40
+ "rxjs": "^7.8.2"
41
+ },
42
+ "devDependencies": {
43
+ "@nestjs/common": "^6.11.11",
44
+ "@nestjs/core": "^6.0.0",
45
+ "@nestjs/platform-express": "^6.0.0",
46
+ "@nestjs/testing": "6.1.1",
47
+ "@types/express": "4.16.1",
48
+ "@types/jest": "24.0.11",
49
+ "@types/node": "^25.0.3",
50
+ "@types/supertest": "2.0.7",
51
+ "jest": "24.7.1",
52
+ "prettier": "1.17.0",
53
+ "supertest": "4.0.2",
54
+ "ts-jest": "24.0.2",
55
+ "ts-node": "8.1.0",
56
+ "tsc-watch": "2.2.1",
57
+ "tsconfig-paths": "3.8.0",
58
+ "tslint": "5.16.0",
59
+ "typescript": "^5.9.3"
60
+ },
61
+ "jest": {
62
+ "moduleFileExtensions": [
63
+ "js",
64
+ "json",
65
+ "ts"
66
+ ],
67
+ "rootDir": "src",
68
+ "testRegex": ".spec.ts$",
69
+ "transform": {
70
+ "^.+\\.(t|j)s$": "ts-jest"
71
+ },
72
+ "coverageDirectory": "../coverage",
73
+ "testEnvironment": "node"
74
+ }
75
+ }