@tyravel/auth 0.1.0

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 (81) hide show
  1. package/dist/auth-manager.d.ts +27 -0
  2. package/dist/auth-manager.d.ts.map +1 -0
  3. package/dist/auth-manager.js +102 -0
  4. package/dist/auth-manager.js.map +1 -0
  5. package/dist/auth.test.d.ts +2 -0
  6. package/dist/auth.test.d.ts.map +1 -0
  7. package/dist/auth.test.js +67 -0
  8. package/dist/auth.test.js.map +1 -0
  9. package/dist/authorization-exceptions.d.ts +7 -0
  10. package/dist/authorization-exceptions.d.ts.map +1 -0
  11. package/dist/authorization-exceptions.js +13 -0
  12. package/dist/authorization-exceptions.js.map +1 -0
  13. package/dist/exceptions.d.ts +7 -0
  14. package/dist/exceptions.d.ts.map +1 -0
  15. package/dist/exceptions.js +13 -0
  16. package/dist/exceptions.js.map +1 -0
  17. package/dist/gate.d.ts +16 -0
  18. package/dist/gate.d.ts.map +1 -0
  19. package/dist/gate.js +66 -0
  20. package/dist/gate.js.map +1 -0
  21. package/dist/gate.test.d.ts +2 -0
  22. package/dist/gate.test.d.ts.map +1 -0
  23. package/dist/gate.test.js +33 -0
  24. package/dist/gate.test.js.map +1 -0
  25. package/dist/hasher.d.ts +5 -0
  26. package/dist/hasher.d.ts.map +1 -0
  27. package/dist/hasher.js +28 -0
  28. package/dist/hasher.js.map +1 -0
  29. package/dist/index.d.ts +18 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +15 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/oauth.d.ts +40 -0
  34. package/dist/oauth.d.ts.map +1 -0
  35. package/dist/oauth.js +178 -0
  36. package/dist/oauth.js.map +1 -0
  37. package/dist/oauth.test.d.ts +2 -0
  38. package/dist/oauth.test.d.ts.map +1 -0
  39. package/dist/oauth.test.js +17 -0
  40. package/dist/oauth.test.js.map +1 -0
  41. package/dist/password-reset-broker.d.ts +20 -0
  42. package/dist/password-reset-broker.d.ts.map +1 -0
  43. package/dist/password-reset-broker.js +68 -0
  44. package/dist/password-reset-broker.js.map +1 -0
  45. package/dist/personal-access-token-repository.d.ts +14 -0
  46. package/dist/personal-access-token-repository.d.ts.map +1 -0
  47. package/dist/personal-access-token-repository.js +55 -0
  48. package/dist/personal-access-token-repository.js.map +1 -0
  49. package/dist/policy.d.ts +3 -0
  50. package/dist/policy.d.ts.map +1 -0
  51. package/dist/policy.js +3 -0
  52. package/dist/policy.js.map +1 -0
  53. package/dist/session-guard.d.ts +26 -0
  54. package/dist/session-guard.d.ts.map +1 -0
  55. package/dist/session-guard.js +118 -0
  56. package/dist/session-guard.js.map +1 -0
  57. package/dist/session-store.d.ts +18 -0
  58. package/dist/session-store.d.ts.map +1 -0
  59. package/dist/session-store.js +69 -0
  60. package/dist/session-store.js.map +1 -0
  61. package/dist/session.d.ts +18 -0
  62. package/dist/session.d.ts.map +1 -0
  63. package/dist/session.js +33 -0
  64. package/dist/session.js.map +1 -0
  65. package/dist/token-guard.d.ts +20 -0
  66. package/dist/token-guard.d.ts.map +1 -0
  67. package/dist/token-guard.js +51 -0
  68. package/dist/token-guard.js.map +1 -0
  69. package/dist/token.test.d.ts +2 -0
  70. package/dist/token.test.d.ts.map +1 -0
  71. package/dist/token.test.js +11 -0
  72. package/dist/token.test.js.map +1 -0
  73. package/dist/types.d.ts +73 -0
  74. package/dist/types.d.ts.map +1 -0
  75. package/dist/types.js +2 -0
  76. package/dist/types.js.map +1 -0
  77. package/dist/user-provider.d.ts +15 -0
  78. package/dist/user-provider.d.ts.map +1 -0
  79. package/dist/user-provider.js +30 -0
  80. package/dist/user-provider.js.map +1 -0
  81. package/package.json +41 -0
@@ -0,0 +1,27 @@
1
+ import type { TyravelRequest } from '@tyravel/http';
2
+ import type { Middleware } from '@tyravel/http';
3
+ import { SessionGuard } from './session-guard.js';
4
+ import type { Authenticatable, AuthConfig, Guard } from './types.js';
5
+ type WebResponse = globalThis.Response;
6
+ export declare class AuthManager {
7
+ private readonly config;
8
+ private readonly guards;
9
+ private readonly sessionGuardName;
10
+ private defaultGuard;
11
+ constructor(config: AuthConfig, guardFactories: Record<string, () => Guard>, sessionGuardName: string);
12
+ guard(name?: string): Guard;
13
+ sessionGuard(): SessionGuard;
14
+ user(guardName?: string): Authenticatable | null;
15
+ id(guardName?: string): string | number | null;
16
+ check(guardName?: string): Promise<boolean>;
17
+ attempt(credentials: Record<string, string>, guardName?: string): Promise<boolean>;
18
+ login(user: Authenticatable, guardName?: string): Promise<void>;
19
+ logout(guardName?: string): Promise<void>;
20
+ startRequest(request: TyravelRequest): Promise<void>;
21
+ endRequest(response: WebResponse): Promise<WebResponse>;
22
+ }
23
+ export declare function createAuthMiddleware(auth: AuthManager, guardName?: string): Middleware;
24
+ export declare function createGuestMiddleware(auth: AuthManager, guardName?: string): Middleware;
25
+ export declare function createStartSessionMiddleware(auth: AuthManager): Middleware;
26
+ export { SessionGuard } from './session-guard.js';
27
+ //# sourceMappingURL=auth-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-manager.d.ts","sourceRoot":"","sources":["../src/auth-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAErE,KAAK,WAAW,GAAG,UAAU,CAAC,QAAQ,CAAC;AAEvC,qBAAa,WAAW;IAMpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IALzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,YAAY,CAAS;gBAGV,MAAM,EAAE,UAAU,EACnC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,KAAK,CAAC,EAC3C,gBAAgB,EAAE,MAAM;IAS1B,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK;IAS3B,YAAY,IAAI,YAAY;IAQ5B,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI;IAIhD,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI;IAIxC,KAAK,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK3C,OAAO,CACX,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC;IAKb,KAAK,CAAC,IAAI,EAAE,eAAe,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO/D,MAAM,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOzC,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAcpD,UAAU,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;CAG9D;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,CAYtF;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,CASvF;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,WAAW,GAAG,UAAU,CAM1E;AAED,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,102 @@
1
+ import { Response as HttpResponse } from '@tyravel/http';
2
+ import { AuthenticationException } from './exceptions.js';
3
+ import { SessionGuard } from './session-guard.js';
4
+ export class AuthManager {
5
+ config;
6
+ guards = new Map();
7
+ sessionGuardName;
8
+ defaultGuard;
9
+ constructor(config, guardFactories, sessionGuardName) {
10
+ this.config = config;
11
+ this.defaultGuard = config.defaults.guard;
12
+ this.sessionGuardName = sessionGuardName;
13
+ for (const [name, factory] of Object.entries(guardFactories)) {
14
+ this.guards.set(name, factory());
15
+ }
16
+ }
17
+ guard(name) {
18
+ const guardName = name ?? this.defaultGuard;
19
+ const guard = this.guards.get(guardName);
20
+ if (!guard) {
21
+ throw new Error(`Auth guard not configured: ${guardName}`);
22
+ }
23
+ return guard;
24
+ }
25
+ sessionGuard() {
26
+ const guard = this.guards.get(this.sessionGuardName);
27
+ if (!guard || !(guard instanceof SessionGuard)) {
28
+ throw new Error(`Session guard not configured: ${this.sessionGuardName}`);
29
+ }
30
+ return guard;
31
+ }
32
+ user(guardName) {
33
+ return this.guard(guardName).user();
34
+ }
35
+ id(guardName) {
36
+ return this.guard(guardName).id();
37
+ }
38
+ async check(guardName) {
39
+ const result = this.guard(guardName).check();
40
+ return result instanceof Promise ? result : result;
41
+ }
42
+ async attempt(credentials, guardName) {
43
+ const guard = this.sessionGuard();
44
+ return guard.attempt(credentials);
45
+ }
46
+ async login(user, guardName) {
47
+ if (guardName && guardName !== this.sessionGuardName) {
48
+ throw new Error('Login is only supported on the session guard.');
49
+ }
50
+ await this.sessionGuard().login(user);
51
+ }
52
+ async logout(guardName) {
53
+ if (guardName && guardName !== this.sessionGuardName) {
54
+ return;
55
+ }
56
+ await this.sessionGuard().logout();
57
+ }
58
+ async startRequest(request) {
59
+ for (const guard of this.guards.values()) {
60
+ guard.setRequest(request);
61
+ }
62
+ await this.sessionGuard().startSession();
63
+ for (const guard of this.guards.values()) {
64
+ if ('authenticate' in guard && typeof guard.authenticate === 'function') {
65
+ await guard.authenticate();
66
+ }
67
+ }
68
+ }
69
+ async endRequest(response) {
70
+ return this.sessionGuard().persistSession(response);
71
+ }
72
+ }
73
+ export function createAuthMiddleware(auth, guardName) {
74
+ return async (request, next) => {
75
+ const guard = auth.guard(guardName);
76
+ const ok = guard.check();
77
+ const authenticated = ok instanceof Promise ? await ok : ok;
78
+ if (!authenticated) {
79
+ throw new AuthenticationException();
80
+ }
81
+ request.user = guard.user();
82
+ return next();
83
+ };
84
+ }
85
+ export function createGuestMiddleware(auth, guardName) {
86
+ return async (_request, next) => {
87
+ const session = auth.sessionGuard();
88
+ if (session.check()) {
89
+ return HttpResponse.json({ message: 'Already authenticated.' }, { status: 409 });
90
+ }
91
+ return next();
92
+ };
93
+ }
94
+ export function createStartSessionMiddleware(auth) {
95
+ return async (request, next) => {
96
+ await auth.startRequest(request);
97
+ const response = await next();
98
+ return auth.endRequest(response);
99
+ };
100
+ }
101
+ export { SessionGuard } from './session-guard.js';
102
+ //# sourceMappingURL=auth-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-manager.js","sourceRoot":"","sources":["../src/auth-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=auth.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.test.d.ts","sourceRoot":"","sources":["../src/auth.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,67 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { TyravelRequest } from '@tyravel/http';
3
+ import { Hasher } from './hasher.js';
4
+ import { MemorySessionStore, SessionGuard } from './index.js';
5
+ class StubUser {
6
+ id;
7
+ passwordHash;
8
+ constructor(id, passwordHash) {
9
+ this.id = id;
10
+ this.passwordHash = passwordHash;
11
+ }
12
+ getAuthIdentifier() {
13
+ return this.id;
14
+ }
15
+ getAuthPassword() {
16
+ return this.passwordHash;
17
+ }
18
+ }
19
+ class StubProvider {
20
+ hasher;
21
+ constructor(hasher) {
22
+ this.hasher = hasher;
23
+ }
24
+ async retrieveById(id) {
25
+ if (Number(id) === 1) {
26
+ return new StubUser(1, this.hasher.make('secret'));
27
+ }
28
+ return null;
29
+ }
30
+ async retrieveByCredentials(credentials) {
31
+ if (credentials.email === 'a@b.c') {
32
+ return new StubUser(1, this.hasher.make('secret'));
33
+ }
34
+ return null;
35
+ }
36
+ async validateCredentials(user, credentials) {
37
+ return this.hasher.check(credentials.password ?? '', user.getAuthPassword());
38
+ }
39
+ }
40
+ describe('SessionGuard', () => {
41
+ const config = {
42
+ cookie: 'tyravel_session',
43
+ lifetimeMinutes: 120,
44
+ table: 'sessions',
45
+ };
46
+ it('logs in and sets session cookie', async () => {
47
+ const hasher = new Hasher();
48
+ const guard = new SessionGuard('web', new StubProvider(hasher), new MemorySessionStore(), config);
49
+ const request = new TyravelRequest(new Request('http://localhost/login', { method: 'POST' }));
50
+ guard.setRequest(request);
51
+ await guard.startSession();
52
+ await guard.attempt({ email: 'a@b.c', password: 'secret' });
53
+ expect(guard.check()).toBe(true);
54
+ expect(guard.id()).toBe(1);
55
+ const response = await guard.persistSession(new globalThis.Response(JSON.stringify({ ok: true }), { status: 200 }));
56
+ expect(response.headers.get('set-cookie')).toContain('tyravel_session=');
57
+ });
58
+ });
59
+ describe('Hasher', () => {
60
+ it('hashes and verifies passwords', () => {
61
+ const hasher = new Hasher();
62
+ const hash = hasher.make('password');
63
+ expect(hasher.check('password', hash)).toBe(true);
64
+ expect(hasher.check('wrong', hash)).toBe(false);
65
+ });
66
+ });
67
+ //# sourceMappingURL=auth.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.test.js","sourceRoot":"","sources":["../src/auth.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare class AuthorizationException extends Error {
2
+ constructor(message?: string);
3
+ }
4
+ export declare class InvalidResetTokenException extends Error {
5
+ constructor(message?: string);
6
+ }
7
+ //# sourceMappingURL=authorization-exceptions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization-exceptions.d.ts","sourceRoot":"","sources":["../src/authorization-exceptions.ts"],"names":[],"mappings":"AAAA,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,OAAO,SAAiC;CAIrD;AAED,qBAAa,0BAA2B,SAAQ,KAAK;gBACvC,OAAO,SAA0C;CAI9D"}
@@ -0,0 +1,13 @@
1
+ export class AuthorizationException extends Error {
2
+ constructor(message = 'This action is unauthorized.') {
3
+ super(message);
4
+ this.name = 'AuthorizationException';
5
+ }
6
+ }
7
+ export class InvalidResetTokenException extends Error {
8
+ constructor(message = 'This password reset token is invalid.') {
9
+ super(message);
10
+ this.name = 'InvalidResetTokenException';
11
+ }
12
+ }
13
+ //# sourceMappingURL=authorization-exceptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization-exceptions.js","sourceRoot":"","sources":["../src/authorization-exceptions.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC/C,YAAY,OAAO,GAAG,8BAA8B;QAClD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF;AAED,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IACnD,YAAY,OAAO,GAAG,uCAAuC;QAC3D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;IAC3C,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ export declare class AuthenticationException extends Error {
2
+ constructor(message?: string);
3
+ }
4
+ export declare class InvalidCredentialsException extends Error {
5
+ constructor(message?: string);
6
+ }
7
+ //# sourceMappingURL=exceptions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exceptions.d.ts","sourceRoot":"","sources":["../src/exceptions.ts"],"names":[],"mappings":"AAAA,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,SAAqB;CAIzC;AAED,qBAAa,2BAA4B,SAAQ,KAAK;gBACxC,OAAO,SAAgD;CAIpE"}
@@ -0,0 +1,13 @@
1
+ export class AuthenticationException extends Error {
2
+ constructor(message = 'Unauthenticated.') {
3
+ super(message);
4
+ this.name = 'AuthenticationException';
5
+ }
6
+ }
7
+ export class InvalidCredentialsException extends Error {
8
+ constructor(message = 'These credentials do not match our records.') {
9
+ super(message);
10
+ this.name = 'InvalidCredentialsException';
11
+ }
12
+ }
13
+ //# sourceMappingURL=exceptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exceptions.js","sourceRoot":"","sources":["../src/exceptions.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAChD,YAAY,OAAO,GAAG,kBAAkB;QACtC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF;AAED,MAAM,OAAO,2BAA4B,SAAQ,KAAK;IACpD,YAAY,OAAO,GAAG,6CAA6C;QACjE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,6BAA6B,CAAC;IAC5C,CAAC;CACF"}
package/dist/gate.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ import type { Container } from '@tyravel/container';
2
+ import type { Constructor } from '@tyravel/container';
3
+ import type { Authenticatable } from './types.js';
4
+ import type { PolicyConstructor } from './types.js';
5
+ export declare class Gate {
6
+ private readonly container;
7
+ private readonly policyMap;
8
+ constructor(container: Container, policies?: Record<string, PolicyConstructor>);
9
+ policy(model: Constructor<unknown>, policy: PolicyConstructor): this;
10
+ allows(user: Authenticatable | null, ability: string, model?: unknown): Promise<boolean>;
11
+ authorize(user: Authenticatable | null, ability: string, model?: unknown): Promise<void>;
12
+ denyUnless(user: Authenticatable | null, ability: string, model?: unknown): Promise<void>;
13
+ private resolvePolicy;
14
+ }
15
+ export declare function createAuthorizeMiddleware(gate: Gate, ability: string, resolveModel?: (request: import('@tyravel/http').TyravelRequest) => Promise<unknown> | unknown): import('@tyravel/http').Middleware;
16
+ //# sourceMappingURL=gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAIpD,qBAAa,IAAI;IAIb,OAAO,CAAC,QAAQ,CAAC,SAAS;IAH5B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwC;gBAG/C,SAAS,EAAE,SAAS,EACrC,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAM;IAOlD,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,iBAAiB,GAAG,IAAI;IAK9D,MAAM,CACV,IAAI,EAAE,eAAe,GAAG,IAAI,EAC5B,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,OAAO,GACd,OAAO,CAAC,OAAO,CAAC;IAmBb,SAAS,CACb,IAAI,EAAE,eAAe,GAAG,IAAI,EAC5B,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC;IAOV,UAAU,CACd,IAAI,EAAE,eAAe,GAAG,IAAI,EAC5B,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC;IAIhB,OAAO,CAAC,aAAa;CAuBtB;AAED,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,eAAe,EAAE,cAAc,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,GAC7F,OAAO,eAAe,EAAE,UAAU,CAOpC"}
package/dist/gate.js ADDED
@@ -0,0 +1,66 @@
1
+ import { AuthorizationException } from './authorization-exceptions.js';
2
+ export class Gate {
3
+ container;
4
+ policyMap = new Map();
5
+ constructor(container, policies = {}) {
6
+ this.container = container;
7
+ for (const [modelName, policy] of Object.entries(policies)) {
8
+ this.policyMap.set(modelName, policy);
9
+ }
10
+ }
11
+ policy(model, policy) {
12
+ this.policyMap.set(model.name, policy);
13
+ return this;
14
+ }
15
+ async allows(user, ability, model) {
16
+ if (!user) {
17
+ return false;
18
+ }
19
+ const policy = this.resolvePolicy(model);
20
+ if (!policy) {
21
+ return false;
22
+ }
23
+ const handler = policy[ability];
24
+ if (typeof handler !== 'function') {
25
+ return false;
26
+ }
27
+ const result = await handler.call(policy, user, model);
28
+ return Boolean(result);
29
+ }
30
+ async authorize(user, ability, model) {
31
+ const allowed = await this.allows(user, ability, model);
32
+ if (!allowed) {
33
+ throw new AuthorizationException();
34
+ }
35
+ }
36
+ async denyUnless(user, ability, model) {
37
+ await this.authorize(user, ability, model);
38
+ }
39
+ resolvePolicy(model) {
40
+ if (!model) {
41
+ return null;
42
+ }
43
+ const modelName = typeof model === 'object' && model !== null && 'constructor' in model
44
+ ? model.constructor.name
45
+ : typeof model === 'function'
46
+ ? model.name
47
+ : undefined;
48
+ if (!modelName) {
49
+ return null;
50
+ }
51
+ const PolicyClass = this.policyMap.get(modelName);
52
+ if (!PolicyClass) {
53
+ return null;
54
+ }
55
+ return this.container.make(PolicyClass);
56
+ }
57
+ }
58
+ export function createAuthorizeMiddleware(gate, ability, resolveModel) {
59
+ return async (request, next) => {
60
+ const user = request.user;
61
+ const model = resolveModel ? await resolveModel(request) : undefined;
62
+ await gate.authorize(user, ability, model);
63
+ return next();
64
+ };
65
+ }
66
+ //# sourceMappingURL=gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.js","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=gate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.test.d.ts","sourceRoot":"","sources":["../src/gate.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,33 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { Container } from '@tyravel/container';
3
+ import { Gate, Policy } from './index.js';
4
+ import { AuthorizationException } from './authorization-exceptions.js';
5
+ class Post {
6
+ id = 1;
7
+ }
8
+ class PostPolicy extends Policy {
9
+ update(user, post) {
10
+ return user.getAuthIdentifier() === post.id;
11
+ }
12
+ }
13
+ const user = {
14
+ getAuthIdentifier: () => 1,
15
+ getAuthPassword: () => 'x',
16
+ };
17
+ describe('Gate', () => {
18
+ it('authorizes when policy allows', async () => {
19
+ const container = new Container();
20
+ container.bind(PostPolicy, () => new PostPolicy());
21
+ const gate = new Gate(container, { Post: PostPolicy });
22
+ await expect(gate.authorize(user, 'update', new Post())).resolves.toBeUndefined();
23
+ });
24
+ it('throws when policy denies', async () => {
25
+ const container = new Container();
26
+ container.bind(PostPolicy, () => new PostPolicy());
27
+ const gate = new Gate(container, { Post: PostPolicy });
28
+ const post = new Post();
29
+ post.id = 2;
30
+ await expect(gate.authorize(user, 'update', post)).rejects.toBeInstanceOf(AuthorizationException);
31
+ });
32
+ });
33
+ //# sourceMappingURL=gate.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.test.js","sourceRoot":"","sources":["../src/gate.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAEvE,MAAM,IAAI;IACR,EAAE,GAAG,CAAC,CAAC;CACR;AAED,MAAM,UAAW,SAAQ,MAAM;IAC7B,MAAM,CAAC,IAAqB,EAAE,IAAU;QACtC,OAAO,IAAI,CAAC,iBAAiB,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;IAC9C,CAAC;CACF;AAED,MAAM,IAAI,GAAoB;IAC5B,iBAAiB,EAAE,GAAG,EAAE,CAAC,CAAC;IAC1B,eAAe,EAAE,GAAG,EAAE,CAAC,GAAG;CAC3B,CAAC;AAEF,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;IACpB,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;QAClC,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI,UAAU,EAAE,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QAEvD,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;IACpF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;QAClC,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI,UAAU,EAAE,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;QAEZ,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CACvE,sBAAsB,CACvB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare class Hasher {
2
+ make(plain: string): string;
3
+ check(plain: string, hashed: string): boolean;
4
+ }
5
+ //# sourceMappingURL=hasher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hasher.d.ts","sourceRoot":"","sources":["../src/hasher.ts"],"names":[],"mappings":"AAKA,qBAAa,MAAM;IACjB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAM3B,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;CA0B9C"}
package/dist/hasher.js ADDED
@@ -0,0 +1,28 @@
1
+ import { randomBytes, scryptSync, timingSafeEqual } from 'node:crypto';
2
+ const SCRYPT_PARAMS = { N: 16384, r: 8, p: 1 };
3
+ const KEY_LENGTH = 64;
4
+ export class Hasher {
5
+ make(plain) {
6
+ const salt = randomBytes(16);
7
+ const hash = scryptSync(plain, salt, KEY_LENGTH, SCRYPT_PARAMS);
8
+ return `scrypt:${salt.toString('base64url')}:${hash.toString('base64url')}`;
9
+ }
10
+ check(plain, hashed) {
11
+ if (!hashed.startsWith('scrypt:')) {
12
+ return false;
13
+ }
14
+ const parts = hashed.split(':');
15
+ const salt = parts[1];
16
+ const digest = parts[2];
17
+ if (!salt || !digest) {
18
+ return false;
19
+ }
20
+ const expected = Buffer.from(digest, 'base64url');
21
+ const actual = scryptSync(plain, Buffer.from(salt, 'base64url'), expected.length, SCRYPT_PARAMS);
22
+ if (expected.length !== actual.length) {
23
+ return false;
24
+ }
25
+ return timingSafeEqual(expected, actual);
26
+ }
27
+ }
28
+ //# sourceMappingURL=hasher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hasher.js","sourceRoot":"","sources":["../src/hasher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEvE,MAAM,aAAa,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAW,CAAC;AACxD,MAAM,UAAU,GAAG,EAAE,CAAC;AAEtB,MAAM,OAAO,MAAM;IACjB,IAAI,CAAC,KAAa;QAChB,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;QAChE,OAAO,UAAU,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;IAC9E,CAAC;IAED,KAAK,CAAC,KAAa,EAAE,MAAc;QACjC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAClC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACrB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,UAAU,CACvB,KAAK,EACL,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,EAC9B,QAAQ,CAAC,MAAM,EACf,aAAa,CACd,CAAC;QAEF,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;YACtC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC3C,CAAC;CACF"}
@@ -0,0 +1,18 @@
1
+ export { AuthManager, createAuthMiddleware, createGuestMiddleware, createStartSessionMiddleware, } from './auth-manager.js';
2
+ export { SessionGuard } from './session-guard.js';
3
+ export { TokenGuard } from './token-guard.js';
4
+ export { Gate, createAuthorizeMiddleware } from './gate.js';
5
+ export { Policy } from './policy.js';
6
+ export { OAuthManager, GithubOAuthDriver, GoogleOAuthDriver } from './oauth.js';
7
+ export type { OAuthUserProfile, OAuthDriver } from './oauth.js';
8
+ export { PasswordResetBroker } from './password-reset-broker.js';
9
+ export { PersonalAccessTokenRepository } from './personal-access-token-repository.js';
10
+ export { AuthenticationException, InvalidCredentialsException } from './exceptions.js';
11
+ export { AuthorizationException, InvalidResetTokenException, } from './authorization-exceptions.js';
12
+ export { Hasher } from './hasher.js';
13
+ export { Session } from './session.js';
14
+ export { DatabaseSessionStore, MemorySessionStore } from './session-store.js';
15
+ export { EloquentUserProvider } from './user-provider.js';
16
+ export type { UserProvider } from './user-provider.js';
17
+ export type { Authenticatable, AuthConfig, EloquentUserProviderConfig, Guard, GuardConfig, SessionGuardConfig, TokenGuardConfig, UserModelConstructor, PasswordBrokerConfig, OAuthProviderConfig, PolicyConstructor, NewAccessToken, } from './types.js';
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,qBAAqB,EACrB,4BAA4B,GAC7B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAChF,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,6BAA6B,EAAE,MAAM,uCAAuC,CAAC;AACtF,OAAO,EAAE,uBAAuB,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AACvF,OAAO,EACL,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,YAAY,EACV,eAAe,EACf,UAAU,EACV,0BAA0B,EAC1B,KAAK,EACL,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,GACf,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ export { AuthManager, createAuthMiddleware, createGuestMiddleware, createStartSessionMiddleware, } from './auth-manager.js';
2
+ export { SessionGuard } from './session-guard.js';
3
+ export { TokenGuard } from './token-guard.js';
4
+ export { Gate, createAuthorizeMiddleware } from './gate.js';
5
+ export { Policy } from './policy.js';
6
+ export { OAuthManager, GithubOAuthDriver, GoogleOAuthDriver } from './oauth.js';
7
+ export { PasswordResetBroker } from './password-reset-broker.js';
8
+ export { PersonalAccessTokenRepository } from './personal-access-token-repository.js';
9
+ export { AuthenticationException, InvalidCredentialsException } from './exceptions.js';
10
+ export { AuthorizationException, InvalidResetTokenException, } from './authorization-exceptions.js';
11
+ export { Hasher } from './hasher.js';
12
+ export { Session } from './session.js';
13
+ export { DatabaseSessionStore, MemorySessionStore } from './session-store.js';
14
+ export { EloquentUserProvider } from './user-provider.js';
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,qBAAqB,EACrB,4BAA4B,GAC7B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEhF,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,6BAA6B,EAAE,MAAM,uCAAuC,CAAC;AACtF,OAAO,EAAE,uBAAuB,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AACvF,OAAO,EACL,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,40 @@
1
+ import type { DatabaseConnection } from '@tyravel/database';
2
+ import type { OAuthProviderConfig } from './types.js';
3
+ import type { Authenticatable, UserModelConstructor } from './types.js';
4
+ export interface OAuthUserProfile {
5
+ id: string;
6
+ email: string | null;
7
+ name: string | null;
8
+ avatar: string | null;
9
+ }
10
+ export interface OAuthDriver {
11
+ readonly name: string;
12
+ authorizationUrl(state: string): string;
13
+ exchangeCode(code: string): Promise<OAuthUserProfile>;
14
+ }
15
+ export declare class GithubOAuthDriver implements OAuthDriver {
16
+ private readonly config;
17
+ readonly name = "github";
18
+ constructor(config: OAuthProviderConfig);
19
+ authorizationUrl(state: string): string;
20
+ exchangeCode(code: string): Promise<OAuthUserProfile>;
21
+ }
22
+ export declare class GoogleOAuthDriver implements OAuthDriver {
23
+ private readonly config;
24
+ readonly name = "google";
25
+ constructor(config: OAuthProviderConfig);
26
+ authorizationUrl(state: string): string;
27
+ exchangeCode(code: string): Promise<OAuthUserProfile>;
28
+ }
29
+ export declare class OAuthManager {
30
+ private readonly connection;
31
+ private readonly accountsTable;
32
+ private readonly userModel;
33
+ private readonly drivers;
34
+ constructor(providers: Record<string, OAuthProviderConfig>, connection: DatabaseConnection, accountsTable: string, userModel: UserModelConstructor);
35
+ createState(): string;
36
+ redirectUrl(provider: string, state: string): string;
37
+ handleCallback(provider: string, code: string): Promise<OAuthUserProfile>;
38
+ findOrCreateUser(provider: string, profile: OAuthUserProfile): Promise<Authenticatable>;
39
+ }
40
+ //# sourceMappingURL=oauth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAExE,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAUD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACxC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;CACvD;AAED,qBAAa,iBAAkB,YAAW,WAAW;IAGvC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,QAAQ,CAAC,IAAI,YAAY;gBAEI,MAAM,EAAE,mBAAmB;IAExD,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAUjC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;CA2C5D;AAED,qBAAa,iBAAkB,YAAW,WAAW;IAGvC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,QAAQ,CAAC,IAAI,YAAY;gBAEI,MAAM,EAAE,mBAAmB;IAExD,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAYjC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAoC5D;AAED,qBAAa,YAAY;IAKrB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAN5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;gBAGxD,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,EAC7B,UAAU,EAAE,kBAAkB,EAC9B,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,oBAAoB;IAWlD,WAAW,IAAI,MAAM;IAIrB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAS9C,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IASzE,gBAAgB,CACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,eAAe,CAAC;CAuD5B"}