@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,70 @@
|
|
|
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, BadImplementationException, compareVersions, ImplementationMissingException, Module } from '@nu-art/ts-common';
|
|
22
|
+
import { ApiDef_ForceUpgrade, HeaderKey_AppVersion, HeaderKey_BrowserType, HeaderKey_UserAgent } from '@nu-art/thunderstorm-shared';
|
|
23
|
+
import { createQueryServerApi } from '../core/typed-api.js';
|
|
24
|
+
import { HeaderKey } from './server/HeaderKey.js';
|
|
25
|
+
import { addRoutes } from './ModuleBE_APIs.js';
|
|
26
|
+
const Header_AppVersion = new HeaderKey(HeaderKey_AppVersion);
|
|
27
|
+
const Header_BrowserType = new HeaderKey(HeaderKey_BrowserType);
|
|
28
|
+
const Header_UserAgent = new HeaderKey(HeaderKey_UserAgent);
|
|
29
|
+
const DefaultRegexps = {
|
|
30
|
+
chrome: 'Chrome/([0-9\.]+)'
|
|
31
|
+
};
|
|
32
|
+
class ModuleBE_ForceUpgrade_Class extends Module {
|
|
33
|
+
static Middleware = async () => ModuleBE_ForceUpgrade.assertVersion();
|
|
34
|
+
constructor() {
|
|
35
|
+
super();
|
|
36
|
+
}
|
|
37
|
+
init() {
|
|
38
|
+
super.init();
|
|
39
|
+
addRoutes([createQueryServerApi(ApiDef_ForceUpgrade.v1.assertAppVersion, async (params) => {
|
|
40
|
+
return this.compareVersion();
|
|
41
|
+
})]);
|
|
42
|
+
}
|
|
43
|
+
compareVersion() {
|
|
44
|
+
const appVersion = Header_AppVersion.get();
|
|
45
|
+
const userAgentString = Header_UserAgent.get();
|
|
46
|
+
const browserType = Header_BrowserType.get();
|
|
47
|
+
if (!browserType)
|
|
48
|
+
throw new ImplementationMissingException(`Browser type not specified`);
|
|
49
|
+
const chromeRegexp = this.config.regexp?.[browserType] || DefaultRegexps[browserType];
|
|
50
|
+
const version = userAgentString.match(new RegExp(chromeRegexp))?.[1];
|
|
51
|
+
if (!version)
|
|
52
|
+
throw new BadImplementationException(`Error extracting version.. \nUserAgent: '${userAgentString}'\n config: '${__stringify(this.config)}'`);
|
|
53
|
+
const requiredBrowserVersion = this.config.browser?.[browserType];
|
|
54
|
+
if (!requiredBrowserVersion)
|
|
55
|
+
throw new ImplementationMissingException(`Unsupported browser type: ${browserType}`);
|
|
56
|
+
let app = false;
|
|
57
|
+
let browser = false;
|
|
58
|
+
if (this.config.app)
|
|
59
|
+
app = compareVersions(appVersion, this.config.app) === 1;
|
|
60
|
+
if (requiredBrowserVersion)
|
|
61
|
+
browser = compareVersions(version, requiredBrowserVersion) === 1;
|
|
62
|
+
return { type: 'upgrade-required', data: { app, browser } };
|
|
63
|
+
}
|
|
64
|
+
async assertVersion() {
|
|
65
|
+
const upgradeRequired = this.compareVersion();
|
|
66
|
+
if (upgradeRequired.data.app || upgradeRequired.data.browser)
|
|
67
|
+
throw new ApiException(426, 'require upgrade..').setErrorBody(upgradeRequired);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export const ModuleBE_ForceUpgrade = new ModuleBE_ForceUpgrade_Class();
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Module } from '@nu-art/ts-common';
|
|
2
|
+
import { BasicServerInfo } from '@nu-art/thunderstorm-shared';
|
|
3
|
+
type Config = BasicServerInfo;
|
|
4
|
+
export declare class ModuleBE_ServerInfo_Class extends Module<Config> {
|
|
5
|
+
private serverInfoData;
|
|
6
|
+
constructor();
|
|
7
|
+
init(): Promise<void>;
|
|
8
|
+
private getServerInfo;
|
|
9
|
+
/**
|
|
10
|
+
* Perform a "ping" to the environment's default Firebase project's Firestore
|
|
11
|
+
*/
|
|
12
|
+
pingFirestore: () => Promise<"ERROR" | "OK">;
|
|
13
|
+
/**
|
|
14
|
+
* Perform a "ping" to the environment's default Firebase project's RTDB
|
|
15
|
+
*/
|
|
16
|
+
pingFirebaseRTDB: () => Promise<"ERROR" | "OK">;
|
|
17
|
+
private writeServerInfoState;
|
|
18
|
+
}
|
|
19
|
+
export declare const ModuleBE_ServerInfo: ModuleBE_ServerInfo_Class;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Module, RuntimeVersion } from '@nu-art/ts-common';
|
|
2
|
+
import { createQueryServerApi } from '../core/typed-api.js';
|
|
3
|
+
import { addRoutes } from './ModuleBE_APIs.js';
|
|
4
|
+
import { Storm } from '../core/Storm.js';
|
|
5
|
+
import { ModuleBE_Firebase } from '@nu-art/firebase-backend';
|
|
6
|
+
import { ApiDef_ServerInfo, Const_ERROR, Const_OK, Default_ServerInfoNodePath } from '@nu-art/thunderstorm-shared';
|
|
7
|
+
import { ModuleBE_SyncManager } from './sync-manager/ModuleBE_SyncManager.js';
|
|
8
|
+
export class ModuleBE_ServerInfo_Class extends Module {
|
|
9
|
+
serverInfoData;
|
|
10
|
+
constructor() {
|
|
11
|
+
super();
|
|
12
|
+
}
|
|
13
|
+
async init() {
|
|
14
|
+
super.init();
|
|
15
|
+
ModuleBE_Firebase.createAdminSession().getStorage().getMainBucket().then(async (bucket) => {
|
|
16
|
+
this.setDefaultConfig({
|
|
17
|
+
environment: Storm.getInstance().getEnvironment(),
|
|
18
|
+
version: RuntimeVersion(),
|
|
19
|
+
bucketName: bucket.getBucketName()
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
addRoutes([
|
|
23
|
+
createQueryServerApi(ApiDef_ServerInfo.v1.getServerInfo, this.getServerInfo),
|
|
24
|
+
createQueryServerApi(ApiDef_ServerInfo.v1.updateServerInfoState, async () => this.writeServerInfoState())
|
|
25
|
+
]);
|
|
26
|
+
this.serverInfoData = ModuleBE_Firebase.createAdminSession().getDatabase().ref(Default_ServerInfoNodePath);
|
|
27
|
+
}
|
|
28
|
+
getServerInfo = async () => {
|
|
29
|
+
const firestoreResponse = await this.pingFirestore();
|
|
30
|
+
const firebaseRTDBResponse = await this.pingFirebaseRTDB();
|
|
31
|
+
const response = {
|
|
32
|
+
environment: this.config.environment,
|
|
33
|
+
version: this.config.version,
|
|
34
|
+
bucketName: this.config.bucketName,
|
|
35
|
+
status: {
|
|
36
|
+
firestore: firestoreResponse,
|
|
37
|
+
firebase: firebaseRTDBResponse
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
return response;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Perform a "ping" to the environment's default Firebase project's Firestore
|
|
44
|
+
*/
|
|
45
|
+
pingFirestore = async () => {
|
|
46
|
+
try {
|
|
47
|
+
await ModuleBE_SyncManager.collection.query.custom({ where: {}, limit: 1 });
|
|
48
|
+
return Const_OK;
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
this.logError(e);
|
|
52
|
+
return Const_ERROR;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Perform a "ping" to the environment's default Firebase project's RTDB
|
|
57
|
+
*/
|
|
58
|
+
pingFirebaseRTDB = async () => {
|
|
59
|
+
try {
|
|
60
|
+
await this.serverInfoData.get();
|
|
61
|
+
return Const_OK;
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
this.logError(e);
|
|
65
|
+
return Const_ERROR;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
writeServerInfoState = async () => {
|
|
69
|
+
await this.serverInfoData.set({
|
|
70
|
+
environment: this.config.environment,
|
|
71
|
+
version: this.config.version,
|
|
72
|
+
bucketName: this.config.bucketName,
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export const ModuleBE_ServerInfo = new ModuleBE_ServerInfo_Class();
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export * from './server/server-api.js';
|
|
2
|
+
export * from './server/HttpServer.js';
|
|
3
|
+
export * from './proxy/RemoteProxyCaller.js';
|
|
4
|
+
export * from './proxy/ModuleBE_RemoteProxy.js';
|
|
5
|
+
export * from '../utils/promisify-request.js';
|
|
6
|
+
export * from './CleanupScheduler.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
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 './server/server-api.js';
|
|
22
|
+
export * from './server/HttpServer.js';
|
|
23
|
+
export * from './proxy/RemoteProxyCaller.js';
|
|
24
|
+
export * from './proxy/ModuleBE_RemoteProxy.js';
|
|
25
|
+
export * from '../utils/promisify-request.js';
|
|
26
|
+
export * from './CleanupScheduler.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Dispatcher, UniqueId } from '@nu-art/ts-common';
|
|
2
|
+
export type ServiceAccountCredentials = {
|
|
3
|
+
serviceAccount: {
|
|
4
|
+
email: string;
|
|
5
|
+
accountId?: string;
|
|
6
|
+
token?: string;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
export type DefaultDef_ServiceAccount = {
|
|
10
|
+
moduleName: string;
|
|
11
|
+
email: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
ttl?: number;
|
|
14
|
+
groupIds?: UniqueId[];
|
|
15
|
+
};
|
|
16
|
+
export interface RequiresServiceAccount {
|
|
17
|
+
__requiresServiceAccount(): DefaultDef_ServiceAccount | DefaultDef_ServiceAccount[];
|
|
18
|
+
}
|
|
19
|
+
export declare const dispatcher_collectServiceAccounts: Dispatcher<RequiresServiceAccount, "__requiresServiceAccount", [], DefaultDef_ServiceAccount | DefaultDef_ServiceAccount[]>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ActionDeclaration } from './types.js';
|
|
2
|
+
export type SetupProjectPromise = {
|
|
3
|
+
priority: number;
|
|
4
|
+
processor: () => Promise<void>;
|
|
5
|
+
};
|
|
6
|
+
export interface PerformProjectSetup {
|
|
7
|
+
__performProjectSetup(): SetupProjectPromise;
|
|
8
|
+
}
|
|
9
|
+
export declare const RAD_SetupProject: ActionDeclaration;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { _keys, Dispatcher, StaticLogger } from '@nu-art/ts-common';
|
|
2
|
+
const dispatcher_ProjectSetup = new Dispatcher('__performProjectSetup');
|
|
3
|
+
const Action_SetupProject = async (logger) => {
|
|
4
|
+
logger.logInfo('Setting up Project');
|
|
5
|
+
const promises = dispatcher_ProjectSetup.dispatchModule();
|
|
6
|
+
const promiseMap = promises.reduce((resultMap, promise) => {
|
|
7
|
+
resultMap[promise.priority] = resultMap[promise.priority] ?? { processors: [] };
|
|
8
|
+
resultMap[promise.priority].processors.push(promise.processor);
|
|
9
|
+
return resultMap;
|
|
10
|
+
}, {});
|
|
11
|
+
const priorities = _keys(promiseMap).sort(); // Start with priority 0, as most important
|
|
12
|
+
for (const priorityKey of priorities) {
|
|
13
|
+
StaticLogger.logInfoBold(`Running SetupProject[${priorityKey}]`);
|
|
14
|
+
await Promise.all(promiseMap[priorityKey].processors.map(async (processor) => processor()));
|
|
15
|
+
}
|
|
16
|
+
logger.logInfo('Project Setup Completed!');
|
|
17
|
+
};
|
|
18
|
+
export const RAD_SetupProject = {
|
|
19
|
+
key: 'setup-project',
|
|
20
|
+
group: 'Initialization',
|
|
21
|
+
description: '...',
|
|
22
|
+
processor: Action_SetupProject
|
|
23
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Logger, Module } from '@nu-art/ts-common';
|
|
2
|
+
import { ActionDeclaration } from './types.js';
|
|
3
|
+
export declare class ModuleBE_ActionProcessor_Class extends Module {
|
|
4
|
+
private readonly actions;
|
|
5
|
+
constructor();
|
|
6
|
+
protected init(): void;
|
|
7
|
+
readonly registerAction: (rad: ActionDeclaration, logger: Logger) => void;
|
|
8
|
+
private refactor;
|
|
9
|
+
private list;
|
|
10
|
+
}
|
|
11
|
+
export declare const ModuleBE_ActionProcessor: ModuleBE_ActionProcessor_Class;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { _values, ApiException, BadImplementationException, exists, isErrorOfType, LogLevel, Module, resolveContent } from '@nu-art/ts-common';
|
|
2
|
+
// import {ApiDefServer} from '../../utils/api-caller-types.js';
|
|
3
|
+
import { ApiDef_ActionProcessing } from '@nu-art/thunderstorm-shared/action-processor/index';
|
|
4
|
+
import { createBodyServerApi, createQueryServerApi } from '../../core/typed-api.js';
|
|
5
|
+
import { addRoutes } from '../ModuleBE_APIs.js';
|
|
6
|
+
import { RAD_SetupProject } from './Action_SetupProject.js';
|
|
7
|
+
import { HttpCodes } from '@nu-art/ts-common/core/exceptions/http-codes';
|
|
8
|
+
export class ModuleBE_ActionProcessor_Class extends Module {
|
|
9
|
+
actions = {};
|
|
10
|
+
constructor() {
|
|
11
|
+
super();
|
|
12
|
+
this.setMinLevel(LogLevel.Verbose);
|
|
13
|
+
}
|
|
14
|
+
init() {
|
|
15
|
+
super.init();
|
|
16
|
+
addRoutes([
|
|
17
|
+
createBodyServerApi(ApiDef_ActionProcessing.vv1.execute, this.refactor),
|
|
18
|
+
createQueryServerApi(ApiDef_ActionProcessing.vv1.list, this.list)
|
|
19
|
+
]);
|
|
20
|
+
this.registerAction(RAD_SetupProject, this);
|
|
21
|
+
}
|
|
22
|
+
registerAction = (rad, logger) => {
|
|
23
|
+
this.logInfo(`Registering action: ${rad.key}`);
|
|
24
|
+
if (this.actions[rad.key])
|
|
25
|
+
throw new BadImplementationException(`ActionProcessor with key ${rad.key} was registered twice!`);
|
|
26
|
+
this.actions[rad.key] = {
|
|
27
|
+
action: (data) => rad.processor(logger || this, data),
|
|
28
|
+
declaration: rad
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
refactor = async (action) => {
|
|
32
|
+
this.logWarning(`RECEIVED ACTION: ${action.key}`);
|
|
33
|
+
const actionObj = this.actions[action.key];
|
|
34
|
+
if (exists(actionObj.declaration.visible) && !resolveContent(actionObj.declaration.visible))
|
|
35
|
+
throw HttpCodes._4XX.FORBIDDEN('Action Forbidden for User');
|
|
36
|
+
const refactoringAction = actionObj.action;
|
|
37
|
+
if (!refactoringAction) {
|
|
38
|
+
throw HttpCodes._4XX.NOT_FOUND(`NO SUCH ACTION: ${action.key}`);
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
this.logWarning(`ACTION '${action.key}' - EXECUTING`);
|
|
42
|
+
await refactoringAction?.(action.data);
|
|
43
|
+
this.logWarning(`ACTION '${action.key}' - SUCCESSFUL`);
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
this.logError(`ACTION '${action.key}' - FAILED`, e);
|
|
47
|
+
if (isErrorOfType(e, ApiException))
|
|
48
|
+
throw e;
|
|
49
|
+
const message = `ACTION FAILED: ${actionObj.declaration.label}`;
|
|
50
|
+
throw HttpCodes._5XX.INTERNAL_SERVER_ERROR(message, '', e);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
list = async () => {
|
|
54
|
+
return _values(this.actions)
|
|
55
|
+
.filter(action => !exists(action.declaration.visible) || resolveContent(action.declaration.visible))
|
|
56
|
+
.map(action => {
|
|
57
|
+
const declaration = action.declaration;
|
|
58
|
+
return {
|
|
59
|
+
key: declaration.key,
|
|
60
|
+
label: declaration.label ?? declaration.key,
|
|
61
|
+
description: declaration.description,
|
|
62
|
+
group: declaration.group,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export const ModuleBE_ActionProcessor = new ModuleBE_ActionProcessor_Class();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Logger, ResolvableContent } from '@nu-art/ts-common';
|
|
2
|
+
export type ActionProcessor = (logger: Logger, data?: any) => Promise<void>;
|
|
3
|
+
export type ActionDeclaration = {
|
|
4
|
+
label?: string;
|
|
5
|
+
visible?: ResolvableContent<boolean>;
|
|
6
|
+
key: string;
|
|
7
|
+
processor: ActionProcessor;
|
|
8
|
+
description: string;
|
|
9
|
+
group: string;
|
|
10
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { DB_Object } from '@nu-art/ts-common';
|
|
2
|
+
import { ModuleBE_FirestoreListener } from '@nu-art/firebase-backend';
|
|
3
|
+
import { ModuleBE_BaseDB } from '../db-api-gen/ModuleBE_BaseDB.js';
|
|
4
|
+
import { RequestBody_HardDeleteUnique, RequestQuery_DeleteAll, RequestQuery_GetHistory } from '@nu-art/thunderstorm-shared';
|
|
5
|
+
type Params = {
|
|
6
|
+
collectionName: string;
|
|
7
|
+
docId: string;
|
|
8
|
+
};
|
|
9
|
+
export declare const Const_ArchivedCollectionPath = "/_archived";
|
|
10
|
+
/**
|
|
11
|
+
* This class extends FirestoreFunctionModule and handles Firestore database operations
|
|
12
|
+
* with custom logic for archiving and Time-To-Live (TTL) functionality.
|
|
13
|
+
*/
|
|
14
|
+
export declare class ModuleBE_ArchiveModule_Class<DBType extends DB_Object> extends ModuleBE_FirestoreListener<DBType> {
|
|
15
|
+
private readonly TTL;
|
|
16
|
+
private readonly lastUpdatedTTL;
|
|
17
|
+
protected readonly moduleMapper: {
|
|
18
|
+
[key: string]: ModuleBE_BaseDB<any>;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Constructor initializes TTL, lastUpdatedTTL moduleMapper and sets api routes for the module.
|
|
22
|
+
*/
|
|
23
|
+
constructor();
|
|
24
|
+
/**
|
|
25
|
+
* Initializes the `moduleMapper` by populating it with Firestore collections.
|
|
26
|
+
* Iterates through all modules obtained from the Storm instance and adds modules
|
|
27
|
+
* which are Firestore DB modules to the `moduleMapper`.
|
|
28
|
+
*/
|
|
29
|
+
protected init(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Deletes a unique document by its ID in a Firestore transaction.
|
|
32
|
+
* This method first retrieves the document with the given ID.
|
|
33
|
+
* If the document is found, it is marked for deletion and an upsert operation is performed.
|
|
34
|
+
* The upsert operation triggers a Firestore OnUpdate event, which will delete the document and its '_archived' sub-collection.
|
|
35
|
+
*
|
|
36
|
+
* @param body - An object of type `RequestBody_HardDeleteUnique` containing the following fields:
|
|
37
|
+
* - _id: The ID of the document to be deleted.
|
|
38
|
+
* - collectionName: The name of the collection the document belongs to.
|
|
39
|
+
* - dbInstance: (optional) The instance of the document. If not provided, the method will attempt to retrieve it using the given ID.
|
|
40
|
+
* @returns - A promise that performs the deletion operation.
|
|
41
|
+
* @throws - A `BadImplementationException` if no module is found for the given collection or if no document with the provided ID is found.
|
|
42
|
+
*/
|
|
43
|
+
hardDeleteUnique: (body: RequestBody_HardDeleteUnique) => Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Deletes all documents in the specified collection.
|
|
46
|
+
* This function first retrieves all documents in the collection.
|
|
47
|
+
* It then deletes each document in the collection in parallel chunks for efficiency.
|
|
48
|
+
*
|
|
49
|
+
* @param queryParams - Params includes the name of the collection in which the documents will be deleted.
|
|
50
|
+
* @returns - A promise that performs the deletion operation.
|
|
51
|
+
* @throws - A BadImplementationException if no corresponding module is found for the given collection.
|
|
52
|
+
*/
|
|
53
|
+
hardDeleteAll: (queryParams: RequestQuery_DeleteAll) => Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Asynchronously retrieves the document history from the '_archived' collection group.
|
|
56
|
+
*
|
|
57
|
+
* This function takes a RequestQuery_GetHistory object as a parameter, which contains the name of the collection
|
|
58
|
+
* and the ID of the document for which the history should be retrieved.
|
|
59
|
+
* It then finds the respective Firestore DB module for the provided collection.
|
|
60
|
+
*
|
|
61
|
+
* If no module is found for the given collection, a BadImplementationException is thrown.
|
|
62
|
+
*
|
|
63
|
+
* The function queries the '_archived' collection group where the '_originDocId' field matches the provided
|
|
64
|
+
* document ID, and orders the results by the '__created' timestamp in descending order.
|
|
65
|
+
* It then maps the document snapshots to their respective data, creating an array of DBType documents, which is returned.
|
|
66
|
+
*
|
|
67
|
+
* @param queryParams - The request query parameters containing the collection name and the document ID.
|
|
68
|
+
* @returns - An array of DBType documents representing the history of the specified document.
|
|
69
|
+
* @throws - A BadImplementationException if no module is found for the given collection.
|
|
70
|
+
*/
|
|
71
|
+
getDocumentHistory: (queryParams: RequestQuery_GetHistory) => Promise<DBType[]>;
|
|
72
|
+
/**
|
|
73
|
+
* Checks if the Time-To-Live (TTL) for a document instance has been exceeded.
|
|
74
|
+
*
|
|
75
|
+
* @param instance - The document instance to check.
|
|
76
|
+
* @param dbModule - The Firestore database module the document belongs to.
|
|
77
|
+
* @returns - A boolean indicating whether the TTL has been exceeded (true) or not (false).
|
|
78
|
+
*/
|
|
79
|
+
private checkTTL;
|
|
80
|
+
/**
|
|
81
|
+
* Checks if the `lastUpdatedTTL` for a document instance has been exceeded.
|
|
82
|
+
* This represents a secondary TTL which is based on the last update time of the document.
|
|
83
|
+
*
|
|
84
|
+
* @param instance - The document instance to check.
|
|
85
|
+
* @param dbModule - The Firestore database module the document belongs to.
|
|
86
|
+
* @returns - A boolean indicating whether the `lastUpdatedTTL` has been exceeded (true) or not (false).
|
|
87
|
+
*/
|
|
88
|
+
private checkLastUpdatedTTL;
|
|
89
|
+
/**
|
|
90
|
+
* Inserts a document into the '_archived' sub-collection.
|
|
91
|
+
* This function is used for archiving the previous state of the document before it was changed.
|
|
92
|
+
*
|
|
93
|
+
* @param dbModule - The Firestore database module the document belongs to.
|
|
94
|
+
* @param before - The state of the document before changes.
|
|
95
|
+
* @returns - A promise that performs the archiving operation or undefined in case of an error.
|
|
96
|
+
*/
|
|
97
|
+
private insertToArchive;
|
|
98
|
+
/**
|
|
99
|
+
* Hard deletes a document and its associated archived documents.
|
|
100
|
+
*
|
|
101
|
+
* @param instance - The instance of the document to delete.
|
|
102
|
+
* @param dbModule - The Firestore database module the document belongs to.
|
|
103
|
+
* @returns - A promise to perform the deletion operation.
|
|
104
|
+
*/
|
|
105
|
+
private hardDeleteDoc;
|
|
106
|
+
/**
|
|
107
|
+
* Processes changes in the Firestore collection.
|
|
108
|
+
* Depending on the state of the documents, it either archives the documents,
|
|
109
|
+
* checks the Time-To-Live (TTL) or performs a hard delete operation.
|
|
110
|
+
*
|
|
111
|
+
* @param params - An object containing the collectionName and the document ID.
|
|
112
|
+
* @param before - The state of the document before changes.
|
|
113
|
+
* @param after - The state of the document after changes.
|
|
114
|
+
* @returns - A promise that performs the necessary operation based on the document states.
|
|
115
|
+
*/
|
|
116
|
+
processChanges(params: Params, before: DBType | undefined, after: DBType | undefined): Promise<void | FirebaseFirestore.WriteResult[]>;
|
|
117
|
+
}
|
|
118
|
+
export declare const ModuleBE_Archiving: ModuleBE_ArchiveModule_Class<DB_Object>;
|
|
119
|
+
export {};
|