@technomoron/api-server-base 2.0.0-beta.10 → 2.0.0-beta.11
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.
|
@@ -619,6 +619,7 @@ class ApiServer {
|
|
|
619
619
|
const path = `${this.apiBasePath}/v1/ping`;
|
|
620
620
|
this.app.get(path, (_req, res) => {
|
|
621
621
|
const payload = {
|
|
622
|
+
success: true,
|
|
622
623
|
status: 'ok',
|
|
623
624
|
apiVersion: this.config.apiVersion ?? '',
|
|
624
625
|
minClientVersion: this.config.minClientVersion ?? '',
|
|
@@ -626,7 +627,7 @@ class ApiServer {
|
|
|
626
627
|
startedAt: this.startedAt,
|
|
627
628
|
timestamp: new Date().toISOString()
|
|
628
629
|
};
|
|
629
|
-
res.status(200).json({ code: 200, message: 'Success', data: payload });
|
|
630
|
+
res.status(200).json({ success: true, code: 200, message: 'Success', data: payload, errors: {} });
|
|
630
631
|
});
|
|
631
632
|
}
|
|
632
633
|
normalizeApiBasePath(path) {
|
|
@@ -649,6 +650,7 @@ class ApiServer {
|
|
|
649
650
|
}
|
|
650
651
|
this.apiNotFoundHandler = (req, res) => {
|
|
651
652
|
const payload = {
|
|
653
|
+
success: false,
|
|
652
654
|
code: 404,
|
|
653
655
|
message: this.describeMissingEndpoint(req),
|
|
654
656
|
data: null,
|
|
@@ -1068,6 +1070,7 @@ class ApiServer {
|
|
|
1068
1070
|
? apiError.errors
|
|
1069
1071
|
: {};
|
|
1070
1072
|
const errorPayload = {
|
|
1073
|
+
success: false,
|
|
1071
1074
|
code: apiError.code,
|
|
1072
1075
|
message: apiError.message,
|
|
1073
1076
|
data: apiError.data ?? null,
|
|
@@ -1077,6 +1080,7 @@ class ApiServer {
|
|
|
1077
1080
|
return;
|
|
1078
1081
|
}
|
|
1079
1082
|
const errorPayload = {
|
|
1083
|
+
success: false,
|
|
1080
1084
|
code: 500,
|
|
1081
1085
|
message: this.guessExceptionText(error),
|
|
1082
1086
|
data: null,
|
|
@@ -1111,7 +1115,7 @@ class ApiServer {
|
|
|
1111
1115
|
throw new ApiError({ code: 500, message: 'Handler result must start with a numeric status code' });
|
|
1112
1116
|
}
|
|
1113
1117
|
const message = typeof rawMessage === 'string' ? rawMessage : 'Success';
|
|
1114
|
-
const responsePayload = { code, message, data };
|
|
1118
|
+
const responsePayload = { success: true, code, message, data, errors: {} };
|
|
1115
1119
|
if (this.config.debug) {
|
|
1116
1120
|
this.dumpResponse(apiReq, responsePayload, code);
|
|
1117
1121
|
}
|
|
@@ -1124,6 +1128,7 @@ class ApiServer {
|
|
|
1124
1128
|
? apiError.errors
|
|
1125
1129
|
: {};
|
|
1126
1130
|
const errorPayload = {
|
|
1131
|
+
success: false,
|
|
1127
1132
|
code: apiError.code,
|
|
1128
1133
|
message: apiError.message,
|
|
1129
1134
|
data: apiError.data ?? null,
|
|
@@ -1136,6 +1141,7 @@ class ApiServer {
|
|
|
1136
1141
|
}
|
|
1137
1142
|
else {
|
|
1138
1143
|
const errorPayload = {
|
|
1144
|
+
success: false,
|
|
1139
1145
|
code: 500,
|
|
1140
1146
|
message: this.guessExceptionText(error),
|
|
1141
1147
|
data: null,
|
|
@@ -565,7 +565,28 @@ class AuthModule extends module_js_1.BaseAuthModule {
|
|
|
565
565
|
: cookiePrefs.refreshTtlSeconds;
|
|
566
566
|
this.setJwtCookies(apiReq, { accessToken: access.token, refreshToken }, { sessionCookie: cookiePrefs.sessionCookie ?? false, refreshTtlSeconds: refreshTtlForCookie });
|
|
567
567
|
}
|
|
568
|
-
|
|
568
|
+
const tokenClaims = verify.data;
|
|
569
|
+
const effectiveUserId = this.storage.getUserId(user);
|
|
570
|
+
const effectiveId = String(effectiveUserId);
|
|
571
|
+
const rawRealId = stored.ruid ?? tokenClaims.ruid;
|
|
572
|
+
const normalizedRealId = rawRealId === undefined || rawRealId === null ? null : String(rawRealId).trim() || null;
|
|
573
|
+
const isImpersonating = normalizedRealId !== null && normalizedRealId !== effectiveId;
|
|
574
|
+
let realUser;
|
|
575
|
+
let realUserId;
|
|
576
|
+
if (isImpersonating && normalizedRealId !== null) {
|
|
577
|
+
const realUserEntity = await this.getUserOrThrow(normalizedRealId, 'Real user not found');
|
|
578
|
+
realUser = this.storage.filterUser(realUserEntity);
|
|
579
|
+
realUserId = this.storage.getUserId(realUserEntity);
|
|
580
|
+
}
|
|
581
|
+
return [
|
|
582
|
+
200,
|
|
583
|
+
{
|
|
584
|
+
user: this.storage.filterUser(user),
|
|
585
|
+
isImpersonating,
|
|
586
|
+
realUser,
|
|
587
|
+
realUserId
|
|
588
|
+
}
|
|
589
|
+
];
|
|
569
590
|
}
|
|
570
591
|
async postPasskeyChallenge(apiReq) {
|
|
571
592
|
if (typeof this.storage.createPasskeyChallenge !== 'function') {
|
|
@@ -611,6 +611,7 @@ export class ApiServer {
|
|
|
611
611
|
const path = `${this.apiBasePath}/v1/ping`;
|
|
612
612
|
this.app.get(path, (_req, res) => {
|
|
613
613
|
const payload = {
|
|
614
|
+
success: true,
|
|
614
615
|
status: 'ok',
|
|
615
616
|
apiVersion: this.config.apiVersion ?? '',
|
|
616
617
|
minClientVersion: this.config.minClientVersion ?? '',
|
|
@@ -618,7 +619,7 @@ export class ApiServer {
|
|
|
618
619
|
startedAt: this.startedAt,
|
|
619
620
|
timestamp: new Date().toISOString()
|
|
620
621
|
};
|
|
621
|
-
res.status(200).json({ code: 200, message: 'Success', data: payload });
|
|
622
|
+
res.status(200).json({ success: true, code: 200, message: 'Success', data: payload, errors: {} });
|
|
622
623
|
});
|
|
623
624
|
}
|
|
624
625
|
normalizeApiBasePath(path) {
|
|
@@ -641,6 +642,7 @@ export class ApiServer {
|
|
|
641
642
|
}
|
|
642
643
|
this.apiNotFoundHandler = (req, res) => {
|
|
643
644
|
const payload = {
|
|
645
|
+
success: false,
|
|
644
646
|
code: 404,
|
|
645
647
|
message: this.describeMissingEndpoint(req),
|
|
646
648
|
data: null,
|
|
@@ -1060,6 +1062,7 @@ export class ApiServer {
|
|
|
1060
1062
|
? apiError.errors
|
|
1061
1063
|
: {};
|
|
1062
1064
|
const errorPayload = {
|
|
1065
|
+
success: false,
|
|
1063
1066
|
code: apiError.code,
|
|
1064
1067
|
message: apiError.message,
|
|
1065
1068
|
data: apiError.data ?? null,
|
|
@@ -1069,6 +1072,7 @@ export class ApiServer {
|
|
|
1069
1072
|
return;
|
|
1070
1073
|
}
|
|
1071
1074
|
const errorPayload = {
|
|
1075
|
+
success: false,
|
|
1072
1076
|
code: 500,
|
|
1073
1077
|
message: this.guessExceptionText(error),
|
|
1074
1078
|
data: null,
|
|
@@ -1103,7 +1107,7 @@ export class ApiServer {
|
|
|
1103
1107
|
throw new ApiError({ code: 500, message: 'Handler result must start with a numeric status code' });
|
|
1104
1108
|
}
|
|
1105
1109
|
const message = typeof rawMessage === 'string' ? rawMessage : 'Success';
|
|
1106
|
-
const responsePayload = { code, message, data };
|
|
1110
|
+
const responsePayload = { success: true, code, message, data, errors: {} };
|
|
1107
1111
|
if (this.config.debug) {
|
|
1108
1112
|
this.dumpResponse(apiReq, responsePayload, code);
|
|
1109
1113
|
}
|
|
@@ -1116,6 +1120,7 @@ export class ApiServer {
|
|
|
1116
1120
|
? apiError.errors
|
|
1117
1121
|
: {};
|
|
1118
1122
|
const errorPayload = {
|
|
1123
|
+
success: false,
|
|
1119
1124
|
code: apiError.code,
|
|
1120
1125
|
message: apiError.message,
|
|
1121
1126
|
data: apiError.data ?? null,
|
|
@@ -1128,6 +1133,7 @@ export class ApiServer {
|
|
|
1128
1133
|
}
|
|
1129
1134
|
else {
|
|
1130
1135
|
const errorPayload = {
|
|
1136
|
+
success: false,
|
|
1131
1137
|
code: 500,
|
|
1132
1138
|
message: this.guessExceptionText(error),
|
|
1133
1139
|
data: null,
|
|
@@ -563,7 +563,28 @@ class AuthModule extends BaseAuthModule {
|
|
|
563
563
|
: cookiePrefs.refreshTtlSeconds;
|
|
564
564
|
this.setJwtCookies(apiReq, { accessToken: access.token, refreshToken }, { sessionCookie: cookiePrefs.sessionCookie ?? false, refreshTtlSeconds: refreshTtlForCookie });
|
|
565
565
|
}
|
|
566
|
-
|
|
566
|
+
const tokenClaims = verify.data;
|
|
567
|
+
const effectiveUserId = this.storage.getUserId(user);
|
|
568
|
+
const effectiveId = String(effectiveUserId);
|
|
569
|
+
const rawRealId = stored.ruid ?? tokenClaims.ruid;
|
|
570
|
+
const normalizedRealId = rawRealId === undefined || rawRealId === null ? null : String(rawRealId).trim() || null;
|
|
571
|
+
const isImpersonating = normalizedRealId !== null && normalizedRealId !== effectiveId;
|
|
572
|
+
let realUser;
|
|
573
|
+
let realUserId;
|
|
574
|
+
if (isImpersonating && normalizedRealId !== null) {
|
|
575
|
+
const realUserEntity = await this.getUserOrThrow(normalizedRealId, 'Real user not found');
|
|
576
|
+
realUser = this.storage.filterUser(realUserEntity);
|
|
577
|
+
realUserId = this.storage.getUserId(realUserEntity);
|
|
578
|
+
}
|
|
579
|
+
return [
|
|
580
|
+
200,
|
|
581
|
+
{
|
|
582
|
+
user: this.storage.filterUser(user),
|
|
583
|
+
isImpersonating,
|
|
584
|
+
realUser,
|
|
585
|
+
realUserId
|
|
586
|
+
}
|
|
587
|
+
];
|
|
567
588
|
}
|
|
568
589
|
async postPasskeyChallenge(apiReq) {
|
|
569
590
|
if (typeof this.storage.createPasskeyChallenge !== 'function') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@technomoron/api-server-base",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.11",
|
|
4
4
|
"description": "Api Server Skeleton / Base Class",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.cjs",
|
|
@@ -42,18 +42,18 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@simplewebauthn/server": "^13.2.2",
|
|
45
|
-
"@types/cookie-parser": "^1.4.
|
|
45
|
+
"@types/cookie-parser": "^1.4.10",
|
|
46
46
|
"@types/cors": "^2.8.19",
|
|
47
|
-
"@types/express": "^4.17.
|
|
47
|
+
"@types/express": "^4.17.25",
|
|
48
48
|
"@types/jsonwebtoken": "^9.0.10",
|
|
49
49
|
"@types/multer": "^1.4.13",
|
|
50
50
|
"bcryptjs": "^2.4.3",
|
|
51
51
|
"cookie-parser": "^1.4.7",
|
|
52
52
|
"cors": "^2.8.5",
|
|
53
|
-
"express": "^4.
|
|
54
|
-
"jsonwebtoken": "^9.0.
|
|
53
|
+
"express": "^4.22.1",
|
|
54
|
+
"jsonwebtoken": "^9.0.3",
|
|
55
55
|
"multer": "^2.0.2",
|
|
56
|
-
"mysql2": "^3.
|
|
56
|
+
"mysql2": "^3.16.0",
|
|
57
57
|
"pg": "^8.16.3",
|
|
58
58
|
"sequelize": "^6.37.7",
|
|
59
59
|
"sqlite3": "^5.1.7"
|
|
@@ -62,14 +62,14 @@
|
|
|
62
62
|
"@types/bcryptjs": "^2.4.6",
|
|
63
63
|
"@types/express-serve-static-core": "^5.1.0",
|
|
64
64
|
"@types/supertest": "^6.0.3",
|
|
65
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
66
|
-
"@typescript-eslint/parser": "^8.
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^8.50.0",
|
|
66
|
+
"@typescript-eslint/parser": "^8.50.0",
|
|
67
67
|
"@vue/eslint-config-prettier": "10.2.0",
|
|
68
68
|
"@vue/eslint-config-typescript": "14.5.0",
|
|
69
|
-
"eslint": "^9.
|
|
69
|
+
"eslint": "^9.39.2",
|
|
70
70
|
"eslint-plugin-import": "^2.32.0",
|
|
71
|
-
"eslint-plugin-vue": "^10.
|
|
72
|
-
"prettier": "^3.
|
|
71
|
+
"eslint-plugin-vue": "^10.6.2",
|
|
72
|
+
"prettier": "^3.7.4",
|
|
73
73
|
"supertest": "^7.1.4",
|
|
74
74
|
"typescript": "^5.9.3",
|
|
75
75
|
"vitest": "^3.2.4"
|