manifest 4.7.1 → 4.8.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.
@@ -19,6 +19,7 @@ const typeorm_1 = require("@nestjs/typeorm");
19
19
  const auth_module_1 = require("./auth/auth.module");
20
20
  const database_1 = __importDefault(require("./config/database"));
21
21
  const general_1 = __importDefault(require("./config/general"));
22
+ const storage_1 = __importDefault(require("./config/storage"));
22
23
  const paths_1 = __importDefault(require("./config/paths"));
23
24
  const crud_module_1 = require("./crud/crud.module");
24
25
  const entity_module_1 = require("./entity/entity.module");
@@ -60,7 +61,7 @@ exports.AppModule = AppModule = __decorate([
60
61
  config_1.ConfigModule.forRoot({
61
62
  isGlobal: true,
62
63
  envFilePath: ['.env', '.env.contribution'],
63
- load: [general_1.default, database_1.default, paths_1.default]
64
+ load: [general_1.default, database_1.default, paths_1.default, storage_1.default]
64
65
  }),
65
66
  typeorm_1.TypeOrmModule.forRootAsync({
66
67
  imports: [config_1.ConfigModule, entity_module_1.EntityModule, manifest_module_1.ManifestModule],
@@ -17,7 +17,12 @@ exports.default = () => {
17
17
  password: process.env.DB_PASSWORD || 'postgres',
18
18
  database: process.env.DB_DATABASE || 'manifest',
19
19
  dropSchema: process.env.DB_DROP_SCHEMA === 'true' || false,
20
- ssl: process.env.DB_SSL === 'true' || false,
20
+ ssl: process.env.DB_SSL === 'true'
21
+ ? {
22
+ rejectUnauthorized: false,
23
+ requestCert: true
24
+ }
25
+ : false,
21
26
  synchronize: true
22
27
  }
23
28
  }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = () => {
4
+ return {
5
+ storage: {
6
+ s3Bucket: process.env.S3_BUCKET,
7
+ s3Endpoint: process.env.S3_ENDPOINT,
8
+ s3Region: process.env.S3_REGION,
9
+ s3AccessKeyId: process.env.S3_ACCESS_KEY_ID,
10
+ s3SecretAccessKey: process.env.S3_SECRET_ACCESS_KEY
11
+ }
12
+ };
13
+ };
@@ -65,12 +65,15 @@ let HandlerService = class HandlerService {
65
65
  if (!fs_1.default.existsSync(handlerPath)) {
66
66
  throw new common_1.HttpException('Handler not found', 404);
67
67
  }
68
- const module = await Promise.resolve(`${handlerPath}`).then(s => __importStar(require(s)));
68
+ const module = await this.dynamicImport(handlerPath);
69
69
  if (typeof module.default !== 'function') {
70
70
  throw new common_1.HttpException('Handler is invalid', 404);
71
71
  }
72
72
  return module.default;
73
73
  }
74
+ async dynamicImport(path) {
75
+ return Promise.resolve(`${path}`).then(s => __importStar(require(s)));
76
+ }
74
77
  };
75
78
  exports.HandlerService = HandlerService;
76
79
  exports.HandlerService = HandlerService = __decorate([
@@ -105,9 +105,9 @@ let SeederService = class SeederService {
105
105
  if (entityManifest.authenticable) {
106
106
  entityManifest.properties.push(...constants_1.AUTHENTICABLE_PROPS);
107
107
  }
108
- entityManifest.properties.forEach((propertyManifest) => {
109
- newRecord[propertyManifest.name] = this.seedProperty(propertyManifest, entityManifest);
110
- });
108
+ for (const propertyManifest of entityManifest.properties) {
109
+ newRecord[propertyManifest.name] = await this.seedProperty(propertyManifest, entityManifest);
110
+ }
111
111
  entityManifest.relationships
112
112
  .filter((relationship) => relationship.type === 'many-to-one')
113
113
  .forEach((relationManifest) => {
@@ -140,7 +140,7 @@ let SeederService = class SeederService {
140
140
  await Promise.all(manyToManyPromises);
141
141
  return;
142
142
  }
143
- seedProperty(propertyManifest, entityManifest) {
143
+ async seedProperty(propertyManifest, entityManifest) {
144
144
  switch (propertyManifest.type) {
145
145
  case types_1.PropType.String:
146
146
  return faker_1.faker.commerce.product();
@@ -189,7 +189,7 @@ let SeederService = class SeederService {
189
189
  if (this.seededFiles[`${entityManifest.slug}.${propertyManifest.name}`]) {
190
190
  return this.seededFiles[`${entityManifest.slug}.${propertyManifest.name}`];
191
191
  }
192
- const filePath = this.seedFile(entityManifest.slug, propertyManifest.name);
192
+ const filePath = await this.seedFile(entityManifest.slug, propertyManifest.name);
193
193
  this.seededFiles[`${entityManifest.slug}.${propertyManifest.name}`] =
194
194
  filePath;
195
195
  return filePath;
@@ -197,7 +197,7 @@ let SeederService = class SeederService {
197
197
  if (this.seededFiles[`${entityManifest.slug}.${propertyManifest.name}`]) {
198
198
  return this.seededFiles[`${entityManifest.slug}.${propertyManifest.name}`];
199
199
  }
200
- const images = this.seedImage(entityManifest.slug, propertyManifest.name, propertyManifest.options?.['sizes']);
200
+ const images = await this.seedImage(entityManifest.slug, propertyManifest.name, propertyManifest.options?.['sizes']);
201
201
  this.seededFiles[`${entityManifest.slug}.${propertyManifest.name}`] =
202
202
  images;
203
203
  return images;
@@ -209,9 +209,9 @@ let SeederService = class SeederService {
209
209
  admin.password = (0, crypto_js_1.SHA3)(constants_1.DEFAULT_ADMIN_CREDENTIALS.password).toString();
210
210
  await repository.save(admin);
211
211
  }
212
- seedFile(entity, property) {
212
+ async seedFile(entity, property) {
213
213
  const dummyFileContent = fs.readFileSync(path.join(__dirname, '..', '..', '..', '..', 'assets', constants_1.DUMMY_FILE_NAME));
214
- const filePath = this.storageService.store(entity, property, {
214
+ const filePath = await this.storageService.store(entity, property, {
215
215
  originalname: constants_1.DUMMY_FILE_NAME,
216
216
  buffer: dummyFileContent
217
217
  });
@@ -50,49 +50,94 @@ const common_1 = require("@nestjs/common");
50
50
  const common_2 = require("../../../../common/src");
51
51
  const constants_1 = require("../../constants");
52
52
  const fs = __importStar(require("fs"));
53
- const mkdirp = __importStar(require("mkdirp"));
54
53
  const sharp_1 = __importDefault(require("sharp"));
54
+ const mkdirp = __importStar(require("mkdirp"));
55
55
  const uniqid_1 = __importDefault(require("uniqid"));
56
56
  const slugify_1 = __importDefault(require("slugify"));
57
57
  const config_1 = require("@nestjs/config");
58
+ const client_s3_1 = require("@aws-sdk/client-s3");
58
59
  let StorageService = class StorageService {
59
60
  constructor(configService) {
60
61
  this.configService = configService;
62
+ this.isS3Enabled = false;
63
+ this.isS3Enabled = !!this.configService.get('storage.s3Bucket');
64
+ this.s3Endpoint = this.configService.get('storage.s3Endpoint');
65
+ this.s3Bucket = this.configService.get('storage.s3Bucket');
66
+ this.s3Region = this.configService.get('storage.s3Region');
67
+ this.s3AccessKeyId = this.configService.get('storage.s3AccessKeyId');
68
+ this.s3SecretAccessKey = this.configService.get('storage.s3SecretAccessKey');
69
+ this.s3provider = this.s3Endpoint?.includes('amazon')
70
+ ? 'aws'
71
+ : this.s3Endpoint?.includes('digitalocean')
72
+ ? 'digitalocean'
73
+ : 'other';
74
+ if (this.isS3Enabled) {
75
+ this.s3Client = new client_s3_1.S3Client({
76
+ region: this.s3Region,
77
+ endpoint: this.s3Endpoint,
78
+ credentials: {
79
+ accessKeyId: this.s3AccessKeyId,
80
+ secretAccessKey: this.s3SecretAccessKey
81
+ },
82
+ forcePathStyle: false
83
+ });
84
+ }
61
85
  }
62
86
  store(entity, property, file) {
63
87
  const folder = this.createUploadFolder(entity, property);
64
88
  const filePath = `${folder}/${(0, uniqid_1.default)()}-${(0, slugify_1.default)(file.originalname)}`;
65
- fs.writeFileSync(`${this.configService.get('paths').publicFolder}/${constants_1.STORAGE_PATH}/${filePath}`, file.buffer);
66
- return this.prependStorageUrl(filePath);
89
+ if (this.isS3Enabled) {
90
+ return this.uploadToS3(filePath, file.buffer);
91
+ }
92
+ else {
93
+ fs.writeFileSync(`${this.configService.get('paths.publicFolder')}/${constants_1.STORAGE_PATH}/${filePath}`, file.buffer);
94
+ return Promise.resolve(this.prependStorageUrl(filePath));
95
+ }
67
96
  }
68
- storeImage(entity, property, image, imageSizes) {
97
+ async storeImage(entity, property, image, imageSizes) {
69
98
  const folder = this.createUploadFolder(entity, property);
70
99
  const uniqueName = (0, uniqid_1.default)();
71
100
  const imagePaths = {};
72
- Object.keys(imageSizes || constants_1.DEFAULT_IMAGE_SIZES).forEach((sizeName) => {
101
+ for (const sizeName in imageSizes || constants_1.DEFAULT_IMAGE_SIZES) {
73
102
  const imagePath = `${folder}/${uniqueName}-${sizeName}.jpg`;
74
- (0, sharp_1.default)(image.buffer)
103
+ const resizedImage = await (0, sharp_1.default)(image.buffer)
75
104
  .jpeg({ quality: 80 })
76
105
  .resize(imageSizes[sizeName].width, imageSizes[sizeName].height, {
77
106
  fit: imageSizes[sizeName].fit
78
107
  })
79
- .toFile(`${this.configService.get('paths').publicFolder}/${constants_1.STORAGE_PATH}/${imagePath}`, () => {
80
- return imagePath;
81
- });
82
- imagePaths[sizeName] = this.prependStorageUrl(imagePath);
83
- });
108
+ .toBuffer();
109
+ if (this.isS3Enabled) {
110
+ imagePaths[sizeName] = await this.uploadToS3(imagePath, resizedImage);
111
+ }
112
+ else {
113
+ fs.writeFileSync(`${this.configService.get('paths.publicFolder')}/${constants_1.STORAGE_PATH}/${imagePath}`, resizedImage);
114
+ imagePaths[sizeName] = this.prependStorageUrl(imagePath);
115
+ }
116
+ }
84
117
  return imagePaths;
85
118
  }
86
119
  createUploadFolder(entity, property) {
87
120
  const dateString = new Date().toLocaleString('en-us', { month: 'short' }) +
88
121
  new Date().getFullYear();
89
122
  const folder = `${(0, common_2.kebabize)(entity)}/${(0, common_2.kebabize)(property)}/${dateString}`;
90
- mkdirp.sync(`${this.configService.get('paths').publicFolder}/${constants_1.STORAGE_PATH}/${folder}`);
123
+ if (!this.isS3Enabled) {
124
+ mkdirp.sync(`${this.configService.get('paths.publicFolder')}/${constants_1.STORAGE_PATH}/${folder}`);
125
+ }
91
126
  return folder;
92
127
  }
93
128
  prependStorageUrl(value) {
94
129
  return `${this.configService.get('baseUrl')}/${constants_1.STORAGE_PATH}/${value}`;
95
130
  }
131
+ async uploadToS3(key, buffer) {
132
+ await this.s3Client.send(new client_s3_1.PutObjectCommand({
133
+ Bucket: this.s3Bucket,
134
+ Key: `${constants_1.STORAGE_PATH}/${key}`,
135
+ Body: buffer,
136
+ ChecksumAlgorithm: undefined,
137
+ ACL: this.s3provider === 'digitalocean' ? 'public-read' : undefined
138
+ }));
139
+ return `${this.s3Endpoint}/${this.s3Bucket}/${constants_1.STORAGE_PATH}/${key}`;
140
+ }
96
141
  };
97
142
  exports.StorageService = StorageService;
98
143
  exports.StorageService = StorageService = __decorate([
@@ -20,9 +20,9 @@ let UploadController = class UploadController {
20
20
  constructor(uploadService) {
21
21
  this.uploadService = uploadService;
22
22
  }
23
- uploadFile(file, entity, property) {
23
+ async uploadFile(file, entity, property) {
24
24
  return {
25
- path: this.uploadService.storeFile({
25
+ path: await this.uploadService.storeFile({
26
26
  file,
27
27
  entity,
28
28
  property
@@ -46,7 +46,7 @@ __decorate([
46
46
  __param(2, (0, common_1.Body)('property')),
47
47
  __metadata("design:type", Function),
48
48
  __metadata("design:paramtypes", [Object, String, String]),
49
- __metadata("design:returntype", Object)
49
+ __metadata("design:returntype", Promise)
50
50
  ], UploadController.prototype, "uploadFile", null);
51
51
  __decorate([
52
52
  (0, common_1.Post)('/image'),
@@ -56,7 +56,7 @@ __decorate([
56
56
  __param(2, (0, common_1.Body)('property')),
57
57
  __metadata("design:type", Function),
58
58
  __metadata("design:paramtypes", [Object, String, String]),
59
- __metadata("design:returntype", Object)
59
+ __metadata("design:returntype", Promise)
60
60
  ], UploadController.prototype, "uploadImage", null);
61
61
  exports.UploadController = UploadController = __decorate([
62
62
  (0, common_1.Controller)('upload'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "manifest",
3
- "version": "4.7.1",
3
+ "version": "4.8.1",
4
4
  "description": "The 1-file micro-backend",
5
5
  "author": "Manifest",
6
6
  "license": "MIT",
@@ -59,6 +59,7 @@
59
59
  "README.md"
60
60
  ],
61
61
  "dependencies": {
62
+ "@aws-sdk/client-s3": "^3.744.0",
62
63
  "@faker-js/faker": "^8.4.1",
63
64
  "@nestjs/common": "^10.4.8",
64
65
  "@nestjs/config": "^3.3.0",