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.
- package/dist/manifest/src/app.module.js +2 -1
- package/dist/manifest/src/config/database.js +6 -1
- package/dist/manifest/src/config/storage.js +13 -0
- package/dist/manifest/src/handler/handler.service.js +4 -1
- package/dist/manifest/src/seed/services/seeder.service.js +8 -8
- package/dist/manifest/src/storage/services/storage.service.js +57 -12
- package/dist/manifest/src/upload/controllers/upload.controller.js +4 -4
- package/package.json +2 -1
|
@@ -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'
|
|
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
|
|
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
|
|
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
|
-
|
|
66
|
-
|
|
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
|
-
|
|
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
|
-
.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
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",
|
|
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",
|
|
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.
|
|
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",
|