@stemy/backend 5.1.1 → 5.2.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/common-types.d.ts +21 -1
- package/esm2020/common-types.mjs +3 -1
- package/esm2020/public_api.mjs +10 -3
- package/esm2020/services/assets.mjs +19 -12
- package/esm2020/services/drivers/asset-grid.driver.mjs +25 -0
- package/esm2020/services/entities/asset.mjs +21 -8
- package/esm2020/services/entities/base-entity.mjs +6 -6
- package/esm2020/services/entities/lazy-asset.mjs +5 -6
- package/esm2020/services/mongo-connector.mjs +1 -7
- package/fesm2015/stemy-backend.mjs +71 -28
- package/fesm2015/stemy-backend.mjs.map +1 -1
- package/fesm2020/stemy-backend.mjs +71 -28
- package/fesm2020/stemy-backend.mjs.map +1 -1
- package/package.json +1 -1
- package/public_api.d.ts +1 -1
- package/services/assets.d.ts +4 -4
- package/services/drivers/asset-grid.driver.d.ts +11 -0
- package/services/entities/asset.d.ts +4 -4
- package/services/entities/base-entity.d.ts +2 -2
- package/services/mongo-connector.d.ts +1 -3
|
@@ -15,7 +15,7 @@ import { exec } from 'child_process';
|
|
|
15
15
|
import { createHash } from 'crypto';
|
|
16
16
|
import { Subscription, Observable, Subject, from, BehaviorSubject } from 'rxjs';
|
|
17
17
|
import { canReportError } from 'rxjs/internal/util/canReportError';
|
|
18
|
-
import { ObjectId
|
|
18
|
+
import { ObjectId } from 'mongodb';
|
|
19
19
|
import mongoose from 'mongoose';
|
|
20
20
|
import { Readable, PassThrough } from 'stream';
|
|
21
21
|
import fileType from 'file-type/core';
|
|
@@ -37,6 +37,7 @@ import * as Handlebars from 'handlebars';
|
|
|
37
37
|
import { CommandsAddon, AnsiCodes } from '@stemy/terminal-commands-addon';
|
|
38
38
|
import { compare } from 'bcrypt';
|
|
39
39
|
import moment from 'moment';
|
|
40
|
+
import { GridFSBucket } from 'mongodb/lib/gridfs';
|
|
40
41
|
import { getModelForClass } from '@typegoose/typegoose';
|
|
41
42
|
import { getValue as getValue$1, setValue } from 'mongoose/lib/utils';
|
|
42
43
|
|
|
@@ -53,6 +54,8 @@ const SOCKET_CONTROLLERS = Symbol.for("socket-controllers-token");
|
|
|
53
54
|
const PARAMETER = Symbol.for("parameter-token");
|
|
54
55
|
const DI_CONTAINER = Symbol.for("di-container-token");
|
|
55
56
|
const OPENAPI_VALIDATION = Symbol.for("openapi-validation-token");
|
|
57
|
+
const LOCAL_DIR = Symbol.for('asset-local-dir');
|
|
58
|
+
const ASSET_DRIVER = Symbol.for('assets-driver');
|
|
56
59
|
class Parameter {
|
|
57
60
|
constructor(name, defaultValue, resolver = null) {
|
|
58
61
|
this.name = name;
|
|
@@ -931,14 +934,10 @@ let MongoConnector = class MongoConnector {
|
|
|
931
934
|
get database() {
|
|
932
935
|
return this.db;
|
|
933
936
|
}
|
|
934
|
-
get bucket() {
|
|
935
|
-
return this.fsBucket;
|
|
936
|
-
}
|
|
937
937
|
constructor(configuration) {
|
|
938
938
|
this.configuration = configuration;
|
|
939
939
|
this.conn = null;
|
|
940
940
|
this.db = null;
|
|
941
|
-
this.fsBucket = null;
|
|
942
941
|
}
|
|
943
942
|
async connect() {
|
|
944
943
|
if (this.db)
|
|
@@ -949,7 +948,6 @@ let MongoConnector = class MongoConnector {
|
|
|
949
948
|
pass: this.configuration.resolve("mongoPassword")
|
|
950
949
|
})).connection;
|
|
951
950
|
this.db = this.conn.db;
|
|
952
|
-
this.fsBucket = new GridFSBucket(this.db, { bucketName: "assets" });
|
|
953
951
|
}
|
|
954
952
|
};
|
|
955
953
|
MongoConnector = __decorate([
|
|
@@ -959,18 +957,18 @@ MongoConnector = __decorate([
|
|
|
959
957
|
|
|
960
958
|
class BaseEntity {
|
|
961
959
|
get id() {
|
|
962
|
-
return this.
|
|
960
|
+
return this.oid.toHexString();
|
|
963
961
|
}
|
|
964
|
-
constructor(
|
|
965
|
-
this.
|
|
962
|
+
constructor(oid, data, collection) {
|
|
963
|
+
this.oid = oid;
|
|
966
964
|
this.data = data;
|
|
967
965
|
this.collection = collection;
|
|
968
966
|
}
|
|
969
967
|
save() {
|
|
970
|
-
return this.collection.updateOne({ _id: this.
|
|
968
|
+
return this.collection.updateOne({ _id: this.oid }, { $set: this.toJSON() }, { upsert: true });
|
|
971
969
|
}
|
|
972
970
|
async load() {
|
|
973
|
-
const res = await this.collection.findOne({ _id: this.
|
|
971
|
+
const res = await this.collection.findOne({ _id: this.oid });
|
|
974
972
|
this.deleted = !res;
|
|
975
973
|
this.data = res || {};
|
|
976
974
|
return this;
|
|
@@ -996,18 +994,31 @@ class Asset extends BaseEntity {
|
|
|
996
994
|
return this.data.metadata;
|
|
997
995
|
}
|
|
998
996
|
get stream() {
|
|
999
|
-
return this.
|
|
997
|
+
return this.driver.openDownloadStream(this.oid);
|
|
1000
998
|
}
|
|
1001
|
-
constructor(id, data, collection,
|
|
999
|
+
constructor(id, data, collection, driver) {
|
|
1002
1000
|
super(id, data, collection);
|
|
1003
|
-
this.
|
|
1001
|
+
this.driver = driver;
|
|
1004
1002
|
}
|
|
1005
1003
|
async unlink() {
|
|
1006
|
-
|
|
1004
|
+
try {
|
|
1005
|
+
await this.driver.delete(this.oid);
|
|
1006
|
+
await this.collection.deleteOne({ _id: this.oid });
|
|
1007
|
+
}
|
|
1008
|
+
catch (error) {
|
|
1009
|
+
let err = error;
|
|
1010
|
+
if (error) {
|
|
1011
|
+
err = error.message || error || "";
|
|
1012
|
+
if (!isString(err) || !err.startsWith("FileNotFound")) {
|
|
1013
|
+
throw err;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
return this.id;
|
|
1007
1018
|
}
|
|
1008
1019
|
async setMeta(metadata) {
|
|
1009
1020
|
metadata = Object.assign(this.metadata, metadata || {});
|
|
1010
|
-
await this.collection.updateOne({ _id: this.
|
|
1021
|
+
await this.collection.updateOne({ _id: this.oid }, { $set: { metadata } });
|
|
1011
1022
|
}
|
|
1012
1023
|
getBuffer() {
|
|
1013
1024
|
return streamToBuffer(this.stream);
|
|
@@ -1019,7 +1030,7 @@ class Asset extends BaseEntity {
|
|
|
1019
1030
|
: metadata.downloadCount + 1;
|
|
1020
1031
|
metadata.firstDownload = metadata.firstDownload || new Date();
|
|
1021
1032
|
metadata.lastDownload = new Date();
|
|
1022
|
-
await this.collection.updateOne({ _id: this.
|
|
1033
|
+
await this.collection.updateOne({ _id: this.oid }, { $set: { metadata } });
|
|
1023
1034
|
return this.stream;
|
|
1024
1035
|
}
|
|
1025
1036
|
async getImage(params = null) {
|
|
@@ -1077,11 +1088,11 @@ class TempAsset {
|
|
|
1077
1088
|
}
|
|
1078
1089
|
|
|
1079
1090
|
let Assets = class Assets {
|
|
1080
|
-
constructor(connector, assetProcessor) {
|
|
1091
|
+
constructor(connector, assetProcessor, driver) {
|
|
1081
1092
|
this.connector = connector;
|
|
1082
1093
|
this.assetProcessor = assetProcessor;
|
|
1083
|
-
this.
|
|
1084
|
-
this.collection = connector.database?.collection(
|
|
1094
|
+
this.driver = driver;
|
|
1095
|
+
this.collection = connector.database?.collection(driver.metaCollection);
|
|
1085
1096
|
}
|
|
1086
1097
|
async write(stream, contentType = null, metadata = null) {
|
|
1087
1098
|
const uploadStream = copyStream(stream);
|
|
@@ -1150,7 +1161,7 @@ let Assets = class Assets {
|
|
|
1150
1161
|
}
|
|
1151
1162
|
async find(where) {
|
|
1152
1163
|
const data = await this.collection.findOne(where);
|
|
1153
|
-
return !data ? null : new Asset(data._id, data, this.collection, this.
|
|
1164
|
+
return !data ? null : new Asset(data._id, data, this.collection, this.driver);
|
|
1154
1165
|
}
|
|
1155
1166
|
async findMany(where) {
|
|
1156
1167
|
const cursor = this.collection.find(where);
|
|
@@ -1159,7 +1170,7 @@ let Assets = class Assets {
|
|
|
1159
1170
|
for (let item of items) {
|
|
1160
1171
|
if (!item)
|
|
1161
1172
|
continue;
|
|
1162
|
-
result.push(new Asset(item._id, item, this.collection, this.
|
|
1173
|
+
result.push(new Asset(item._id, item, this.collection, this.driver));
|
|
1163
1174
|
}
|
|
1164
1175
|
return result;
|
|
1165
1176
|
}
|
|
@@ -1183,7 +1194,11 @@ let Assets = class Assets {
|
|
|
1183
1194
|
metadata.filename = metadata.filename || new ObjectId$1().toHexString();
|
|
1184
1195
|
metadata.extension = (fileType.ext || "").trim();
|
|
1185
1196
|
return new Promise(((resolve, reject) => {
|
|
1186
|
-
const uploaderStream = this.
|
|
1197
|
+
const uploaderStream = this.driver.openUploadStream(metadata.filename, {
|
|
1198
|
+
chunkSizeBytes: 1048576,
|
|
1199
|
+
metadata,
|
|
1200
|
+
contentType: fileType.mime
|
|
1201
|
+
});
|
|
1187
1202
|
stream.pipe(uploaderStream)
|
|
1188
1203
|
.on("error", error => {
|
|
1189
1204
|
reject(error.message || error);
|
|
@@ -1193,7 +1208,7 @@ let Assets = class Assets {
|
|
|
1193
1208
|
filename: metadata.filename,
|
|
1194
1209
|
contentType,
|
|
1195
1210
|
metadata
|
|
1196
|
-
}, this.collection, this.
|
|
1211
|
+
}, this.collection, this.driver);
|
|
1197
1212
|
asset.save().then(() => {
|
|
1198
1213
|
resolve(asset);
|
|
1199
1214
|
}, error => {
|
|
@@ -1206,7 +1221,9 @@ let Assets = class Assets {
|
|
|
1206
1221
|
Assets = __decorate([
|
|
1207
1222
|
injectable(),
|
|
1208
1223
|
scoped(Lifecycle.ContainerScoped),
|
|
1209
|
-
|
|
1224
|
+
__param(2, inject(ASSET_DRIVER)),
|
|
1225
|
+
__metadata("design:paramtypes", [MongoConnector,
|
|
1226
|
+
AssetProcessor, Object])
|
|
1210
1227
|
], Assets);
|
|
1211
1228
|
|
|
1212
1229
|
class LazyAsset extends BaseEntity {
|
|
@@ -1240,9 +1257,9 @@ class LazyAsset extends BaseEntity {
|
|
|
1240
1257
|
async unlink() {
|
|
1241
1258
|
await this.load();
|
|
1242
1259
|
if (!this.progressId) {
|
|
1243
|
-
await this.collection.deleteOne({ _id: this.
|
|
1260
|
+
await this.collection.deleteOne({ _id: this.oid });
|
|
1244
1261
|
}
|
|
1245
|
-
return
|
|
1262
|
+
return this.assets.unlink(this.assetId);
|
|
1246
1263
|
}
|
|
1247
1264
|
startWorking() {
|
|
1248
1265
|
this.load().then(() => {
|
|
@@ -1285,7 +1302,7 @@ class LazyAsset extends BaseEntity {
|
|
|
1285
1302
|
this.data.progressId = (await this.progresses.create()).id;
|
|
1286
1303
|
this.data.assetId = null;
|
|
1287
1304
|
await this.save();
|
|
1288
|
-
await
|
|
1305
|
+
await this.assets.unlink(oldAsset);
|
|
1289
1306
|
const jobParams = JSON.parse(await gunzipPromised(this.data.jobParams));
|
|
1290
1307
|
await this.progresses.jobMan.enqueueWithName(this.data.jobName, { ...jobParams, lazyId: this.id, fromLoad });
|
|
1291
1308
|
}
|
|
@@ -3843,6 +3860,26 @@ const fixtures = [
|
|
|
3843
3860
|
TtlFixture,
|
|
3844
3861
|
];
|
|
3845
3862
|
|
|
3863
|
+
let AssetGridDriver = class AssetGridDriver {
|
|
3864
|
+
constructor(connector) {
|
|
3865
|
+
this.bucket = new GridFSBucket(connector.database, { bucketName: 'assets' });
|
|
3866
|
+
this.metaCollection = "assets.files";
|
|
3867
|
+
}
|
|
3868
|
+
openUploadStream(filename, opts) {
|
|
3869
|
+
return this.bucket.openUploadStream(filename, opts);
|
|
3870
|
+
}
|
|
3871
|
+
openDownloadStream(id) {
|
|
3872
|
+
return this.bucket.openDownloadStream(id);
|
|
3873
|
+
}
|
|
3874
|
+
delete(id) {
|
|
3875
|
+
return this.bucket.delete(id);
|
|
3876
|
+
}
|
|
3877
|
+
};
|
|
3878
|
+
AssetGridDriver = __decorate([
|
|
3879
|
+
injectable(),
|
|
3880
|
+
__metadata("design:paramtypes", [MongoConnector])
|
|
3881
|
+
], AssetGridDriver);
|
|
3882
|
+
|
|
3846
3883
|
class BaseDoc {
|
|
3847
3884
|
/**
|
|
3848
3885
|
* Casts this to DocumentType<this> to allow using document methods in get/set-s
|
|
@@ -4373,6 +4410,12 @@ async function setupBackend(config, providers, parent) {
|
|
|
4373
4410
|
diContainer.register(OPENAPI_VALIDATION, {
|
|
4374
4411
|
useValue: config.customValidation || (() => null)
|
|
4375
4412
|
});
|
|
4413
|
+
diContainer.register(LOCAL_DIR, {
|
|
4414
|
+
useValue: config.assetLocalDir || "assets_files"
|
|
4415
|
+
});
|
|
4416
|
+
diContainer.register(ASSET_DRIVER, {
|
|
4417
|
+
useClass: config.assetDriver || AssetGridDriver
|
|
4418
|
+
});
|
|
4376
4419
|
diContainers.appContainer = diContainers.appContainer || diContainer;
|
|
4377
4420
|
// Authentication
|
|
4378
4421
|
restOptions.authorizationChecker = async (action, roles) => {
|