@ah-oh/ao-workspaces-api-sdk 1.0.22 → 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 (43) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +91 -3
  3. package/package.json +2 -2
  4. package/src/index.d.ts +1 -0
  5. package/src/index.js +1 -0
  6. package/src/index.js.map +1 -1
  7. package/src/lib/auth.module.js +15 -22
  8. package/src/lib/auth.module.js.map +1 -1
  9. package/src/lib/customer-center.service.d.ts +42 -6
  10. package/src/lib/customer-center.service.js +136 -42
  11. package/src/lib/customer-center.service.js.map +1 -1
  12. package/src/lib/guards/auth.guard.js +3 -4
  13. package/src/lib/guards/auth.guard.js.map +1 -1
  14. package/src/lib/guards/company.guard.js +3 -0
  15. package/src/lib/guards/company.guard.js.map +1 -1
  16. package/src/lib/guards/sethub-permissions.guard.js +4 -1
  17. package/src/lib/guards/sethub-permissions.guard.js.map +1 -1
  18. package/src/lib/guards/super-admin.guard.js +3 -0
  19. package/src/lib/guards/super-admin.guard.js.map +1 -1
  20. package/src/lib/guards/szales-basic-auth.guard.js +33 -14
  21. package/src/lib/guards/szales-basic-auth.guard.js.map +1 -1
  22. package/src/lib/mail-settings.service.d.ts +3 -3
  23. package/src/lib/mail-settings.service.js +63 -251
  24. package/src/lib/mail-settings.service.js.map +1 -1
  25. package/src/lib/models/auth.options.d.ts +13 -0
  26. package/src/lib/print.client.d.ts +76 -0
  27. package/src/lib/print.client.js +154 -0
  28. package/src/lib/print.client.js.map +1 -0
  29. package/src/lib/utils/axios-error.handler.d.ts +11 -0
  30. package/src/lib/utils/axios-error.handler.js +24 -3
  31. package/src/lib/utils/axios-error.handler.js.map +1 -1
  32. package/src/lib/utils/http-client.d.ts +9 -0
  33. package/src/lib/utils/http-client.js +35 -0
  34. package/src/lib/utils/http-client.js.map +1 -0
  35. package/src/lib/utils/jwt.util.d.ts +6 -0
  36. package/src/lib/utils/jwt.util.js +21 -0
  37. package/src/lib/utils/jwt.util.js.map +1 -0
  38. package/src/lib/utils/ttl-cache.d.ts +26 -0
  39. package/src/lib/utils/ttl-cache.js +66 -0
  40. package/src/lib/utils/ttl-cache.js.map +1 -0
  41. package/src/lib/utils/url-path.d.ts +7 -0
  42. package/src/lib/utils/url-path.js +28 -0
  43. package/src/lib/utils/url-path.js.map +1 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,27 @@
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
+
12
+ ## 1.0.23 (2026-09-24)
13
+
14
+ ### 🚀 Features
15
+
16
+ - **api-sdk:** add PrintClient for hardware connector print jobs ([7b1d334](https://github.com/ah-oh/ao-workspaces/commit/7b1d334))
17
+ - update TypeScript configuration and ESLint migration documentation ([2993a37](https://github.com/ah-oh/ao-workspaces/commit/2993a37))
18
+
19
+ ### ❤️ Thank You
20
+
21
+ - Claude Opus 5.5
22
+ - Jan Kessler
23
+ - Jan Keßler @jannks
24
+
1
25
  ## 1.0.22 (2026-05-21)
2
26
 
3
27
  This was a version bump only for api-sdk to align it with other projects, there were no code changes.
package/README.md CHANGED
@@ -1,11 +1,99 @@
1
- # customer-center-sdk
1
+ # api-sdk
2
2
 
3
3
  This library was generated with [Nx](https://nx.dev).
4
4
 
5
5
  ## Building
6
6
 
7
- Run `nx build customer-center-sdk` to build the library.
7
+ Run `nx build api-sdk` to build the library.
8
8
 
9
9
  ## Running unit tests
10
10
 
11
- Run `nx test customer-center-sdk` to execute the unit tests via [Jest](https://jestjs.io).
11
+ Run `nx test api-sdk` to execute the unit tests via [Jest](https://jestjs.io).
12
+
13
+ ## Drucken über den Hardware Connector
14
+
15
+ Produkt-Apps drucken über den `PrintClient` auf **Druckziele** der Company
16
+ (z. B. `shipping-label`). Welcher Drucker dahinter steht, legt die Company im
17
+ Admin fest. Fachliche Regeln: `docs/features/hardware-connector/` im Repository
18
+ `ah-oh/ao-workspaces`.
19
+
20
+ Der `PrintClient` wird vom `AuthModule` bereitgestellt (`forRoot` oder
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` –
24
+ nur so gilt der Aufruf als App und der Job trägt die App als Auslöser.
25
+
26
+ ```ts
27
+ import { PrintClient, PrintClientError } from '@ah-oh/ao-workspaces-api-sdk';
28
+ import { PrintContentType, Product } from '@ah-oh/ao-workspaces-types';
29
+
30
+ const job = await printClient.print({
31
+ tokenId,
32
+ tokenKey,
33
+ product: Product.SZALES,
34
+ companyId,
35
+ target: 'shipping-label',
36
+ contentType: PrintContentType.ZPL,
37
+ content: Buffer.from(zpl),
38
+ fileName: `label-${orderId}.zpl`,
39
+ idempotencyKey: `label-${orderId}`,
40
+ });
41
+
42
+ const current = await printClient.getJob({
43
+ tokenId,
44
+ tokenKey,
45
+ product: Product.SZALES,
46
+ companyId,
47
+ jobId: job._id,
48
+ });
49
+ ```
50
+
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. |
57
+
58
+ Hinweise:
59
+
60
+ - **Idempotenz:** Derselbe `idempotencyKey` liefert innerhalb einer Company
61
+ denselben Job zurück, statt erneut zu drucken. Für Wiederholungen nach
62
+ Netzwerkfehlern immer einen Schlüssel mitgeben.
63
+ - **Ohne Verbindung:** Ist der Connector offline, bleibt der Job `queued` und
64
+ wird beim Wiederverbinden gedruckt – bis zur Ablaufzeit (Standard 1 Stunde,
65
+ über `expiresInSeconds` änderbar), danach `expired`.
66
+ - **`completed`** heißt „vom Drucksystem angenommen“, nicht „physisch gedruckt“.
67
+
68
+ ### Fehler
69
+
70
+ Fehler der Hardware-API werden als `PrintClientError` geworfen (abgeleitet von
71
+ Nests `HttpException`). `code` enthält den maschinenlesbaren Fehlercode,
72
+ `getStatus()` den HTTP-Status:
73
+
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`.
89
+
90
+ ```ts
91
+ try {
92
+ await printClient.print({ ... });
93
+ } catch (error) {
94
+ if (error instanceof PrintClientError && error.code === 'target_unassigned') {
95
+ // Hinweis an die Company: Druckziel im Admin einem Drucker zuordnen
96
+ }
97
+ throw error;
98
+ }
99
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ah-oh/ao-workspaces-api-sdk",
3
- "version": "1.0.22",
3
+ "version": "1.0.24",
4
4
  "type": "commonjs",
5
5
  "main": "./src/index.js",
6
6
  "types": "./src/index.d.ts",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "tslib": "^2.3.0",
17
- "@ah-oh/ao-workspaces-types": "^0.0.6"
17
+ "@ah-oh/ao-workspaces-types": "^0.0.10"
18
18
  },
19
19
  "peerDependencies": {
20
20
  "@nestjs/common": ">=9.0.0",
package/src/index.d.ts CHANGED
@@ -13,3 +13,4 @@ export * from './lib/models/api-key.model';
13
13
  export * from './lib/auth.module';
14
14
  export * from './lib/customer-center.service';
15
15
  export * from './lib/mail-settings.service';
16
+ export * from './lib/print.client';
package/src/index.js CHANGED
@@ -16,4 +16,5 @@ tslib_1.__exportStar(require("./lib/models/api-key.model"), exports);
16
16
  tslib_1.__exportStar(require("./lib/auth.module"), exports);
17
17
  tslib_1.__exportStar(require("./lib/customer-center.service"), exports);
18
18
  tslib_1.__exportStar(require("./lib/mail-settings.service"), exports);
19
+ tslib_1.__exportStar(require("./lib/print.client"), exports);
19
20
  //# sourceMappingURL=index.js.map
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/api-sdk/src/index.ts"],"names":[],"mappings":";;;AAAA,kEAAwC;AACxC,+EAAqD;AACrD,6EAAmD;AACnD,qEAA2C;AAC3C,gFAAsD;AACtD,yEAA+C;AAE/C,+EAAqD;AACrD,oEAA0C;AAC1C,+EAAqD;AACrD,0EAAgD;AAChD,oEAA0C;AAC1C,qEAA2C;AAE3C,4DAAkC;AAClC,wEAA8C;AAC9C,sEAA4C"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/api-sdk/src/index.ts"],"names":[],"mappings":";;;AAAA,kEAAwC;AACxC,+EAAqD;AACrD,6EAAmD;AACnD,qEAA2C;AAC3C,gFAAsD;AACtD,yEAA+C;AAE/C,+EAAqD;AACrD,oEAA0C;AAC1C,+EAAqD;AACrD,0EAAgD;AAChD,oEAA0C;AAC1C,qEAA2C;AAE3C,4DAAkC;AAClC,wEAA8C;AAC9C,sEAA4C;AAC5C,6DAAmC"}
@@ -7,42 +7,38 @@ const common_1 = require("@nestjs/common");
7
7
  const auth_constants_1 = require("./auth.constants");
8
8
  const customer_center_service_1 = require("./customer-center.service");
9
9
  const mail_settings_service_1 = require("./mail-settings.service");
10
+ const print_client_1 = require("./print.client");
10
11
  var auth_constants_2 = require("./auth.constants");
11
12
  Object.defineProperty(exports, "AUTH_MODULE_OPTIONS", { enumerable: true, get: function () { return auth_constants_2.AUTH_MODULE_OPTIONS; } });
12
13
  Object.defineProperty(exports, "AUTH_TOKEN", { enumerable: true, get: function () { return auth_constants_2.AUTH_TOKEN; } });
13
14
  Object.defineProperty(exports, "AUTH_MODULE", { enumerable: true, get: function () { return auth_constants_2.AUTH_MODULE; } });
14
- const getAuthOptions = (options) => new customer_center_service_1.CustomerCenterService(options);
15
- const createAuthProvider = (options) => {
16
- return {
17
- provide: auth_constants_1.AUTH_TOKEN,
18
- useValue: getAuthOptions(options),
19
- };
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,
20
22
  };
23
+ const services = [customer_center_service_1.CustomerCenterService, mail_settings_service_1.MailSettingsService, print_client_1.PrintClient];
21
24
  let AuthModule = AuthModule_1 = class AuthModule {
22
25
  static forRoot(options) {
23
- const provider = createAuthProvider(options);
24
26
  return {
25
27
  module: AuthModule_1,
26
28
  providers: [
27
29
  { provide: auth_constants_1.AUTH_MODULE_OPTIONS, useValue: options },
28
- provider,
29
- customer_center_service_1.CustomerCenterService,
30
- mail_settings_service_1.MailSettingsService,
30
+ authTokenProvider,
31
+ ...services,
31
32
  ],
32
- exports: [provider, customer_center_service_1.CustomerCenterService, mail_settings_service_1.MailSettingsService],
33
+ exports: [auth_constants_1.AUTH_TOKEN, ...services],
33
34
  };
34
35
  }
35
36
  static forRootAsync(options) {
36
- const provider = {
37
- inject: [auth_constants_1.AUTH_MODULE_OPTIONS],
38
- provide: auth_constants_1.AUTH_TOKEN,
39
- useFactory: async (options) => getAuthOptions(options),
40
- };
41
37
  return {
42
38
  module: AuthModule_1,
43
39
  imports: options.imports,
44
- providers: [...this.createAsyncProviders(options), provider, customer_center_service_1.CustomerCenterService, mail_settings_service_1.MailSettingsService],
45
- exports: [provider, customer_center_service_1.CustomerCenterService, mail_settings_service_1.MailSettingsService],
40
+ providers: [...this.createAsyncProviders(options), authTokenProvider, ...services],
41
+ exports: [auth_constants_1.AUTH_TOKEN, ...services],
46
42
  };
47
43
  }
48
44
  static createAsyncProviders(options) {
@@ -66,10 +62,7 @@ let AuthModule = AuthModule_1 = class AuthModule {
66
62
  inject: options.inject || [],
67
63
  };
68
64
  }
69
- const inject = [
70
- (options.useClass ||
71
- options.useExisting),
72
- ];
65
+ const inject = [(options.useClass || options.useExisting)];
73
66
  return {
74
67
  provide: auth_constants_1.AUTH_MODULE_OPTIONS,
75
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;AAO9D,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;aACtB;YACD,OAAO,EAAE,CAAC,QAAQ,EAAE,+CAAqB,EAAE,2CAAmB,CAAC;SAClE,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,CAAC;YACxG,OAAO,EAAE,CAAC,QAAQ,EAAE,+CAAqB,EAAE,2CAAmB,CAAC;SAClE,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;AAxEY,gCAAU;qBAAV,UAAU;IAFtB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,UAAU,CAwEtB"}
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"}