@pvh-afl/core 1.1.20 → 1.1.22

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/dist/auth/auth.module.d.ts +58 -0
  2. package/dist/auth/auth.module.d.ts.map +1 -0
  3. package/dist/auth/auth.module.js +87 -0
  4. package/dist/auth/auth.module.js.map +1 -0
  5. package/dist/auth/auth.types.d.ts +122 -0
  6. package/dist/auth/auth.types.d.ts.map +1 -0
  7. package/dist/auth/auth.types.js +41 -0
  8. package/dist/auth/auth.types.js.map +1 -0
  9. package/dist/auth/current-user.decorator.d.ts +17 -0
  10. package/dist/auth/current-user.decorator.d.ts.map +1 -0
  11. package/dist/auth/current-user.decorator.js +22 -0
  12. package/dist/auth/current-user.decorator.js.map +1 -0
  13. package/dist/auth/index.d.ts +10 -0
  14. package/dist/auth/index.d.ts.map +1 -0
  15. package/dist/auth/index.js +19 -0
  16. package/dist/auth/index.js.map +1 -0
  17. package/dist/auth/jwt-auth.guard.d.ts +21 -0
  18. package/dist/auth/jwt-auth.guard.d.ts.map +1 -0
  19. package/dist/auth/jwt-auth.guard.js +84 -0
  20. package/dist/auth/jwt-auth.guard.js.map +1 -0
  21. package/dist/auth/jwt.service.d.ts +93 -0
  22. package/dist/auth/jwt.service.d.ts.map +1 -0
  23. package/dist/auth/jwt.service.js +185 -0
  24. package/dist/auth/jwt.service.js.map +1 -0
  25. package/dist/auth/optional-jwt-auth.guard.d.ts +34 -0
  26. package/dist/auth/optional-jwt-auth.guard.d.ts.map +1 -0
  27. package/dist/auth/optional-jwt-auth.guard.js +55 -0
  28. package/dist/auth/optional-jwt-auth.guard.js.map +1 -0
  29. package/dist/auth/ownership.d.ts +65 -0
  30. package/dist/auth/ownership.d.ts.map +1 -0
  31. package/dist/auth/ownership.js +117 -0
  32. package/dist/auth/ownership.js.map +1 -0
  33. package/dist/auth/utils.d.ts +53 -0
  34. package/dist/auth/utils.d.ts.map +1 -0
  35. package/dist/auth/utils.js +86 -0
  36. package/dist/auth/utils.js.map +1 -0
  37. package/dist/integrations/commerce/commerce.types.d.ts +5 -1
  38. package/dist/integrations/commerce/commerce.types.d.ts.map +1 -1
  39. package/dist/integrations/commerce/shopify.service.d.ts +2 -2
  40. package/dist/integrations/commerce/shopify.service.d.ts.map +1 -1
  41. package/dist/integrations/commerce/shopify.service.js +23 -4
  42. package/dist/integrations/commerce/shopify.service.js.map +1 -1
  43. package/package.json +1 -1
@@ -0,0 +1,58 @@
1
+ import { DynamicModule, InjectionToken, OptionalFactoryDependency, Type } from '@nestjs/common';
2
+ import { AuthModuleOptions } from './auth.types';
3
+ /**
4
+ * Authentication module.
5
+ *
6
+ * Provides {@link AuthTokenService} for issuing tokens and {@link JwtAuthGuard}
7
+ * for requiring one. Registered global so a guard applied in any module can
8
+ * resolve its dependencies without that module importing this one.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * AuthModule.forRoot({
13
+ * privateKey: process.env.AUTH_JWT_PRIVATE_KEY!,
14
+ * publicKey: process.env.AUTH_JWT_PUBLIC_KEY!,
15
+ * issuer: process.env.AUTH_JWT_ISSUER!,
16
+ * audience: process.env.AUTH_JWT_AUDIENCE!,
17
+ * ttlSeconds: Number(process.env.AUTH_JWT_TTL ?? 1800),
18
+ * })
19
+ * ```
20
+ */
21
+ /**
22
+ * Options for {@link AuthModule.forRootAsync}.
23
+ *
24
+ * Use this when the settings come from a provider — typically `ConfigService`,
25
+ * so authentication is configured from the brand config file alongside every
26
+ * other integration rather than read from `process.env` at module definition.
27
+ */
28
+ export interface AuthModuleAsyncOptions {
29
+ imports?: Type<unknown>[];
30
+ inject?: Array<InjectionToken | OptionalFactoryDependency>;
31
+ /**
32
+ * `any[]` rather than `unknown[]`: parameters are contravariant under
33
+ * `strictFunctionTypes`, so a factory declared as `(config: ConfigService)`
34
+ * would not be assignable to one declared as `(...args: unknown[])`. This
35
+ * mirrors how Nest types its own async module options.
36
+ */
37
+ useFactory: (...args: any[]) => AuthModuleOptions | Promise<AuthModuleOptions>;
38
+ }
39
+ export declare class AuthModule {
40
+ /**
41
+ * Configure from values resolved by a provider.
42
+ *
43
+ * The factory runs during application init, so a missing key still fails at
44
+ * startup rather than at the first request.
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * AuthModule.forRootAsync({
49
+ * imports: [ConfigModule],
50
+ * inject: [ConfigService],
51
+ * useFactory: (config: ConfigService) => config.getAuthConfig('tommy'),
52
+ * })
53
+ * ```
54
+ */
55
+ static forRootAsync(options: AuthModuleAsyncOptions): DynamicModule;
56
+ static forRoot(options: AuthModuleOptions): DynamicModule;
57
+ }
58
+ //# sourceMappingURL=auth.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.module.d.ts","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,EAEd,yBAAyB,EAEzB,IAAI,EACL,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAgB,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAK/D;;;;;;;;;;;;;;;;;GAiBG;AACH;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,cAAc,GAAG,yBAAyB,CAAC,CAAC;IAC3D;;;;;OAKG;IAEH,UAAU,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAChF;AAED,qBACa,UAAU;IACrB;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,sBAAsB,GAAG,aAAa;IAqBnE,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,aAAa;CAmB1D"}
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ var AuthModule_1;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.AuthModule = void 0;
5
+ const tslib_1 = require("tslib");
6
+ const common_1 = require("@nestjs/common");
7
+ const jwt_1 = require("@nestjs/jwt");
8
+ const auth_types_1 = require("./auth.types");
9
+ const jwt_service_1 = require("./jwt.service");
10
+ const jwt_auth_guard_1 = require("./jwt-auth.guard");
11
+ const optional_jwt_auth_guard_1 = require("./optional-jwt-auth.guard");
12
+ let AuthModule = AuthModule_1 = class AuthModule {
13
+ /**
14
+ * Configure from values resolved by a provider.
15
+ *
16
+ * The factory runs during application init, so a missing key still fails at
17
+ * startup rather than at the first request.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * AuthModule.forRootAsync({
22
+ * imports: [ConfigModule],
23
+ * inject: [ConfigService],
24
+ * useFactory: (config: ConfigService) => config.getAuthConfig('tommy'),
25
+ * })
26
+ * ```
27
+ */
28
+ static forRootAsync(options) {
29
+ const optionsProvider = {
30
+ provide: auth_types_1.AUTH_OPTIONS,
31
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
+ useFactory: async (...args) => {
33
+ const resolved = await options.useFactory(...args);
34
+ assertUsableOptions(resolved);
35
+ return resolved;
36
+ },
37
+ inject: options.inject ?? [],
38
+ };
39
+ return {
40
+ module: AuthModule_1,
41
+ global: true,
42
+ imports: [jwt_1.JwtModule.register({}), ...(options.imports ?? [])],
43
+ providers: [optionsProvider, jwt_service_1.AuthTokenService, jwt_auth_guard_1.JwtAuthGuard, optional_jwt_auth_guard_1.OptionalJwtAuthGuard],
44
+ exports: [jwt_service_1.AuthTokenService, jwt_auth_guard_1.JwtAuthGuard, optional_jwt_auth_guard_1.OptionalJwtAuthGuard],
45
+ };
46
+ }
47
+ static forRoot(options) {
48
+ assertUsableOptions(options);
49
+ return {
50
+ module: AuthModule_1,
51
+ global: true,
52
+ // Keys are passed per call in AuthTokenService rather than registered
53
+ // here, so the pinned algorithm and the key travel together and cannot
54
+ // drift apart.
55
+ imports: [jwt_1.JwtModule.register({})],
56
+ providers: [
57
+ { provide: auth_types_1.AUTH_OPTIONS, useValue: options },
58
+ jwt_service_1.AuthTokenService,
59
+ jwt_auth_guard_1.JwtAuthGuard,
60
+ optional_jwt_auth_guard_1.OptionalJwtAuthGuard,
61
+ ],
62
+ exports: [jwt_service_1.AuthTokenService, jwt_auth_guard_1.JwtAuthGuard, optional_jwt_auth_guard_1.OptionalJwtAuthGuard],
63
+ };
64
+ }
65
+ };
66
+ exports.AuthModule = AuthModule;
67
+ exports.AuthModule = AuthModule = AuthModule_1 = tslib_1.__decorate([
68
+ (0, common_1.Module)({})
69
+ ], AuthModule);
70
+ /**
71
+ * Fail at startup rather than at the first request.
72
+ *
73
+ * A missing key would otherwise surface as every token failing to verify, which
74
+ * looks like a client bug and is slow to trace back to configuration. An empty
75
+ * environment variable is the likely cause, so it is worth catching loudly.
76
+ */
77
+ function assertUsableOptions(options) {
78
+ const missing = ['privateKey', 'publicKey', 'issuer', 'audience'].filter((key) => {
79
+ const value = options?.[key];
80
+ return typeof value !== 'string' || value.trim() === '';
81
+ });
82
+ if (missing.length > 0) {
83
+ throw new Error(`AuthModule.forRoot() is missing required options: ${missing.join(', ')}. ` +
84
+ 'Check the AUTH_JWT_* environment variables.');
85
+ }
86
+ }
87
+ //# sourceMappingURL=auth.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":";;;;;AAAA,2CAOwB;AACxB,qCAAwC;AACxC,6CAA+D;AAC/D,+CAAiD;AACjD,qDAAgD;AAChD,uEAAiE;AAyC1D,IAAM,UAAU,kBAAhB,MAAM,UAAU;IACrB;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,YAAY,CAAC,OAA+B;QACjD,MAAM,eAAe,GAAa;YAChC,OAAO,EAAE,yBAAY;YACrB,8DAA8D;YAC9D,UAAU,EAAE,KAAK,EAAE,GAAG,IAAW,EAAE,EAAE;gBACnC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;gBACnD,mBAAmB,CAAC,QAAQ,CAAC,CAAC;gBAC9B,OAAO,QAAQ,CAAC;YAClB,CAAC;YACD,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;SAC7B,CAAC;QAEF,OAAO;YACL,MAAM,EAAE,YAAU;YAClB,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,CAAC,eAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;YAC7D,SAAS,EAAE,CAAC,eAAe,EAAE,8BAAgB,EAAE,6BAAY,EAAE,8CAAoB,CAAC;YAClF,OAAO,EAAE,CAAC,8BAAgB,EAAE,6BAAY,EAAE,8CAAoB,CAAC;SAChE,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,OAA0B;QACvC,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAE7B,OAAO;YACL,MAAM,EAAE,YAAU;YAClB,MAAM,EAAE,IAAI;YACZ,sEAAsE;YACtE,uEAAuE;YACvE,eAAe;YACf,OAAO,EAAE,CAAC,eAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YACjC,SAAS,EAAE;gBACT,EAAE,OAAO,EAAE,yBAAY,EAAE,QAAQ,EAAE,OAAO,EAAE;gBAC5C,8BAAgB;gBAChB,6BAAY;gBACZ,8CAAoB;aACrB;YACD,OAAO,EAAE,CAAC,8BAAgB,EAAE,6BAAY,EAAE,8CAAoB,CAAC;SAChE,CAAC;IACJ,CAAC;CACF,CAAA;AAxDY,gCAAU;qBAAV,UAAU;IADtB,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,UAAU,CAwDtB;AAED;;;;;;GAMG;AACH,SAAS,mBAAmB,CAAC,OAA0B;IACrD,MAAM,OAAO,GACX,CAAC,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,CACjD,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE;QACf,MAAM,KAAK,GAAG,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC;QAC7B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,qDAAqD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;YACzE,6CAA6C,CAChD,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Authentication types.
3
+ *
4
+ * The JWT issued here is an authentication gate only. It proves *which customer*
5
+ * is calling; it carries no Shopify credential and grants no capability of its
6
+ * own. Shopify remains the source of truth for identity — the token is minted
7
+ * only after Shopify has validated a customer access token.
8
+ */
9
+ /**
10
+ * Configuration for {@link AuthModule.forRoot}.
11
+ */
12
+ export interface AuthModuleOptions {
13
+ /** RSA private key (PEM) used to sign tokens. Keep in a secret manager. */
14
+ privateKey: string;
15
+ /** RSA public key (PEM) used to verify tokens. Safe to distribute. */
16
+ publicKey: string;
17
+ /** `iss` claim, and the only issuer accepted on verify. */
18
+ issuer: string;
19
+ /** `aud` claim, and the only audience accepted on verify. */
20
+ audience: string;
21
+ /**
22
+ * Access token lifetime in seconds. Kept short because there is no
23
+ * server-side revocation — a stolen token is usable until it expires.
24
+ *
25
+ * @default 1800 (30 minutes)
26
+ */
27
+ ttlSeconds?: number;
28
+ /**
29
+ * Refresh token lifetime in seconds.
30
+ *
31
+ * This is the absolute length of a session: refresh tokens are **not** rotated,
32
+ * so the customer logs in again when this elapses regardless of activity.
33
+ *
34
+ * Not rotating is deliberate. Rotation only adds safety when the server can
35
+ * remember which token is current and spot an old one being replayed, and that
36
+ * needs stored state. Without it, rotation would instead let a stolen refresh
37
+ * token be renewed indefinitely. A fixed expiry means a stolen token dies at a
38
+ * known time.
39
+ *
40
+ * Raising this widens the window in which a stolen refresh token works, and
41
+ * there is no way to cut that short.
42
+ *
43
+ * @default 604800 (7 days)
44
+ */
45
+ refreshTtlSeconds?: number;
46
+ }
47
+ /**
48
+ * Which kind of token this is.
49
+ *
50
+ * Carried in every token and checked on every verify, so the two cannot be
51
+ * swapped. Without it a refresh token — deliberately long-lived — would be
52
+ * accepted as an access token and quietly bypass the short access window.
53
+ */
54
+ export declare const TokenType: {
55
+ readonly ACCESS: "access";
56
+ readonly REFRESH: "refresh";
57
+ };
58
+ export type TokenType = (typeof TokenType)[keyof typeof TokenType];
59
+ /**
60
+ * The claims carried in a token we issue.
61
+ *
62
+ * Everything here is readable by anyone holding the token — base64url is
63
+ * encoding, not encryption. Nothing secret goes in, which is why the phone
64
+ * number is stored as a hash rather than in the clear.
65
+ */
66
+ export interface CustomerJwtPayload {
67
+ /** Issuer. */
68
+ iss: string;
69
+ /** Audience. */
70
+ aud: string;
71
+ /** Access or refresh. Enforced on verify so the two cannot be interchanged. */
72
+ typ: TokenType;
73
+ /**
74
+ * The authenticated customer, as a Shopify GID.
75
+ * Read from Shopify's response at issue time — never from client input.
76
+ */
77
+ sub: string;
78
+ /**
79
+ * SHA-256 of the customer's normalised mobile number, or undefined when
80
+ * Shopify holds no phone number for them.
81
+ *
82
+ * Enough to verify that a `mobile` value in a request belongs to the caller,
83
+ * without putting the number itself in a readable token.
84
+ */
85
+ phone_hash?: string;
86
+ /** Issued at (seconds since epoch). */
87
+ iat: number;
88
+ /** Expires at (seconds since epoch). */
89
+ exp: number;
90
+ }
91
+ /**
92
+ * What the guard attaches to the request after a token verifies.
93
+ *
94
+ * Handlers and resolvers must read identity from here — never from the request
95
+ * body, query string or GraphQL arguments.
96
+ */
97
+ export interface AuthUser {
98
+ /** Shopify customer GID, from the token's `sub`. */
99
+ customerId: string;
100
+ /** SHA-256 of the caller's normalised mobile, when Shopify has one. */
101
+ phoneHash?: string;
102
+ }
103
+ /** Error codes returned to callers. Stable — clients branch on these. */
104
+ export declare const AuthErrorCode: {
105
+ /** No `Authorization` header, or not a Bearer token. */
106
+ readonly TOKEN_MISSING: "TOKEN_MISSING";
107
+ /** Signature, issuer, audience or shape rejected. */
108
+ readonly TOKEN_INVALID: "TOKEN_INVALID";
109
+ /** Well-formed and correctly signed, but past `exp`. Refresh and retry. */
110
+ readonly TOKEN_EXPIRED: "TOKEN_EXPIRED";
111
+ /** Authenticated, but the request names a resource belonging to someone else. */
112
+ readonly FORBIDDEN: "FORBIDDEN";
113
+ /**
114
+ * A refresh token was sent where an access token belongs, or the reverse.
115
+ * Signals a client bug rather than an expired session.
116
+ */
117
+ readonly TOKEN_WRONG_TYPE: "TOKEN_WRONG_TYPE";
118
+ };
119
+ export type AuthErrorCode = (typeof AuthErrorCode)[keyof typeof AuthErrorCode];
120
+ /** DI token for the resolved {@link AuthModuleOptions}. */
121
+ export declare const AUTH_OPTIONS: unique symbol;
122
+ //# sourceMappingURL=auth.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.types.d.ts","sourceRoot":"","sources":["../../src/auth/auth.types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,2EAA2E;IAC3E,UAAU,EAAE,MAAM,CAAC;IAEnB,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAC;IAElB,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC;IAEf,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;;;;;;;;;;;OAgBG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,SAAS;;;CAGZ,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,cAAc;IACd,GAAG,EAAE,MAAM,CAAC;IAEZ,gBAAgB;IAChB,GAAG,EAAE,MAAM,CAAC;IAEZ,+EAA+E;IAC/E,GAAG,EAAE,SAAS,CAAC;IAEf;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IAEZ,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;IAEnB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,yEAAyE;AACzE,eAAO,MAAM,aAAa;IACxB,wDAAwD;;IAGxD,qDAAqD;;IAGrD,2EAA2E;;IAG3E,iFAAiF;;IAGjF;;;OAGG;;CAEK,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,OAAO,aAAa,CAAC,CAAC;AAE/E,2DAA2D;AAC3D,eAAO,MAAM,YAAY,eAAyB,CAAC"}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ /**
3
+ * Authentication types.
4
+ *
5
+ * The JWT issued here is an authentication gate only. It proves *which customer*
6
+ * is calling; it carries no Shopify credential and grants no capability of its
7
+ * own. Shopify remains the source of truth for identity — the token is minted
8
+ * only after Shopify has validated a customer access token.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.AUTH_OPTIONS = exports.AuthErrorCode = exports.TokenType = void 0;
12
+ /**
13
+ * Which kind of token this is.
14
+ *
15
+ * Carried in every token and checked on every verify, so the two cannot be
16
+ * swapped. Without it a refresh token — deliberately long-lived — would be
17
+ * accepted as an access token and quietly bypass the short access window.
18
+ */
19
+ exports.TokenType = {
20
+ ACCESS: 'access',
21
+ REFRESH: 'refresh',
22
+ };
23
+ /** Error codes returned to callers. Stable — clients branch on these. */
24
+ exports.AuthErrorCode = {
25
+ /** No `Authorization` header, or not a Bearer token. */
26
+ TOKEN_MISSING: 'TOKEN_MISSING',
27
+ /** Signature, issuer, audience or shape rejected. */
28
+ TOKEN_INVALID: 'TOKEN_INVALID',
29
+ /** Well-formed and correctly signed, but past `exp`. Refresh and retry. */
30
+ TOKEN_EXPIRED: 'TOKEN_EXPIRED',
31
+ /** Authenticated, but the request names a resource belonging to someone else. */
32
+ FORBIDDEN: 'FORBIDDEN',
33
+ /**
34
+ * A refresh token was sent where an access token belongs, or the reverse.
35
+ * Signals a client bug rather than an expired session.
36
+ */
37
+ TOKEN_WRONG_TYPE: 'TOKEN_WRONG_TYPE',
38
+ };
39
+ /** DI token for the resolved {@link AuthModuleOptions}. */
40
+ exports.AUTH_OPTIONS = Symbol('AUTH_OPTIONS');
41
+ //# sourceMappingURL=auth.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.types.js","sourceRoot":"","sources":["../../src/auth/auth.types.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AA8CH;;;;;;GAMG;AACU,QAAA,SAAS,GAAG;IACvB,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;CACV,CAAC;AAyDX,yEAAyE;AAC5D,QAAA,aAAa,GAAG;IAC3B,wDAAwD;IACxD,aAAa,EAAE,eAAe;IAE9B,qDAAqD;IACrD,aAAa,EAAE,eAAe;IAE9B,2EAA2E;IAC3E,aAAa,EAAE,eAAe;IAE9B,iFAAiF;IACjF,SAAS,EAAE,WAAW;IAEtB;;;OAGG;IACH,gBAAgB,EAAE,kBAAkB;CAC5B,CAAC;AAIX,2DAA2D;AAC9C,QAAA,YAAY,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Injects the authenticated caller, as established by {@link JwtAuthGuard}.
3
+ *
4
+ * Only valid on handlers that carry the guard — without it there is no verified
5
+ * user and this resolves to undefined.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * @UseGuards(JwtAuthGuard)
10
+ * @Get()
11
+ * async getItems(@CurrentUser() user: AuthUser) {
12
+ * return this.service.getItems(user.customerId);
13
+ * }
14
+ * ```
15
+ */
16
+ export declare const CurrentUser: (...dataOrPipes: unknown[]) => ParameterDecorator;
17
+ //# sourceMappingURL=current-user.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"current-user.decorator.d.ts","sourceRoot":"","sources":["../../src/auth/current-user.decorator.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,WAAW,mDAGvB,CAAC"}
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CurrentUser = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ const utils_1 = require("./utils");
6
+ /**
7
+ * Injects the authenticated caller, as established by {@link JwtAuthGuard}.
8
+ *
9
+ * Only valid on handlers that carry the guard — without it there is no verified
10
+ * user and this resolves to undefined.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * @UseGuards(JwtAuthGuard)
15
+ * @Get()
16
+ * async getItems(@CurrentUser() user: AuthUser) {
17
+ * return this.service.getItems(user.customerId);
18
+ * }
19
+ * ```
20
+ */
21
+ exports.CurrentUser = (0, common_1.createParamDecorator)((_data, context) => (0, utils_1.getRequest)(context).user);
22
+ //# sourceMappingURL=current-user.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"current-user.decorator.js","sourceRoot":"","sources":["../../src/auth/current-user.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAAwE;AAExE,mCAAqC;AAErC;;;;;;;;;;;;;;GAcG;AACU,QAAA,WAAW,GAAG,IAAA,6BAAoB,EAC7C,CAAC,KAAc,EAAE,OAAyB,EAAY,EAAE,CACtD,IAAA,kBAAU,EAAC,OAAO,CAAC,CAAC,IAAgB,CACvC,CAAC"}
@@ -0,0 +1,10 @@
1
+ export * from './auth.types';
2
+ export * from './auth.module';
3
+ export * from './jwt.service';
4
+ export * from './jwt-auth.guard';
5
+ export * from './optional-jwt-auth.guard';
6
+ export * from './current-user.decorator';
7
+ export * from './ownership';
8
+ export { getRequest, bearer, normalizeGid, normalizePhone, sha256, hashPhone, } from './utils';
9
+ export type { AuthRequest } from './utils';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,aAAa,CAAC;AAC5B,OAAO,EACL,UAAU,EACV,MAAM,EACN,YAAY,EACZ,cAAc,EACd,MAAM,EACN,SAAS,GACV,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hashPhone = exports.sha256 = exports.normalizePhone = exports.normalizeGid = exports.bearer = exports.getRequest = void 0;
4
+ const tslib_1 = require("tslib");
5
+ tslib_1.__exportStar(require("./auth.types"), exports);
6
+ tslib_1.__exportStar(require("./auth.module"), exports);
7
+ tslib_1.__exportStar(require("./jwt.service"), exports);
8
+ tslib_1.__exportStar(require("./jwt-auth.guard"), exports);
9
+ tslib_1.__exportStar(require("./optional-jwt-auth.guard"), exports);
10
+ tslib_1.__exportStar(require("./current-user.decorator"), exports);
11
+ tslib_1.__exportStar(require("./ownership"), exports);
12
+ var utils_1 = require("./utils");
13
+ Object.defineProperty(exports, "getRequest", { enumerable: true, get: function () { return utils_1.getRequest; } });
14
+ Object.defineProperty(exports, "bearer", { enumerable: true, get: function () { return utils_1.bearer; } });
15
+ Object.defineProperty(exports, "normalizeGid", { enumerable: true, get: function () { return utils_1.normalizeGid; } });
16
+ Object.defineProperty(exports, "normalizePhone", { enumerable: true, get: function () { return utils_1.normalizePhone; } });
17
+ Object.defineProperty(exports, "sha256", { enumerable: true, get: function () { return utils_1.sha256; } });
18
+ Object.defineProperty(exports, "hashPhone", { enumerable: true, get: function () { return utils_1.hashPhone; } });
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":";;;;AAAA,uDAA6B;AAC7B,wDAA8B;AAC9B,wDAA8B;AAC9B,2DAAiC;AACjC,oEAA0C;AAC1C,mEAAyC;AACzC,sDAA4B;AAC5B,iCAOiB;AANf,mGAAA,UAAU,OAAA;AACV,+FAAA,MAAM,OAAA;AACN,qGAAA,YAAY,OAAA;AACZ,uGAAA,cAAc,OAAA;AACd,+FAAA,MAAM,OAAA;AACN,kGAAA,SAAS,OAAA"}
@@ -0,0 +1,21 @@
1
+ import { CanActivate, ExecutionContext } from '@nestjs/common';
2
+ import { AuthTokenService } from './jwt.service';
3
+ /**
4
+ * Requires a valid authentication token, and attaches the caller to the request.
5
+ *
6
+ * Apply with `@UseGuards(JwtAuthGuard)` on endpoints that read or change one
7
+ * customer's data. Endpoints that serve public data carry no guard.
8
+ *
9
+ * On success `request.user` holds an {@link AuthUser}, which handlers read via
10
+ * `@CurrentUser()`. Identity must come from there and never from the request
11
+ * body, query string or GraphQL arguments — a caller controls those.
12
+ *
13
+ * Note that this guard answers only "who is calling". It does not check that
14
+ * the records a request names belong to that caller; see `ownership.ts`.
15
+ */
16
+ export declare class JwtAuthGuard implements CanActivate {
17
+ private readonly tokens;
18
+ constructor(tokens: AuthTokenService);
19
+ canActivate(context: ExecutionContext): Promise<boolean>;
20
+ }
21
+ //# sourceMappingURL=jwt-auth.guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt-auth.guard.d.ts","sourceRoot":"","sources":["../../src/auth/jwt-auth.guard.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,gBAAgB,EAGjB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,gBAAgB,EAIjB,MAAM,eAAe,CAAC;AAGvB;;;;;;;;;;;;GAYG;AACH,qBACa,YAAa,YAAW,WAAW;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,gBAAgB;IAE/C,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;CAwD/D"}
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JwtAuthGuard = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const common_1 = require("@nestjs/common");
6
+ const logger_1 = require("../common/logger");
7
+ const auth_types_1 = require("./auth.types");
8
+ const jwt_service_1 = require("./jwt.service");
9
+ const utils_1 = require("./utils");
10
+ /**
11
+ * Requires a valid authentication token, and attaches the caller to the request.
12
+ *
13
+ * Apply with `@UseGuards(JwtAuthGuard)` on endpoints that read or change one
14
+ * customer's data. Endpoints that serve public data carry no guard.
15
+ *
16
+ * On success `request.user` holds an {@link AuthUser}, which handlers read via
17
+ * `@CurrentUser()`. Identity must come from there and never from the request
18
+ * body, query string or GraphQL arguments — a caller controls those.
19
+ *
20
+ * Note that this guard answers only "who is calling". It does not check that
21
+ * the records a request names belong to that caller; see `ownership.ts`.
22
+ */
23
+ let JwtAuthGuard = class JwtAuthGuard {
24
+ tokens;
25
+ constructor(tokens) {
26
+ this.tokens = tokens;
27
+ }
28
+ async canActivate(context) {
29
+ const request = (0, utils_1.getRequest)(context);
30
+ const token = (0, utils_1.bearer)(request);
31
+ if (!token) {
32
+ throw new common_1.UnauthorizedException({
33
+ code: auth_types_1.AuthErrorCode.TOKEN_MISSING,
34
+ message: 'Authentication required',
35
+ });
36
+ }
37
+ try {
38
+ request.user = await this.tokens.verifyAccess(token);
39
+ return true;
40
+ }
41
+ catch (error) {
42
+ if (error instanceof jwt_service_1.TokenExpiredError) {
43
+ // Expected and routine — the client refreshes and retries, so this is
44
+ // not worth logging on every occurrence.
45
+ throw new common_1.UnauthorizedException({
46
+ code: auth_types_1.AuthErrorCode.TOKEN_EXPIRED,
47
+ message: 'Token has expired',
48
+ });
49
+ }
50
+ if (error instanceof jwt_service_1.TokenWrongTypeError) {
51
+ // Almost certainly a client bug: the refresh token was sent on a normal
52
+ // request. Distinguished from TOKEN_INVALID so it is obvious in a log.
53
+ logger_1.logger.warn('Wrong token type on a protected route', {
54
+ reason: error.message,
55
+ path: typeof request.url === 'string' ? request.url : undefined,
56
+ });
57
+ throw new common_1.UnauthorizedException({
58
+ code: auth_types_1.AuthErrorCode.TOKEN_WRONG_TYPE,
59
+ message: 'Invalid token',
60
+ });
61
+ }
62
+ if (error instanceof jwt_service_1.TokenInvalidError) {
63
+ // A bad signature, wrong issuer or malformed token is not something a
64
+ // healthy client produces. Log it — a rise here is worth noticing —
65
+ // but keep the reason out of the response so probing gains nothing.
66
+ logger_1.logger.warn('Rejected authentication token', {
67
+ reason: error.message,
68
+ path: typeof request.url === 'string' ? request.url : undefined,
69
+ });
70
+ throw new common_1.UnauthorizedException({
71
+ code: auth_types_1.AuthErrorCode.TOKEN_INVALID,
72
+ message: 'Invalid token',
73
+ });
74
+ }
75
+ throw error;
76
+ }
77
+ }
78
+ };
79
+ exports.JwtAuthGuard = JwtAuthGuard;
80
+ exports.JwtAuthGuard = JwtAuthGuard = tslib_1.__decorate([
81
+ (0, common_1.Injectable)(),
82
+ tslib_1.__metadata("design:paramtypes", [jwt_service_1.AuthTokenService])
83
+ ], JwtAuthGuard);
84
+ //# sourceMappingURL=jwt-auth.guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt-auth.guard.js","sourceRoot":"","sources":["../../src/auth/jwt-auth.guard.ts"],"names":[],"mappings":";;;;AAAA,2CAKwB;AACxB,6CAA0C;AAC1C,6CAA6C;AAC7C,+CAKuB;AACvB,mCAA6C;AAE7C;;;;;;;;;;;;GAYG;AAEI,IAAM,YAAY,GAAlB,MAAM,YAAY;IACM;IAA7B,YAA6B,MAAwB;QAAxB,WAAM,GAAN,MAAM,CAAkB;IAAG,CAAC;IAEzD,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,OAAO,GAAG,IAAA,kBAAU,EAAC,OAAO,CAAC,CAAC;QACpC,MAAM,KAAK,GAAG,IAAA,cAAM,EAAC,OAAO,CAAC,CAAC;QAE9B,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,8BAAqB,CAAC;gBAC9B,IAAI,EAAE,0BAAa,CAAC,aAAa;gBACjC,OAAO,EAAE,yBAAyB;aACnC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;YACrD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,+BAAiB,EAAE,CAAC;gBACvC,sEAAsE;gBACtE,yCAAyC;gBACzC,MAAM,IAAI,8BAAqB,CAAC;oBAC9B,IAAI,EAAE,0BAAa,CAAC,aAAa;oBACjC,OAAO,EAAE,mBAAmB;iBAC7B,CAAC,CAAC;YACL,CAAC;YAED,IAAI,KAAK,YAAY,iCAAmB,EAAE,CAAC;gBACzC,wEAAwE;gBACxE,uEAAuE;gBACvE,eAAM,CAAC,IAAI,CAAC,uCAAuC,EAAE;oBACnD,MAAM,EAAE,KAAK,CAAC,OAAO;oBACrB,IAAI,EAAE,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;iBAChE,CAAC,CAAC;gBAEH,MAAM,IAAI,8BAAqB,CAAC;oBAC9B,IAAI,EAAE,0BAAa,CAAC,gBAAgB;oBACpC,OAAO,EAAE,eAAe;iBACzB,CAAC,CAAC;YACL,CAAC;YAED,IAAI,KAAK,YAAY,+BAAiB,EAAE,CAAC;gBACvC,sEAAsE;gBACtE,oEAAoE;gBACpE,oEAAoE;gBACpE,eAAM,CAAC,IAAI,CAAC,+BAA+B,EAAE;oBAC3C,MAAM,EAAE,KAAK,CAAC,OAAO;oBACrB,IAAI,EAAE,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;iBAChE,CAAC,CAAC;gBAEH,MAAM,IAAI,8BAAqB,CAAC;oBAC9B,IAAI,EAAE,0BAAa,CAAC,aAAa;oBACjC,OAAO,EAAE,eAAe;iBACzB,CAAC,CAAC;YACL,CAAC;YAED,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF,CAAA;AA3DY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;6CAE0B,8BAAgB;GAD1C,YAAY,CA2DxB"}
@@ -0,0 +1,93 @@
1
+ import { JwtService as NestJwtService } from '@nestjs/jwt';
2
+ import { AuthModuleOptions, AuthUser } from './auth.types';
3
+ /** Thrown when a token is well-formed and correctly signed but has expired. */
4
+ export declare class TokenExpiredError extends Error {
5
+ }
6
+ /** Thrown when a token fails any other check. */
7
+ export declare class TokenInvalidError extends Error {
8
+ }
9
+ /** Thrown when a refresh token is used as an access token, or the reverse. */
10
+ export declare class TokenWrongTypeError extends Error {
11
+ }
12
+ /** A freshly issued pair. */
13
+ export interface TokenPair {
14
+ accessToken: string;
15
+ accessExpiresAt: Date;
16
+ refreshToken: string;
17
+ refreshExpiresAt: Date;
18
+ }
19
+ /**
20
+ * Signs and verifies the authentication tokens this service issues.
21
+ *
22
+ * Two kinds, distinguished by a `typ` claim that is checked on every verify:
23
+ *
24
+ * - **access** (30 min) — sent on every protected request.
25
+ * - **refresh** (7 days) — sent only to `/auth/refresh`, to mint a new access
26
+ * token without going back to Shopify.
27
+ *
28
+ * The refresh token carries the same identity claims as an access token, which is
29
+ * what lets renewal be a purely local operation: no Shopify call, so renewal
30
+ * costs nothing against Shopify's rate limit.
31
+ *
32
+ * Fixed to RS256, and the algorithm is pinned on verify rather than read from the
33
+ * token. That is deliberate: the JWT spec allows `alg: none`, and a verifier that
34
+ * trusts the token's own header can also be tricked into validating an RS256
35
+ * token as HS256 using the public key as the HMAC secret. Both attacks fail
36
+ * against an explicit allow-list of one algorithm.
37
+ */
38
+ export declare class AuthTokenService {
39
+ private readonly jwt;
40
+ private readonly options;
41
+ private readonly ttlSeconds;
42
+ private readonly refreshTtlSeconds;
43
+ constructor(jwt: NestJwtService, options: AuthModuleOptions);
44
+ /**
45
+ * Issue an access and refresh token for a customer whose identity Shopify has
46
+ * already confirmed.
47
+ *
48
+ * @param customerId - Shopify customer GID, taken from Shopify's response.
49
+ * @param phone - The customer's phone number as Shopify holds it, if any.
50
+ * Stored as a hash so a `mobile` value in a later request can be checked
51
+ * against it without the number appearing in the token.
52
+ * @param maxExpiresAt - Optional upper bound on both expiries, normally an
53
+ * upstream credential's own expiry, so neither token outlives it.
54
+ */
55
+ issuePair(customerId: string, phone?: string | null, maxExpiresAt?: Date | string | null): Promise<TokenPair>;
56
+ /**
57
+ * Issue a replacement access token from a verified refresh token.
58
+ *
59
+ * The refresh token itself is **not** replaced: its expiry is the absolute end
60
+ * of the session (see `refreshTtlSeconds`). The caller keeps using the same one
61
+ * until it expires, then logs in again.
62
+ */
63
+ issueAccessToken(user: AuthUser, maxExpiresAt?: Date | string | null): Promise<{
64
+ token: string;
65
+ expiresAt: Date;
66
+ }>;
67
+ /**
68
+ * Verify an access token and return the caller it identifies.
69
+ *
70
+ * @throws {TokenExpiredError} past `exp` — the client should refresh and retry.
71
+ * @throws {TokenWrongTypeError} a refresh token was sent instead.
72
+ * @throws {TokenInvalidError} anything else.
73
+ */
74
+ verifyAccess(token: string): Promise<AuthUser>;
75
+ /**
76
+ * Verify a refresh token and return the caller it identifies.
77
+ *
78
+ * @throws {TokenExpiredError} the session has reached its absolute end; the
79
+ * customer has to log in again.
80
+ * @throws {TokenWrongTypeError} an access token was sent instead.
81
+ * @throws {TokenInvalidError} anything else.
82
+ */
83
+ verifyRefresh(token: string): Promise<AuthUser>;
84
+ private verify;
85
+ private sign;
86
+ private signFromHash;
87
+ /**
88
+ * Work out the `exp` claim: the given lifetime, shortened if an upstream
89
+ * credential expires sooner.
90
+ */
91
+ private resolveExpiry;
92
+ }
93
+ //# sourceMappingURL=jwt.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.service.d.ts","sourceRoot":"","sources":["../../src/auth/jwt.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAEL,iBAAiB,EACjB,QAAQ,EAGT,MAAM,cAAc,CAAC;AAGtB,+EAA+E;AAC/E,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAE/C,iDAAiD;AACjD,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAE/C,8EAA8E;AAC9E,qBAAa,mBAAoB,SAAQ,KAAK;CAAG;AAKjD,6BAA6B;AAC7B,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,IAAI,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,IAAI,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBACa,gBAAgB;IAKzB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACE,OAAO,CAAC,QAAQ,CAAC,OAAO;IALhD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;gBAGxB,GAAG,EAAE,cAAc,EACG,OAAO,EAAE,iBAAiB;IAOnE;;;;;;;;;;OAUG;IACG,SAAS,CACb,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,EACrB,YAAY,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,GAClC,OAAO,CAAC,SAAS,CAAC;IAoBrB;;;;;;OAMG;IACG,gBAAgB,CACpB,IAAI,EAAE,QAAQ,EACd,YAAY,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,GAClC,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,IAAI,CAAA;KAAE,CAAC;IAU9C;;;;;;OAMG;IACG,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAIpD;;;;;;;OAOG;IACG,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;YAIvC,MAAM;IA2CpB,OAAO,CAAC,IAAI;YAgBE,YAAY;IA8B1B;;;OAGG;IACH,OAAO,CAAC,aAAa;CActB"}