node-server-engine 1.4.8 → 1.5.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/.commitlintrc.js +27 -0
- package/.releaserc.js +56 -0
- package/README.md +154 -2
- package/dist/const/tokenIssuer.js +1 -0
- package/dist/const/tokenIssuer.js.map +1 -1
- package/dist/db/models/SequelizeMeta.js +3 -1
- package/dist/db/models/SequelizeMeta.js.map +1 -1
- package/dist/entities/ElasticSearch/ElasticSearch.js +1 -2
- package/dist/entities/ElasticSearch/ElasticSearch.js.map +1 -1
- package/dist/entities/SocketClient/SocketClient.js +1 -0
- package/dist/entities/SocketClient/SocketClient.js.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/middleware/checkPermission/checkPermission.d.ts +1 -1
- package/dist/middleware/checkPermission/checkPermission.js +4 -2
- package/dist/middleware/checkPermission/checkPermission.js.map +1 -1
- package/dist/utils/createHttpServer/createHttpServer.js +1 -1
- package/dist/utils/createHttpServer/createHttpServer.js.map +1 -1
- package/dist/utils/jwt/jwt.js +1 -1
- package/dist/utils/jwt/jwt.js.map +1 -1
- package/dist/utils/semverCompare/semverCompare.js +1 -5
- package/dist/utils/semverCompare/semverCompare.js.map +1 -1
- package/package.json +30 -19
- package/.env.example +0 -186
- package/.github/workflows/publish.yml +0 -41
- package/.prettierrc +0 -7
- package/Dockerfile +0 -31
- package/babel.config.json +0 -34
- package/eslint.config.mjs +0 -11
- package/src/const/DebeziumEvent.ts +0 -6
- package/src/const/LogSeverity.ts +0 -7
- package/src/const/index.ts +0 -5
- package/src/const/metrics.ts +0 -6
- package/src/const/mime.ts +0 -37
- package/src/const/tokenIssuer.ts +0 -7
- package/src/db/migrations/20241030121500-create-sequelize-meta-table.ts +0 -29
- package/src/db/models/SequelizeMeta.ts +0 -16
- package/src/db/models/index.ts +0 -2
- package/src/entities/ElasticSearch/ElasticSearch.ts +0 -103
- package/src/entities/ElasticSearch/ElasticSearch.types.ts +0 -7
- package/src/entities/ElasticSearch/index.ts +0 -2
- package/src/entities/Endpoint/Endpoint.test.ts +0 -248
- package/src/entities/Endpoint/Endpoint.ts +0 -221
- package/src/entities/Endpoint/Endpoint.types.ts +0 -181
- package/src/entities/Endpoint/index.ts +0 -2
- package/src/entities/EngineError/EngineError.ts +0 -28
- package/src/entities/EngineError/EngineError.types.ts +0 -15
- package/src/entities/EngineError/index.ts +0 -2
- package/src/entities/KeySet/KeySet.test.ts +0 -126
- package/src/entities/KeySet/KeySet.ts +0 -172
- package/src/entities/KeySet/KeySet.types.ts +0 -28
- package/src/entities/KeySet/index.ts +0 -2
- package/src/entities/LifecycleController/LifecycleController.test.ts +0 -48
- package/src/entities/LifecycleController/LifecycleController.ts +0 -24
- package/src/entities/LifecycleController/LifecycleController.types.ts +0 -5
- package/src/entities/LifecycleController/index.ts +0 -2
- package/src/entities/Localizator/Localizator.ts +0 -139
- package/src/entities/Localizator/Localizator.types.ts +0 -52
- package/src/entities/Localizator/guessNamingConvention/guessNamingConvention.test.ts +0 -165
- package/src/entities/Localizator/guessNamingConvention/guessNamingConvention.ts +0 -58
- package/src/entities/Localizator/guessNamingConvention/index.ts +0 -1
- package/src/entities/Localizator/index.ts +0 -2
- package/src/entities/MessageHandler/MessageHandler.test.ts +0 -130
- package/src/entities/MessageHandler/MessageHandler.ts +0 -72
- package/src/entities/MessageHandler/MessageHandler.types.ts +0 -15
- package/src/entities/MessageHandler/index.ts +0 -2
- package/src/entities/PubSub/PubSub.test.ts +0 -297
- package/src/entities/PubSub/PubSub.ts +0 -202
- package/src/entities/PubSub/PubSub.types.ts +0 -76
- package/src/entities/PubSub/handleMessage/handleMessage.test.ts +0 -102
- package/src/entities/PubSub/handleMessage/handleMessage.ts +0 -65
- package/src/entities/PubSub/handleMessage/index.ts +0 -1
- package/src/entities/PubSub/index.ts +0 -2
- package/src/entities/PushNotification/PushNotification.test.ts +0 -35
- package/src/entities/PushNotification/PushNotification.ts +0 -44
- package/src/entities/PushNotification/PushNotification.types.ts +0 -25
- package/src/entities/PushNotification/index.ts +0 -2
- package/src/entities/Redis/Redis.ts +0 -71
- package/src/entities/Redis/Redis.types.ts +0 -19
- package/src/entities/Redis/Redis.validate.ts +0 -17
- package/src/entities/Redis/index.ts +0 -2
- package/src/entities/Sequelize/Sequelize.config.ts +0 -59
- package/src/entities/Sequelize/Sequelize.test.ts +0 -21
- package/src/entities/Sequelize/Sequelize.ts +0 -75
- package/src/entities/Sequelize/Sequelize.types.ts +0 -10
- package/src/entities/Sequelize/Sequelize.validate.ts +0 -15
- package/src/entities/Sequelize/index.ts +0 -2
- package/src/entities/Server/Server.const.ts +0 -56
- package/src/entities/Server/Server.test.ts +0 -272
- package/src/entities/Server/Server.ts +0 -471
- package/src/entities/Server/Server.types.ts +0 -88
- package/src/entities/Server/index.ts +0 -2
- package/src/entities/SocketClient/SocketClient.test.ts +0 -392
- package/src/entities/SocketClient/SocketClient.ts +0 -401
- package/src/entities/SocketClient/SocketClient.types.ts +0 -62
- package/src/entities/SocketClient/index.ts +0 -2
- package/src/entities/SocketClient/parseMessage/index.ts +0 -1
- package/src/entities/SocketClient/parseMessage/parseMessage.test.ts +0 -20
- package/src/entities/SocketClient/parseMessage/parseMessage.ts +0 -26
- package/src/entities/Storage/Storage.test.ts +0 -58
- package/src/entities/Storage/Storage.ts +0 -219
- package/src/entities/Storage/Storage.types.ts +0 -57
- package/src/entities/Storage/index.ts +0 -2
- package/src/entities/ValidationError/ValidationError.ts +0 -34
- package/src/entities/ValidationError/index.ts +0 -1
- package/src/entities/WebError/WebError.test.ts +0 -18
- package/src/entities/WebError/WebError.ts +0 -23
- package/src/entities/WebError/WebError.types.ts +0 -9
- package/src/entities/WebError/index.ts +0 -2
- package/src/entities/index.ts +0 -16
- package/src/index.ts +0 -6
- package/src/metrics/debug.ts +0 -10
- package/src/metrics/index.ts +0 -2
- package/src/metrics/request.ts +0 -17
- package/src/middleware/authHmac/authHmac.test.ts +0 -86
- package/src/middleware/authHmac/authHmac.ts +0 -56
- package/src/middleware/authHmac/authHmac.types.ts +0 -7
- package/src/middleware/authHmac/index.ts +0 -2
- package/src/middleware/authJwt/authJwt.test.ts +0 -54
- package/src/middleware/authJwt/authJwt.ts +0 -55
- package/src/middleware/authJwt/authJwt.types.ts +0 -14
- package/src/middleware/authJwt/index.ts +0 -2
- package/src/middleware/authStatic/authStatic.test.ts +0 -36
- package/src/middleware/authStatic/authStatic.ts +0 -45
- package/src/middleware/authStatic/index.ts +0 -1
- package/src/middleware/authTls/authTls.test.ts +0 -138
- package/src/middleware/authTls/authTls.ts +0 -119
- package/src/middleware/authTls/authTls.types.ts +0 -13
- package/src/middleware/authTls/index.ts +0 -2
- package/src/middleware/checkPermission/checkPermission.ts +0 -33
- package/src/middleware/checkPermission/index.ts +0 -1
- package/src/middleware/error/error.test.ts +0 -60
- package/src/middleware/error/error.ts +0 -25
- package/src/middleware/error/index.ts +0 -1
- package/src/middleware/fileUploader/fileUploader.ts +0 -154
- package/src/middleware/fileUploader/fileUploader.types.ts +0 -35
- package/src/middleware/fileUploader/index.ts +0 -2
- package/src/middleware/fileUploader/isMultiPart/index.ts +0 -1
- package/src/middleware/fileUploader/isMultiPart/isMultipart.ts +0 -9
- package/src/middleware/fileUploader/validate/index.ts +0 -1
- package/src/middleware/fileUploader/validate/validate.ts +0 -27
- package/src/middleware/fourOhFour/fourOhFour.test.ts +0 -14
- package/src/middleware/fourOhFour/fourOhFour.ts +0 -13
- package/src/middleware/fourOhFour/index.ts +0 -1
- package/src/middleware/geminiFileUploader/geminiFileUploader.ts +0 -68
- package/src/middleware/geminiFileUploader/index.ts +0 -1
- package/src/middleware/healthCheck/healthCheck.test.ts +0 -12
- package/src/middleware/healthCheck/healthCheck.ts +0 -14
- package/src/middleware/healthCheck/index.ts +0 -1
- package/src/middleware/index.ts +0 -17
- package/src/middleware/metrics/index.ts +0 -1
- package/src/middleware/metrics/metrics.test.ts +0 -46
- package/src/middleware/metrics/metrics.ts +0 -24
- package/src/middleware/multiPartFileUploader/index.ts +0 -2
- package/src/middleware/multiPartFileUploader/multiPartFileUploader.ts +0 -249
- package/src/middleware/multiPartFileUploader/multiPartFileUploader.types.ts +0 -23
- package/src/middleware/multiPartFileUploader/validate/index.ts +0 -1
- package/src/middleware/multiPartFileUploader/validate/validate.ts +0 -27
- package/src/middleware/requestMetrics/index.ts +0 -1
- package/src/middleware/requestMetrics/requestMetrics.test.ts +0 -77
- package/src/middleware/requestMetrics/requestMetrics.ts +0 -20
- package/src/middleware/swaggerDocs/index.ts +0 -2
- package/src/middleware/swaggerDocs/swaggerDocs.ts +0 -114
- package/src/middleware/swaggerDocs/swaggerDocs.types.ts +0 -41
- package/src/middleware/userResolver/index.ts +0 -1
- package/src/middleware/userResolver/userResolver.ts +0 -53
- package/src/middleware/validate/index.ts +0 -1
- package/src/middleware/validate/validate.test.ts +0 -43
- package/src/middleware/validate/validate.ts +0 -25
- package/src/middleware/version/index.ts +0 -1
- package/src/middleware/version/version.test.ts +0 -23
- package/src/middleware/version/version.ts +0 -12
- package/src/utils/checkEnvironment/index.ts +0 -49
- package/src/utils/createHttpServer/createHttpServer.test.ts +0 -24
- package/src/utils/createHttpServer/createHttpServer.ts +0 -34
- package/src/utils/createHttpServer/createHttpServer.validate.ts +0 -17
- package/src/utils/createHttpServer/index.ts +0 -1
- package/src/utils/createSortedObject/createSortedObject.ts +0 -20
- package/src/utils/createSortedObject/createSortedObjet.test.ts +0 -47
- package/src/utils/createSortedObject/index.ts +0 -1
- package/src/utils/dbMigration/dbMigration.test.ts +0 -209
- package/src/utils/dbMigration/dbMigration.ts +0 -199
- package/src/utils/dbMigration/dbMigration.types.ts +0 -11
- package/src/utils/dbMigration/index.ts +0 -2
- package/src/utils/dbMigration/migrateMetadataTable/index.ts +0 -1
- package/src/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.test.ts +0 -59
- package/src/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.ts +0 -102
- package/src/utils/envAssert/envAssert.ts +0 -31
- package/src/utils/envAssert/index.ts +0 -1
- package/src/utils/envAssert/validators/hostList.ts +0 -17
- package/src/utils/envAssert/validators/index.ts +0 -5
- package/src/utils/envAssert/validators/ipList.ts +0 -13
- package/src/utils/envAssert/validators/path.ts +0 -13
- package/src/utils/envAssert/validators/string.ts +0 -9
- package/src/utils/envAssert/validators/stringList.ts +0 -13
- package/src/utils/filter/filter.ts +0 -17
- package/src/utils/filter/index.ts +0 -1
- package/src/utils/geminiFileUpload/geminiFileUpload.ts +0 -93
- package/src/utils/geminiFileUpload/index.ts +0 -1
- package/src/utils/hmac/checkEnv/checkEnv.test.ts +0 -18
- package/src/utils/hmac/checkEnv/checkEnv.ts +0 -9
- package/src/utils/hmac/checkEnv/index.ts +0 -1
- package/src/utils/hmac/createHmac/createHmac.ts +0 -33
- package/src/utils/hmac/createHmac/index.ts +0 -1
- package/src/utils/hmac/index.ts +0 -4
- package/src/utils/hmac/index.types.ts +0 -13
- package/src/utils/hmac/signPayload/index.ts +0 -1
- package/src/utils/hmac/signPayload/signPayload.ts +0 -16
- package/src/utils/hmac/verifySignature/index.ts +0 -1
- package/src/utils/hmac/verifySignature/verifySignature.ts +0 -24
- package/src/utils/index.ts +0 -29
- package/src/utils/jwt/index.ts +0 -2
- package/src/utils/jwt/jwt.test.ts +0 -28
- package/src/utils/jwt/jwt.ts +0 -182
- package/src/utils/jwt/jwt.types.ts +0 -21
- package/src/utils/report/index.ts +0 -3
- package/src/utils/report/output.ts +0 -45
- package/src/utils/report/output.types.ts +0 -70
- package/src/utils/report/report.test.ts +0 -133
- package/src/utils/report/report.ts +0 -133
- package/src/utils/report/report.types.ts +0 -13
- package/src/utils/request/index.ts +0 -1
- package/src/utils/request/request.test.ts +0 -26
- package/src/utils/request/request.ts +0 -48
- package/src/utils/secretManager/index.ts +0 -2
- package/src/utils/secretManager/secretLoader.ts +0 -62
- package/src/utils/secretManager/secretResolver.ts +0 -35
- package/src/utils/semverCompare/index.ts +0 -1
- package/src/utils/semverCompare/semverCompare.test.ts +0 -49
- package/src/utils/semverCompare/semverCompare.ts +0 -60
- package/src/utils/sendEmail/index.ts +0 -2
- package/src/utils/sendEmail/sendEmail.ts +0 -61
- package/src/utils/sendEmail/sendEmail.types.ts +0 -61
- package/src/utils/sendPush/index.ts +0 -2
- package/src/utils/sendPush/sendPush.ts +0 -20
- package/src/utils/sendPush/sendPush.types.ts +0 -25
- package/src/utils/tlsConfig/index.ts +0 -2
- package/src/utils/tlsConfig/tlsConfig.test.ts +0 -32
- package/src/utils/tlsConfig/tlsConfig.ts +0 -47
- package/src/utils/tlsConfig/tlsConfig.types.ts +0 -11
- package/src/utils/tlsConfig/tlsConfig.validate.ts +0 -25
- package/src/utils/tlsRequest/index.ts +0 -1
- package/src/utils/tlsRequest/tlsRequest.test.ts +0 -63
- package/src/utils/tlsRequest/tlsRequest.ts +0 -12
- package/src/utils/trimPathSlash/index.ts +0 -1
- package/src/utils/trimPathSlash/trimPathSlash.test.ts +0 -26
- package/src/utils/trimPathSlash/trimPathSlash.ts +0 -8
- package/test/env.ts +0 -53
- package/test/factory/index.ts +0 -8
- package/test/factory/sequelizeMeta.ts +0 -12
- package/test/hooks.ts +0 -35
- package/test/index.ts +0 -3
- package/test/stub/index.ts +0 -3
- package/test/stub/stubLocales.ts +0 -68
- package/test/stub/stubPubSub.ts +0 -7
- package/test/stub/stubStorage.ts +0 -77
- package/test/stub/stubStorage.types.ts +0 -11
- package/test/utils/app.ts +0 -31
- package/test/utils/index.ts +0 -1
- package/tsconfig.build.json +0 -5
- package/tsconfig.json +0 -32
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { guessNamingConvention } from './guessNamingConvention';
|
|
2
|
-
import {
|
|
3
|
-
LocalizatorLocalizationData,
|
|
4
|
-
LocalizatorLocalizationDataElement,
|
|
5
|
-
LocalizatorScripts,
|
|
6
|
-
LocalizatorNamingConventions
|
|
7
|
-
} from './Localizator.types';
|
|
8
|
-
import { EngineError } from 'entities/EngineError';
|
|
9
|
-
import { LifecycleController } from 'entities/LifecycleController';
|
|
10
|
-
import { Storage } from 'entities/Storage';
|
|
11
|
-
import { checkEnvironment } from 'utils/checkEnvironment';
|
|
12
|
-
import { envAssert } from 'utils/envAssert';
|
|
13
|
-
import { reportError, reportDebug } from 'utils/report';
|
|
14
|
-
|
|
15
|
-
const namespace = 'engine:localizator';
|
|
16
|
-
|
|
17
|
-
const REFRESH_FREQUENCY = 10 * 60 * 1000;
|
|
18
|
-
|
|
19
|
-
let localeData: undefined | LocalizatorLocalizationData;
|
|
20
|
-
let scripts: undefined | LocalizatorScripts;
|
|
21
|
-
let interval: NodeJS.Timeout | string | number | undefined;
|
|
22
|
-
|
|
23
|
-
/** Service handling contextual localization */
|
|
24
|
-
export const Localizator = {
|
|
25
|
-
async init(): Promise<void> {
|
|
26
|
-
checkEnvironment({ LOCALES_BUCKET: envAssert.isString() });
|
|
27
|
-
await Localizator.synchronize();
|
|
28
|
-
// Keep synchronizing
|
|
29
|
-
interval = setInterval(() => {
|
|
30
|
-
Localizator.synchronize().catch((error) => {
|
|
31
|
-
reportError(error);
|
|
32
|
-
});
|
|
33
|
-
}, REFRESH_FREQUENCY);
|
|
34
|
-
LifecycleController.register(Localizator);
|
|
35
|
-
},
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Fetch a JSON file from the locales bucket
|
|
39
|
-
*/
|
|
40
|
-
async getLocaleFile<T>(file: string): Promise<T> {
|
|
41
|
-
reportDebug({
|
|
42
|
-
namespace,
|
|
43
|
-
message: `Starting download of localization file [${file}]`,
|
|
44
|
-
data: { bucket: process.env.LOCALES_BUCKET, file }
|
|
45
|
-
});
|
|
46
|
-
const { data } = await Storage.get(
|
|
47
|
-
process.env.LOCALES_BUCKET as string,
|
|
48
|
-
file
|
|
49
|
-
);
|
|
50
|
-
const stringified = data.toString('utf-8');
|
|
51
|
-
const result = JSON.parse(stringified) as T;
|
|
52
|
-
reportDebug({
|
|
53
|
-
namespace,
|
|
54
|
-
message: `Fetched localization file [${file}]`,
|
|
55
|
-
data: { bucket: process.env.LOCALES_BUCKET, file, result }
|
|
56
|
-
});
|
|
57
|
-
return result;
|
|
58
|
-
},
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Synchronizes the localeData and scripts files
|
|
62
|
-
* Should be called only once on startup
|
|
63
|
-
*/
|
|
64
|
-
async synchronize(): Promise<void> {
|
|
65
|
-
reportDebug({ namespace, message: `Starting synchronizing` });
|
|
66
|
-
const [fetchedLocaleData, fetchedScripts] = await Promise.all([
|
|
67
|
-
Localizator.getLocaleFile<LocalizatorLocalizationData>('localeData.json'),
|
|
68
|
-
Localizator.getLocaleFile<LocalizatorScripts>('scripts.json')
|
|
69
|
-
]);
|
|
70
|
-
localeData = fetchedLocaleData;
|
|
71
|
-
scripts = Localizator.buildRangeRegex(fetchedScripts);
|
|
72
|
-
reportDebug({ namespace, message: `Finished synchronizing` });
|
|
73
|
-
},
|
|
74
|
-
|
|
75
|
-
/** Transform unicode ranges in scripts data to regex */
|
|
76
|
-
buildRangeRegex(script: LocalizatorScripts): LocalizatorScripts {
|
|
77
|
-
for (const i of Object.keys(script)) {
|
|
78
|
-
const ranges = script[i].ranges;
|
|
79
|
-
if (ranges) {
|
|
80
|
-
script[i].rangeRegex = new RegExp(`[${ranges.join('')}]`, 'u');
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return script;
|
|
84
|
-
},
|
|
85
|
-
|
|
86
|
-
/** Guess the naming convention to use for a given name and locale */
|
|
87
|
-
guessNamingConvention(
|
|
88
|
-
firstName: string,
|
|
89
|
-
lastName: string,
|
|
90
|
-
locale: string
|
|
91
|
-
): LocalizatorNamingConventions {
|
|
92
|
-
if (!scripts || !localeData)
|
|
93
|
-
throw new EngineError({ message: 'Localizator is not initialized' });
|
|
94
|
-
const name = firstName + lastName; // merge two names if possible
|
|
95
|
-
return guessNamingConvention(scripts, localeData, name, locale);
|
|
96
|
-
},
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Calculate the different display names for a user
|
|
100
|
-
*/
|
|
101
|
-
getDisplayNames(
|
|
102
|
-
firstName: string,
|
|
103
|
-
lastName: string,
|
|
104
|
-
locale: string
|
|
105
|
-
): LocalizatorNamingConventions {
|
|
106
|
-
const convention = Localizator.guessNamingConvention(
|
|
107
|
-
firstName,
|
|
108
|
-
lastName,
|
|
109
|
-
locale
|
|
110
|
-
);
|
|
111
|
-
return Object.keys(convention).reduce((convention, type) => {
|
|
112
|
-
const safeType = type as keyof LocalizatorNamingConventions;
|
|
113
|
-
convention[safeType] = convention[safeType]
|
|
114
|
-
.replace('{firstName}', firstName)
|
|
115
|
-
.replace('{lastName}', lastName ?? '')
|
|
116
|
-
.trim();
|
|
117
|
-
return convention;
|
|
118
|
-
}, convention);
|
|
119
|
-
},
|
|
120
|
-
|
|
121
|
-
/** Get the localization data for a locale */
|
|
122
|
-
getLocaleData(locale: string): LocalizatorLocalizationDataElement {
|
|
123
|
-
if (!localeData)
|
|
124
|
-
throw new EngineError({ message: 'Localizator is not initialized' });
|
|
125
|
-
return localeData[locale];
|
|
126
|
-
},
|
|
127
|
-
|
|
128
|
-
/** Check if a locale exists */
|
|
129
|
-
isValidLocale(locale: string): boolean {
|
|
130
|
-
if (!localeData)
|
|
131
|
-
throw new EngineError({ message: 'Localizator is not initialized' });
|
|
132
|
-
return localeData[locale] !== undefined;
|
|
133
|
-
},
|
|
134
|
-
|
|
135
|
-
/** Cleanup the instance */
|
|
136
|
-
shutdown(): void {
|
|
137
|
-
if (interval) clearTimeout(interval);
|
|
138
|
-
}
|
|
139
|
-
};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/** Defines how a name should be displayed for a locale in diferent context */
|
|
2
|
-
export interface LocalizatorNamingConventions {
|
|
3
|
-
/** How the name is displayed in a common way */
|
|
4
|
-
regular: string;
|
|
5
|
-
/** How the name is displayed in a formal way */
|
|
6
|
-
formal: string;
|
|
7
|
-
/** How the name is displayed in a casual way */
|
|
8
|
-
casual: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/** Localization data for each of the locales */
|
|
12
|
-
export interface LocalizatorLocalizationData {
|
|
13
|
-
[locale: string]: LocalizatorLocalizationDataElement;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** Describes localization settings for a locale */
|
|
17
|
-
export interface LocalizatorLocalizationDataElement {
|
|
18
|
-
/** Is this locale available to the public */
|
|
19
|
-
enabled: boolean;
|
|
20
|
-
/** How this locale is displayed to the user */
|
|
21
|
-
display: string;
|
|
22
|
-
/** Configuration on how to display names in that locale */
|
|
23
|
-
names: {
|
|
24
|
-
/** Should the first name or the last name be displayed first */
|
|
25
|
-
firstNameFirst: boolean;
|
|
26
|
-
/** Is there a space between the two parts of the name */
|
|
27
|
-
spacing: boolean;
|
|
28
|
-
/** In case the user's name is not displayed in this language's script, how should it be displayed */
|
|
29
|
-
fallback?: LocalizatorNamingConventions;
|
|
30
|
-
};
|
|
31
|
-
/** Script used to identify text written in that language */
|
|
32
|
-
script?: string;
|
|
33
|
-
/** Key in google translation to identify that language */
|
|
34
|
-
cloudTranslationKey: string;
|
|
35
|
-
/** Unicode CLDR key to identify that language if it is different from the locale */
|
|
36
|
-
unicode?: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** Script config data indexed by the script id */
|
|
40
|
-
export interface LocalizatorScripts {
|
|
41
|
-
[script: string]: LocalizatorScript;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/** Localization config for a script */
|
|
45
|
-
export interface LocalizatorScript {
|
|
46
|
-
/** Unicode range used to detect the script */
|
|
47
|
-
ranges: Array<string>;
|
|
48
|
-
/** How names are displayed when written in the script */
|
|
49
|
-
names: LocalizatorNamingConventions;
|
|
50
|
-
/** Regex added by the Localizator, used to match with the script unicode ranges */
|
|
51
|
-
rangeRegex?: RegExp;
|
|
52
|
-
}
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import { expect } from 'chai';
|
|
2
|
-
import { faker } from '@faker-js/faker';
|
|
3
|
-
import {
|
|
4
|
-
LocalizatorScript,
|
|
5
|
-
LocalizatorLocalizationDataElement
|
|
6
|
-
} from '../Localizator.types';
|
|
7
|
-
import {
|
|
8
|
-
guessNamingConvention,
|
|
9
|
-
DEFAULT_NAMING_CONVENTION
|
|
10
|
-
} from './guessNamingConvention';
|
|
11
|
-
|
|
12
|
-
/** Generate fake script config */
|
|
13
|
-
function generateScriptData(
|
|
14
|
-
overrides: Partial<LocalizatorScript> = {}
|
|
15
|
-
): LocalizatorScript {
|
|
16
|
-
return {
|
|
17
|
-
rangeRegex: new RegExp(`^\b$`, 'u'),
|
|
18
|
-
ranges: ['a'],
|
|
19
|
-
names: {
|
|
20
|
-
casual: faker.lorem.slug(),
|
|
21
|
-
regular: faker.lorem.slug(),
|
|
22
|
-
formal: faker.lorem.slug()
|
|
23
|
-
},
|
|
24
|
-
...overrides
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/** Generate locales file random data */
|
|
29
|
-
function generateLocalizationData(
|
|
30
|
-
overrides: Partial<LocalizatorLocalizationDataElement> = {}
|
|
31
|
-
): LocalizatorLocalizationDataElement {
|
|
32
|
-
return {
|
|
33
|
-
script: faker.lorem.word(),
|
|
34
|
-
enabled: true,
|
|
35
|
-
display: faker.lorem.word(),
|
|
36
|
-
names: {
|
|
37
|
-
firstNameFirst: true,
|
|
38
|
-
spacing: true
|
|
39
|
-
},
|
|
40
|
-
cloudTranslationKey: faker.location.countryCode(),
|
|
41
|
-
...overrides
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
describe('Service - Localizator - Guess naming convention', function () {
|
|
46
|
-
it('should return the convention for the locale specifc script', function () {
|
|
47
|
-
const locale = faker.location.country();
|
|
48
|
-
const userScript = faker.lorem.word();
|
|
49
|
-
const name = faker.lorem.word();
|
|
50
|
-
const scriptData = generateScriptData({
|
|
51
|
-
rangeRegex: new RegExp(name, 'u')
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
const Localizator = {
|
|
55
|
-
localeData: {
|
|
56
|
-
[faker.location.countryCode()]: generateLocalizationData(),
|
|
57
|
-
[locale]: generateLocalizationData({ script: userScript })
|
|
58
|
-
},
|
|
59
|
-
scripts: {
|
|
60
|
-
[faker.lorem.word()]: generateScriptData(),
|
|
61
|
-
[userScript]: scriptData
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
const result = guessNamingConvention(
|
|
65
|
-
Localizator.scripts,
|
|
66
|
-
Localizator.localeData,
|
|
67
|
-
name,
|
|
68
|
-
locale
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
expect(result).to.equal(scriptData.names);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('should return the convention for the the script detected in the name if no match wirth the default script', function () {
|
|
75
|
-
const locale = faker.location.country();
|
|
76
|
-
const expectedResult = {
|
|
77
|
-
casual: faker.lorem.word(),
|
|
78
|
-
regular: faker.lorem.word(),
|
|
79
|
-
formal: faker.lorem.word()
|
|
80
|
-
};
|
|
81
|
-
const userScript = faker.lorem.word();
|
|
82
|
-
const name = faker.lorem.word();
|
|
83
|
-
const Localizator = {
|
|
84
|
-
localeData: {
|
|
85
|
-
[faker.location.countryCode()]: generateLocalizationData(),
|
|
86
|
-
[locale]: generateLocalizationData({ script: userScript })
|
|
87
|
-
},
|
|
88
|
-
scripts: {
|
|
89
|
-
[faker.lorem.word()]: generateScriptData(),
|
|
90
|
-
[userScript]: generateScriptData(),
|
|
91
|
-
[faker.lorem.word()]: generateScriptData({
|
|
92
|
-
rangeRegex: new RegExp(name, 'u'),
|
|
93
|
-
names: expectedResult
|
|
94
|
-
})
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
const result = guessNamingConvention(
|
|
98
|
-
Localizator.scripts,
|
|
99
|
-
Localizator.localeData,
|
|
100
|
-
name,
|
|
101
|
-
locale
|
|
102
|
-
);
|
|
103
|
-
expect(result).to.equal(expectedResult);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('should return the convention for the locale if no script match', function () {
|
|
107
|
-
const locale = faker.location.country();
|
|
108
|
-
const expectedResult = {
|
|
109
|
-
casual: faker.lorem.word(),
|
|
110
|
-
regular: faker.lorem.word(),
|
|
111
|
-
formal: faker.lorem.word()
|
|
112
|
-
};
|
|
113
|
-
const userScript = faker.lorem.word();
|
|
114
|
-
const name = faker.lorem.word();
|
|
115
|
-
const Localizator = {
|
|
116
|
-
localeData: {
|
|
117
|
-
[faker.location.countryCode()]: generateLocalizationData({
|
|
118
|
-
script: faker.lorem.word()
|
|
119
|
-
}),
|
|
120
|
-
[locale]: generateLocalizationData({
|
|
121
|
-
script: userScript,
|
|
122
|
-
names: {
|
|
123
|
-
firstNameFirst: true,
|
|
124
|
-
spacing: true,
|
|
125
|
-
fallback: expectedResult
|
|
126
|
-
}
|
|
127
|
-
})
|
|
128
|
-
},
|
|
129
|
-
scripts: {
|
|
130
|
-
[faker.lorem.word()]: generateScriptData(),
|
|
131
|
-
[userScript]: generateScriptData()
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
const result = guessNamingConvention(
|
|
135
|
-
Localizator.scripts,
|
|
136
|
-
Localizator.localeData,
|
|
137
|
-
name,
|
|
138
|
-
locale
|
|
139
|
-
);
|
|
140
|
-
expect(result).to.equal(expectedResult);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('should use the default if no fallback exist', function () {
|
|
144
|
-
const locale = faker.location.country();
|
|
145
|
-
const userScript = faker.lorem.word();
|
|
146
|
-
const name = faker.lorem.word();
|
|
147
|
-
const Localizator = {
|
|
148
|
-
localeData: {
|
|
149
|
-
[faker.location.countryCode()]: generateLocalizationData(),
|
|
150
|
-
[locale]: generateLocalizationData({ script: userScript })
|
|
151
|
-
},
|
|
152
|
-
scripts: {
|
|
153
|
-
[faker.lorem.word()]: generateScriptData(),
|
|
154
|
-
[userScript]: generateScriptData()
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
const result = guessNamingConvention(
|
|
158
|
-
Localizator.scripts,
|
|
159
|
-
Localizator.localeData,
|
|
160
|
-
name,
|
|
161
|
-
locale
|
|
162
|
-
);
|
|
163
|
-
expect(result).to.equal(DEFAULT_NAMING_CONVENTION);
|
|
164
|
-
});
|
|
165
|
-
});
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
LocalizatorLocalizationData,
|
|
3
|
-
LocalizatorScripts,
|
|
4
|
-
LocalizatorNamingConventions
|
|
5
|
-
} from '../Localizator.types';
|
|
6
|
-
|
|
7
|
-
export const DEFAULT_NAMING_CONVENTION = {
|
|
8
|
-
regular: '{firstName} {lastName}',
|
|
9
|
-
formal: '{firstName}',
|
|
10
|
-
casual: '{firstName}'
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
/** Guess the naming convention to use for a given name and locale */
|
|
14
|
-
export function guessNamingConvention(
|
|
15
|
-
scripts: LocalizatorScripts,
|
|
16
|
-
localeData: LocalizatorLocalizationData,
|
|
17
|
-
name: string,
|
|
18
|
-
locale: string
|
|
19
|
-
): LocalizatorNamingConventions {
|
|
20
|
-
// When the locale has a specific script
|
|
21
|
-
// Check if the name matches that script, and use its naming convention
|
|
22
|
-
if (localeData[locale]?.script) {
|
|
23
|
-
const defaultScript = localeData[locale].script as string;
|
|
24
|
-
if (
|
|
25
|
-
testScriptMatch(scripts, defaultScript, name) &&
|
|
26
|
-
scripts[defaultScript].names
|
|
27
|
-
) {
|
|
28
|
-
return scripts[defaultScript].names;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Check if there is a match with any given script and use its naming convention
|
|
33
|
-
for (const script of Object.keys(scripts)) {
|
|
34
|
-
if (testScriptMatch(scripts, script, name) && scripts[script].names) {
|
|
35
|
-
return scripts[script].names;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Use the current locale's fallback convention
|
|
40
|
-
if (localeData[locale]?.names?.fallback) {
|
|
41
|
-
return localeData[locale].names.fallback as LocalizatorNamingConventions;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// If everything fails, use the default convention
|
|
45
|
-
return DEFAULT_NAMING_CONVENTION;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** Test if a given string is in a given script */
|
|
49
|
-
function testScriptMatch(
|
|
50
|
-
scripts: LocalizatorScripts,
|
|
51
|
-
script: string,
|
|
52
|
-
string: string
|
|
53
|
-
): boolean {
|
|
54
|
-
if (scripts[script]?.rangeRegex) {
|
|
55
|
-
return (scripts[script].rangeRegex as RegExp).test(string);
|
|
56
|
-
}
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './guessNamingConvention';
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import Ajv, { JSONSchemaType } from 'ajv';
|
|
2
|
-
import { expect } from 'chai';
|
|
3
|
-
import { faker } from '@faker-js/faker';
|
|
4
|
-
import { fake, match } from 'sinon';
|
|
5
|
-
import { MessageHandler } from './MessageHandler';
|
|
6
|
-
import { SocketClient } from 'entities/SocketClient';
|
|
7
|
-
|
|
8
|
-
const ajv = new Ajv();
|
|
9
|
-
|
|
10
|
-
/** */
|
|
11
|
-
interface TestPayload {
|
|
12
|
-
/** */
|
|
13
|
-
test?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
type TestSchema = JSONSchemaType<TestPayload>;
|
|
17
|
-
|
|
18
|
-
const schema: TestSchema = {
|
|
19
|
-
type: 'object',
|
|
20
|
-
properties: {
|
|
21
|
-
test: { type: 'string', nullable: true }
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const validator = ajv.compile(schema);
|
|
26
|
-
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
28
|
-
// @ts-ignore
|
|
29
|
-
const client = { isAuthenticated: () => true } as SocketClient;
|
|
30
|
-
|
|
31
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
32
|
-
// @ts-ignore
|
|
33
|
-
const unauthenticatedClient = { isAuthenticated: () => false } as SocketClient;
|
|
34
|
-
|
|
35
|
-
describe('Entities - Message Handler', () => {
|
|
36
|
-
it('should call the handler', async () => {
|
|
37
|
-
const type = faker.lorem.word();
|
|
38
|
-
const handler = fake();
|
|
39
|
-
const entity = new MessageHandler(type, handler, validator);
|
|
40
|
-
const message = { type, payload: {} };
|
|
41
|
-
|
|
42
|
-
await entity.handle(message, client);
|
|
43
|
-
|
|
44
|
-
expect(handler).to.have.been.calledOnceWithExactly(
|
|
45
|
-
message.payload,
|
|
46
|
-
match(client)
|
|
47
|
-
);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should not call the handler if the type is different', async () => {
|
|
51
|
-
const handler = fake();
|
|
52
|
-
const entity = new MessageHandler(faker.lorem.word(), handler, validator);
|
|
53
|
-
const message = { type: faker.lorem.word(), payload: {} };
|
|
54
|
-
|
|
55
|
-
await entity.handle(message, client);
|
|
56
|
-
|
|
57
|
-
expect(handler).to.not.have.been.called;
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('should not call the handler if the client is not authenticated', async () => {
|
|
61
|
-
const type = faker.lorem.word();
|
|
62
|
-
const handler = fake();
|
|
63
|
-
const entity = new MessageHandler(type, handler, validator);
|
|
64
|
-
const message = { type, payload: {} };
|
|
65
|
-
|
|
66
|
-
await entity.handle(message, unauthenticatedClient);
|
|
67
|
-
|
|
68
|
-
expect(handler).to.not.have.been.called;
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('should call the handler if the client is not authenticated, but that it is not required', async () => {
|
|
72
|
-
const type = faker.lorem.word();
|
|
73
|
-
const handler = fake();
|
|
74
|
-
const entity = new MessageHandler(type, handler, validator, {
|
|
75
|
-
authenticated: false
|
|
76
|
-
});
|
|
77
|
-
const message = { type, payload: {} };
|
|
78
|
-
|
|
79
|
-
await entity.handle(message, unauthenticatedClient);
|
|
80
|
-
|
|
81
|
-
expect(handler).to.have.been.calledOnceWithExactly(
|
|
82
|
-
message.payload,
|
|
83
|
-
match(unauthenticatedClient)
|
|
84
|
-
);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
describe('schema validation', () => {
|
|
88
|
-
/** */
|
|
89
|
-
interface TestPayload {
|
|
90
|
-
/** */
|
|
91
|
-
test: string;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
type TestSchema = JSONSchemaType<TestPayload>;
|
|
95
|
-
|
|
96
|
-
const schema: TestSchema = {
|
|
97
|
-
type: 'object',
|
|
98
|
-
properties: {
|
|
99
|
-
test: { type: 'string' }
|
|
100
|
-
},
|
|
101
|
-
required: ['test']
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
const validator = ajv.compile(schema);
|
|
105
|
-
|
|
106
|
-
it('should call the handler if the payload passes validation', async () => {
|
|
107
|
-
const type = faker.lorem.word();
|
|
108
|
-
const handler = fake();
|
|
109
|
-
const entity = new MessageHandler(type, handler, validator);
|
|
110
|
-
const message = { type, payload: { test: faker.lorem.word() } };
|
|
111
|
-
|
|
112
|
-
await entity.handle(message, client);
|
|
113
|
-
|
|
114
|
-
expect(handler).to.have.been.calledOnceWithExactly(
|
|
115
|
-
message.payload,
|
|
116
|
-
match(client)
|
|
117
|
-
);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it('should throw an error if the payload does not pass validation', async () => {
|
|
121
|
-
const type = faker.lorem.word();
|
|
122
|
-
const handler = fake();
|
|
123
|
-
const entity = new MessageHandler(type, handler, validator);
|
|
124
|
-
const message = { type, payload: { test: faker.number.int() } };
|
|
125
|
-
|
|
126
|
-
const result = entity.handle(message, client);
|
|
127
|
-
await expect(result).to.be.rejected;
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
});
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { ValidateFunction } from 'ajv';
|
|
2
|
-
import { EngineError } from '../EngineError';
|
|
3
|
-
import {
|
|
4
|
-
MessageHandlerOptions,
|
|
5
|
-
MessageHandlerHandler
|
|
6
|
-
} from './MessageHandler.types';
|
|
7
|
-
import { SocketMessage, SocketClient } from 'entities/SocketClient';
|
|
8
|
-
import { WebError } from 'entities/WebError';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Message handlers should be used to define how messages should be handled in web socket servers
|
|
12
|
-
*/
|
|
13
|
-
export class MessageHandler {
|
|
14
|
-
/** The type of messages that are handled by the instance */
|
|
15
|
-
public readonly type: string;
|
|
16
|
-
/** Function that should handle the message */
|
|
17
|
-
private handler: MessageHandlerHandler;
|
|
18
|
-
/** Schema against which incoming messages should be validated */
|
|
19
|
-
private validator: ValidateFunction;
|
|
20
|
-
/** Indicates that this handler should only run when the client is authenticated */
|
|
21
|
-
private authenticated: boolean;
|
|
22
|
-
|
|
23
|
-
/** Create a new websocket message handler */
|
|
24
|
-
public constructor(
|
|
25
|
-
type: string,
|
|
26
|
-
handler: MessageHandlerHandler,
|
|
27
|
-
validator: ValidateFunction,
|
|
28
|
-
options: MessageHandlerOptions = {}
|
|
29
|
-
) {
|
|
30
|
-
if (!type)
|
|
31
|
-
throw new EngineError({ message: 'MessageHandler has no type defined' });
|
|
32
|
-
this.type = type;
|
|
33
|
-
if (!handler)
|
|
34
|
-
throw new EngineError({
|
|
35
|
-
message: 'MessageHandler should have a handler function'
|
|
36
|
-
});
|
|
37
|
-
this.handler = handler;
|
|
38
|
-
this.validator = validator;
|
|
39
|
-
this.authenticated = options.authenticated ?? true;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** Handle received messages, and propagate them to the handler if needed */
|
|
43
|
-
public async handle(
|
|
44
|
-
message: SocketMessage,
|
|
45
|
-
client: SocketClient
|
|
46
|
-
): Promise<void> {
|
|
47
|
-
const valid = this.validator(message.payload);
|
|
48
|
-
if (!valid) {
|
|
49
|
-
const hint = this.validator.errors?.reduce(
|
|
50
|
-
(hint, error) => ({
|
|
51
|
-
...hint,
|
|
52
|
-
[error.instancePath]: error.message
|
|
53
|
-
? `${error.keyword}: ${error.message}`
|
|
54
|
-
: error.keyword
|
|
55
|
-
}),
|
|
56
|
-
{}
|
|
57
|
-
);
|
|
58
|
-
throw new WebError({
|
|
59
|
-
statusCode: 400,
|
|
60
|
-
errorCode: 'invalid-message',
|
|
61
|
-
message: 'Message validation failed',
|
|
62
|
-
data: hint,
|
|
63
|
-
hint
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
// Do not handle if it not for this type of handler
|
|
67
|
-
if (this.type !== message.type) return;
|
|
68
|
-
// When handler requires authentication but that client is not authenticated, do not handle the message.
|
|
69
|
-
if (this.authenticated && !client.isAuthenticated()) return;
|
|
70
|
-
await this.handler(message.payload ?? {}, client);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { ValidateFunction } from 'ajv';
|
|
2
|
-
import { SocketClient } from 'entities/SocketClient';
|
|
3
|
-
|
|
4
|
-
/** Initialization options for the message handler */
|
|
5
|
-
export interface MessageHandlerOptions {
|
|
6
|
-
/** The handler will only be called for authenticated clients (default: true) */
|
|
7
|
-
authenticated?: boolean;
|
|
8
|
-
/** Schema to validate the message before passing it to the handler */
|
|
9
|
-
validator?: ValidateFunction;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export type MessageHandlerHandler = (
|
|
13
|
-
payload: unknown,
|
|
14
|
-
client: SocketClient
|
|
15
|
-
) => unknown | Promise<unknown>;
|