@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
- return [200, this.storage.filterUser(user)];
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
- return [200, this.storage.filterUser(user)];
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.10",
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.9",
45
+ "@types/cookie-parser": "^1.4.10",
46
46
  "@types/cors": "^2.8.19",
47
- "@types/express": "^4.17.23",
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.21.2",
54
- "jsonwebtoken": "^9.0.2",
53
+ "express": "^4.22.1",
54
+ "jsonwebtoken": "^9.0.3",
55
55
  "multer": "^2.0.2",
56
- "mysql2": "^3.15.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.46.1",
66
- "@typescript-eslint/parser": "^8.46.1",
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.37.0",
69
+ "eslint": "^9.39.2",
70
70
  "eslint-plugin-import": "^2.32.0",
71
- "eslint-plugin-vue": "^10.5.1",
72
- "prettier": "^3.6.2",
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"