@nu-art/thunderstorm-backend 0.400.5
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/_entity/app-config/ModuleBE_AppConfigAPI.d.ts +9 -0
- package/_entity/app-config/ModuleBE_AppConfigAPI.js +20 -0
- package/_entity/app-config/ModuleBE_AppConfigDB.d.ts +27 -0
- package/_entity/app-config/ModuleBE_AppConfigDB.js +91 -0
- package/_entity/app-config/index.d.ts +2 -0
- package/_entity/app-config/index.js +2 -0
- package/_entity/app-config/module-pack.d.ts +2 -0
- package/_entity/app-config/module-pack.js +3 -0
- package/_entity/backup-doc/ModuleBE_BackupDocDB.d.ts +52 -0
- package/_entity/backup-doc/ModuleBE_BackupDocDB.js +350 -0
- package/_entity/backup-doc/ModuleBE_BackupScheduler.d.ts +7 -0
- package/_entity/backup-doc/ModuleBE_BackupScheduler.js +14 -0
- package/_entity/backup-doc/index.d.ts +3 -0
- package/_entity/backup-doc/index.js +3 -0
- package/_entity/backup-doc/module-pack.d.ts +2 -0
- package/_entity/backup-doc/module-pack.js +3 -0
- package/_entity/editable-test/ModuleBE_EditableTestDB.d.ts +8 -0
- package/_entity/editable-test/ModuleBE_EditableTestDB.js +8 -0
- package/_entity/editable-test/index.d.ts +1 -0
- package/_entity/editable-test/index.js +1 -0
- package/_entity/editable-test/module-pack.d.ts +1 -0
- package/_entity/editable-test/module-pack.js +3 -0
- package/_entity.d.ts +3 -0
- package/_entity.js +3 -0
- package/core/BaseStorm.d.ts +17 -0
- package/core/BaseStorm.js +77 -0
- package/core/Storm.d.ts +15 -0
- package/core/Storm.js +93 -0
- package/core/db-def.d.ts +10 -0
- package/core/db-def.js +11 -0
- package/core/default-storm.d.ts +3 -0
- package/core/default-storm.js +30 -0
- package/core/storm-modulepack.d.ts +3 -0
- package/core/storm-modulepack.js +20 -0
- package/core/typed-api.d.ts +7 -0
- package/core/typed-api.js +46 -0
- package/exceptions.d.ts +1 -0
- package/exceptions.js +21 -0
- package/index.d.ts +27 -0
- package/index.js +48 -0
- package/modules/CleanupScheduler.d.ts +14 -0
- package/modules/CleanupScheduler.js +50 -0
- package/modules/ModuleBE_APIs.d.ts +11 -0
- package/modules/ModuleBE_APIs.js +19 -0
- package/modules/ModuleBE_CSVParser.d.ts +9 -0
- package/modules/ModuleBE_CSVParser.js +50 -0
- package/modules/ModuleBE_ForceUpgrade.d.ts +21 -0
- package/modules/ModuleBE_ForceUpgrade.js +70 -0
- package/modules/ModuleBE_ServerInfo.d.ts +20 -0
- package/modules/ModuleBE_ServerInfo.js +76 -0
- package/modules/_imports.d.ts +6 -0
- package/modules/_imports.js +26 -0
- package/modules/_tdb/service-accounts.d.ts +19 -0
- package/modules/_tdb/service-accounts.js +2 -0
- package/modules/action-processor/Action_SetupProject.d.ts +9 -0
- package/modules/action-processor/Action_SetupProject.js +23 -0
- package/modules/action-processor/ModuleBE_ActionProcessor.d.ts +11 -0
- package/modules/action-processor/ModuleBE_ActionProcessor.js +67 -0
- package/modules/action-processor/types.d.ts +10 -0
- package/modules/action-processor/types.js +1 -0
- package/modules/archiving/ModuleBE_Archiving.d.ts +119 -0
- package/modules/archiving/ModuleBE_Archiving.js +236 -0
- package/modules/collection-actions/ModuleBE_CollectionActions.d.ts +12 -0
- package/modules/collection-actions/ModuleBE_CollectionActions.js +69 -0
- package/modules/collection-actions/dispatcher.d.ts +7 -0
- package/modules/collection-actions/dispatcher.js +2 -0
- package/modules/db-api-gen/ModuleBE_BaseApi.d.ts +16 -0
- package/modules/db-api-gen/ModuleBE_BaseApi.js +74 -0
- package/modules/db-api-gen/ModuleBE_BaseDB.d.ts +78 -0
- package/modules/db-api-gen/ModuleBE_BaseDB.js +298 -0
- package/modules/http/AxiosHttpModule.d.ts +25 -0
- package/modules/http/AxiosHttpModule.js +132 -0
- package/modules/http/types.d.ts +6 -0
- package/modules/http/types.js +1 -0
- package/modules/proxy/ModuleBE_RemoteProxy.d.ts +35 -0
- package/modules/proxy/ModuleBE_RemoteProxy.js +86 -0
- package/modules/proxy/RemoteProxyCaller.d.ts +19 -0
- package/modules/proxy/RemoteProxyCaller.js +82 -0
- package/modules/proxy/assert-secret-middleware.d.ts +2 -0
- package/modules/proxy/assert-secret-middleware.js +24 -0
- package/modules/server/HeaderKey.d.ts +8 -0
- package/modules/server/HeaderKey.js +41 -0
- package/modules/server/HttpServer.d.ts +41 -0
- package/modules/server/HttpServer.js +223 -0
- package/modules/server/consts.d.ts +13 -0
- package/modules/server/consts.js +9 -0
- package/modules/server/route-resolvers/RouteResolver_Dummy.d.ts +7 -0
- package/modules/server/route-resolvers/RouteResolver_Dummy.js +34 -0
- package/modules/server/route-resolvers/RouteResolver_ModulePath.d.ts +22 -0
- package/modules/server/route-resolvers/RouteResolver_ModulePath.js +84 -0
- package/modules/server/route-resolvers/index.d.ts +7 -0
- package/modules/server/route-resolvers/index.js +21 -0
- package/modules/server/server-api.d.ts +85 -0
- package/modules/server/server-api.js +362 -0
- package/modules/server/server-errors.d.ts +4 -0
- package/modules/server/server-errors.js +79 -0
- package/modules/sync-env/ModuleBE_SyncEnv.d.ts +36 -0
- package/modules/sync-env/ModuleBE_SyncEnv.js +212 -0
- package/modules/sync-manager/ModuleBE_SyncManager.d.ts +63 -0
- package/modules/sync-manager/ModuleBE_SyncManager.js +254 -0
- package/package.json +104 -0
- package/shared.d.ts +1 -0
- package/shared.js +21 -0
- package/test/StormTest.d.ts +23 -0
- package/test/StormTest.js +49 -0
- package/utils/file.d.ts +2 -0
- package/utils/file.js +29 -0
- package/utils/promisify-request.d.ts +3 -0
- package/utils/promisify-request.js +33 -0
- package/utils/types.d.ts +11 -0
- package/utils/types.js +21 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Thunderstorm is a full web app framework!
|
|
3
|
+
*
|
|
4
|
+
* Typescript & Express backend infrastructure that natively runs on firebase function
|
|
5
|
+
* Typescript & React frontend infrastructure
|
|
6
|
+
*
|
|
7
|
+
* Copyright (C) 2020 Adam van der Kruk aka TacB0sS
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
import { __stringify, ApiException, composeUrl, ImplementationMissingException, MimeType_json, Module, } from '@nu-art/ts-common';
|
|
22
|
+
import { promisifyRequest } from '../../utils/promisify-request.js';
|
|
23
|
+
import { HeaderKey_ContentType } from '../../shared.js';
|
|
24
|
+
export class RemoteProxyCaller extends Module {
|
|
25
|
+
init() {
|
|
26
|
+
if (!this.config)
|
|
27
|
+
throw new ImplementationMissingException('MUST specify config for this module!!');
|
|
28
|
+
if (!this.config.proxyId)
|
|
29
|
+
throw new ImplementationMissingException('MUST specify the proxyId for the proxy caller!!');
|
|
30
|
+
if (!this.config.url)
|
|
31
|
+
throw new ImplementationMissingException('MUST specify the url for the remote server!!');
|
|
32
|
+
if (!this.config.secret)
|
|
33
|
+
throw new ImplementationMissingException('MUST specify the secret for the remote server!!');
|
|
34
|
+
if (!this.config.secretHeaderName)
|
|
35
|
+
this.config.secretHeaderName = 'x-secret';
|
|
36
|
+
if (!this.config.proxyHeaderName)
|
|
37
|
+
this.config.proxyHeaderName = 'x-proxy';
|
|
38
|
+
}
|
|
39
|
+
executeGetRequest = async (url, _params, _headers) => {
|
|
40
|
+
const proxyRequest = {
|
|
41
|
+
headers: {
|
|
42
|
+
..._headers,
|
|
43
|
+
[this.config.secretHeaderName]: this.config.secret,
|
|
44
|
+
[this.config.proxyHeaderName]: this.config.proxyId,
|
|
45
|
+
},
|
|
46
|
+
uri: `${composeUrl(`${this.config.url}${url}`, _params)}`,
|
|
47
|
+
method: 'GET',
|
|
48
|
+
json: true
|
|
49
|
+
};
|
|
50
|
+
return await this.executeRequest(proxyRequest);
|
|
51
|
+
};
|
|
52
|
+
executePostRequest = async (url, body, _headers) => {
|
|
53
|
+
const proxyRequest = {
|
|
54
|
+
headers: {
|
|
55
|
+
..._headers,
|
|
56
|
+
[HeaderKey_ContentType]: MimeType_json,
|
|
57
|
+
[this.config.secretHeaderName]: this.config.secret,
|
|
58
|
+
[this.config.proxyHeaderName]: this.config.proxyId,
|
|
59
|
+
},
|
|
60
|
+
json: true,
|
|
61
|
+
uri: `${composeUrl(`${this.config.url}${url}`)}`,
|
|
62
|
+
body: body,
|
|
63
|
+
method: 'POST'
|
|
64
|
+
};
|
|
65
|
+
return this.executeRequest(proxyRequest);
|
|
66
|
+
};
|
|
67
|
+
executeRequest = async (proxyRequest) => {
|
|
68
|
+
const response = await promisifyRequest(proxyRequest, false);
|
|
69
|
+
if (proxyRequest.headers)
|
|
70
|
+
delete proxyRequest.headers[this.config.secretHeaderName];
|
|
71
|
+
if (response.statusCode !== 200) {
|
|
72
|
+
const errorResponse = response.body;
|
|
73
|
+
if (!errorResponse)
|
|
74
|
+
throw new ApiException(500, `Extraneous error ${__stringify(response)}, Proxy Request: ${__stringify(proxyRequest, true)}`);
|
|
75
|
+
const e = new ApiException(response.statusCode, `Redirect proxy error: ${errorResponse.debugMessage} \n Proxy Request: ${__stringify(proxyRequest, true)}`);
|
|
76
|
+
if (errorResponse.error)
|
|
77
|
+
e.setErrorBody(errorResponse.error);
|
|
78
|
+
throw e;
|
|
79
|
+
}
|
|
80
|
+
return response.toJSON().body;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Thunderstorm is a full web app framework!
|
|
3
|
+
*
|
|
4
|
+
* Typescript & Express backend infrastructure that natively runs on firebase function
|
|
5
|
+
* Typescript & React frontend infrastructure
|
|
6
|
+
*
|
|
7
|
+
* Copyright (C) 2020 Adam van der Kruk aka TacB0sS
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
import { ModuleBE_RemoteProxy } from './ModuleBE_RemoteProxy.js';
|
|
22
|
+
export const AssertSecretMiddleware = async () => {
|
|
23
|
+
ModuleBE_RemoteProxy.assertSecret();
|
|
24
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Thunderstorm is a full web app framework!
|
|
3
|
+
*
|
|
4
|
+
* Typescript & Express backend infrastructure that natively runs on firebase function
|
|
5
|
+
* Typescript & React frontend infrastructure
|
|
6
|
+
*
|
|
7
|
+
* Copyright (C) 2020 Adam van der Kruk aka TacB0sS
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
import { MemKey_HttpRequest } from './consts.js';
|
|
22
|
+
import { ApiException } from '@nu-art/ts-common';
|
|
23
|
+
export class HeaderKey {
|
|
24
|
+
key;
|
|
25
|
+
responseCode;
|
|
26
|
+
processor = (value) => value;
|
|
27
|
+
constructor(key, responseCode = 400) {
|
|
28
|
+
this.key = key.toLowerCase();
|
|
29
|
+
this.responseCode = responseCode;
|
|
30
|
+
}
|
|
31
|
+
get() {
|
|
32
|
+
const value = MemKey_HttpRequest.get().header(this.key);
|
|
33
|
+
if (!value)
|
|
34
|
+
throw new ApiException(this.responseCode, `Missing expected header: ${this.key}`);
|
|
35
|
+
return this.processor(value);
|
|
36
|
+
}
|
|
37
|
+
setProcessor(processor) {
|
|
38
|
+
this.processor = processor;
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Module } from '@nu-art/ts-common';
|
|
2
|
+
import { Express, ExpressRequestHandler, HttpErrorHandler } from '../../utils/types.js';
|
|
3
|
+
import { Firebase_ExpressFunction, TBR_ExpressFunctionInterface } from '@nu-art/firebase-backend';
|
|
4
|
+
type ConfigType = {
|
|
5
|
+
port: number;
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
cors: {
|
|
8
|
+
origins?: string[];
|
|
9
|
+
methods?: string[];
|
|
10
|
+
headers: string[];
|
|
11
|
+
responseHeaders: string[];
|
|
12
|
+
};
|
|
13
|
+
ssl: {
|
|
14
|
+
key: string;
|
|
15
|
+
cert: string;
|
|
16
|
+
};
|
|
17
|
+
bodyParserLimit: number | string;
|
|
18
|
+
};
|
|
19
|
+
export type CustomOrigin = (origin: string | undefined, callback: (err: Error | null, origin?: string) => void) => (boolean | Promise<boolean>);
|
|
20
|
+
export declare class HttpServer_Class extends Module<ConfigType> implements TBR_ExpressFunctionInterface {
|
|
21
|
+
private static readonly expressMiddleware;
|
|
22
|
+
errorMessageComposer: HttpErrorHandler;
|
|
23
|
+
readonly express: Express;
|
|
24
|
+
private server;
|
|
25
|
+
private socketId;
|
|
26
|
+
private customCorsOriginValidator;
|
|
27
|
+
constructor();
|
|
28
|
+
getExpress(): Express;
|
|
29
|
+
getExpressFunction(): Firebase_ExpressFunction;
|
|
30
|
+
setErrorMessageComposer(errorMessageComposer: HttpErrorHandler): void;
|
|
31
|
+
static addMiddleware(middleware: ExpressRequestHandler): typeof HttpServer_Class;
|
|
32
|
+
getBaseUrl(): string;
|
|
33
|
+
setCustomCorsOriginValidator(validator: CustomOrigin): void;
|
|
34
|
+
protected init(): Promise<void>;
|
|
35
|
+
private createServer;
|
|
36
|
+
startServer(): Promise<void>;
|
|
37
|
+
private connectImpl;
|
|
38
|
+
terminate(): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
export declare const HttpServer: HttpServer_Class;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Thunderstorm is a full web app framework!
|
|
3
|
+
*
|
|
4
|
+
* Typescript & Express backend infrastructure that natively runs on firebase function
|
|
5
|
+
* Typescript & React frontend infrastructure
|
|
6
|
+
*
|
|
7
|
+
* Copyright (C) 2020 Adam van der Kruk aka TacB0sS
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Module dependencies.
|
|
23
|
+
*/
|
|
24
|
+
import { createServer as createHttpServer } from 'http';
|
|
25
|
+
import { createServer as createHttpsServer } from 'https';
|
|
26
|
+
import * as fs from 'fs';
|
|
27
|
+
import { addItemToArray, LogLevel, Module } from '@nu-art/ts-common';
|
|
28
|
+
import express from 'express';
|
|
29
|
+
import { DefaultApiErrorMessageComposer } from './server-errors.js';
|
|
30
|
+
import { Firebase_ExpressFunction } from '@nu-art/firebase-backend';
|
|
31
|
+
import { ServerApi } from './server-api.js';
|
|
32
|
+
import compression from 'compression';
|
|
33
|
+
import cors from 'cors';
|
|
34
|
+
const ALL_Methods = [
|
|
35
|
+
'GET',
|
|
36
|
+
'PUT',
|
|
37
|
+
'PATCH',
|
|
38
|
+
'POST',
|
|
39
|
+
'DELETE',
|
|
40
|
+
'OPTIONS'
|
|
41
|
+
];
|
|
42
|
+
const DefaultHeaders = [
|
|
43
|
+
'content-type',
|
|
44
|
+
'content-encoding',
|
|
45
|
+
];
|
|
46
|
+
export class HttpServer_Class extends Module {
|
|
47
|
+
static expressMiddleware = [];
|
|
48
|
+
errorMessageComposer = DefaultApiErrorMessageComposer();
|
|
49
|
+
express;
|
|
50
|
+
server;
|
|
51
|
+
socketId = 0;
|
|
52
|
+
customCorsOriginValidator;
|
|
53
|
+
constructor() {
|
|
54
|
+
super('http-server');
|
|
55
|
+
// this.express = express();
|
|
56
|
+
}
|
|
57
|
+
getExpress() {
|
|
58
|
+
if (this.express)
|
|
59
|
+
return this.express;
|
|
60
|
+
// Originally Express was created in the constructor, and this class is a singleton module, meaning Express is created in the import part of the file that starts Storm.
|
|
61
|
+
// Express now is initialized during the builder of Storm, instead of the import stage of the file.
|
|
62
|
+
// @ts-ignore
|
|
63
|
+
return this.express = express();
|
|
64
|
+
}
|
|
65
|
+
getExpressFunction() {
|
|
66
|
+
return new Firebase_ExpressFunction(this.getExpress());
|
|
67
|
+
}
|
|
68
|
+
setErrorMessageComposer(errorMessageComposer) {
|
|
69
|
+
this.errorMessageComposer = errorMessageComposer;
|
|
70
|
+
}
|
|
71
|
+
static addMiddleware(middleware) {
|
|
72
|
+
HttpServer_Class.expressMiddleware.push(middleware);
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
75
|
+
getBaseUrl() {
|
|
76
|
+
return this.config.baseUrl;
|
|
77
|
+
}
|
|
78
|
+
setCustomCorsOriginValidator(validator) {
|
|
79
|
+
this.customCorsOriginValidator = validator;
|
|
80
|
+
}
|
|
81
|
+
async init() {
|
|
82
|
+
this.setMinLevel(ServerApi.isDebug ? LogLevel.Verbose : LogLevel.Info);
|
|
83
|
+
const baseUrl = this.config.baseUrl;
|
|
84
|
+
if (baseUrl) {
|
|
85
|
+
if (baseUrl.endsWith('/'))
|
|
86
|
+
this.config.baseUrl = baseUrl.substring(0, baseUrl.length - 1);
|
|
87
|
+
this.config.baseUrl = baseUrl.replace(/\/\//g, '/');
|
|
88
|
+
}
|
|
89
|
+
this.getExpress().use((req, res, next) => {
|
|
90
|
+
if (req)
|
|
91
|
+
req.url = req.url.replace(/\/\//g, '/');
|
|
92
|
+
next();
|
|
93
|
+
});
|
|
94
|
+
const parserLimit = this.config.bodyParserLimit;
|
|
95
|
+
if (parserLimit)
|
|
96
|
+
this.getExpress().use(express.json({ limit: parserLimit }));
|
|
97
|
+
this.getExpress().use(compression());
|
|
98
|
+
for (const middleware of HttpServer_Class.expressMiddleware) {
|
|
99
|
+
this.getExpress().use(middleware);
|
|
100
|
+
}
|
|
101
|
+
const _cors = this.config.cors || {};
|
|
102
|
+
_cors.headers = DefaultHeaders.reduce((toRet, item) => {
|
|
103
|
+
if (!toRet.includes(item))
|
|
104
|
+
addItemToArray(toRet, item);
|
|
105
|
+
return toRet;
|
|
106
|
+
}, _cors.headers || []);
|
|
107
|
+
const resolveCorsOrigin = (origin) => {
|
|
108
|
+
let _origin;
|
|
109
|
+
if (!origin)
|
|
110
|
+
return;
|
|
111
|
+
if (typeof origin === 'string')
|
|
112
|
+
_origin = origin;
|
|
113
|
+
else
|
|
114
|
+
_origin = origin[0];
|
|
115
|
+
if (!_cors.origins)
|
|
116
|
+
return _origin;
|
|
117
|
+
for (const allowedOrigin of _cors.origins) {
|
|
118
|
+
if (allowedOrigin === _origin.toLowerCase() ||
|
|
119
|
+
(allowedOrigin.includes('*') && new RegExp(`^${allowedOrigin.replace(/\*/g, '.*')}$`).test(_origin.toLowerCase()))) {
|
|
120
|
+
return _origin;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
this.getExpress().use(cors({
|
|
125
|
+
origin: async (origin, callback) => {
|
|
126
|
+
if (!origin)
|
|
127
|
+
return callback(null);
|
|
128
|
+
const resolvedOrigin = resolveCorsOrigin(origin);
|
|
129
|
+
if (!resolvedOrigin)
|
|
130
|
+
return callback(new Error(`CORS issue!!!\n Origin: '${origin}' does not exist in config: ${JSON.stringify(_cors.origins)}`), undefined);
|
|
131
|
+
if (this.customCorsOriginValidator && !(await this.customCorsOriginValidator?.(origin, callback))) {
|
|
132
|
+
return callback(new Error(`CORS issue!!!\n Origin: '${origin}' is not valid`), undefined);
|
|
133
|
+
}
|
|
134
|
+
callback(null, resolvedOrigin);
|
|
135
|
+
},
|
|
136
|
+
methods: _cors.methods || ALL_Methods,
|
|
137
|
+
allowedHeaders: _cors.headers,
|
|
138
|
+
exposedHeaders: _cors.responseHeaders,
|
|
139
|
+
}));
|
|
140
|
+
this.getExpress().options('*', (req, res) => {
|
|
141
|
+
res.end();
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
createServer() {
|
|
145
|
+
const ssl = this.config.ssl;
|
|
146
|
+
if (!ssl) {
|
|
147
|
+
this.logDebug('starting HTTP server');
|
|
148
|
+
return createHttpServer(this.getExpress());
|
|
149
|
+
}
|
|
150
|
+
this.logDebug('starting HTTPS server');
|
|
151
|
+
let key = ssl.key;
|
|
152
|
+
if (!ssl.key.startsWith('-----BEGIN'))
|
|
153
|
+
key = fs.readFileSync(ssl.key, 'utf8');
|
|
154
|
+
let cert = ssl.cert;
|
|
155
|
+
if (!ssl.cert.startsWith('-----BEGIN'))
|
|
156
|
+
cert = fs.readFileSync(ssl.cert, 'utf8');
|
|
157
|
+
const options = {
|
|
158
|
+
key: key,
|
|
159
|
+
cert: cert,
|
|
160
|
+
rejectUnauthorized: false,
|
|
161
|
+
requestCert: false,
|
|
162
|
+
};
|
|
163
|
+
return createHttpsServer(options, this.getExpress());
|
|
164
|
+
}
|
|
165
|
+
async startServer() {
|
|
166
|
+
return new Promise((resolve, rejected) => {
|
|
167
|
+
this.connectImpl((err) => {
|
|
168
|
+
if (err)
|
|
169
|
+
return rejected(err);
|
|
170
|
+
resolve();
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
connectImpl(onCompletion) {
|
|
175
|
+
this.server = this.createServer();
|
|
176
|
+
this.server.listen(this.config.port);
|
|
177
|
+
this.server.on('connection', (socket) => {
|
|
178
|
+
this.logInfo(`Got a new connection(${this.socketId++}): ${socket}`);
|
|
179
|
+
// Extend socket lifetime for demo purposes
|
|
180
|
+
// socket.setTimeout(4000);
|
|
181
|
+
});
|
|
182
|
+
this.server.on('error', (error) => {
|
|
183
|
+
switch (error.code) {
|
|
184
|
+
case 'EACCES':
|
|
185
|
+
this.logErrorBold(`Server port: ${this.config.port} requires elevated privileges`);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
break;
|
|
188
|
+
case 'EADDRINUSE':
|
|
189
|
+
this.logErrorBold(`Unable to start server port(${this.config.port}) is already in use!`);
|
|
190
|
+
onCompletion(error);
|
|
191
|
+
break;
|
|
192
|
+
default:
|
|
193
|
+
this.logErrorBold(`Error starting server... unknown state: ${error.code}`);
|
|
194
|
+
onCompletion(error);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (error.syscall !== 'listen') {
|
|
198
|
+
onCompletion(error);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
this.server.on('listening', () => {
|
|
203
|
+
const address = this.server.address();
|
|
204
|
+
// Explicit check has to be made due to address.port
|
|
205
|
+
if (!address) {
|
|
206
|
+
this.logDebug(`Exiting !!`);
|
|
207
|
+
process.exit(1);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
this.logDebug(`Server is listening on ${(typeof address === 'string' ? `pipe: ${JSON.stringify(address)}` : `port: ${address.port}`)}`);
|
|
211
|
+
onCompletion();
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
terminate() {
|
|
215
|
+
return new Promise((resolve) => {
|
|
216
|
+
this.server.close(() => {
|
|
217
|
+
this.logInfo('Server is terminated!');
|
|
218
|
+
resolve();
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
export const HttpServer = new HttpServer_Class();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { MemKey } from '@nu-art/ts-common/mem-storage/MemStorage';
|
|
2
|
+
import { QueryParams } from '@nu-art/thunderstorm-shared';
|
|
3
|
+
import { IncomingHttpHeaders } from 'http';
|
|
4
|
+
import { ExpressRequest } from '../../utils/types.js';
|
|
5
|
+
import { ApiResponse } from './server-api.js';
|
|
6
|
+
export declare const MemKey_HttpRequest: MemKey<ExpressRequest>;
|
|
7
|
+
export declare const MemKey_HttpResponse: MemKey<ApiResponse>;
|
|
8
|
+
export declare const MemKey_HttpRequestHeaders: MemKey<IncomingHttpHeaders>;
|
|
9
|
+
export declare const MemKey_HttpRequestBody: MemKey<any>;
|
|
10
|
+
export declare const MemKey_HttpRequestQuery: MemKey<QueryParams>;
|
|
11
|
+
export declare const MemKey_HttpRequestUrl: MemKey<string>;
|
|
12
|
+
export declare const MemKey_HttpRequestPath: MemKey<string>;
|
|
13
|
+
export declare const MemKey_HttpRequestMethod: MemKey<any>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { MemKey } from '@nu-art/ts-common/mem-storage/MemStorage';
|
|
2
|
+
export const MemKey_HttpRequest = new MemKey('http-request', true);
|
|
3
|
+
export const MemKey_HttpResponse = new MemKey('http-response', true);
|
|
4
|
+
export const MemKey_HttpRequestHeaders = new MemKey('http-request--incoming-headers', true);
|
|
5
|
+
export const MemKey_HttpRequestBody = new MemKey('http-request--incoming-body', true);
|
|
6
|
+
export const MemKey_HttpRequestQuery = new MemKey('http-request--query', true);
|
|
7
|
+
export const MemKey_HttpRequestUrl = new MemKey('http-request--url', true);
|
|
8
|
+
export const MemKey_HttpRequestPath = new MemKey('http-request--original-url', true);
|
|
9
|
+
export const MemKey_HttpRequestMethod = new MemKey('http-request--method', true);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Thunderstorm is a full web app framework!
|
|
3
|
+
*
|
|
4
|
+
* Typescript & Express backend infrastructure that natively runs on firebase function
|
|
5
|
+
* Typescript & React frontend infrastructure
|
|
6
|
+
*
|
|
7
|
+
* Copyright (C) 2020 Adam van der Kruk aka TacB0sS
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
import { Logger, LogLevel } from '@nu-art/ts-common';
|
|
22
|
+
export class RouteResolver_Dummy extends Logger {
|
|
23
|
+
constructor() {
|
|
24
|
+
super();
|
|
25
|
+
this.setMinLevel(LogLevel.Debug);
|
|
26
|
+
}
|
|
27
|
+
resolveApi() {
|
|
28
|
+
}
|
|
29
|
+
printRoutes() {
|
|
30
|
+
}
|
|
31
|
+
resolveRoutes = () => {
|
|
32
|
+
return [];
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Express } from 'express';
|
|
2
|
+
import { ServerApi_Middleware } from '../../../utils/types.js';
|
|
3
|
+
import { Logger } from '@nu-art/ts-common';
|
|
4
|
+
import { ApiDef } from '@nu-art/thunderstorm-shared';
|
|
5
|
+
export type HttpRoute = {
|
|
6
|
+
methods: string[];
|
|
7
|
+
path: string;
|
|
8
|
+
};
|
|
9
|
+
export type MiddlewareConfig = {
|
|
10
|
+
filter: (apiDef: ApiDef<any>) => boolean;
|
|
11
|
+
middlewares: ServerApi_Middleware[];
|
|
12
|
+
};
|
|
13
|
+
export declare class RouteResolver_ModulePath extends Logger {
|
|
14
|
+
readonly express: Express;
|
|
15
|
+
private middlewares;
|
|
16
|
+
private initialPath;
|
|
17
|
+
constructor(express: Express, initialPath: string);
|
|
18
|
+
resolveApi(): void;
|
|
19
|
+
printRoutes(): void;
|
|
20
|
+
addMiddleware(filter?: (apiDef: ApiDef<any>) => boolean, ...middlewares: ServerApi_Middleware[]): void;
|
|
21
|
+
resolveRoutes: () => HttpRoute[];
|
|
22
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Thunderstorm is a full web app framework!
|
|
3
|
+
*
|
|
4
|
+
* Typescript & Express backend infrastructure that natively runs on firebase function
|
|
5
|
+
* Typescript & React frontend infrastructure
|
|
6
|
+
*
|
|
7
|
+
* Copyright (C) 2020 Adam van der Kruk aka TacB0sS
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
import { asArray, Logger, LogLevel, MUSTNeverHappenException, RuntimeModules } from '@nu-art/ts-common';
|
|
22
|
+
export class RouteResolver_ModulePath extends Logger {
|
|
23
|
+
express;
|
|
24
|
+
middlewares = [];
|
|
25
|
+
initialPath;
|
|
26
|
+
constructor(express, initialPath) {
|
|
27
|
+
super();
|
|
28
|
+
this.express = express;
|
|
29
|
+
this.initialPath = !process.env.GCLOUD_PROJECT ? initialPath : '';
|
|
30
|
+
this.setMinLevel(LogLevel.Debug);
|
|
31
|
+
}
|
|
32
|
+
resolveApi() {
|
|
33
|
+
const modules = RuntimeModules().filter((module) => !!module.useRoutes);
|
|
34
|
+
//Filter Api modules
|
|
35
|
+
const routes = [];
|
|
36
|
+
for (const module of modules) {
|
|
37
|
+
this.logInfo(module.getName());
|
|
38
|
+
const _routes = module.useRoutes();
|
|
39
|
+
routes.push(..._routes);
|
|
40
|
+
}
|
|
41
|
+
// console.log(routes);
|
|
42
|
+
routes.forEach(api => {
|
|
43
|
+
if (!api.addMiddlewares)
|
|
44
|
+
throw new MUSTNeverHappenException(`Missing api.middleware for`);
|
|
45
|
+
this.middlewares.filter(config => config.filter(api.apiDef) && api.addMiddlewares(...config.middlewares));
|
|
46
|
+
api.route(this.express, this.initialPath);
|
|
47
|
+
});
|
|
48
|
+
this.express.all('*', (req, res, next) => {
|
|
49
|
+
this.logErrorBold(`Received unknown url with path: '${req.path}' - url: '${req.url}'`);
|
|
50
|
+
res.status(404).send(`The requested URL '${req.url}' was not found on this server.`);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
printRoutes() {
|
|
54
|
+
const routes = this.resolveRoutes();
|
|
55
|
+
routes.forEach(route => {
|
|
56
|
+
const methodString = JSON.stringify(route.methods).padEnd(11, ' ');
|
|
57
|
+
return this.logInfo(`${methodString} ${this.initialPath}${route.path}`);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
addMiddleware(filter = () => true, ...middlewares) {
|
|
61
|
+
this.middlewares.push({ middlewares, filter });
|
|
62
|
+
}
|
|
63
|
+
resolveRoutes = () => {
|
|
64
|
+
const resolveStack = (_stack) => {
|
|
65
|
+
return _stack.map((layer) => {
|
|
66
|
+
if (layer.route && typeof layer.route.path === 'string') {
|
|
67
|
+
let methods = Object.keys(layer.route.methods);
|
|
68
|
+
if (methods.length > 20)
|
|
69
|
+
methods = ['ALL'];
|
|
70
|
+
return { methods: methods, path: layer.route.path };
|
|
71
|
+
}
|
|
72
|
+
if (layer.name === 'router')
|
|
73
|
+
return resolveStack(layer.handle.stack);
|
|
74
|
+
}).filter(route => route);
|
|
75
|
+
};
|
|
76
|
+
const routes = resolveStack(this.express._router.stack);
|
|
77
|
+
return routes.reduce((toRet, route) => {
|
|
78
|
+
const toAdd = asArray(route);
|
|
79
|
+
toRet.push(...toAdd);
|
|
80
|
+
//addAllItemToArray(toRet, toAdd);
|
|
81
|
+
return toRet;
|
|
82
|
+
}, []);
|
|
83
|
+
};
|
|
84
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { HttpRoute } from './RouteResolver_ModulePath.js';
|
|
2
|
+
export * from './RouteResolver_ModulePath.js';
|
|
3
|
+
export type RouteResolver = {
|
|
4
|
+
resolveApi: (urlPrefix?: string) => void;
|
|
5
|
+
printRoutes: (urlPrefix?: string) => void;
|
|
6
|
+
resolveRoutes: (urlPrefix?: string) => HttpRoute[];
|
|
7
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Thunderstorm is a full web app framework!
|
|
3
|
+
*
|
|
4
|
+
* Typescript & Express backend infrastructure that natively runs on firebase function
|
|
5
|
+
* Typescript & React frontend infrastructure
|
|
6
|
+
*
|
|
7
|
+
* Copyright (C) 2020 Adam van der Kruk aka TacB0sS
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
export * from './RouteResolver_ModulePath.js';
|