@stemy/backend 5.1.0 → 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.
Files changed (32) hide show
  1. package/common-types.d.ts +37 -17
  2. package/esm2020/common-types.mjs +3 -1
  3. package/esm2020/public_api.mjs +10 -3
  4. package/esm2020/rest-middlewares/error-handler.middleware.mjs +4 -4
  5. package/esm2020/services/assets.mjs +19 -12
  6. package/esm2020/services/backend-provider.mjs +5 -5
  7. package/esm2020/services/drivers/asset-grid.driver.mjs +25 -0
  8. package/esm2020/services/entities/asset.mjs +23 -10
  9. package/esm2020/services/entities/base-entity.mjs +8 -8
  10. package/esm2020/services/entities/lazy-asset.mjs +11 -12
  11. package/esm2020/services/entities/progress.mjs +17 -17
  12. package/esm2020/services/entities/temp-asset.mjs +4 -4
  13. package/esm2020/services/mail-sender.mjs +4 -4
  14. package/esm2020/services/mongo-connector.mjs +5 -11
  15. package/esm2020/services/open-api.mjs +6 -6
  16. package/esm2020/utilities/base-doc.mjs +1 -1
  17. package/esm2020/utilities/di-container.mjs +7 -7
  18. package/esm2020/utilities/lazy-asset-generator.mjs +6 -6
  19. package/esm2020/utilities/tree.mjs +4 -4
  20. package/fesm2015/stemy-backend.mjs +134 -91
  21. package/fesm2015/stemy-backend.mjs.map +1 -1
  22. package/fesm2020/stemy-backend.mjs +133 -90
  23. package/fesm2020/stemy-backend.mjs.map +1 -1
  24. package/package.json +1 -1
  25. package/public_api.d.ts +1 -1
  26. package/services/assets.d.ts +4 -4
  27. package/services/drivers/asset-grid.driver.d.ts +11 -0
  28. package/services/entities/asset.d.ts +4 -4
  29. package/services/entities/base-entity.d.ts +2 -2
  30. package/services/mongo-connector.d.ts +1 -3
  31. package/utilities/base-doc.d.ts +3 -3
  32. package/utils.d.ts +1 -1
@@ -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, GridFSBucket } from 'mongodb';
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;
@@ -925,20 +928,16 @@ Configuration = __decorate([
925
928
  ], Configuration);
926
929
 
927
930
  let MongoConnector = class MongoConnector {
928
- constructor(configuration) {
929
- this.configuration = configuration;
930
- this.conn = null;
931
- this.db = null;
932
- this.fsBucket = null;
933
- }
934
931
  get connection() {
935
932
  return this.conn;
936
933
  }
937
934
  get database() {
938
935
  return this.db;
939
936
  }
940
- get bucket() {
941
- return this.fsBucket;
937
+ constructor(configuration) {
938
+ this.configuration = configuration;
939
+ this.conn = null;
940
+ this.db = 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([
@@ -958,19 +956,19 @@ MongoConnector = __decorate([
958
956
  ], MongoConnector);
959
957
 
960
958
  class BaseEntity {
961
- constructor(mId, data, collection) {
962
- this.mId = mId;
959
+ get id() {
960
+ return this.oid.toHexString();
961
+ }
962
+ constructor(oid, data, collection) {
963
+ this.oid = oid;
963
964
  this.data = data;
964
965
  this.collection = collection;
965
966
  }
966
- get id() {
967
- return this.mId.toHexString();
968
- }
969
967
  save() {
970
- return this.collection.updateOne({ _id: this.mId }, { $set: this.toJSON() });
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.mId });
971
+ const res = await this.collection.findOne({ _id: this.oid });
974
972
  this.deleted = !res;
975
973
  this.data = res || {};
976
974
  return this;
@@ -986,10 +984,6 @@ class BaseEntity {
986
984
  }
987
985
 
988
986
  class Asset extends BaseEntity {
989
- constructor(id, data, collection, bucket) {
990
- super(id, data, collection);
991
- this.bucket = bucket;
992
- }
993
987
  get filename() {
994
988
  return this.data.filename;
995
989
  }
@@ -1000,14 +994,31 @@ class Asset extends BaseEntity {
1000
994
  return this.data.metadata;
1001
995
  }
1002
996
  get stream() {
1003
- return this.bucket.openDownloadStream(this.mId);
997
+ return this.driver.openDownloadStream(this.oid);
998
+ }
999
+ constructor(id, data, collection, driver) {
1000
+ super(id, data, collection);
1001
+ this.driver = driver;
1004
1002
  }
1005
1003
  async unlink() {
1006
- return deleteFromBucket(this.bucket, this.mId);
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.mId }, { $set: { metadata } });
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.mId }, { $set: { metadata } });
1033
+ await this.collection.updateOne({ _id: this.oid }, { $set: { metadata } });
1023
1034
  return this.stream;
1024
1035
  }
1025
1036
  async getImage(params = null) {
@@ -1031,6 +1042,9 @@ class Asset extends BaseEntity {
1031
1042
  }
1032
1043
 
1033
1044
  class TempAsset {
1045
+ get stream() {
1046
+ return bufferToStream(this.buffer);
1047
+ }
1034
1048
  constructor(buffer, filename, contentType, metadata) {
1035
1049
  this.buffer = buffer;
1036
1050
  this.filename = filename;
@@ -1038,9 +1052,6 @@ class TempAsset {
1038
1052
  this.metadata = metadata;
1039
1053
  this.id = new ObjectId$1().toHexString();
1040
1054
  }
1041
- get stream() {
1042
- return bufferToStream(this.buffer);
1043
- }
1044
1055
  async unlink() {
1045
1056
  throw new Error(`Temp asset '${this.id}' can not be removed!`);
1046
1057
  }
@@ -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.bucket = connector.bucket;
1084
- this.collection = connector.database?.collection("assets.files");
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.bucket);
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.bucket));
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.bucket.openUploadStream(metadata.filename);
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.bucket);
1211
+ }, this.collection, this.driver);
1197
1212
  asset.save().then(() => {
1198
1213
  resolve(asset);
1199
1214
  }, error => {
@@ -1206,16 +1221,12 @@ let Assets = class Assets {
1206
1221
  Assets = __decorate([
1207
1222
  injectable(),
1208
1223
  scoped(Lifecycle.ContainerScoped),
1209
- __metadata("design:paramtypes", [MongoConnector, AssetProcessor])
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 {
1213
- constructor(id, data, collection, logger, assets, progresses) {
1214
- super(id, data, collection);
1215
- this.logger = logger;
1216
- this.assets = assets;
1217
- this.progresses = progresses;
1218
- }
1219
1230
  get jobName() {
1220
1231
  return this.data.jobName;
1221
1232
  }
@@ -1237,12 +1248,18 @@ class LazyAsset extends BaseEntity {
1237
1248
  get assetId() {
1238
1249
  return this.data.assetId;
1239
1250
  }
1251
+ constructor(id, data, collection, logger, assets, progresses) {
1252
+ super(id, data, collection);
1253
+ this.logger = logger;
1254
+ this.assets = assets;
1255
+ this.progresses = progresses;
1256
+ }
1240
1257
  async unlink() {
1241
1258
  await this.load();
1242
1259
  if (!this.progressId) {
1243
- await this.collection.deleteOne({ _id: this.mId });
1260
+ await this.collection.deleteOne({ _id: this.oid });
1244
1261
  }
1245
- return deleteFromBucket(this.assets.bucket, new ObjectId$1(this.assetId));
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 deleteFromBucket(this.assets.bucket, oldAsset);
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
  }
@@ -1485,9 +1502,6 @@ JobManager = __decorate([
1485
1502
  ], JobManager);
1486
1503
 
1487
1504
  class Progress extends BaseEntity {
1488
- constructor(id, data, collection) {
1489
- super(id, data, collection);
1490
- }
1491
1505
  get current() {
1492
1506
  return this.data.current;
1493
1507
  }
@@ -1509,6 +1523,9 @@ class Progress extends BaseEntity {
1509
1523
  get remaining() {
1510
1524
  return this.max > 0 ? this.max - this.current : 0;
1511
1525
  }
1526
+ constructor(id, data, collection) {
1527
+ super(id, data, collection);
1528
+ }
1512
1529
  setMessageBridge(messageBridge) {
1513
1530
  this.messageBridge = messageBridge || this.messageBridge;
1514
1531
  return this;
@@ -1562,19 +1579,6 @@ class Progress extends BaseEntity {
1562
1579
  }
1563
1580
  }
1564
1581
  class SubProgress {
1565
- constructor(parent, progressFrom, progressValue, mMax = 100) {
1566
- this.parent = parent;
1567
- this.progressFrom = progressFrom;
1568
- this.progressValue = progressValue;
1569
- this.mMax = mMax;
1570
- if (progressFrom < 0) {
1571
- throw "Progress from must be bigger than or zero";
1572
- }
1573
- if (progressValue <= 0) {
1574
- throw "Progress value must be bigger than zero";
1575
- }
1576
- this.mCurrent = 0;
1577
- }
1578
1582
  get id() {
1579
1583
  return this.parent.id;
1580
1584
  }
@@ -1599,6 +1603,19 @@ class SubProgress {
1599
1603
  get canceled() {
1600
1604
  return !this.parent || this.parent.canceled;
1601
1605
  }
1606
+ constructor(parent, progressFrom, progressValue, mMax = 100) {
1607
+ this.parent = parent;
1608
+ this.progressFrom = progressFrom;
1609
+ this.progressValue = progressValue;
1610
+ this.mMax = mMax;
1611
+ if (progressFrom < 0) {
1612
+ throw "Progress from must be bigger than or zero";
1613
+ }
1614
+ if (progressValue <= 0) {
1615
+ throw "Progress value must be bigger than zero";
1616
+ }
1617
+ this.mCurrent = 0;
1618
+ }
1602
1619
  setMessageBridge(messageBridge) {
1603
1620
  if (!this.parent)
1604
1621
  return this;
@@ -1862,11 +1879,6 @@ IsObjectId = __decorate([
1862
1879
  ], IsObjectId);
1863
1880
 
1864
1881
  let OpenApi = class OpenApi {
1865
- constructor(container, customValidation) {
1866
- this.container = container;
1867
- this.customValidation = customValidation;
1868
- this.docs = null;
1869
- }
1870
1882
  get apiDocs() {
1871
1883
  if (!this.docs)
1872
1884
  this.docs = this.createApiDocs();
@@ -1877,6 +1889,11 @@ let OpenApi = class OpenApi {
1877
1889
  this.docsStr = JSON.stringify(this.apiDocs);
1878
1890
  return this.docsStr;
1879
1891
  }
1892
+ constructor(container, customValidation) {
1893
+ this.container = container;
1894
+ this.customValidation = customValidation;
1895
+ this.docs = null;
1896
+ }
1880
1897
  async schemaToExample(src, req) {
1881
1898
  const maybeRef = src;
1882
1899
  if (maybeRef.$ref) {
@@ -2002,10 +2019,6 @@ Fixtures = __decorate([
2002
2019
 
2003
2020
  const express = express_;
2004
2021
  let BackendProvider = class BackendProvider {
2005
- constructor(config, container) {
2006
- this.config = config;
2007
- this.container = container;
2008
- }
2009
2022
  get io() {
2010
2023
  this.ioServer = this.ioServer || new Server(this.server, {
2011
2024
  path: "/socket",
@@ -2039,6 +2052,10 @@ let BackendProvider = class BackendProvider {
2039
2052
  this.httpServer = this.httpServer || createServer(this.express);
2040
2053
  return this.httpServer;
2041
2054
  }
2055
+ constructor(config, container) {
2056
+ this.config = config;
2057
+ this.container = container;
2058
+ }
2042
2059
  async quickStart() {
2043
2060
  const port = this.config.resolve("appPort");
2044
2061
  const isWorker = this.config.resolve("isWorker");
@@ -2504,6 +2521,9 @@ TemplateRenderer = __decorate([
2504
2521
  ], TemplateRenderer);
2505
2522
 
2506
2523
  let MailSender = class MailSender {
2524
+ get translator() {
2525
+ return this.renderer.translator;
2526
+ }
2507
2527
  constructor(config, renderer) {
2508
2528
  this.config = config;
2509
2529
  this.renderer = renderer;
@@ -2516,9 +2536,6 @@ let MailSender = class MailSender {
2516
2536
  }
2517
2537
  });
2518
2538
  }
2519
- get translator() {
2520
- return this.renderer.translator;
2521
- }
2522
2539
  async sendMail(language, options) {
2523
2540
  const subject = await this.translator.getTranslation(language, options.subject || "-");
2524
2541
  const html = await this.renderer.render(options.template, language, options.context);
@@ -3228,13 +3245,13 @@ TerminalController$1 = __decorate([
3228
3245
  ], TerminalController$1);
3229
3246
 
3230
3247
  let ErrorHandlerMiddleware = class ErrorHandlerMiddleware {
3248
+ get isDev() {
3249
+ return this.configuration.resolve("nodeEnv") === "development";
3250
+ }
3231
3251
  constructor(configuration, translator) {
3232
3252
  this.configuration = configuration;
3233
3253
  this.translator = translator;
3234
3254
  }
3235
- get isDev() {
3236
- return this.configuration.resolve("nodeEnv") === "development";
3237
- }
3238
3255
  async error(error, req, res, next) {
3239
3256
  const result = await this.getResult(error, req, res);
3240
3257
  if (this.isDev) {
@@ -3563,15 +3580,15 @@ CompressionMiddleware = __decorate([
3563
3580
  ], CompressionMiddleware);
3564
3581
 
3565
3582
  class Tree {
3583
+ get parentTree() {
3584
+ return this.container.parent.tree;
3585
+ }
3566
3586
  constructor(container, exists, path) {
3567
3587
  this.container = container;
3568
3588
  this.exists = exists;
3569
3589
  this.path = path;
3570
3590
  this.map = new Map();
3571
3591
  }
3572
- get parentTree() {
3573
- return this.container.parent.tree;
3574
- }
3575
3592
  resolveService() {
3576
3593
  return !this.exists ? null : this.container.resolve(this.path);
3577
3594
  }
@@ -3677,6 +3694,12 @@ class Tree {
3677
3694
  }
3678
3695
 
3679
3696
  class DiContainer {
3697
+ get registeredTokens() {
3698
+ return (this.parent?.registeredTokens || []).concat(this.tokens);
3699
+ }
3700
+ get tree() {
3701
+ return this.root;
3702
+ }
3680
3703
  constructor(container, parent = null) {
3681
3704
  this.container = container;
3682
3705
  this.parent = parent;
@@ -3685,12 +3708,6 @@ class DiContainer {
3685
3708
  this.tokenSet = new Set();
3686
3709
  this.root = new Tree(this, false, "");
3687
3710
  }
3688
- get registeredTokens() {
3689
- return (this.parent?.registeredTokens || []).concat(this.tokens);
3690
- }
3691
- get tree() {
3692
- return this.root;
3693
- }
3694
3711
  beforeResolution(token, callback, options) {
3695
3712
  this.container.beforeResolution(token, callback, options);
3696
3713
  }
@@ -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
@@ -3912,17 +3949,17 @@ function ResponseType(type, options = {}) {
3912
3949
  }
3913
3950
 
3914
3951
  class LazyAssetGenerator {
3915
- constructor(assetResolver, progresses, lazyId) {
3916
- this.assetResolver = assetResolver;
3917
- this.progresses = progresses;
3918
- this.lazyId = lazyId;
3919
- }
3920
3952
  get assets() {
3921
3953
  return this.assetResolver.assets;
3922
3954
  }
3923
3955
  get lazyAssets() {
3924
3956
  return this.assetResolver.lazyAssets;
3925
3957
  }
3958
+ constructor(assetResolver, progresses, lazyId) {
3959
+ this.assetResolver = assetResolver;
3960
+ this.progresses = progresses;
3961
+ this.lazyId = lazyId;
3962
+ }
3926
3963
  async process(messaging) {
3927
3964
  const lazyAsset = await this.lazyAssets.read(this.lazyId);
3928
3965
  let progress = await this.progresses.get(lazyAsset.progressId);
@@ -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) => {