@stemy/backend 5.0.7 → 5.0.8

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.
@@ -1,5 +1,4 @@
1
1
  import { dirname, basename, join, resolve } from 'path';
2
- import bodyParser from 'body-parser';
3
2
  import webToken from 'jsonwebtoken';
4
3
  import { injectable, scoped, Lifecycle, singleton, injectAll, inject, isFactoryProvider, container } from 'tsyringe';
5
4
  import { HttpError, getMetadataArgsStorage, Authorized, Post, UploadedFile, Body, Get, Param, QueryParam, Res, QueryParams, Controller, UnauthorizedError, CurrentUser, Header, BadRequestError, Middleware, createParamDecorator, useContainer, useExpressServer } from 'routing-controllers';
@@ -25,15 +24,16 @@ import cron from 'node-cron';
25
24
  import { socket } from 'zeromq';
26
25
  import { filter as filter$1, map, first, timeout } from 'rxjs/operators';
27
26
  import { createServer } from 'http';
28
- import express_ from 'express';
29
27
  import { Server } from 'socket.io';
30
- import { v4 } from 'uuid';
31
- import { createTransport } from 'nodemailer';
32
- import * as Handlebars from 'handlebars';
28
+ import express_ from 'express';
29
+ import bodyParser from 'body-parser';
33
30
  import { routingControllersToSpec, OpenAPI, getStatusCode } from 'routing-controllers-openapi';
34
31
  import { defaultMetadataStorage } from 'class-transformer/cjs/storage';
35
32
  import { validationMetadatasToSchemas } from 'class-validator-jsonschema';
36
33
  import { ValidatorConstraint, ValidationTypes, Min, Max, IsOptional, IsBoolean } from 'class-validator';
34
+ import { v4 } from 'uuid';
35
+ import { createTransport } from 'nodemailer';
36
+ 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';
@@ -1237,13 +1237,6 @@ class LazyAsset extends BaseEntity {
1237
1237
  });
1238
1238
  });
1239
1239
  }
1240
- async load() {
1241
- await super.load();
1242
- if (this.deleted)
1243
- return this;
1244
- this.data.jobParams = JSON.parse(await gunzipPromised(this.data.jobParams));
1245
- return this;
1246
- }
1247
1240
  async loadAsset() {
1248
1241
  await this.load();
1249
1242
  if (this.deleted)
@@ -1267,7 +1260,8 @@ class LazyAsset extends BaseEntity {
1267
1260
  this.data.progressId = (await this.progresses.create()).id;
1268
1261
  this.data.assetId = null;
1269
1262
  await this.save();
1270
- await this.progresses.jobMan.enqueueWithName(this.data.jobName, { ...this.data.jobParams, lazyId: this.id, fromLoad });
1263
+ const jobParams = JSON.parse(await gunzipPromised(this.data.jobParams));
1264
+ await this.progresses.jobMan.enqueueWithName(this.data.jobName, { ...jobParams, lazyId: this.id, fromLoad });
1271
1265
  }
1272
1266
  }
1273
1267
 
@@ -1312,7 +1306,7 @@ let JobManager = class JobManager {
1312
1306
  return res;
1313
1307
  }, {});
1314
1308
  this.messages = new Subject();
1315
- this.processing = false;
1309
+ this.processing = null;
1316
1310
  this.maxTimeout = this.config.resolve("jobTimeout");
1317
1311
  }
1318
1312
  on(message, cb) {
@@ -1359,22 +1353,15 @@ let JobManager = class JobManager {
1359
1353
  });
1360
1354
  });
1361
1355
  }
1362
- async startProcessing() {
1363
- if (this.processing)
1364
- return null;
1365
- this.processing = true;
1366
- if (!this.config.resolve("isWorker")) {
1367
- this.logger.log("job-manager", colorize(`Processing can not be started because this is NOT a worker process!`, ConsoleColor.FgRed));
1368
- return null;
1369
- }
1356
+ async initProcessing() {
1370
1357
  const host = this.config.resolve("zmqRemoteHost");
1371
1358
  const pushHost = `${host}:${this.config.resolve("zmqBackPort")}`;
1372
1359
  this.workerPush = socket("push");
1373
- await this.workerPush.connect(pushHost);
1360
+ this.workerPush.connect(pushHost);
1374
1361
  this.logger.log("job-manager", `Worker producer connected to: ${pushHost}`);
1375
1362
  const pullHost = `${host}:${this.config.resolve("zmqPort")}`;
1376
1363
  this.workerPull = socket("pull");
1377
- await this.workerPull.connect(pullHost);
1364
+ this.workerPull.connect(pullHost);
1378
1365
  this.logger.log("job-manager", `Worker consumer connected to: ${pullHost}`);
1379
1366
  this.workerPull.on("message", async (name, args, uniqId) => {
1380
1367
  try {
@@ -1397,6 +1384,10 @@ let JobManager = class JobManager {
1397
1384
  }
1398
1385
  });
1399
1386
  }
1387
+ startProcessing() {
1388
+ this.processing = this.processing || this.initProcessing();
1389
+ return this.processing;
1390
+ }
1400
1391
  tryResolve(jobType, params) {
1401
1392
  const jobName = getConstructorName(jobType);
1402
1393
  if (!this.jobs[jobName]) {
@@ -1454,15 +1445,13 @@ let JobManager = class JobManager {
1454
1445
  return container.resolve(jobType);
1455
1446
  }
1456
1447
  async sendToWorkers(jobName, params) {
1457
- const publisher = await this.apiPush;
1458
1448
  const uniqueId = new ObjectId$1().toHexString();
1459
- await publisher.send([jobName, JSON.stringify(params), uniqueId]);
1449
+ this.apiPush.send([jobName, JSON.stringify(params), uniqueId]);
1460
1450
  return uniqueId;
1461
1451
  }
1462
1452
  };
1463
1453
  JobManager = __decorate([
1464
- injectable(),
1465
- scoped(Lifecycle.ContainerScoped),
1454
+ singleton(),
1466
1455
  __param(2, inject(DI_CONTAINER)),
1467
1456
  __param(3, injectAll(JOB)),
1468
1457
  __metadata("design:paramtypes", [Configuration,
@@ -1803,12 +1792,182 @@ AssetResolver = __decorate([
1803
1792
  __metadata("design:paramtypes", [Assets, LazyAssets])
1804
1793
  ], AssetResolver);
1805
1794
 
1795
+ function checkValue(multi, value) {
1796
+ if (multi) {
1797
+ return Array.isArray(value) && value.every(v => {
1798
+ try {
1799
+ const id = new ObjectId$1(v);
1800
+ return id instanceof ObjectId$1;
1801
+ }
1802
+ catch (e) {
1803
+ return false;
1804
+ }
1805
+ });
1806
+ }
1807
+ if (null === value)
1808
+ return true;
1809
+ try {
1810
+ const id = new ObjectId$1(value);
1811
+ return id instanceof ObjectId$1;
1812
+ }
1813
+ catch (e) {
1814
+ return false;
1815
+ }
1816
+ }
1817
+ let IsFile = class IsFile {
1818
+ validate(value, validationArguments) {
1819
+ const [multi] = (validationArguments.constraints || []);
1820
+ return checkValue(multi, value);
1821
+ }
1822
+ };
1823
+ IsFile = __decorate([
1824
+ ValidatorConstraint()
1825
+ ], IsFile);
1826
+ let IsObjectId = class IsObjectId {
1827
+ validate(value, validationArguments) {
1828
+ const [_, multi] = (validationArguments.constraints || []);
1829
+ return checkValue(multi, value);
1830
+ }
1831
+ };
1832
+ IsObjectId = __decorate([
1833
+ ValidatorConstraint()
1834
+ ], IsObjectId);
1835
+
1836
+ let OpenApi = class OpenApi {
1837
+ constructor(container, customValidation) {
1838
+ this.container = container;
1839
+ this.customValidation = customValidation;
1840
+ this.docs = null;
1841
+ }
1842
+ get apiDocs() {
1843
+ if (!this.docs)
1844
+ this.docs = this.createApiDocs();
1845
+ return this.docs;
1846
+ }
1847
+ get apiDocsStr() {
1848
+ if (!this.docsStr)
1849
+ this.docsStr = JSON.stringify(this.apiDocs);
1850
+ return this.docsStr;
1851
+ }
1852
+ async schemaToExample(src, req) {
1853
+ const maybeRef = src;
1854
+ if (maybeRef.$ref) {
1855
+ const schemas = this.apiDocs.components.schemas;
1856
+ const schema = maybeRef.$ref
1857
+ .replace("#/components/schemas/", "")
1858
+ .replace("#/definitions/", "");
1859
+ return this.schemaToExample(schemas[schema], req);
1860
+ }
1861
+ let schema = src;
1862
+ if (schema.oneOf) {
1863
+ schema = Object.assign({}, schema, schema.oneOf[0]);
1864
+ }
1865
+ if (schema.type === "object") {
1866
+ const result = {};
1867
+ await Promise.all(Object.keys(schema.properties).map(async (key) => {
1868
+ result[key] = await this.schemaToExample(schema.properties[key], req);
1869
+ }));
1870
+ return result;
1871
+ }
1872
+ if (schema.type === "array") {
1873
+ return [await this.schemaToExample(schema.items, req)];
1874
+ }
1875
+ if (schema.type === "string") {
1876
+ if (isDefined(schema.default)) {
1877
+ if (isFunction(schema.default)) {
1878
+ return schema.default(this.container);
1879
+ }
1880
+ return schema.default;
1881
+ }
1882
+ if (schema.format == "date") {
1883
+ return new Date().toISOString().substr(0, 10);
1884
+ }
1885
+ if (schema.format == "date-time") {
1886
+ return new Date().toISOString();
1887
+ }
1888
+ if (schema.enum) {
1889
+ return schema.enum[0];
1890
+ }
1891
+ return "string";
1892
+ }
1893
+ if (schema.type === "number") {
1894
+ return schema.default ?? 0;
1895
+ }
1896
+ else if (schema.type === "boolean") {
1897
+ return schema.default ?? false;
1898
+ }
1899
+ else {
1900
+ return schema.default ?? null;
1901
+ }
1902
+ }
1903
+ createApiDocs() {
1904
+ const storage = getMetadataArgsStorage();
1905
+ const docs = routingControllersToSpec(storage);
1906
+ docs.basePath = "/api/";
1907
+ docs.definitions = validationMetadatasToSchemas({
1908
+ classTransformerMetadataStorage: defaultMetadataStorage,
1909
+ additionalConverters: {
1910
+ [ValidationTypes.CUSTOM_VALIDATION]: (meta, options) => {
1911
+ const res = isFunction(this.customValidation) ? this.customValidation(meta, options) : this.customValidation;
1912
+ if (isObject(res))
1913
+ return res;
1914
+ const constraints = meta.constraints || [];
1915
+ if (meta.constraintCls === IsFile) {
1916
+ return {
1917
+ multi: constraints[0] || false,
1918
+ type: "file"
1919
+ };
1920
+ }
1921
+ if (meta.constraintCls === IsObjectId) {
1922
+ return {
1923
+ endpoint: constraints[0] || false,
1924
+ multi: constraints[1] || false,
1925
+ type: "list"
1926
+ };
1927
+ }
1928
+ return null;
1929
+ }
1930
+ }
1931
+ });
1932
+ docs.components.schemas = docs.definitions;
1933
+ return docs;
1934
+ }
1935
+ };
1936
+ OpenApi = __decorate([
1937
+ singleton(),
1938
+ __param(0, inject(DI_CONTAINER)),
1939
+ __param(1, inject(OPENAPI_VALIDATION)),
1940
+ __metadata("design:paramtypes", [Object, Object])
1941
+ ], OpenApi);
1942
+
1943
+ let Fixtures = class Fixtures {
1944
+ constructor(fixtures) {
1945
+ this.fixtures = fixtures;
1946
+ }
1947
+ async load(output) {
1948
+ if (!this.fixtures)
1949
+ return;
1950
+ output = output || {
1951
+ write: console.log,
1952
+ writeln: t => console.log(t + "\n")
1953
+ };
1954
+ for (let fixture of this.fixtures) {
1955
+ await fixture.load(output);
1956
+ }
1957
+ }
1958
+ };
1959
+ Fixtures = __decorate([
1960
+ injectable(),
1961
+ scoped(Lifecycle.ContainerScoped),
1962
+ __param(0, injectAll(FIXTURE)),
1963
+ __metadata("design:paramtypes", [Array])
1964
+ ], Fixtures);
1965
+
1806
1966
  const express = express_;
1807
1967
  let BackendProvider = class BackendProvider {
1808
- constructor() {
1809
- this.express = express();
1810
- this.express.set("trust proxy", true);
1811
- this.server = createServer(this.express);
1968
+ constructor(config, container) {
1969
+ this.config = config;
1970
+ this.container = container;
1812
1971
  }
1813
1972
  get io() {
1814
1973
  this.ioServer = this.ioServer || new Server(this.server, {
@@ -1823,10 +1982,48 @@ let BackendProvider = class BackendProvider {
1823
1982
  });
1824
1983
  return this.ioServer;
1825
1984
  }
1985
+ get express() {
1986
+ if (!this.expressApp) {
1987
+ this.expressApp = express();
1988
+ this.expressApp.set("trust proxy", true);
1989
+ this.expressApp.use(bodyParser.json({
1990
+ limit: this.config.resolve("jsonLimit")
1991
+ }));
1992
+ this.expressApp.get("/api-docs", (req, res) => {
1993
+ this.openApi = this.openApi || this.container.get(OpenApi);
1994
+ res.header("Content-Type", "application/json")
1995
+ .status(200)
1996
+ .end(this.openApi.apiDocsStr);
1997
+ });
1998
+ }
1999
+ return this.expressApp;
2000
+ }
2001
+ get server() {
2002
+ this.httpServer = this.httpServer || createServer(this.express);
2003
+ return this.httpServer;
2004
+ }
2005
+ async quickStart() {
2006
+ const port = this.config.resolve("appPort");
2007
+ const isWorker = this.config.resolve("isWorker");
2008
+ if (isWorker || this.config.resolve("startWorker")) {
2009
+ await this.container.resolve(JobManager).startProcessing();
2010
+ if (isWorker) {
2011
+ return;
2012
+ }
2013
+ }
2014
+ if (this.config.resolve("fixtures")) {
2015
+ const fixtures = this.container.resolve(Fixtures);
2016
+ await fixtures.load();
2017
+ }
2018
+ return new Promise(resolve => {
2019
+ this.server.listen(port, () => resolve(`Service listening on port ${port}!`));
2020
+ });
2021
+ }
1826
2022
  };
1827
2023
  BackendProvider = __decorate([
1828
2024
  singleton(),
1829
- __metadata("design:paramtypes", [])
2025
+ __param(1, inject(DI_CONTAINER)),
2026
+ __metadata("design:paramtypes", [Configuration, Object])
1830
2027
  ], BackendProvider);
1831
2028
 
1832
2029
  let CacheProcessor = class CacheProcessor {
@@ -1912,29 +2109,6 @@ EndpointProvider = __decorate([
1912
2109
  scoped(Lifecycle.ContainerScoped)
1913
2110
  ], EndpointProvider);
1914
2111
 
1915
- let Fixtures = class Fixtures {
1916
- constructor(fixtures) {
1917
- this.fixtures = fixtures;
1918
- }
1919
- async load(output) {
1920
- if (!this.fixtures)
1921
- return;
1922
- output = output || {
1923
- write: console.log,
1924
- writeln: t => console.log(t + "\n")
1925
- };
1926
- for (let fixture of this.fixtures) {
1927
- await fixture.load(output);
1928
- }
1929
- }
1930
- };
1931
- Fixtures = __decorate([
1932
- injectable(),
1933
- scoped(Lifecycle.ContainerScoped),
1934
- __param(0, injectAll(FIXTURE)),
1935
- __metadata("design:paramtypes", [Array])
1936
- ], Fixtures);
1937
-
1938
2112
  const sharp$1 = sharp_;
1939
2113
  const bigSize = 1500;
1940
2114
  const thumbSize = 250;
@@ -2380,154 +2554,6 @@ MemoryCache = __decorate([
2380
2554
  __metadata("design:paramtypes", [Cache])
2381
2555
  ], MemoryCache);
2382
2556
 
2383
- function checkValue(multi, value) {
2384
- if (multi) {
2385
- return Array.isArray(value) && value.every(v => {
2386
- try {
2387
- const id = new ObjectId$1(v);
2388
- return id instanceof ObjectId$1;
2389
- }
2390
- catch (e) {
2391
- return false;
2392
- }
2393
- });
2394
- }
2395
- if (null === value)
2396
- return true;
2397
- try {
2398
- const id = new ObjectId$1(value);
2399
- return id instanceof ObjectId$1;
2400
- }
2401
- catch (e) {
2402
- return false;
2403
- }
2404
- }
2405
- let IsFile = class IsFile {
2406
- validate(value, validationArguments) {
2407
- const [multi] = (validationArguments.constraints || []);
2408
- return checkValue(multi, value);
2409
- }
2410
- };
2411
- IsFile = __decorate([
2412
- ValidatorConstraint()
2413
- ], IsFile);
2414
- let IsObjectId = class IsObjectId {
2415
- validate(value, validationArguments) {
2416
- const [_, multi] = (validationArguments.constraints || []);
2417
- return checkValue(multi, value);
2418
- }
2419
- };
2420
- IsObjectId = __decorate([
2421
- ValidatorConstraint()
2422
- ], IsObjectId);
2423
-
2424
- let OpenApi = class OpenApi {
2425
- constructor(container, customValidation) {
2426
- this.container = container;
2427
- this.customValidation = customValidation;
2428
- this.docs = null;
2429
- }
2430
- get apiDocs() {
2431
- if (!this.docs)
2432
- this.docs = this.createApiDocs();
2433
- return this.docs;
2434
- }
2435
- get apiDocsStr() {
2436
- if (!this.docsStr)
2437
- this.docsStr = JSON.stringify(this.apiDocs);
2438
- return this.docsStr;
2439
- }
2440
- async schemaToExample(src, req) {
2441
- const maybeRef = src;
2442
- if (maybeRef.$ref) {
2443
- const schemas = this.apiDocs.components.schemas;
2444
- const schema = maybeRef.$ref
2445
- .replace("#/components/schemas/", "")
2446
- .replace("#/definitions/", "");
2447
- return this.schemaToExample(schemas[schema], req);
2448
- }
2449
- let schema = src;
2450
- if (schema.oneOf) {
2451
- schema = Object.assign({}, schema, schema.oneOf[0]);
2452
- }
2453
- if (schema.type === "object") {
2454
- const result = {};
2455
- await Promise.all(Object.keys(schema.properties).map(async (key) => {
2456
- result[key] = await this.schemaToExample(schema.properties[key], req);
2457
- }));
2458
- return result;
2459
- }
2460
- if (schema.type === "array") {
2461
- return [await this.schemaToExample(schema.items, req)];
2462
- }
2463
- if (schema.type === "string") {
2464
- if (isDefined(schema.default)) {
2465
- if (isFunction(schema.default)) {
2466
- return schema.default(this.container);
2467
- }
2468
- return schema.default;
2469
- }
2470
- if (schema.format == "date") {
2471
- return new Date().toISOString().substr(0, 10);
2472
- }
2473
- if (schema.format == "date-time") {
2474
- return new Date().toISOString();
2475
- }
2476
- if (schema.enum) {
2477
- return schema.enum[0];
2478
- }
2479
- return "string";
2480
- }
2481
- if (schema.type === "number") {
2482
- return schema.default ?? 0;
2483
- }
2484
- else if (schema.type === "boolean") {
2485
- return schema.default ?? false;
2486
- }
2487
- else {
2488
- return schema.default ?? null;
2489
- }
2490
- }
2491
- createApiDocs() {
2492
- const storage = getMetadataArgsStorage();
2493
- const docs = routingControllersToSpec(storage);
2494
- docs.basePath = "/api/";
2495
- docs.definitions = validationMetadatasToSchemas({
2496
- classTransformerMetadataStorage: defaultMetadataStorage,
2497
- additionalConverters: {
2498
- [ValidationTypes.CUSTOM_VALIDATION]: (meta, options) => {
2499
- const res = isFunction(this.customValidation) ? this.customValidation(meta, options) : this.customValidation;
2500
- if (isObject(res))
2501
- return res;
2502
- const constraints = meta.constraints || [];
2503
- if (meta.constraintCls === IsFile) {
2504
- return {
2505
- multi: constraints[0] || false,
2506
- type: "file"
2507
- };
2508
- }
2509
- if (meta.constraintCls === IsObjectId) {
2510
- return {
2511
- endpoint: constraints[0] || false,
2512
- multi: constraints[1] || false,
2513
- type: "list"
2514
- };
2515
- }
2516
- return null;
2517
- }
2518
- }
2519
- });
2520
- docs.components.schemas = docs.definitions;
2521
- return docs;
2522
- }
2523
- };
2524
- OpenApi = __decorate([
2525
- singleton(),
2526
- __param(0, inject(DI_CONTAINER)),
2527
- __param(1, inject(OPENAPI_VALIDATION)),
2528
- __metadata("design:paramtypes", [Object, Object])
2529
- ], OpenApi);
2530
-
2531
2557
  let TerminalManager = class TerminalManager {
2532
2558
  constructor(logger, config, commands) {
2533
2559
  this.logger = logger;
@@ -4125,6 +4151,8 @@ function createServices() {
4125
4151
  new Parameter("zmqBackPort", 3100),
4126
4152
  new Parameter("zmqRemoteHost", "tcp://127.0.0.1"),
4127
4153
  new Parameter("isWorker", false),
4154
+ new Parameter("startWorker", false),
4155
+ new Parameter("fixtures", true),
4128
4156
  new Parameter("mainEndpoint", ""),
4129
4157
  new Parameter("idChars", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
4130
4158
  new Parameter("idSeparator", "-"),
@@ -4330,28 +4358,17 @@ async function setupBackend(config, providers, parent) {
4330
4358
  const configuration = diContainer.resolve(Configuration);
4331
4359
  const bp = diContainer.resolve(BackendProvider);
4332
4360
  if (config.restOptions) {
4333
- bp.express.use(bodyParser.json({
4334
- limit: configuration.hasParam("jsonLimit")
4335
- ? configuration.resolve("jsonLimit")
4336
- : "250mb"
4337
- }));
4338
4361
  useContainer(diContainer);
4339
4362
  useExpressServer(bp.express, restOptions);
4340
- // Setup rest ai docs
4341
- let openApi = null;
4342
- bp.express.get("/api-docs", (req, res) => {
4343
- openApi = openApi || diContainer.get(OpenApi);
4344
- res.header("Content-Type", "application/json")
4345
- .status(200)
4346
- .end(openApi.apiDocsStr);
4363
+ }
4364
+ if (config.socketOptions) {
4365
+ diContainer.register(SOCKET_CONTROLLERS, {
4366
+ useValue: new SocketControllers({
4367
+ io: bp.io,
4368
+ ...socketOptions,
4369
+ })
4347
4370
  });
4348
4371
  }
4349
- diContainer.register(SOCKET_CONTROLLERS, {
4350
- useValue: new SocketControllers({
4351
- io: bp.io,
4352
- ...socketOptions,
4353
- })
4354
- });
4355
4372
  // Connect to mongo if necessary
4356
4373
  if (configuration.hasParam("mongoUri") && configuration.resolve("mongoUri")) {
4357
4374
  console.log("Connecting to MongoDB...");