@ah-oh/ao-workspaces-api-sdk 1.0.23 → 1.0.24

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.
Files changed (40) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +24 -21
  3. package/package.json +1 -1
  4. package/src/lib/auth.module.js +14 -23
  5. package/src/lib/auth.module.js.map +1 -1
  6. package/src/lib/customer-center.service.d.ts +42 -6
  7. package/src/lib/customer-center.service.js +136 -42
  8. package/src/lib/customer-center.service.js.map +1 -1
  9. package/src/lib/guards/auth.guard.js +3 -4
  10. package/src/lib/guards/auth.guard.js.map +1 -1
  11. package/src/lib/guards/company.guard.js +3 -0
  12. package/src/lib/guards/company.guard.js.map +1 -1
  13. package/src/lib/guards/sethub-permissions.guard.js +4 -1
  14. package/src/lib/guards/sethub-permissions.guard.js.map +1 -1
  15. package/src/lib/guards/super-admin.guard.js +3 -0
  16. package/src/lib/guards/super-admin.guard.js.map +1 -1
  17. package/src/lib/guards/szales-basic-auth.guard.js +33 -14
  18. package/src/lib/guards/szales-basic-auth.guard.js.map +1 -1
  19. package/src/lib/mail-settings.service.d.ts +3 -3
  20. package/src/lib/mail-settings.service.js +63 -251
  21. package/src/lib/mail-settings.service.js.map +1 -1
  22. package/src/lib/models/auth.options.d.ts +13 -0
  23. package/src/lib/print.client.d.ts +4 -3
  24. package/src/lib/print.client.js +46 -32
  25. package/src/lib/print.client.js.map +1 -1
  26. package/src/lib/utils/axios-error.handler.d.ts +11 -0
  27. package/src/lib/utils/axios-error.handler.js +24 -3
  28. package/src/lib/utils/axios-error.handler.js.map +1 -1
  29. package/src/lib/utils/http-client.d.ts +9 -0
  30. package/src/lib/utils/http-client.js +35 -0
  31. package/src/lib/utils/http-client.js.map +1 -0
  32. package/src/lib/utils/jwt.util.d.ts +6 -0
  33. package/src/lib/utils/jwt.util.js +21 -0
  34. package/src/lib/utils/jwt.util.js.map +1 -0
  35. package/src/lib/utils/ttl-cache.d.ts +26 -0
  36. package/src/lib/utils/ttl-cache.js +66 -0
  37. package/src/lib/utils/ttl-cache.js.map +1 -0
  38. package/src/lib/utils/url-path.d.ts +7 -0
  39. package/src/lib/utils/url-path.js +28 -0
  40. package/src/lib/utils/url-path.js.map +1 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## 1.0.24 (2026-10-18)
2
+
3
+ ### 🚀 Features
4
+
5
+ - **api-sdk:** cache sign-in tokens and harden requests ([ec22d4b](https://github.com/ah-oh/ao-workspaces/commit/ec22d4b))
6
+
7
+ ### ❤️ Thank You
8
+
9
+ - Claude Opus 5.5
10
+ - Jan Kessler
11
+
1
12
  ## 1.0.23 (2026-09-24)
2
13
 
3
14
  ### 🚀 Features
package/README.md CHANGED
@@ -18,8 +18,9 @@ Admin fest. Fachliche Regeln: `docs/features/hardware-connector/` im Repository
18
18
  `ah-oh/ao-workspaces`.
19
19
 
20
20
  Der `PrintClient` wird vom `AuthModule` bereitgestellt (`forRoot` oder
21
- `forRootAsync`) und meldet sich pro Aufruf mit dem User-Token der App an
22
- (`tokenId`, `tokenKey`). `product` ist die aufrufende App, **nicht** `admin` –
21
+ `forRootAsync`) und meldet sich mit dem User-Token der App an (`tokenId`,
22
+ `tokenKey`). Das JWT wird pro Zugangsdaten zwischengespeichert (siehe
23
+ `docs/api-sdk-authentifizierung.md`, Abschnitt Token-Cache). `product` ist die aufrufende App, **nicht** `admin` –
23
24
  nur so gilt der Aufruf als App und der Job trägt die App als Auslöser.
24
25
 
25
26
  ```ts
@@ -47,12 +48,12 @@ const current = await printClient.getJob({
47
48
  });
48
49
  ```
49
50
 
50
- | Methode | Zweck |
51
- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
52
- | `print` | Legt einen Job an und liefert ihn im Zustand `queued`. Optionen: `copies` (1–99), bei PDF `paperSize` und `color`, `idempotencyKey`, `expiresInSeconds`. |
53
- | `getJob` | Liefert den aktuellen Zustand eines Jobs inklusive `error`. |
54
- | `waitForJob` | Fragt den Job ab, bis er abgeschlossen ist (`completed`, `failed`, `expired`, `canceled`) oder `timeoutMs` (Standard 60 s) vergangen ist. Meldet sich einmal an. |
55
- | `isFinal` (statisch) | Prüft, ob ein Job sich nicht mehr ändert. `waitForJob` liefert nach Ablauf der Wartezeit den letzten, noch offenen Zustand. |
51
+ | Methode | Zweck |
52
+ | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
53
+ | `print` | Legt einen Job an und liefert ihn im Zustand `queued`. Optionen: `copies` (1–99), bei PDF `paperSize` und `color`, `idempotencyKey`, `expiresInSeconds`. |
54
+ | `getJob` | Liefert den aktuellen Zustand eines Jobs inklusive `error`. |
55
+ | `waitForJob` | Fragt den Job ab, bis er abgeschlossen ist (`completed`, `failed`, `expired`, `canceled`) oder `timeoutMs` (Standard 60 s) vergangen ist. Nutzt ein Token für alle Abfragen. |
56
+ | `isFinal` (statisch) | Prüft, ob ein Job sich nicht mehr ändert. `waitForJob` liefert nach Ablauf der Wartezeit den letzten, noch offenen Zustand. |
56
57
 
57
58
  Hinweise:
58
59
 
@@ -70,19 +71,21 @@ Fehler der Hardware-API werden als `PrintClientError` geworfen (abgeleitet von
70
71
  Nests `HttpException`). `code` enthält den maschinenlesbaren Fehlercode,
71
72
  `getStatus()` den HTTP-Status:
72
73
 
73
- | `code` | Status | Bedeutung |
74
- | ----------------------- | ------ | --------------------------------------------------------- |
75
- | `target_not_found` | 404 | Druckziel gibt es in der Company nicht |
76
- | `target_unassigned` | 422 | Druckziel ist keinem Drucker zugeordnet |
77
- | `option_not_allowed` | 422 | `paperSize` oder `color` bei ZPL |
78
- | `content_type_mismatch` | 422 | Drucker bzw. Druckziel akzeptiert diesen Inhaltstyp nicht |
79
- | `printer_disabled` | 422 | Zugeordneter Drucker ist nicht freigegeben |
80
- | `content_missing` | 400 | Kein Inhalt übergeben |
81
- | `content_invalid` | 422 | Inhalt ist kein gültiges PDF |
82
- | `content_too_large` | 413 | Inhalt größer als 50 MB |
83
- | `job_not_found` | 404 | Job-ID unbekannt |
84
-
85
- Validierungsfehler (400) und Netzwerkfehler (502) haben keinen `code`.
74
+ | `code` | Status | Bedeutung |
75
+ | ----------------------- | ------ | ---------------------------------------------------------------- |
76
+ | `target_not_found` | 404 | Druckziel gibt es in der Company nicht |
77
+ | `target_unassigned` | 422 | Druckziel ist keinem Drucker zugeordnet |
78
+ | `option_not_allowed` | 422 | `paperSize` oder `color` bei ZPL |
79
+ | `content_type_mismatch` | 422 | Drucker bzw. Druckziel akzeptiert diesen Inhaltstyp nicht |
80
+ | `printer_disabled` | 422 | Zugeordneter Drucker ist nicht freigegeben |
81
+ | `content_missing` | 400 | Kein Inhalt übergeben |
82
+ | `content_invalid` | 422 | Inhalt ist kein gültiges PDF |
83
+ | `content_too_large` | 413 | Inhalt größer als 50 MB (prüft schon der Client, vor dem Upload) |
84
+ | `job_not_found` | 404 | Job-ID unbekannt |
85
+
86
+ Validierungsfehler (400), Netzwerkfehler (502) und Zeitüberschreitungen (504)
87
+ haben keinen `code`. Ungültige IDs (leer, `.` oder `..`) wirft der Client
88
+ vorab als `BadRequestException`.
86
89
 
87
90
  ```ts
88
91
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ah-oh/ao-workspaces-api-sdk",
3
- "version": "1.0.23",
3
+ "version": "1.0.24",
4
4
  "type": "commonjs",
5
5
  "main": "./src/index.js",
6
6
  "types": "./src/index.d.ts",
@@ -12,39 +12,33 @@ var auth_constants_2 = require("./auth.constants");
12
12
  Object.defineProperty(exports, "AUTH_MODULE_OPTIONS", { enumerable: true, get: function () { return auth_constants_2.AUTH_MODULE_OPTIONS; } });
13
13
  Object.defineProperty(exports, "AUTH_TOKEN", { enumerable: true, get: function () { return auth_constants_2.AUTH_TOKEN; } });
14
14
  Object.defineProperty(exports, "AUTH_MODULE", { enumerable: true, get: function () { return auth_constants_2.AUTH_MODULE; } });
15
- const getAuthOptions = (options) => new customer_center_service_1.CustomerCenterService(options);
16
- const createAuthProvider = (options) => {
17
- return {
18
- provide: auth_constants_1.AUTH_TOKEN,
19
- useValue: getAuthOptions(options),
20
- };
15
+ /**
16
+ * `AUTH_TOKEN` points to the same instance as `CustomerCenterService`, so the
17
+ * guards and the clients share one token and session cache.
18
+ */
19
+ const authTokenProvider = {
20
+ provide: auth_constants_1.AUTH_TOKEN,
21
+ useExisting: customer_center_service_1.CustomerCenterService,
21
22
  };
23
+ const services = [customer_center_service_1.CustomerCenterService, mail_settings_service_1.MailSettingsService, print_client_1.PrintClient];
22
24
  let AuthModule = AuthModule_1 = class AuthModule {
23
25
  static forRoot(options) {
24
- const provider = createAuthProvider(options);
25
26
  return {
26
27
  module: AuthModule_1,
27
28
  providers: [
28
29
  { provide: auth_constants_1.AUTH_MODULE_OPTIONS, useValue: options },
29
- provider,
30
- customer_center_service_1.CustomerCenterService,
31
- mail_settings_service_1.MailSettingsService,
32
- print_client_1.PrintClient,
30
+ authTokenProvider,
31
+ ...services,
33
32
  ],
34
- exports: [provider, customer_center_service_1.CustomerCenterService, mail_settings_service_1.MailSettingsService, print_client_1.PrintClient],
33
+ exports: [auth_constants_1.AUTH_TOKEN, ...services],
35
34
  };
36
35
  }
37
36
  static forRootAsync(options) {
38
- const provider = {
39
- inject: [auth_constants_1.AUTH_MODULE_OPTIONS],
40
- provide: auth_constants_1.AUTH_TOKEN,
41
- useFactory: async (options) => getAuthOptions(options),
42
- };
43
37
  return {
44
38
  module: AuthModule_1,
45
39
  imports: options.imports,
46
- providers: [...this.createAsyncProviders(options), provider, customer_center_service_1.CustomerCenterService, mail_settings_service_1.MailSettingsService, print_client_1.PrintClient],
47
- exports: [provider, customer_center_service_1.CustomerCenterService, mail_settings_service_1.MailSettingsService, print_client_1.PrintClient],
40
+ providers: [...this.createAsyncProviders(options), authTokenProvider, ...services],
41
+ exports: [auth_constants_1.AUTH_TOKEN, ...services],
48
42
  };
49
43
  }
50
44
  static createAsyncProviders(options) {
@@ -68,10 +62,7 @@ let AuthModule = AuthModule_1 = class AuthModule {
68
62
  inject: options.inject || [],
69
63
  };
70
64
  }
71
- const inject = [
72
- (options.useClass ||
73
- options.useExisting),
74
- ];
65
+ const inject = [(options.useClass || options.useExisting)];
75
66
  return {
76
67
  provide: auth_constants_1.AUTH_MODULE_OPTIONS,
77
68
  useFactory: async (optionsFactory) => await optionsFactory.createHttpModuleOptions(),
@@ -1 +1 @@
1
- {"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../../../../../libs/api-sdk/src/lib/auth.module.ts"],"names":[],"mappings":";;;;;AAAA,2CAA+E;AAE/E,qDAAmE;AACnE,uEAAkE;AAClE,mEAA8D;AAC9D,iDAA6C;AAO7C,mDAAgF;AAAvE,qHAAA,mBAAmB,OAAA;AAAE,4GAAA,UAAU,OAAA;AAAE,6GAAA,WAAW,OAAA;AAErD,MAAM,cAAc,GAAG,CAAC,OAA0B,EAAyB,EAAE,CACzE,IAAI,+CAAqB,CAAC,OAAO,CAAC,CAAC;AAEvC,MAAM,kBAAkB,GAAG,CAAC,OAA0B,EAAY,EAAE;IAChE,OAAO;QACH,OAAO,EAAE,2BAAU;QACnB,QAAQ,EAAE,cAAc,CAAC,OAAO,CAAC;KACpC,CAAC;AACN,CAAC,CAAC;AAIK,IAAM,UAAU,kBAAhB,MAAM,UAAU;IACZ,MAAM,CAAC,OAAO,CAAC,OAA0B;QAC5C,MAAM,QAAQ,GAAa,kBAAkB,CAAC,OAAO,CAAC,CAAC;QACvD,OAAO;YACH,MAAM,EAAE,YAAU;YAClB,SAAS,EAAE;gBACP,EAAE,OAAO,EAAE,oCAAmB,EAAE,QAAQ,EAAE,OAAO,EAAE;gBACnD,QAAQ;gBACR,+CAAqB;gBACrB,2CAAmB;gBACnB,0BAAW;aACd;YACD,OAAO,EAAE,CAAC,QAAQ,EAAE,+CAAqB,EAAE,2CAAmB,EAAE,0BAAW,CAAC;SAC/E,CAAC;IACN,CAAC;IAEM,MAAM,CAAC,YAAY,CAAC,OAA+B;QACtD,MAAM,QAAQ,GAAa;YACvB,MAAM,EAAE,CAAC,oCAAmB,CAAC;YAC7B,OAAO,EAAE,2BAAU;YACnB,UAAU,EAAE,KAAK,EAAE,OAA0B,EAAE,EAAE,CAC7C,cAAc,CAAC,OAAO,CAAC;SAC9B,CAAC;QAEF,OAAO;YACH,MAAM,EAAE,YAAU;YAClB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,SAAS,EAAE,CAAC,GAAG,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,+CAAqB,EAAE,2CAAmB,EAAE,0BAAW,CAAC;YACrH,OAAO,EAAE,CAAC,QAAQ,EAAE,+CAAqB,EAAE,2CAAmB,EAAE,0BAAW,CAAC;SAC/E,CAAC;IACN,CAAC;IAEO,MAAM,CAAC,oBAAoB,CAC/B,OAA+B;QAE/B,IAAI,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YAC5C,OAAO,CAAC,IAAI,CAAC,0BAA0B,CAAC,OAAO,CAAC,CAAC,CAAC;QACtD,CAAC;QAED,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAmC,CAAC;QAE7D,OAAO;YACH,IAAI,CAAC,0BAA0B,CAAC,OAAO,CAAC;YACxC;gBACI,OAAO,EAAE,QAAQ;gBACjB,QAAQ;aACX;SACJ,CAAC;IACN,CAAC;IAEO,MAAM,CAAC,0BAA0B,CACrC,OAA+B;QAE/B,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACrB,OAAO;gBACH,OAAO,EAAE,oCAAmB;gBAC5B,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;aAC/B,CAAC;QACN,CAAC;QAED,MAAM,MAAM,GAAG;YACX,CAAC,OAAO,CAAC,QAAQ;gBACb,OAAO,CAAC,WAAW,CAA4B;SACtD,CAAC;QAEF,OAAO;YACH,OAAO,EAAE,oCAAmB;YAC5B,UAAU,EAAE,KAAK,EAAE,cAAiC,EAAE,EAAE,CACpD,MAAM,cAAc,CAAC,uBAAuB,EAAE;YAClD,MAAM;SACT,CAAC;IACN,CAAC;CACJ,CAAA;AAzEY,gCAAU;qBAAV,UAAU;IAFtB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,UAAU,CAyEtB"}
1
+ {"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../../../../../libs/api-sdk/src/lib/auth.module.ts"],"names":[],"mappings":";;;;;AAAA,2CAA+E;AAE/E,qDAAmE;AACnE,uEAAkE;AAClE,mEAA8D;AAC9D,iDAA6C;AAO7C,mDAAgF;AAAvE,qHAAA,mBAAmB,OAAA;AAAE,4GAAA,UAAU,OAAA;AAAE,6GAAA,WAAW,OAAA;AAErD;;;GAGG;AACH,MAAM,iBAAiB,GAAa;IAClC,OAAO,EAAE,2BAAU;IACnB,WAAW,EAAE,+CAAqB;CACnC,CAAC;AAEF,MAAM,QAAQ,GAAG,CAAC,+CAAqB,EAAE,2CAAmB,EAAE,0BAAW,CAAC,CAAC;AAIpE,IAAM,UAAU,kBAAhB,MAAM,UAAU;IACd,MAAM,CAAC,OAAO,CAAC,OAA0B;QAC9C,OAAO;YACL,MAAM,EAAE,YAAU;YAClB,SAAS,EAAE;gBACT,EAAE,OAAO,EAAE,oCAAmB,EAAE,QAAQ,EAAE,OAAO,EAAE;gBACnD,iBAAiB;gBACjB,GAAG,QAAQ;aACZ;YACD,OAAO,EAAE,CAAC,2BAAU,EAAE,GAAG,QAAQ,CAAC;SACnC,CAAC;IACJ,CAAC;IAEM,MAAM,CAAC,YAAY,CAAC,OAA+B;QACxD,OAAO;YACL,MAAM,EAAE,YAAU;YAClB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,SAAS,EAAE,CAAC,GAAG,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAAE,iBAAiB,EAAE,GAAG,QAAQ,CAAC;YAClF,OAAO,EAAE,CAAC,2BAAU,EAAE,GAAG,QAAQ,CAAC;SACnC,CAAC;IACJ,CAAC;IAEO,MAAM,CAAC,oBAAoB,CAAC,OAA+B;QACjE,IAAI,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YAC9C,OAAO,CAAC,IAAI,CAAC,0BAA0B,CAAC,OAAO,CAAC,CAAC,CAAC;QACpD,CAAC;QAED,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAmC,CAAC;QAE7D,OAAO;YACL,IAAI,CAAC,0BAA0B,CAAC,OAAO,CAAC;YACxC;gBACE,OAAO,EAAE,QAAQ;gBACjB,QAAQ;aACT;SACF,CAAC;IACJ,CAAC;IAEO,MAAM,CAAC,0BAA0B,CAAC,OAA+B;QACvE,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACvB,OAAO;gBACL,OAAO,EAAE,oCAAmB;gBAC5B,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;aAC7B,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,WAAW,CAA4B,CAAC,CAAC;QAEtF,OAAO;YACL,OAAO,EAAE,oCAAmB;YAC5B,UAAU,EAAE,KAAK,EAAE,cAAiC,EAAE,EAAE,CACtD,MAAM,cAAc,CAAC,uBAAuB,EAAE;YAChD,MAAM;SACP,CAAC;IACJ,CAAC;CACF,CAAA;AAxDY,gCAAU;qBAAV,UAAU;IAFtB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,UAAU,CAwDtB"}
@@ -1,25 +1,61 @@
1
1
  import { ApiKey, ApiKeyType } from './models/api-key.model';
2
2
  import { AuthModuleOptions } from './models/auth.options';
3
3
  import { Product, UserSession } from './models/user-session.model';
4
+ export interface TokenSignInDto {
5
+ tokenId: string;
6
+ tokenKey: string;
7
+ product: Product;
8
+ }
4
9
  export declare class CustomerCenterService {
5
10
  private readonly options;
6
- private BASE_URL;
11
+ private readonly http;
12
+ /** Cache keys are HMACs, so the heap holds neither token keys nor tokens as keys. */
13
+ private readonly cacheKeySecret;
14
+ private readonly tokenCache;
15
+ private readonly sessionCache;
16
+ /** Until then `verifyInstanceToken` uses `GET /auth/verify/:token` directly. */
17
+ private legacyVerifyUntil;
7
18
  constructor(options: AuthModuleOptions);
19
+ /**
20
+ * Verifies a token and returns its session. The token travels in the
21
+ * `Authorization` header, not in the URL, so access logs do not record it.
22
+ * Concurrent calls with the same token share one request; with
23
+ * `sessionCacheTtlMs` the session is cached.
24
+ */
8
25
  verifyInstanceToken(token: string): Promise<UserSession>;
9
26
  sendCompanyRefreshTokenMail(id: string, expiresIn: number): Promise<{
10
27
  done: boolean;
11
28
  }>;
12
- tokenSignIn(dto: {
13
- tokenId: string;
14
- tokenKey: string;
15
- product: Product;
16
- }): Promise<{
29
+ /**
30
+ * Exchanges a user token for a JWT. Unless `tokenCache` is `false`, the JWT
31
+ * is reused for the same credentials until shortly before it expires.
32
+ */
33
+ tokenSignIn(dto: TokenSignInDto): Promise<{
17
34
  token: string;
18
35
  }>;
36
+ /**
37
+ * Runs `call` with `Bearer <jwt>` for the credentials. If the server rejects
38
+ * a cached token with 401, the token is dropped and `call` runs once more
39
+ * with a new one.
40
+ */
41
+ withToken<T>(dto: TokenSignInDto, call: (authorization: string) => Promise<T>): Promise<T>;
42
+ /** Drops all cached tokens and sessions. */
43
+ clearCache(): void;
19
44
  getApiKey(args: {
20
45
  company: string;
21
46
  type: ApiKeyType;
22
47
  ip: string;
23
48
  authorization: string;
24
49
  }): Promise<ApiKey>;
50
+ private signIn;
51
+ /**
52
+ * Servers before `POST /auth/verify` answer it with 404; for them the token
53
+ * goes into the path as before.
54
+ */
55
+ private fetchSession;
56
+ private tokenTtl;
57
+ private sessionTtl;
58
+ private tokenCacheKey;
59
+ private cacheKey;
60
+ private request;
25
61
  }
@@ -3,75 +3,163 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CustomerCenterService = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const common_1 = require("@nestjs/common");
6
- const axios_1 = require("axios");
6
+ const node_crypto_1 = require("node:crypto");
7
7
  const auth_constants_1 = require("./auth.constants");
8
8
  const axios_error_handler_1 = require("./utils/axios-error.handler");
9
+ const http_client_1 = require("./utils/http-client");
10
+ const jwt_util_1 = require("./utils/jwt.util");
11
+ const ttl_cache_1 = require("./utils/ttl-cache");
12
+ const url_path_1 = require("./utils/url-path");
13
+ /** Cached tokens are renewed this long before they expire. */
14
+ const TOKEN_REFRESH_MARGIN_MS = 5 * 60_000;
15
+ /** Upper bound for caching a token, so a revoked user token stops working soon. */
16
+ const TOKEN_MAX_CACHE_MS = 60 * 60_000;
17
+ const TOKEN_CACHE_SIZE = 1_000;
18
+ const SESSION_CACHE_SIZE = 10_000;
19
+ /** How long to use the legacy verify endpoint after the server lacked `POST /auth/verify`. */
20
+ const LEGACY_VERIFY_RECHECK_MS = 10 * 60_000;
21
+ /** Visible ASCII only: the token goes into a header and, on old servers, into the path. */
22
+ const TOKEN_PATTERN = /^[\x21-\x7e]+$/;
9
23
  let CustomerCenterService = class CustomerCenterService {
10
24
  options;
11
- BASE_URL = 'https://admin.ah-oh.com';
25
+ http;
26
+ /** Cache keys are HMACs, so the heap holds neither token keys nor tokens as keys. */
27
+ cacheKeySecret = (0, node_crypto_1.randomBytes)(32);
28
+ tokenCache = new ttl_cache_1.TtlCache(TOKEN_CACHE_SIZE);
29
+ sessionCache = new ttl_cache_1.TtlCache(SESSION_CACHE_SIZE);
30
+ /** Until then `verifyInstanceToken` uses `GET /auth/verify/:token` directly. */
31
+ legacyVerifyUntil = 0;
12
32
  constructor(options) {
13
33
  this.options = options;
14
- this.BASE_URL = this.options.baseUrl;
34
+ this.http = (0, http_client_1.createHttpClient)(options);
15
35
  }
36
+ /**
37
+ * Verifies a token and returns its session. The token travels in the
38
+ * `Authorization` header, not in the URL, so access logs do not record it.
39
+ * Concurrent calls with the same token share one request; with
40
+ * `sessionCacheTtlMs` the session is cached.
41
+ */
16
42
  async verifyInstanceToken(token) {
17
- const options = {
18
- method: 'GET',
19
- baseURL: this.BASE_URL,
20
- url: `/auth-api/auth/verify/${token}`,
21
- headers: { accept: 'application/json' },
22
- };
23
- try {
24
- const res = await axios_1.default.request(options);
25
- return res.data;
26
- }
27
- catch (error) {
28
- (0, axios_error_handler_1.handleAxiosError)(error);
43
+ if (typeof token !== 'string' || !TOKEN_PATTERN.test(token) || !(0, url_path_1.isValidPathSegment)(token)) {
44
+ throw new common_1.UnauthorizedException('Invalid authentication token');
29
45
  }
46
+ const { value } = await this.sessionCache.getOrLoad(this.cacheKey('session', token), async () => ({
47
+ value: await this.fetchSession(token),
48
+ ttlMs: this.sessionTtl(token),
49
+ }));
50
+ // Callers get their own copy, so changing one request's session leaves the others alone.
51
+ return structuredClone(value);
30
52
  }
31
53
  async sendCompanyRefreshTokenMail(id, expiresIn) {
32
- const options = {
54
+ return this.request({
33
55
  method: 'GET',
34
- baseURL: this.BASE_URL,
35
- url: `/public/companies/${id}/${expiresIn}/mail`,
36
- headers: { accept: 'application/json' },
37
- };
38
- try {
39
- const res = await axios_1.default.request(options);
40
- return res.data;
41
- }
42
- catch (error) {
43
- (0, axios_error_handler_1.handleAxiosError)(error);
44
- }
56
+ url: (0, url_path_1.urlPath) `/public/companies/${id}/${expiresIn}/mail`,
57
+ });
45
58
  }
59
+ /**
60
+ * Exchanges a user token for a JWT. Unless `tokenCache` is `false`, the JWT
61
+ * is reused for the same credentials until shortly before it expires.
62
+ */
46
63
  async tokenSignIn(dto) {
47
- const options = {
48
- method: 'POST',
49
- baseURL: this.BASE_URL,
50
- url: `/auth-api/token/auth/sign-in`,
51
- headers: { accept: 'application/json' },
52
- data: dto,
53
- };
64
+ const { token } = await this.signIn(dto);
65
+ return { token };
66
+ }
67
+ /**
68
+ * Runs `call` with `Bearer <jwt>` for the credentials. If the server rejects
69
+ * a cached token with 401, the token is dropped and `call` runs once more
70
+ * with a new one.
71
+ */
72
+ async withToken(dto, call) {
73
+ const { token, fromCache } = await this.signIn(dto);
54
74
  try {
55
- const res = await axios_1.default.request(options);
56
- return res.data;
75
+ return await call(`Bearer ${token}`);
57
76
  }
58
77
  catch (error) {
59
- (0, axios_error_handler_1.handleAxiosError)(error);
78
+ if (!fromCache || !(0, axios_error_handler_1.isUnauthorizedError)(error))
79
+ throw error;
80
+ this.tokenCache.delete(this.tokenCacheKey(dto), token);
81
+ const renewed = await this.signIn(dto);
82
+ return call(`Bearer ${renewed.token}`);
60
83
  }
61
84
  }
85
+ /** Drops all cached tokens and sessions. */
86
+ clearCache() {
87
+ this.tokenCache.clear();
88
+ this.sessionCache.clear();
89
+ }
62
90
  async getApiKey(args) {
63
- const options = {
91
+ return this.request({
64
92
  method: 'GET',
65
- baseURL: this.BASE_URL,
66
- url: `/api-keys/${args.company}/${args.type}/with-key`,
93
+ url: (0, url_path_1.urlPath) `/api-keys/${args.company}/${args.type}/with-key`,
67
94
  headers: {
68
- accept: 'application/json',
69
95
  'x-real-ip': args.ip,
70
96
  authorization: args.authorization,
71
97
  },
98
+ });
99
+ }
100
+ async signIn(dto) {
101
+ const load = async () => {
102
+ const { token } = await this.request({
103
+ method: 'POST',
104
+ url: '/auth-api/token/auth/sign-in',
105
+ data: { tokenId: dto.tokenId, tokenKey: dto.tokenKey, product: dto.product },
106
+ });
107
+ return { value: token, ttlMs: this.tokenTtl(token) };
72
108
  };
109
+ if (this.options.tokenCache === false) {
110
+ return { token: (await load()).value, fromCache: false };
111
+ }
112
+ const { value, fromCache } = await this.tokenCache.getOrLoad(this.tokenCacheKey(dto), load);
113
+ return { token: value, fromCache };
114
+ }
115
+ /**
116
+ * Servers before `POST /auth/verify` answer it with 404; for them the token
117
+ * goes into the path as before.
118
+ */
119
+ async fetchSession(token) {
120
+ if (Date.now() >= this.legacyVerifyUntil) {
121
+ try {
122
+ return await this.request({
123
+ method: 'POST',
124
+ url: '/auth-api/auth/verify',
125
+ headers: { authorization: `Bearer ${token}` },
126
+ });
127
+ }
128
+ catch (error) {
129
+ if (!isMissingEndpoint(error))
130
+ throw error;
131
+ this.legacyVerifyUntil = Date.now() + LEGACY_VERIFY_RECHECK_MS;
132
+ }
133
+ }
134
+ return this.request({
135
+ method: 'GET',
136
+ url: (0, url_path_1.urlPath) `/auth-api/auth/verify/${token}`,
137
+ });
138
+ }
139
+ tokenTtl(token) {
140
+ const expiresAt = (0, jwt_util_1.getJwtExpiresAt)(token);
141
+ if (expiresAt === undefined)
142
+ return 0;
143
+ return Math.min(expiresAt - Date.now() - TOKEN_REFRESH_MARGIN_MS, TOKEN_MAX_CACHE_MS);
144
+ }
145
+ sessionTtl(token) {
146
+ const ttl = this.options.sessionCacheTtlMs ?? 0;
147
+ if (ttl <= 0)
148
+ return 0;
149
+ const expiresAt = (0, jwt_util_1.getJwtExpiresAt)(token);
150
+ return expiresAt === undefined ? ttl : Math.min(ttl, expiresAt - Date.now());
151
+ }
152
+ tokenCacheKey(dto) {
153
+ return this.cacheKey('token', dto.tokenId, dto.tokenKey, dto.product);
154
+ }
155
+ cacheKey(...parts) {
156
+ return (0, node_crypto_1.createHmac)('sha256', this.cacheKeySecret)
157
+ .update(JSON.stringify(parts))
158
+ .digest('base64url');
159
+ }
160
+ async request(config) {
73
161
  try {
74
- const res = await axios_1.default.request(options);
162
+ const res = await this.http.request(config);
75
163
  return res.data;
76
164
  }
77
165
  catch (error) {
@@ -85,4 +173,10 @@ exports.CustomerCenterService = CustomerCenterService = tslib_1.__decorate([
85
173
  tslib_1.__param(0, (0, common_1.Inject)(auth_constants_1.AUTH_MODULE_OPTIONS)),
86
174
  tslib_1.__metadata("design:paramtypes", [Object])
87
175
  ], CustomerCenterService);
176
+ function isMissingEndpoint(error) {
177
+ if (!(error instanceof common_1.HttpException))
178
+ return false;
179
+ const status = error.getStatus();
180
+ return status === common_1.HttpStatus.NOT_FOUND || status === common_1.HttpStatus.METHOD_NOT_ALLOWED;
181
+ }
88
182
  //# sourceMappingURL=customer-center.service.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"customer-center.service.js","sourceRoot":"","sources":["../../../../../libs/api-sdk/src/lib/customer-center.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"customer-center.service.js","sourceRoot":"","sources":["../../../../../libs/api-sdk/src/lib/customer-center.service.ts"],"names":[],"mappings":"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"}
@@ -12,10 +12,9 @@ let AuthGuard = class AuthGuard {
12
12
  }
13
13
  async canActivate(context) {
14
14
  const request = context.switchToHttp().getRequest();
15
- let token = request.headers.dev ??
16
- request.cookies['jwt'] ??
17
- request.headers.authorization;
18
- token = token?.replace('Bearer ', '');
15
+ // `cookies` only exists with the cookie-parser middleware.
16
+ const raw = request.headers.dev ?? request.cookies?.['jwt'] ?? request.headers.authorization;
17
+ const token = typeof raw === 'string' ? raw.replace(/^Bearer\s+/i, '').trim() : undefined;
19
18
  if (!token?.length) {
20
19
  throw new common_1.UnauthorizedException('No authentication token provided');
21
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"auth.guard.js","sourceRoot":"","sources":["../../../../../../libs/api-sdk/src/lib/guards/auth.guard.ts"],"names":[],"mappings":";;;;AAAA,2CAMwB;AAExB,gDAA4C;AAC5C,wEAAmE;AAG5D,IAAM,SAAS,GAAf,MAAM,SAAS;IAGG;IAFrB,YAEqB,qBAA4C;QAA5C,0BAAqB,GAArB,qBAAqB,CAAuB;IAC9D,CAAC;IAEJ,KAAK,CAAC,WAAW,CAAC,OAAyB;QACvC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QAEpD,IAAI,KAAK,GACL,OAAO,CAAC,OAAO,CAAC,GAAG;YACnB,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;YACtB,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;QAElC,KAAK,GAAG,KAAK,EAAE,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAEtC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,8BAAqB,CAAC,kCAAkC,CAAC,CAAC;QACxE,CAAC;QAED,OAAO,CAAC,OAAO,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,mBAAmB,CAClE,KAAK,CACR,CAAC;QAEF,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ,CAAA;AA1BY,8BAAS;oBAAT,SAAS;IADrB,IAAA,mBAAU,GAAE;IAGJ,mBAAA,IAAA,eAAM,EAAC,wBAAU,CAAC,CAAA;6CACqB,+CAAqB;GAHxD,SAAS,CA0BrB"}
1
+ {"version":3,"file":"auth.guard.js","sourceRoot":"","sources":["../../../../../../libs/api-sdk/src/lib/guards/auth.guard.ts"],"names":[],"mappings":";;;;AAAA,2CAMwB;AAExB,gDAA4C;AAC5C,wEAAmE;AAG5D,IAAM,SAAS,GAAf,MAAM,SAAS;IAGD;IAFnB,YAEmB,qBAA4C;QAA5C,0BAAqB,GAArB,qBAAqB,CAAuB;IAC5D,CAAC;IAEJ,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QAEpD,2DAA2D;QAC3D,MAAM,GAAG,GACP,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;QACnF,MAAM,KAAK,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAE1F,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;YACnB,MAAM,IAAI,8BAAqB,CAAC,kCAAkC,CAAC,CAAC;QACtE,CAAC;QAED,OAAO,CAAC,OAAO,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;QAE9E,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AAtBY,8BAAS;oBAAT,SAAS;IADrB,IAAA,mBAAU,GAAE;IAGR,mBAAA,IAAA,eAAM,EAAC,wBAAU,CAAC,CAAA;6CACqB,+CAAqB;GAHpD,SAAS,CAsBrB"}
@@ -9,6 +9,9 @@ let CompanyGuard = class CompanyGuard {
9
9
  const request = context.switchToHttp().getRequest();
10
10
  const companyId = request.params.companyId;
11
11
  const session = request.session;
12
+ if (!session) {
13
+ throw new common_1.UnauthorizedException('No session; use AuthGuard first');
14
+ }
12
15
  if (user_session_model_1.AllAccessRoles.includes(session.role) ||
13
16
  (companyId && session.enabledCompanies?.includes(companyId))) {
14
17
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"company.guard.js","sourceRoot":"","sources":["../../../../../../libs/api-sdk/src/lib/guards/company.guard.ts"],"names":[],"mappings":";;;;AAAA,2CAMwB;AAExB,qEAA2E;AAGpE,IAAM,YAAY,GAAlB,MAAM,YAAY;IACrB,KAAK,CAAC,WAAW,CAAC,OAAyB;QACvC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QAEpD,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC;QAC3C,MAAM,OAAO,GAAgB,OAAO,CAAC,OAAO,CAAC;QAC7C,IACI,mCAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;YACrC,CAAC,SAAS,IAAI,OAAO,CAAC,gBAAgB,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,EAC9D,CAAC;YACC,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,MAAM,IAAI,sBAAa,CAAC,oBAAoB,EAAE,mBAAU,CAAC,WAAW,CAAC,CAAC;IAC1E,CAAC;CACJ,CAAA;AAfY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;GACA,YAAY,CAexB"}
1
+ {"version":3,"file":"company.guard.js","sourceRoot":"","sources":["../../../../../../libs/api-sdk/src/lib/guards/company.guard.ts"],"names":[],"mappings":";;;;AAAA,2CAOwB;AAExB,qEAA2E;AAGpE,IAAM,YAAY,GAAlB,MAAM,YAAY;IACvB,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QAEpD,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC;QAC3C,MAAM,OAAO,GAA4B,OAAO,CAAC,OAAO,CAAC;QACzD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,8BAAqB,CAAC,iCAAiC,CAAC,CAAC;QACrE,CAAC;QACD,IACE,mCAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;YACrC,CAAC,SAAS,IAAI,OAAO,CAAC,gBAAgB,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,EAC5D,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,IAAI,sBAAa,CAAC,oBAAoB,EAAE,mBAAU,CAAC,WAAW,CAAC,CAAC;IACxE,CAAC;CACF,CAAA;AAlBY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;GACA,YAAY,CAkBxB"}
@@ -16,11 +16,14 @@ let SetHubPermissionsGuard = class SetHubPermissionsGuard {
16
16
  return true;
17
17
  }
18
18
  const request = context.switchToHttp().getRequest();
19
+ if (!request.session) {
20
+ throw new common_1.UnauthorizedException('No session; use AuthGuard first');
21
+ }
19
22
  const { setHubPermission, product, role } = request.session;
20
23
  if (user_session_model_1.AllAccessRoles.includes(role) ||
21
24
  (setHubPermission &&
22
25
  product === user_session_model_1.Product.SETHUB &&
23
- permissions.every((p) => setHubPermission[p] === true))) {
26
+ permissions.every(p => setHubPermission[p] === true))) {
24
27
  return true;
25
28
  }
26
29
  throw new common_1.HttpException('Missing permission', common_1.HttpStatus.UNAUTHORIZED);
@@ -1 +1 @@
1
- {"version":3,"file":"sethub-permissions.guard.js","sourceRoot":"","sources":["../../../../../../libs/api-sdk/src/lib/guards/sethub-permissions.guard.ts"],"names":[],"mappings":";;;;AAAA,2CAMwB;AACxB,uCAAyC;AAGzC,qEAAuE;AAGhE,IAAM,sBAAsB,GAA5B,MAAM,sBAAsB;IACX;IAApB,YAAoB,SAAoB;QAApB,cAAS,GAAT,SAAS,CAAW;IAAG,CAAC;IAE5C,WAAW,CAAC,OAAyB;QACjC,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAClC,aAAa,EACb,OAAO,CAAC,UAAU,EAAE,CACvB,CAAC;QACF,IAAI,CAAC,WAAW,EAAE,CAAC;YACf,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QACpD,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;QAE5D,IACI,mCAAc,CAAC,QAAQ,CAAC,IAAI,CAAC;YAC7B,CAAC,gBAAgB;gBACb,OAAO,KAAK,4BAAO,CAAC,MAAM;gBAC1B,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,EAC7D,CAAC;YACC,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,MAAM,IAAI,sBAAa,CAAC,oBAAoB,EAAE,mBAAU,CAAC,YAAY,CAAC,CAAC;IAC3E,CAAC;CACJ,CAAA;AAzBY,wDAAsB;iCAAtB,sBAAsB;IADlC,IAAA,mBAAU,GAAE;6CAEsB,gBAAS;GAD/B,sBAAsB,CAyBlC"}
1
+ {"version":3,"file":"sethub-permissions.guard.js","sourceRoot":"","sources":["../../../../../../libs/api-sdk/src/lib/guards/sethub-permissions.guard.ts"],"names":[],"mappings":";;;;AAAA,2CAOwB;AACxB,uCAAyC;AAGzC,qEAAuE;AAGhE,IAAM,sBAAsB,GAA5B,MAAM,sBAAsB;IACb;IAApB,YAAoB,SAAoB;QAApB,cAAS,GAAT,SAAS,CAAW;IAAG,CAAC;IAE5C,WAAW,CAAC,OAAyB;QACnC,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAqB,aAAa,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;QAChG,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QACpD,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACrB,MAAM,IAAI,8BAAqB,CAAC,iCAAiC,CAAC,CAAC;QACrE,CAAC;QACD,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;QAE5D,IACE,mCAAc,CAAC,QAAQ,CAAC,IAAI,CAAC;YAC7B,CAAC,gBAAgB;gBACf,OAAO,KAAK,4BAAO,CAAC,MAAM;gBAC1B,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,EACvD,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,IAAI,sBAAa,CAAC,oBAAoB,EAAE,mBAAU,CAAC,YAAY,CAAC,CAAC;IACzE,CAAC;CACF,CAAA;AAzBY,wDAAsB;iCAAtB,sBAAsB;IADlC,IAAA,mBAAU,GAAE;6CAEoB,gBAAS;GAD7B,sBAAsB,CAyBlC"}
@@ -8,6 +8,9 @@ let SuperAdminGuard = class SuperAdminGuard {
8
8
  async canActivate(context) {
9
9
  const request = context.switchToHttp().getRequest();
10
10
  const session = request.session;
11
+ if (!session) {
12
+ throw new common_1.UnauthorizedException('No session; use AuthGuard first');
13
+ }
11
14
  if (user_session_model_1.AllAccessRoles.includes(session.role)) {
12
15
  return true;
13
16
  }
@@ -1 +1 @@
1
- {"version":3,"file":"super-admin.guard.js","sourceRoot":"","sources":["../../../../../../libs/api-sdk/src/lib/guards/super-admin.guard.ts"],"names":[],"mappings":";;;;AAAA,2CAMwB;AAExB,qEAA2E;AAGpE,IAAM,eAAe,GAArB,MAAM,eAAe;IACxB,KAAK,CAAC,WAAW,CAAC,OAAyB;QACvC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QAEpD,MAAM,OAAO,GAAgB,OAAO,CAAC,OAAO,CAAC;QAC7C,IAAI,mCAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACxC,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,MAAM,IAAI,sBAAa,CAAC,oBAAoB,EAAE,mBAAU,CAAC,WAAW,CAAC,CAAC;IAC1E,CAAC;CACJ,CAAA;AAXY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,mBAAU,GAAE;GACA,eAAe,CAW3B"}
1
+ {"version":3,"file":"super-admin.guard.js","sourceRoot":"","sources":["../../../../../../libs/api-sdk/src/lib/guards/super-admin.guard.ts"],"names":[],"mappings":";;;;AAAA,2CAOwB;AAExB,qEAA2E;AAGpE,IAAM,eAAe,GAArB,MAAM,eAAe;IAC1B,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QAEpD,MAAM,OAAO,GAA4B,OAAO,CAAC,OAAO,CAAC;QACzD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,8BAAqB,CAAC,iCAAiC,CAAC,CAAC;QACrE,CAAC;QACD,IAAI,mCAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,IAAI,sBAAa,CAAC,oBAAoB,EAAE,mBAAU,CAAC,WAAW,CAAC,CAAC;IACxE,CAAC;CACF,CAAA;AAdY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,mBAAU,GAAE;GACA,eAAe,CAc3B"}