@stemy/backend 6.0.4 → 6.1.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/commands/clear.command.d.ts +6 -0
- package/commands/fixtures.command.d.ts +9 -0
- package/commands/move-assets.command.d.ts +10 -0
- package/common-types.d.ts +22 -15
- package/esm2022/commands/clear.command.mjs +15 -0
- package/esm2022/commands/fixtures.command.mjs +26 -0
- package/esm2022/commands/index.mjs +6 -4
- package/esm2022/commands/move-assets.command.mjs +45 -0
- package/esm2022/common-types.mjs +3 -5
- package/esm2022/public_api.mjs +15 -14
- package/esm2022/services/assets.mjs +46 -13
- package/esm2022/services/backend-provider.mjs +7 -1
- package/esm2022/services/cli-terminal.mjs +56 -0
- package/esm2022/services/configuration.mjs +11 -4
- package/esm2022/services/drivers/asset-grid.driver.mjs +5 -5
- package/esm2022/services/drivers/asset-local.driver.mjs +19 -16
- package/esm2022/services/drivers/asset-storage-proxy.driver.mjs +15 -10
- package/esm2022/services/drivers/fallback-streams.mjs +1 -39
- package/esm2022/services/entities/asset.mjs +47 -6
- package/esm2022/services/entities/temp-asset.mjs +15 -3
- package/esm2022/services/terminal-manager.mjs +30 -16
- package/esm2022/socket-controllers/socket-terminal.mjs +89 -0
- package/esm2022/socket-controllers/terminal.controller.mjs +3 -3
- package/fesm2022/stemy-backend.mjs +357 -213
- package/fesm2022/stemy-backend.mjs.map +1 -1
- package/package.json +2 -2
- package/public_api.d.ts +1 -1
- package/services/assets.d.ts +13 -5
- package/services/cli-terminal.d.ts +18 -0
- package/services/configuration.d.ts +2 -0
- package/services/drivers/asset-grid.driver.d.ts +4 -4
- package/services/drivers/asset-local.driver.d.ts +6 -5
- package/services/drivers/asset-storage-proxy.driver.d.ts +5 -5
- package/services/drivers/fallback-streams.d.ts +1 -8
- package/services/entities/asset.d.ts +8 -3
- package/services/entities/temp-asset.d.ts +6 -1
- package/services/terminal-manager.d.ts +3 -0
- package/socket-controllers/socket-terminal.d.ts +19 -0
- package/socket-controllers/terminal.controller.d.ts +2 -2
|
@@ -8,14 +8,14 @@ import { create } from 'fontkit';
|
|
|
8
8
|
import sharp_ from 'sharp';
|
|
9
9
|
import { ObjectId as ObjectId$1 } from 'bson';
|
|
10
10
|
import axios from 'axios';
|
|
11
|
-
import { mkdir, unlink, readFile as readFile$1, writeFile as writeFile$1, lstat, readdir, access, constants, lstatSync, readFileSync, existsSync, mkdirSync, createWriteStream, createReadStream } from 'fs';
|
|
11
|
+
import { mkdir, unlink, readFile as readFile$1, writeFile as writeFile$1, lstat, readdir, access, constants, lstatSync, readFileSync, existsSync, mkdirSync, createWriteStream, writeFileSync, createReadStream } from 'fs';
|
|
12
12
|
import { gzip, gunzip } from 'zlib';
|
|
13
13
|
import { fileURLToPath } from 'url';
|
|
14
14
|
import { exec } from 'child_process';
|
|
15
15
|
import { createHash } from 'crypto';
|
|
16
16
|
import { Subscription, Observable, Subject, from, BehaviorSubject } from 'rxjs';
|
|
17
17
|
import { ObjectId } from 'mongodb';
|
|
18
|
-
import mongoose
|
|
18
|
+
import mongoose from 'mongoose';
|
|
19
19
|
import { Readable, PassThrough } from 'stream';
|
|
20
20
|
import fileType from 'file-type/core';
|
|
21
21
|
import dotenv from 'dotenv';
|
|
@@ -31,14 +31,15 @@ import { routingControllersToSpec, OpenAPI, getStatusCode } from 'routing-contro
|
|
|
31
31
|
import { defaultMetadataStorage } from 'class-transformer/cjs/storage';
|
|
32
32
|
import { validationMetadatasToSchemas } from 'class-validator-jsonschema';
|
|
33
33
|
import { ValidatorConstraint, ValidationTypes, Min, Max, IsOptional, IsBoolean } from 'class-validator';
|
|
34
|
+
import { CommandsAddon, AnsiCodes } from '@stemy/terminal-commands-addon';
|
|
35
|
+
import * as readline from 'readline';
|
|
34
36
|
import { v4 } from 'uuid';
|
|
35
37
|
import { createTransport } from 'nodemailer';
|
|
36
38
|
import * as Handlebars from 'handlebars';
|
|
37
|
-
import { CommandsAddon, AnsiCodes } from '@stemy/terminal-commands-addon';
|
|
38
39
|
import { compare } from 'bcrypt';
|
|
39
40
|
import moment from 'moment';
|
|
40
41
|
import { GridFSBucket } from 'mongodb/lib/gridfs';
|
|
41
|
-
import {
|
|
42
|
+
import { rm } from 'fs/promises';
|
|
42
43
|
import got from 'got';
|
|
43
44
|
import { getModelForClass } from '@typegoose/typegoose';
|
|
44
45
|
import { getValue as getValue$1, setValue } from 'mongoose/lib/utils';
|
|
@@ -56,10 +57,8 @@ const SOCKET_CONTROLLERS = Symbol.for("socket-controllers-token");
|
|
|
56
57
|
const PARAMETER = Symbol.for("parameter-token");
|
|
57
58
|
const DI_CONTAINER = Symbol.for("di-container-token");
|
|
58
59
|
const OPENAPI_VALIDATION = Symbol.for("openapi-validation-token");
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
const ASSET_MAIN_DRIVER = Symbol.for('assets-main-driver');
|
|
62
|
-
const ASSET_FALLBACK_DRIVER = Symbol.for('assets-fallback-driver');
|
|
60
|
+
const ASSET_LOCAL_DIR = Symbol.for('asset-local-dir');
|
|
61
|
+
const ASSET_DRIVER_FACTORIES = Symbol.for('assets-driver-factories');
|
|
63
62
|
class Parameter {
|
|
64
63
|
name;
|
|
65
64
|
defaultValue;
|
|
@@ -867,10 +866,12 @@ async function fileTypeFromBuffer(buffer) {
|
|
|
867
866
|
}
|
|
868
867
|
|
|
869
868
|
let Configuration = class Configuration {
|
|
869
|
+
isCli;
|
|
870
870
|
paramMap;
|
|
871
871
|
paramValues;
|
|
872
872
|
constructor(params) {
|
|
873
873
|
dotenv.config();
|
|
874
|
+
this.isCli = process.env.IS_CLI === 'true';
|
|
874
875
|
this.paramMap = {};
|
|
875
876
|
this.paramValues = {};
|
|
876
877
|
(params || []).forEach(param => this.add(param));
|
|
@@ -891,15 +892,15 @@ let Configuration = class Configuration {
|
|
|
891
892
|
const value = isFunction(param.resolver)
|
|
892
893
|
? param.resolver(envValue, helper)
|
|
893
894
|
: convertValue(envValue, getType(param.defaultValue));
|
|
894
|
-
|
|
895
|
+
this.log(colorize(`Processing param value`, ConsoleColor.FgYellow), colorize(param.name, ConsoleColor.FgGreen), colorize(envName, ConsoleColor.FgBlue), `"${envValue}"`, value);
|
|
895
896
|
return value;
|
|
896
897
|
}
|
|
897
898
|
else if (isFunction(param.resolver)) {
|
|
898
899
|
const value = param.resolver(param.defaultValue, helper);
|
|
899
|
-
|
|
900
|
+
this.log(colorize(`Processing default param value`, ConsoleColor.FgYellow), colorize(param.name, ConsoleColor.FgGreen), param.defaultValue, value);
|
|
900
901
|
return value;
|
|
901
902
|
}
|
|
902
|
-
|
|
903
|
+
this.log(colorize(`Using default param value`, ConsoleColor.FgYellow), colorize(param.name, ConsoleColor.FgGreen), param.defaultValue);
|
|
903
904
|
return param.defaultValue;
|
|
904
905
|
}
|
|
905
906
|
hasParam(name) {
|
|
@@ -921,6 +922,11 @@ let Configuration = class Configuration {
|
|
|
921
922
|
}
|
|
922
923
|
return this.paramValues[name];
|
|
923
924
|
}
|
|
925
|
+
log(...args) {
|
|
926
|
+
if (this.isCli)
|
|
927
|
+
return;
|
|
928
|
+
console.log(...args);
|
|
929
|
+
}
|
|
924
930
|
};
|
|
925
931
|
Configuration = __decorate([
|
|
926
932
|
singleton(),
|
|
@@ -992,10 +998,19 @@ class BaseEntity {
|
|
|
992
998
|
}
|
|
993
999
|
|
|
994
1000
|
class Asset extends BaseEntity {
|
|
995
|
-
|
|
1001
|
+
drivers;
|
|
996
1002
|
get filename() {
|
|
997
1003
|
return this.data.filename;
|
|
998
1004
|
}
|
|
1005
|
+
get streamId() {
|
|
1006
|
+
return this.data.streamId || this.oid;
|
|
1007
|
+
}
|
|
1008
|
+
get driverId() {
|
|
1009
|
+
return this.data.driverId;
|
|
1010
|
+
}
|
|
1011
|
+
get driver() {
|
|
1012
|
+
return this.drivers.getDriver(this.driverId || this.drivers.missingDriver);
|
|
1013
|
+
}
|
|
999
1014
|
get contentType() {
|
|
1000
1015
|
return this.data.contentType;
|
|
1001
1016
|
}
|
|
@@ -1003,15 +1018,15 @@ class Asset extends BaseEntity {
|
|
|
1003
1018
|
return this.data.metadata;
|
|
1004
1019
|
}
|
|
1005
1020
|
get stream() {
|
|
1006
|
-
return this.driver.openDownloadStream(this
|
|
1021
|
+
return this.driver.openDownloadStream(this);
|
|
1007
1022
|
}
|
|
1008
|
-
constructor(id, data, collection,
|
|
1023
|
+
constructor(id, data, collection, drivers) {
|
|
1009
1024
|
super(id, data, collection);
|
|
1010
|
-
this.
|
|
1025
|
+
this.drivers = drivers;
|
|
1011
1026
|
}
|
|
1012
1027
|
async unlink() {
|
|
1013
1028
|
try {
|
|
1014
|
-
await this.driver.delete(this
|
|
1029
|
+
await this.driver.delete(this);
|
|
1015
1030
|
}
|
|
1016
1031
|
catch (error) {
|
|
1017
1032
|
console.log("Failed to unlink", error?.message);
|
|
@@ -1026,6 +1041,38 @@ class Asset extends BaseEntity {
|
|
|
1026
1041
|
getBuffer() {
|
|
1027
1042
|
return streamToBuffer(this.stream);
|
|
1028
1043
|
}
|
|
1044
|
+
async move(driverId) {
|
|
1045
|
+
const oldDriver = this.driver;
|
|
1046
|
+
const targetDriver = this.drivers.getDriver(driverId);
|
|
1047
|
+
if (targetDriver === oldDriver)
|
|
1048
|
+
return this;
|
|
1049
|
+
const oldAsset = new Asset(this.oid, this.data, this.collection, this.drivers);
|
|
1050
|
+
const streamId = await this.uploadTo(targetDriver);
|
|
1051
|
+
this.data = {
|
|
1052
|
+
...this.data,
|
|
1053
|
+
streamId,
|
|
1054
|
+
driverId,
|
|
1055
|
+
};
|
|
1056
|
+
await this.save();
|
|
1057
|
+
await oldDriver.delete(oldAsset);
|
|
1058
|
+
}
|
|
1059
|
+
uploadTo(driver) {
|
|
1060
|
+
return new Promise((resolve, reject) => {
|
|
1061
|
+
const uploaderStream = driver.openUploadStream(this.filename, {
|
|
1062
|
+
chunkSizeBytes: 1048576,
|
|
1063
|
+
contentType: this.contentType,
|
|
1064
|
+
extension: this.metadata.extension,
|
|
1065
|
+
metadata: this.metadata,
|
|
1066
|
+
});
|
|
1067
|
+
this.stream.pipe(uploaderStream)
|
|
1068
|
+
.on("error", error => {
|
|
1069
|
+
reject(error.message || error);
|
|
1070
|
+
})
|
|
1071
|
+
.on("finish", async () => {
|
|
1072
|
+
resolve(uploaderStream.id);
|
|
1073
|
+
});
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1029
1076
|
async download(metadata) {
|
|
1030
1077
|
metadata = Object.assign(this.metadata, metadata || {});
|
|
1031
1078
|
metadata.downloadCount = isNaN(metadata.downloadCount) || !metadata.firstDownload
|
|
@@ -1049,16 +1096,25 @@ class TempAsset {
|
|
|
1049
1096
|
filename;
|
|
1050
1097
|
contentType;
|
|
1051
1098
|
metadata;
|
|
1052
|
-
id
|
|
1099
|
+
get id() {
|
|
1100
|
+
return this.oid.toHexString();
|
|
1101
|
+
}
|
|
1102
|
+
get streamId() {
|
|
1103
|
+
return this.oid;
|
|
1104
|
+
}
|
|
1105
|
+
get driverId() {
|
|
1106
|
+
return "temp";
|
|
1107
|
+
}
|
|
1053
1108
|
get stream() {
|
|
1054
1109
|
return bufferToStream(this.buffer);
|
|
1055
1110
|
}
|
|
1111
|
+
oid;
|
|
1056
1112
|
constructor(buffer, filename, contentType, metadata) {
|
|
1057
1113
|
this.buffer = buffer;
|
|
1058
1114
|
this.filename = filename;
|
|
1059
1115
|
this.contentType = contentType;
|
|
1060
1116
|
this.metadata = metadata;
|
|
1061
|
-
this.
|
|
1117
|
+
this.oid = new ObjectId$1();
|
|
1062
1118
|
}
|
|
1063
1119
|
async unlink() {
|
|
1064
1120
|
throw new Error(`Temp asset '${this.id}' can not be removed!`);
|
|
@@ -1069,6 +1125,9 @@ class TempAsset {
|
|
|
1069
1125
|
async getBuffer() {
|
|
1070
1126
|
return this.buffer;
|
|
1071
1127
|
}
|
|
1128
|
+
async move() {
|
|
1129
|
+
throw new Error(`Temp asset '${this.id}' can not be moved!`);
|
|
1130
|
+
}
|
|
1072
1131
|
async download(metadata) {
|
|
1073
1132
|
return this.stream;
|
|
1074
1133
|
}
|
|
@@ -1098,13 +1157,38 @@ class TempAsset {
|
|
|
1098
1157
|
let Assets = class Assets {
|
|
1099
1158
|
connector;
|
|
1100
1159
|
assetProcessor;
|
|
1101
|
-
|
|
1160
|
+
config;
|
|
1161
|
+
container;
|
|
1162
|
+
driverFactoryMap;
|
|
1102
1163
|
collection;
|
|
1103
|
-
|
|
1164
|
+
driverMap;
|
|
1165
|
+
mainDriver;
|
|
1166
|
+
missingDriver;
|
|
1167
|
+
drivers;
|
|
1168
|
+
constructor(connector, assetProcessor, config, container, driverFactoryMap) {
|
|
1104
1169
|
this.connector = connector;
|
|
1105
1170
|
this.assetProcessor = assetProcessor;
|
|
1106
|
-
this.
|
|
1171
|
+
this.config = config;
|
|
1172
|
+
this.container = container;
|
|
1173
|
+
this.driverFactoryMap = driverFactoryMap;
|
|
1107
1174
|
this.collection = connector.database?.collection("assets.metadata");
|
|
1175
|
+
this.driverMap = new Map();
|
|
1176
|
+
this.mainDriver = this.config.resolve("assetsMainDriver");
|
|
1177
|
+
this.missingDriver = this.config.resolve("assetsMissingDriver");
|
|
1178
|
+
this.drivers = Object.keys(driverFactoryMap);
|
|
1179
|
+
}
|
|
1180
|
+
getDriver(name) {
|
|
1181
|
+
if (!name) {
|
|
1182
|
+
throw new Error(`No name provider for asset driver!`);
|
|
1183
|
+
}
|
|
1184
|
+
if (!this.driverMap.has(name)) {
|
|
1185
|
+
const factory = this.driverFactoryMap[name];
|
|
1186
|
+
if (!factory) {
|
|
1187
|
+
throw new Error(`No asset driver factory found with name: '${name}'!`);
|
|
1188
|
+
}
|
|
1189
|
+
this.driverMap.set(name, factory(this.container));
|
|
1190
|
+
}
|
|
1191
|
+
return this.driverMap.get(name);
|
|
1108
1192
|
}
|
|
1109
1193
|
async write(stream, contentType = null, metadata = null) {
|
|
1110
1194
|
const uploadStream = copyStream(stream);
|
|
@@ -1173,7 +1257,7 @@ let Assets = class Assets {
|
|
|
1173
1257
|
}
|
|
1174
1258
|
async find(where) {
|
|
1175
1259
|
const data = await this.collection.findOne(where);
|
|
1176
|
-
return !data ? null : new Asset(data._id, data, this.collection, this
|
|
1260
|
+
return !data ? null : new Asset(data._id, data, this.collection, this);
|
|
1177
1261
|
}
|
|
1178
1262
|
async findMany(where) {
|
|
1179
1263
|
const cursor = this.collection.find(where);
|
|
@@ -1182,7 +1266,7 @@ let Assets = class Assets {
|
|
|
1182
1266
|
for (let item of items) {
|
|
1183
1267
|
if (!item)
|
|
1184
1268
|
continue;
|
|
1185
|
-
result.push(new Asset(item._id, item, this.collection, this
|
|
1269
|
+
result.push(new Asset(item._id, item, this.collection, this));
|
|
1186
1270
|
}
|
|
1187
1271
|
return result;
|
|
1188
1272
|
}
|
|
@@ -1206,10 +1290,13 @@ let Assets = class Assets {
|
|
|
1206
1290
|
metadata.filename = metadata.filename || new ObjectId$1().toHexString();
|
|
1207
1291
|
metadata.extension = (fileType.ext || "").trim();
|
|
1208
1292
|
return new Promise(((resolve, reject) => {
|
|
1209
|
-
const
|
|
1293
|
+
const driverId = this.mainDriver;
|
|
1294
|
+
const driver = this.getDriver(driverId);
|
|
1295
|
+
const uploaderStream = driver.openUploadStream(metadata.filename, {
|
|
1210
1296
|
chunkSizeBytes: 1048576,
|
|
1297
|
+
contentType: fileType.mime,
|
|
1298
|
+
extension: fileType.ext,
|
|
1211
1299
|
metadata,
|
|
1212
|
-
contentType: fileType.mime
|
|
1213
1300
|
});
|
|
1214
1301
|
stream.pipe(uploaderStream)
|
|
1215
1302
|
.on("error", error => {
|
|
@@ -1217,10 +1304,12 @@ let Assets = class Assets {
|
|
|
1217
1304
|
})
|
|
1218
1305
|
.on("finish", () => {
|
|
1219
1306
|
const asset = new Asset(uploaderStream.id, {
|
|
1307
|
+
streamId: uploaderStream.id,
|
|
1220
1308
|
filename: metadata.filename,
|
|
1221
1309
|
contentType,
|
|
1222
|
-
metadata
|
|
1223
|
-
|
|
1310
|
+
metadata,
|
|
1311
|
+
driverId
|
|
1312
|
+
}, this.collection, this);
|
|
1224
1313
|
asset.save().then(() => {
|
|
1225
1314
|
resolve(asset);
|
|
1226
1315
|
}, error => {
|
|
@@ -1233,9 +1322,11 @@ let Assets = class Assets {
|
|
|
1233
1322
|
Assets = __decorate([
|
|
1234
1323
|
injectable(),
|
|
1235
1324
|
scoped(Lifecycle.ContainerScoped),
|
|
1236
|
-
__param(
|
|
1325
|
+
__param(3, inject(DI_CONTAINER)),
|
|
1326
|
+
__param(4, inject(ASSET_DRIVER_FACTORIES)),
|
|
1237
1327
|
__metadata("design:paramtypes", [MongoConnector,
|
|
1238
|
-
AssetProcessor,
|
|
1328
|
+
AssetProcessor,
|
|
1329
|
+
Configuration, Object, Object])
|
|
1239
1330
|
], Assets);
|
|
1240
1331
|
|
|
1241
1332
|
class LazyAsset extends BaseEntity {
|
|
@@ -2083,6 +2174,154 @@ Fixtures = __decorate([
|
|
|
2083
2174
|
__metadata("design:paramtypes", [Object])
|
|
2084
2175
|
], Fixtures);
|
|
2085
2176
|
|
|
2177
|
+
class CliTerminal {
|
|
2178
|
+
callbacks = new Set();
|
|
2179
|
+
stdin = process.stdin;
|
|
2180
|
+
constructor() {
|
|
2181
|
+
// Set stdin to raw mode to get character-by-character data
|
|
2182
|
+
if (this.stdin.isTTY) {
|
|
2183
|
+
this.stdin.setRawMode(true);
|
|
2184
|
+
}
|
|
2185
|
+
this.clearScreen();
|
|
2186
|
+
this.stdin.setEncoding('utf8');
|
|
2187
|
+
this.stdin.on('data', this.handleInput);
|
|
2188
|
+
}
|
|
2189
|
+
clearScreen() {
|
|
2190
|
+
readline.cursorTo(process.stdout, 0, 0);
|
|
2191
|
+
readline.clearScreenDown(process.stdout);
|
|
2192
|
+
}
|
|
2193
|
+
handleInput = (data) => {
|
|
2194
|
+
const input = data.toString();
|
|
2195
|
+
// Standard "Ctrl+C" exit handling
|
|
2196
|
+
if (input === '\u0003') {
|
|
2197
|
+
this.clearScreen();
|
|
2198
|
+
this.dispose();
|
|
2199
|
+
}
|
|
2200
|
+
this.callbacks.forEach((cb) => cb(input));
|
|
2201
|
+
};
|
|
2202
|
+
/**
|
|
2203
|
+
* Registers a listener for data input.
|
|
2204
|
+
* Returns an IDisposable to unregister the listener.
|
|
2205
|
+
*/
|
|
2206
|
+
onData(cb) {
|
|
2207
|
+
this.callbacks.add(cb);
|
|
2208
|
+
return {
|
|
2209
|
+
dispose: () => this.callbacks.delete(cb),
|
|
2210
|
+
};
|
|
2211
|
+
}
|
|
2212
|
+
write(data) {
|
|
2213
|
+
process.stdout.write(data);
|
|
2214
|
+
}
|
|
2215
|
+
writeln(data) {
|
|
2216
|
+
process.stdout.write(data + '\n');
|
|
2217
|
+
}
|
|
2218
|
+
loadAddon(addon) {
|
|
2219
|
+
addon.activate(this);
|
|
2220
|
+
}
|
|
2221
|
+
dispose() {
|
|
2222
|
+
if (this.stdin.isTTY) {
|
|
2223
|
+
this.stdin.setRawMode(false);
|
|
2224
|
+
}
|
|
2225
|
+
this.stdin.removeListener('data', this.handleInput);
|
|
2226
|
+
this.stdin.pause();
|
|
2227
|
+
this.callbacks.clear();
|
|
2228
|
+
process.exit();
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
|
|
2232
|
+
let TerminalManager = class TerminalManager {
|
|
2233
|
+
logger;
|
|
2234
|
+
config;
|
|
2235
|
+
cliTerminal;
|
|
2236
|
+
servicePassword;
|
|
2237
|
+
suggestions;
|
|
2238
|
+
commands;
|
|
2239
|
+
loggedOutCommands;
|
|
2240
|
+
loggedInCommands;
|
|
2241
|
+
constructor(logger, config, commands) {
|
|
2242
|
+
this.logger = logger;
|
|
2243
|
+
this.config = config;
|
|
2244
|
+
this.servicePassword = config.resolve("servicePassword");
|
|
2245
|
+
this.suggestions = {
|
|
2246
|
+
login: async (args) => {
|
|
2247
|
+
if (args.length > 2) {
|
|
2248
|
+
return null;
|
|
2249
|
+
}
|
|
2250
|
+
const input = `${args.at(1).label}`;
|
|
2251
|
+
return (!input) ? [] : [{
|
|
2252
|
+
id: input,
|
|
2253
|
+
label: input,
|
|
2254
|
+
masked: true
|
|
2255
|
+
}];
|
|
2256
|
+
},
|
|
2257
|
+
...commands.reduce((acc, command) => {
|
|
2258
|
+
command.name = camelCaseToDash(command.name || command.constructor.name || "");
|
|
2259
|
+
if (!command.name || !command.suggest)
|
|
2260
|
+
return acc;
|
|
2261
|
+
acc[command.name] = async (a, t) => command.suggest(a, t);
|
|
2262
|
+
return acc;
|
|
2263
|
+
}, {})
|
|
2264
|
+
};
|
|
2265
|
+
this.commands = commands.reduce((acc, command) => {
|
|
2266
|
+
if (!command.name)
|
|
2267
|
+
return acc;
|
|
2268
|
+
acc[command.name] = async (a, t, p) => command.execute(a, t, p);
|
|
2269
|
+
return acc;
|
|
2270
|
+
}, {});
|
|
2271
|
+
this.loggedOutCommands = ["login", "clear"];
|
|
2272
|
+
this.loggedInCommands = Object.keys(this.commands);
|
|
2273
|
+
this.loggedInCommands.push("logout");
|
|
2274
|
+
console.log(`Current service password is: ${colorize(this.servicePassword, ConsoleColor.FgGreen)}`);
|
|
2275
|
+
}
|
|
2276
|
+
runCli() {
|
|
2277
|
+
this.cliTerminal = new CliTerminal();
|
|
2278
|
+
this.loadAddons(this.cliTerminal);
|
|
2279
|
+
}
|
|
2280
|
+
loadAddons(terminal) {
|
|
2281
|
+
const isCli = terminal === this.cliTerminal;
|
|
2282
|
+
let loggedIn = isCli;
|
|
2283
|
+
const commands = isCli ? {
|
|
2284
|
+
logout: async () => {
|
|
2285
|
+
terminal.dispose();
|
|
2286
|
+
}
|
|
2287
|
+
} : {
|
|
2288
|
+
login: async (args, terminal) => {
|
|
2289
|
+
if (args.at(1).label === this.servicePassword) {
|
|
2290
|
+
loggedIn = true;
|
|
2291
|
+
terminal.writeln("Logged in as admin");
|
|
2292
|
+
}
|
|
2293
|
+
else {
|
|
2294
|
+
throw new Error("Invalid login");
|
|
2295
|
+
}
|
|
2296
|
+
},
|
|
2297
|
+
logout: async (args, terminal) => {
|
|
2298
|
+
loggedIn = false;
|
|
2299
|
+
terminal.writeln("Logged out");
|
|
2300
|
+
}
|
|
2301
|
+
};
|
|
2302
|
+
const addon = new CommandsAddon({
|
|
2303
|
+
commands: {
|
|
2304
|
+
...commands,
|
|
2305
|
+
...this.commands
|
|
2306
|
+
},
|
|
2307
|
+
suggestCommands: async () => {
|
|
2308
|
+
if (loggedIn) {
|
|
2309
|
+
return this.loggedInCommands;
|
|
2310
|
+
}
|
|
2311
|
+
return this.loggedOutCommands;
|
|
2312
|
+
},
|
|
2313
|
+
suggestions: this.suggestions
|
|
2314
|
+
});
|
|
2315
|
+
terminal.loadAddon(addon);
|
|
2316
|
+
}
|
|
2317
|
+
};
|
|
2318
|
+
TerminalManager = __decorate([
|
|
2319
|
+
singleton(),
|
|
2320
|
+
__param(2, injectAll(TERMINAL_COMMAND)),
|
|
2321
|
+
__metadata("design:paramtypes", [Logger,
|
|
2322
|
+
Configuration, Array])
|
|
2323
|
+
], TerminalManager);
|
|
2324
|
+
|
|
2086
2325
|
const express = express_;
|
|
2087
2326
|
let BackendProvider = class BackendProvider {
|
|
2088
2327
|
config;
|
|
@@ -2131,6 +2370,11 @@ let BackendProvider = class BackendProvider {
|
|
|
2131
2370
|
}
|
|
2132
2371
|
async quickStart() {
|
|
2133
2372
|
const port = this.config.resolve("appPort");
|
|
2373
|
+
const isCli = this.config.isCli;
|
|
2374
|
+
if (isCli) {
|
|
2375
|
+
this.container.resolve(TerminalManager).runCli();
|
|
2376
|
+
return `Running CLI mode`;
|
|
2377
|
+
}
|
|
2134
2378
|
const isWorker = this.config.resolve("isWorker");
|
|
2135
2379
|
if (isWorker || this.config.resolve("startWorker")) {
|
|
2136
2380
|
await this.container.resolve(JobManager).startProcessing();
|
|
@@ -2714,86 +2958,6 @@ MemoryCache = __decorate([
|
|
|
2714
2958
|
__metadata("design:paramtypes", [Cache])
|
|
2715
2959
|
], MemoryCache);
|
|
2716
2960
|
|
|
2717
|
-
let TerminalManager = class TerminalManager {
|
|
2718
|
-
logger;
|
|
2719
|
-
config;
|
|
2720
|
-
servicePassword;
|
|
2721
|
-
suggestions;
|
|
2722
|
-
commands;
|
|
2723
|
-
loggedOutCommands;
|
|
2724
|
-
loggedInCommands;
|
|
2725
|
-
constructor(logger, config, commands) {
|
|
2726
|
-
this.logger = logger;
|
|
2727
|
-
this.config = config;
|
|
2728
|
-
this.servicePassword = config.resolve("servicePassword");
|
|
2729
|
-
this.suggestions = {
|
|
2730
|
-
login: async (args) => {
|
|
2731
|
-
if (args.length > 2) {
|
|
2732
|
-
return null;
|
|
2733
|
-
}
|
|
2734
|
-
const input = `${args.at(1).label}`;
|
|
2735
|
-
return (!input) ? [] : [{
|
|
2736
|
-
id: input,
|
|
2737
|
-
label: input,
|
|
2738
|
-
masked: true
|
|
2739
|
-
}];
|
|
2740
|
-
},
|
|
2741
|
-
...commands.reduce((acc, command) => {
|
|
2742
|
-
command.name = camelCaseToDash(command.name || command.constructor.name || "");
|
|
2743
|
-
if (!command.name || !command.suggest)
|
|
2744
|
-
return acc;
|
|
2745
|
-
acc[command.name] = async (a, t) => command.suggest(a, t);
|
|
2746
|
-
return acc;
|
|
2747
|
-
}, {})
|
|
2748
|
-
};
|
|
2749
|
-
this.commands = commands.reduce((acc, command) => {
|
|
2750
|
-
if (!command.name)
|
|
2751
|
-
return acc;
|
|
2752
|
-
acc[command.name] = async (a, t) => command.execute(a, t);
|
|
2753
|
-
return acc;
|
|
2754
|
-
}, {});
|
|
2755
|
-
this.loggedOutCommands = ["login", "clear"];
|
|
2756
|
-
this.loggedInCommands = Object.keys(this.commands);
|
|
2757
|
-
this.loggedInCommands.push("logout");
|
|
2758
|
-
console.log(`Current service password is: ${colorize(this.servicePassword, ConsoleColor.FgGreen)}`);
|
|
2759
|
-
}
|
|
2760
|
-
loadAddons(terminal) {
|
|
2761
|
-
let loggedIn = false;
|
|
2762
|
-
const addon = new CommandsAddon({
|
|
2763
|
-
commands: {
|
|
2764
|
-
login: async (args, terminal) => {
|
|
2765
|
-
if (args.at(1).label === this.servicePassword) {
|
|
2766
|
-
loggedIn = true;
|
|
2767
|
-
terminal.writeln("Logged in as admin");
|
|
2768
|
-
}
|
|
2769
|
-
else {
|
|
2770
|
-
throw new Error("Invalid login");
|
|
2771
|
-
}
|
|
2772
|
-
},
|
|
2773
|
-
logout: async (args, terminal) => {
|
|
2774
|
-
loggedIn = false;
|
|
2775
|
-
terminal.writeln("Logged out");
|
|
2776
|
-
},
|
|
2777
|
-
...this.commands
|
|
2778
|
-
},
|
|
2779
|
-
suggestCommands: async () => {
|
|
2780
|
-
if (loggedIn) {
|
|
2781
|
-
return this.loggedInCommands;
|
|
2782
|
-
}
|
|
2783
|
-
return this.loggedOutCommands;
|
|
2784
|
-
},
|
|
2785
|
-
suggestions: this.suggestions
|
|
2786
|
-
});
|
|
2787
|
-
terminal.loadAddon(addon);
|
|
2788
|
-
}
|
|
2789
|
-
};
|
|
2790
|
-
TerminalManager = __decorate([
|
|
2791
|
-
singleton(),
|
|
2792
|
-
__param(2, injectAll(TERMINAL_COMMAND)),
|
|
2793
|
-
__metadata("design:paramtypes", [Logger,
|
|
2794
|
-
Configuration, Array])
|
|
2795
|
-
], TerminalManager);
|
|
2796
|
-
|
|
2797
2961
|
let TokenGenerator = class TokenGenerator {
|
|
2798
2962
|
chars;
|
|
2799
2963
|
constructor() {
|
|
@@ -3573,7 +3737,7 @@ ProgressController = __decorate([
|
|
|
3573
3737
|
__metadata("design:paramtypes", [Progresses, Server])
|
|
3574
3738
|
], ProgressController);
|
|
3575
3739
|
|
|
3576
|
-
class
|
|
3740
|
+
class SocketTerminal {
|
|
3577
3741
|
client;
|
|
3578
3742
|
addons;
|
|
3579
3743
|
files$;
|
|
@@ -3667,7 +3831,7 @@ let TerminalController = class TerminalController {
|
|
|
3667
3831
|
this.terminals = {};
|
|
3668
3832
|
}
|
|
3669
3833
|
async terminalInit(client) {
|
|
3670
|
-
const terminal = new
|
|
3834
|
+
const terminal = new SocketTerminal(client);
|
|
3671
3835
|
this.manager.loadAddons(terminal);
|
|
3672
3836
|
this.terminals[client.id] = terminal;
|
|
3673
3837
|
client.on("disconnect", () => terminal.dispose());
|
|
@@ -3986,9 +4150,50 @@ FixturesCommand = __decorate([
|
|
|
3986
4150
|
__metadata("design:paramtypes", [Fixtures])
|
|
3987
4151
|
], FixturesCommand);
|
|
3988
4152
|
|
|
4153
|
+
let MoveAssetsCommand = class MoveAssetsCommand {
|
|
4154
|
+
assets;
|
|
4155
|
+
name = "move-assets";
|
|
4156
|
+
constructor(assets) {
|
|
4157
|
+
this.assets = assets;
|
|
4158
|
+
}
|
|
4159
|
+
async execute(args, terminal, progress) {
|
|
4160
|
+
await promiseTimeout(1000);
|
|
4161
|
+
const from = `${args.at(1).id}`;
|
|
4162
|
+
const to = `${args.at(2).id}`;
|
|
4163
|
+
const assets = await this.assets.findMany(from === this.assets.missingDriver ? {
|
|
4164
|
+
$or: [
|
|
4165
|
+
{ driverId: from },
|
|
4166
|
+
{ driverId: { "$exists": false } }
|
|
4167
|
+
]
|
|
4168
|
+
} : { driverId: from });
|
|
4169
|
+
progress.setMax(assets.length);
|
|
4170
|
+
for (const asset of assets) {
|
|
4171
|
+
await asset.move(to);
|
|
4172
|
+
progress.advance();
|
|
4173
|
+
}
|
|
4174
|
+
terminal.writeln(colorize(`Assets successfully moved to: ${to}`, ConsoleColor.FgGreen));
|
|
4175
|
+
}
|
|
4176
|
+
async suggest(args) {
|
|
4177
|
+
if (args.length > 3) {
|
|
4178
|
+
return null;
|
|
4179
|
+
}
|
|
4180
|
+
// Replace regex special characters
|
|
4181
|
+
const prev = args.length === 3 ? args.at(1) : null;
|
|
4182
|
+
const id = regexEscape(args.search);
|
|
4183
|
+
const regex = new RegExp(id, "g");
|
|
4184
|
+
return this.assets.drivers.filter(d => d.match(regex) && (!prev || d !== prev.id));
|
|
4185
|
+
}
|
|
4186
|
+
};
|
|
4187
|
+
MoveAssetsCommand = __decorate([
|
|
4188
|
+
injectable(),
|
|
4189
|
+
scoped(Lifecycle.ContainerScoped),
|
|
4190
|
+
__metadata("design:paramtypes", [Assets])
|
|
4191
|
+
], MoveAssetsCommand);
|
|
4192
|
+
|
|
3989
4193
|
const commands = [
|
|
3990
4194
|
ClearCommand,
|
|
3991
|
-
FixturesCommand
|
|
4195
|
+
FixturesCommand,
|
|
4196
|
+
MoveAssetsCommand
|
|
3992
4197
|
];
|
|
3993
4198
|
|
|
3994
4199
|
let TtlFixture = class TtlFixture {
|
|
@@ -4022,11 +4227,11 @@ let AssetGridDriver = class AssetGridDriver {
|
|
|
4022
4227
|
openUploadStream(filename, opts) {
|
|
4023
4228
|
return this.bucket.openUploadStream(filename, opts);
|
|
4024
4229
|
}
|
|
4025
|
-
openDownloadStream(
|
|
4026
|
-
return this.bucket.openDownloadStream(
|
|
4230
|
+
openDownloadStream(asset) {
|
|
4231
|
+
return this.bucket.openDownloadStream(asset.streamId);
|
|
4027
4232
|
}
|
|
4028
|
-
delete(
|
|
4029
|
-
return this.bucket.delete(
|
|
4233
|
+
delete(asset) {
|
|
4234
|
+
return this.bucket.delete(asset.streamId);
|
|
4030
4235
|
}
|
|
4031
4236
|
};
|
|
4032
4237
|
AssetGridDriver = __decorate([
|
|
@@ -4040,29 +4245,31 @@ let AssetLocalDriver = class AssetLocalDriver {
|
|
|
4040
4245
|
this.dir = dir;
|
|
4041
4246
|
}
|
|
4042
4247
|
openUploadStream(filename, opts) {
|
|
4043
|
-
const id = new
|
|
4248
|
+
const id = new ObjectId$1();
|
|
4044
4249
|
const dir = `${this.dir}/${id.toHexString()}`;
|
|
4045
4250
|
mkdirSync(dir, { recursive: true });
|
|
4046
|
-
const stream = createWriteStream(
|
|
4047
|
-
stream.id = id;
|
|
4251
|
+
const stream = createWriteStream(this.getPath(id, filename, opts.extension));
|
|
4048
4252
|
stream.done = false;
|
|
4049
4253
|
stream.on('finish', () => {
|
|
4050
|
-
|
|
4051
|
-
writeFile$2(`${dir}/metadata.json`, JSON.stringify(opts?.metadata || {}));
|
|
4254
|
+
stream.id = id;
|
|
4052
4255
|
stream.done = true;
|
|
4256
|
+
writeFileSync(`${dir}/metadata.json`, JSON.stringify(opts?.metadata || {}));
|
|
4053
4257
|
});
|
|
4054
4258
|
return stream;
|
|
4055
4259
|
}
|
|
4056
|
-
openDownloadStream(
|
|
4057
|
-
return createReadStream(
|
|
4260
|
+
openDownloadStream(asset) {
|
|
4261
|
+
return createReadStream(this.getPath(asset.streamId, asset.filename, asset.metadata.extension), { autoClose: true, emitClose: true });
|
|
4058
4262
|
}
|
|
4059
|
-
delete(
|
|
4060
|
-
return rm(
|
|
4263
|
+
delete(asset) {
|
|
4264
|
+
return rm(this.getPath(asset.streamId, asset.filename, asset.metadata.extension), { recursive: true, force: true });
|
|
4265
|
+
}
|
|
4266
|
+
getPath(id, name, ext) {
|
|
4267
|
+
return join(this.dir, id.toHexString(), `${name}.${ext}`);
|
|
4061
4268
|
}
|
|
4062
4269
|
};
|
|
4063
4270
|
AssetLocalDriver = __decorate([
|
|
4064
4271
|
injectable(),
|
|
4065
|
-
__param(0, inject(
|
|
4272
|
+
__param(0, inject(ASSET_LOCAL_DIR)),
|
|
4066
4273
|
__metadata("design:paramtypes", [String])
|
|
4067
4274
|
], AssetLocalDriver);
|
|
4068
4275
|
|
|
@@ -4098,74 +4305,6 @@ function createFallbackReadable(primary, fallbackFactory) {
|
|
|
4098
4305
|
});
|
|
4099
4306
|
return proxy;
|
|
4100
4307
|
}
|
|
4101
|
-
/**
|
|
4102
|
-
* Creates a Writable proxy that switches to a fallback destination on error.
|
|
4103
|
-
* @param primary The initial Writable destination.
|
|
4104
|
-
* @param fallbackFactory A function that returns a new Writable destination.
|
|
4105
|
-
*/
|
|
4106
|
-
function createFallbackWritable(primary, fallbackFactory) {
|
|
4107
|
-
// 1. The Proxy acts as the stable "entry point" for your data
|
|
4108
|
-
const proxy = new PassThrough();
|
|
4109
|
-
let currentDestination = primary;
|
|
4110
|
-
let hasSwitched = false;
|
|
4111
|
-
// Function to handle the swap
|
|
4112
|
-
const handleSwitch = (err) => {
|
|
4113
|
-
if (hasSwitched)
|
|
4114
|
-
return; // Prevent infinite loops if fallback also fails
|
|
4115
|
-
hasSwitched = true;
|
|
4116
|
-
// 2. Unpipe from the failed stream and destroy it
|
|
4117
|
-
proxy.unpipe(currentDestination);
|
|
4118
|
-
currentDestination.destroy();
|
|
4119
|
-
// 3. Create the new destination and pipe the remaining data to it
|
|
4120
|
-
const fallback = fallbackFactory();
|
|
4121
|
-
currentDestination = fallback;
|
|
4122
|
-
// Pipe the proxy into the fallback
|
|
4123
|
-
proxy.pipe(fallback);
|
|
4124
|
-
// Ensure errors on the fallback are bubbled up
|
|
4125
|
-
fallback.on('error', (fallbackErr) => {
|
|
4126
|
-
proxy.emit('error', fallbackErr);
|
|
4127
|
-
});
|
|
4128
|
-
};
|
|
4129
|
-
// Initial setup
|
|
4130
|
-
primary.on('error', handleSwitch);
|
|
4131
|
-
proxy.on('finish', () => {
|
|
4132
|
-
const final = proxy;
|
|
4133
|
-
final.id = currentDestination.id;
|
|
4134
|
-
final.done = true;
|
|
4135
|
-
});
|
|
4136
|
-
proxy.pipe(primary);
|
|
4137
|
-
return proxy;
|
|
4138
|
-
}
|
|
4139
|
-
|
|
4140
|
-
let AssetFallbackDriver = class AssetFallbackDriver {
|
|
4141
|
-
main;
|
|
4142
|
-
fallback;
|
|
4143
|
-
constructor(main, fallback) {
|
|
4144
|
-
this.main = main;
|
|
4145
|
-
this.fallback = fallback;
|
|
4146
|
-
}
|
|
4147
|
-
openDownloadStream(id) {
|
|
4148
|
-
return createFallbackReadable(this.main.openDownloadStream(id), () => this.fallback.openDownloadStream(id));
|
|
4149
|
-
}
|
|
4150
|
-
openUploadStream(filename, opts) {
|
|
4151
|
-
return createFallbackWritable(this.main.openUploadStream(filename, opts), () => this.fallback.openUploadStream(filename, opts));
|
|
4152
|
-
}
|
|
4153
|
-
async delete(id) {
|
|
4154
|
-
try {
|
|
4155
|
-
await this.main.delete(id);
|
|
4156
|
-
}
|
|
4157
|
-
catch (e) {
|
|
4158
|
-
console.log("Failed to delete from primary: ", e.message);
|
|
4159
|
-
await this.fallback.delete(id);
|
|
4160
|
-
}
|
|
4161
|
-
}
|
|
4162
|
-
};
|
|
4163
|
-
AssetFallbackDriver = __decorate([
|
|
4164
|
-
injectable(),
|
|
4165
|
-
__param(0, inject(ASSET_MAIN_DRIVER)),
|
|
4166
|
-
__param(1, inject(ASSET_FALLBACK_DRIVER)),
|
|
4167
|
-
__metadata("design:paramtypes", [Object, Object])
|
|
4168
|
-
], AssetFallbackDriver);
|
|
4169
4308
|
|
|
4170
4309
|
let AssetStorageProxyDriver = class AssetStorageProxyDriver {
|
|
4171
4310
|
config;
|
|
@@ -4176,12 +4315,9 @@ let AssetStorageProxyDriver = class AssetStorageProxyDriver {
|
|
|
4176
4315
|
this.baseUrl = this.config.resolve("storageProxyUri");
|
|
4177
4316
|
this.url = this.baseUrl + this.config.resolve("storageProxyBucket");
|
|
4178
4317
|
}
|
|
4179
|
-
openDownloadStream(id) {
|
|
4180
|
-
return got.stream.get(this.getUrl(id));
|
|
4181
|
-
}
|
|
4182
4318
|
openUploadStream(_, opts) {
|
|
4183
4319
|
const id = new ObjectId$1();
|
|
4184
|
-
const stream = got.stream.put(this.getUrl(id), { headers: {
|
|
4320
|
+
const stream = got.stream.put(this.getUrl(id, opts.extension), { headers: {
|
|
4185
4321
|
'Content-Type': opts?.contentType || 'application/octet-stream'
|
|
4186
4322
|
} });
|
|
4187
4323
|
stream.done = false;
|
|
@@ -4191,12 +4327,19 @@ let AssetStorageProxyDriver = class AssetStorageProxyDriver {
|
|
|
4191
4327
|
});
|
|
4192
4328
|
return stream;
|
|
4193
4329
|
}
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
await got.delete(this.getUrl(id));
|
|
4330
|
+
openDownloadStream(asset) {
|
|
4331
|
+
return createFallbackReadable(got.stream.get(this.getUrl(asset.streamId, asset.metadata.extension)), () => got.stream.get(this.getUrl(asset.streamId)));
|
|
4197
4332
|
}
|
|
4198
|
-
|
|
4199
|
-
|
|
4333
|
+
async delete(asset) {
|
|
4334
|
+
try {
|
|
4335
|
+
await got.delete(this.getUrl(asset.streamId, asset.metadata.extension));
|
|
4336
|
+
}
|
|
4337
|
+
catch (e) {
|
|
4338
|
+
await got.delete(this.getUrl(asset.streamId));
|
|
4339
|
+
}
|
|
4340
|
+
}
|
|
4341
|
+
getUrl(id, ext) {
|
|
4342
|
+
return !ext ? `${this.url}/${id.toHexString()}` : `${this.url}/${id.toHexString()}.${ext}`;
|
|
4200
4343
|
}
|
|
4201
4344
|
};
|
|
4202
4345
|
AssetStorageProxyDriver = __decorate([
|
|
@@ -4581,8 +4724,10 @@ function createServices() {
|
|
|
4581
4724
|
new Parameter("mongoDb", "node-backend"),
|
|
4582
4725
|
new Parameter("mongoUser", null),
|
|
4583
4726
|
new Parameter("mongoPassword", null),
|
|
4584
|
-
new Parameter("storageProxyUri", "http://localhost:4500/",
|
|
4727
|
+
new Parameter("storageProxyUri", "http://localhost:4500/files", prepareUrlSlash),
|
|
4585
4728
|
new Parameter("storageProxyBucket", "something"),
|
|
4729
|
+
new Parameter("assetsMainDriver", "grid"),
|
|
4730
|
+
new Parameter("assetsMissingDriver", "grid"),
|
|
4586
4731
|
new Parameter("nodeEnv", "production"),
|
|
4587
4732
|
new Parameter("appPort", 80),
|
|
4588
4733
|
new Parameter("zmqPort", 3000),
|
|
@@ -4752,17 +4897,16 @@ async function setupBackend(config, providers, parent) {
|
|
|
4752
4897
|
diContainer.register(OPENAPI_VALIDATION, {
|
|
4753
4898
|
useValue: config.customValidation || (() => null)
|
|
4754
4899
|
});
|
|
4755
|
-
diContainer.register(
|
|
4900
|
+
diContainer.register(ASSET_LOCAL_DIR, {
|
|
4756
4901
|
useValue: config.assetLocalDir || "assets_files"
|
|
4757
4902
|
});
|
|
4758
|
-
diContainer.register(
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
useClass: config.assetFallbackDriver || AssetLocalDriver
|
|
4903
|
+
diContainer.register(ASSET_DRIVER_FACTORIES, {
|
|
4904
|
+
useValue: {
|
|
4905
|
+
grid: container => container.resolve(AssetGridDriver),
|
|
4906
|
+
storageProxy: container => container.resolve(AssetStorageProxyDriver),
|
|
4907
|
+
local: container => container.resolve(AssetLocalDriver),
|
|
4908
|
+
...(config.assetDrivers || {}),
|
|
4909
|
+
}
|
|
4766
4910
|
});
|
|
4767
4911
|
diContainers.appContainer = diContainers.appContainer || diContainer;
|
|
4768
4912
|
// Authentication
|