@passflow/core 0.0.1 → 0.2.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 (87) hide show
  1. package/dist/index.js +1 -1
  2. package/dist/index.js.map +1 -1
  3. package/dist/index.mjs +3174 -574
  4. package/dist/index.mjs.map +1 -1
  5. package/dist/lib/api/app.d.ts +4 -1
  6. package/dist/lib/api/app.d.ts.map +1 -1
  7. package/dist/lib/api/auth.d.ts +6 -4
  8. package/dist/lib/api/auth.d.ts.map +1 -1
  9. package/dist/lib/api/axios-client.d.ts +26 -4
  10. package/dist/lib/api/axios-client.d.ts.map +1 -1
  11. package/dist/lib/api/index.d.ts +4 -3
  12. package/dist/lib/api/index.d.ts.map +1 -1
  13. package/dist/lib/api/invitation.d.ts +4 -1
  14. package/dist/lib/api/invitation.d.ts.map +1 -1
  15. package/dist/lib/api/model.d.ts +180 -11
  16. package/dist/lib/api/model.d.ts.map +1 -1
  17. package/dist/lib/api/setting.d.ts +4 -1
  18. package/dist/lib/api/setting.d.ts.map +1 -1
  19. package/dist/lib/api/tenant.d.ts +4 -1
  20. package/dist/lib/api/tenant.d.ts.map +1 -1
  21. package/dist/lib/api/two-factor.d.ts +75 -0
  22. package/dist/lib/api/two-factor.d.ts.map +1 -0
  23. package/dist/lib/api/user.d.ts +4 -1
  24. package/dist/lib/api/user.d.ts.map +1 -1
  25. package/dist/lib/constants/index.d.ts +25 -0
  26. package/dist/lib/constants/index.d.ts.map +1 -1
  27. package/dist/lib/device/index.d.ts +17 -0
  28. package/dist/lib/device/index.d.ts.map +1 -0
  29. package/dist/lib/index.d.ts +10 -3
  30. package/dist/lib/index.d.ts.map +1 -1
  31. package/dist/lib/m2m/client.d.ts +196 -0
  32. package/dist/lib/m2m/client.d.ts.map +1 -0
  33. package/dist/lib/m2m/errors.d.ts +107 -0
  34. package/dist/lib/m2m/errors.d.ts.map +1 -0
  35. package/dist/lib/m2m/index.d.ts +27 -0
  36. package/dist/lib/m2m/index.d.ts.map +1 -0
  37. package/dist/lib/m2m/types.d.ts +217 -0
  38. package/dist/lib/m2m/types.d.ts.map +1 -0
  39. package/dist/lib/passflow.d.ts +972 -11
  40. package/dist/lib/passflow.d.ts.map +1 -1
  41. package/dist/lib/services/auth-service.d.ts +29 -4
  42. package/dist/lib/services/auth-service.d.ts.map +1 -1
  43. package/dist/lib/services/index.d.ts +2 -1
  44. package/dist/lib/services/index.d.ts.map +1 -1
  45. package/dist/lib/services/invitation-service.d.ts +2 -2
  46. package/dist/lib/services/tenant-service.d.ts +2 -2
  47. package/dist/lib/services/token-cache-service.d.ts +14 -6
  48. package/dist/lib/services/token-cache-service.d.ts.map +1 -1
  49. package/dist/lib/services/two-factor-service.d.ts +120 -0
  50. package/dist/lib/services/two-factor-service.d.ts.map +1 -0
  51. package/dist/lib/services/user-service.d.ts +1 -1
  52. package/dist/lib/services/user-service.d.ts.map +1 -1
  53. package/dist/lib/storage/index.d.ts +96 -0
  54. package/dist/lib/storage/index.d.ts.map +1 -0
  55. package/dist/lib/store.d.ts +67 -1
  56. package/dist/lib/store.d.ts.map +1 -1
  57. package/dist/lib/token/delivery-manager.d.ts +121 -0
  58. package/dist/lib/token/delivery-manager.d.ts.map +1 -0
  59. package/dist/lib/{token-service → token}/index.d.ts +1 -1
  60. package/dist/lib/token/index.d.ts.map +1 -0
  61. package/dist/lib/token/membership.d.ts.map +1 -0
  62. package/dist/lib/{token-service → token}/service.d.ts +15 -3
  63. package/dist/lib/token/service.d.ts.map +1 -0
  64. package/dist/lib/token/token.d.ts +55 -0
  65. package/dist/lib/token/token.d.ts.map +1 -0
  66. package/dist/lib/types/index.d.ts +5 -3
  67. package/dist/lib/types/index.d.ts.map +1 -1
  68. package/dist/lib/utils/validation.d.ts +54 -0
  69. package/dist/lib/utils/validation.d.ts.map +1 -0
  70. package/dist/tests/storage/fake-storage.d.ts.map +1 -0
  71. package/dist/tests/storage/storage-manager.test.d.ts.map +1 -0
  72. package/dist/tsconfig.tsbuildinfo +1 -1
  73. package/package.json +14 -15
  74. package/dist/lib/device-service/index.d.ts +0 -7
  75. package/dist/lib/device-service/index.d.ts.map +0 -1
  76. package/dist/lib/storage-manager/index.d.ts +0 -37
  77. package/dist/lib/storage-manager/index.d.ts.map +0 -1
  78. package/dist/lib/token-service/index.d.ts.map +0 -1
  79. package/dist/lib/token-service/membership.d.ts.map +0 -1
  80. package/dist/lib/token-service/service.d.ts.map +0 -1
  81. package/dist/lib/token-service/token.d.ts +0 -34
  82. package/dist/lib/token-service/token.d.ts.map +0 -1
  83. package/dist/tests/storage-manager/fake-storage.d.ts.map +0 -1
  84. package/dist/tests/storage-manager/storage-manager.test.d.ts.map +0 -1
  85. /package/dist/lib/{token-service → token}/membership.d.ts +0 -0
  86. /package/dist/tests/{storage-manager → storage}/fake-storage.d.ts +0 -0
  87. /package/dist/tests/{storage-manager → storage}/storage-manager.test.d.ts +0 -0
@@ -0,0 +1,75 @@
1
+ import { DeviceService } from '../device';
2
+ import { StorageManager } from '../storage';
3
+ import { AxiosClient } from './axios-client';
4
+ import { PassflowConfig, TwoFactorConfirmRequest, TwoFactorConfirmResponse, TwoFactorDisableRequest, TwoFactorDisableResponse, TwoFactorRecoveryRequest, TwoFactorRecoveryResponse, TwoFactorRegenerateRequest, TwoFactorRegenerateResponse, TwoFactorSetupMagicLinkValidationResponse, TwoFactorSetupResponse, TwoFactorStatusResponse, TwoFactorVerifyRequest, TwoFactorVerifyResponse } from './model';
5
+ /**
6
+ * API client for Two-Factor Authentication operations
7
+ */
8
+ export declare class TwoFactorApiClient {
9
+ protected axiosClient: AxiosClient;
10
+ constructor(config: PassflowConfig, storageManager?: StorageManager, deviceService?: DeviceService);
11
+ setAppId(appId: string): void;
12
+ /**
13
+ * Get current 2FA enrollment status
14
+ * GET /user/2fa/status
15
+ */
16
+ getStatus(): Promise<TwoFactorStatusResponse>;
17
+ /**
18
+ * Begin 2FA setup process
19
+ * POST /user/2fa/setup/begin
20
+ * Returns secret and QR code for authenticator app
21
+ */
22
+ beginSetup(): Promise<TwoFactorSetupResponse>;
23
+ /**
24
+ * Confirm 2FA setup with TOTP code
25
+ * POST /user/2fa/setup/confirm
26
+ * Returns recovery codes on success
27
+ */
28
+ confirmSetup(payload: TwoFactorConfirmRequest): Promise<TwoFactorConfirmResponse>;
29
+ /**
30
+ * Verify TOTP code during login
31
+ * POST /auth/2fa/verify
32
+ * Uses tfa_token as Bearer token for authentication
33
+ */
34
+ verify(payload: TwoFactorVerifyRequest): Promise<TwoFactorVerifyResponse>;
35
+ /**
36
+ * Use recovery code for authentication
37
+ * POST /auth/2fa/recovery
38
+ * Uses tfa_token as Bearer token for authentication
39
+ */
40
+ useRecoveryCode(payload: TwoFactorRecoveryRequest): Promise<TwoFactorRecoveryResponse>;
41
+ /**
42
+ * Disable 2FA (requires TOTP verification)
43
+ * DELETE /user/2fa
44
+ */
45
+ disable(payload: TwoFactorDisableRequest): Promise<TwoFactorDisableResponse>;
46
+ /**
47
+ * Regenerate recovery codes
48
+ * POST /user/2fa/recovery-codes/regenerate
49
+ */
50
+ regenerateRecoveryCodes(payload: TwoFactorRegenerateRequest): Promise<TwoFactorRegenerateResponse>;
51
+ /**
52
+ * Validate magic link token for 2FA setup
53
+ * GET /auth/2fa-setup/:token
54
+ *
55
+ * This endpoint validates an admin-generated magic link token
56
+ * and returns a scoped session (scope: "2fa_setup") that can ONLY
57
+ * be used for completing 2FA setup operations.
58
+ *
59
+ * This method never throws - it always returns a TwoFactorSetupMagicLinkValidationResponse
60
+ * with either success=true and session data, or success=false and error details.
61
+ *
62
+ * @param token - Magic link token from URL parameter
63
+ * @returns Validation response with scoped session token or error
64
+ */
65
+ validateTwoFactorSetupMagicLink(token: string): Promise<TwoFactorSetupMagicLinkValidationResponse>;
66
+ /**
67
+ * Map HTTP status code to magic link error code
68
+ */
69
+ private mapStatusToErrorCode;
70
+ /**
71
+ * Get default error message for HTTP status code
72
+ */
73
+ private getDefaultErrorMessage;
74
+ }
75
+ //# sourceMappingURL=two-factor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"two-factor.d.ts","sourceRoot":"","sources":["../../../lib/api/two-factor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EACL,cAAc,EAEd,uBAAuB,EACvB,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,EACxB,wBAAwB,EACxB,yBAAyB,EACzB,0BAA0B,EAC1B,2BAA2B,EAE3B,yCAAyC,EACzC,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACxB,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC;gBAEvB,MAAM,EAAE,cAAc,EAAE,cAAc,CAAC,EAAE,cAAc,EAAE,aAAa,CAAC,EAAE,aAAa;IAIlG,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI7B;;;OAGG;IACH,SAAS,IAAI,OAAO,CAAC,uBAAuB,CAAC;IAI7C;;;;OAIG;IACH,UAAU,IAAI,OAAO,CAAC,sBAAsB,CAAC;IAI7C;;;;OAIG;IACH,YAAY,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAOjF;;;;OAIG;IACH,MAAM,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAazE;;;;OAIG;IACH,eAAe,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAatF;;;OAGG;IACH,OAAO,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAI5E;;;OAGG;IACH,uBAAuB,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAOlG;;;;;;;;;;;;;OAaG;IACH,+BAA+B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,yCAAyC,CAAC;IA4DlG;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAe5B;;OAEG;IACH,OAAO,CAAC,sBAAsB;CAc/B"}
@@ -1,9 +1,12 @@
1
1
  import { RegistrationResponseJSON } from '@simplewebauthn/types';
2
+ import { DeviceService } from '../device';
3
+ import { StorageManager } from '../storage';
2
4
  import { AxiosClient } from './axios-client';
3
5
  import { OS, PassflowConfig, PassflowPasskeyStart, PassflowSuccessResponse, PassflowUserPasskey } from './model';
4
6
  export declare class UserAPI {
5
7
  protected axiosClient: AxiosClient;
6
- constructor(config: PassflowConfig);
8
+ constructor(config: PassflowConfig, storageManager?: StorageManager, deviceService?: DeviceService);
9
+ setAppId(appId: string): void;
7
10
  getUserPasskeys(): Promise<PassflowUserPasskey[]>;
8
11
  renameUserPasskey(name: string, passkeyId: string): Promise<PassflowSuccessResponse>;
9
12
  deleteUserPasskey(passkeyId: string): Promise<PassflowSuccessResponse>;
@@ -1 +1 @@
1
- {"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../../lib/api/user.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EACL,EAAE,EACF,cAAc,EAGd,oBAAoB,EACpB,uBAAuB,EACvB,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAEjB,qBAAa,OAAO;IAClB,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC;gBAEvB,MAAM,EAAE,cAAc;IAIlC,eAAe;IAIf,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC;IASpF,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAItE,mBAAmB,CAAC,EAClB,cAAc,EACd,QAAQ,EACR,EAAE,EACF,kBAAkB,EAClB,eAAe,GAChB,EAAE;QACD,cAAc,EAAE,MAAM,CAAC;QACvB,QAAQ,EAAE,MAAM,CAAC;QACjB,EAAE,EAAE,EAAE,CAAC;QACP,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAYjC,sBAAsB,CAAC,WAAW,EAAE,wBAAwB,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAOpH"}
1
+ {"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../../lib/api/user.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EACL,EAAE,EACF,cAAc,EAGd,oBAAoB,EACpB,uBAAuB,EACvB,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAEjB,qBAAa,OAAO;IAClB,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC;gBAEvB,MAAM,EAAE,cAAc,EAAE,cAAc,CAAC,EAAE,cAAc,EAAE,aAAa,CAAC,EAAE,aAAa;IAIlG,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI7B,eAAe;IAIf,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC;IASpF,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAItE,mBAAmB,CAAC,EAClB,cAAc,EACd,QAAQ,EACR,EAAE,EACF,kBAAkB,EAClB,eAAe,GAChB,EAAE;QACD,cAAc,EAAE,MAAM,CAAC;QACvB,QAAQ,EAAE,MAAM,CAAC;QACjB,EAAE,EAAE,EAAE,CAAC;QACP,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAYjC,sBAAsB,CAAC,WAAW,EAAE,wBAAwB,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAOpH"}
@@ -2,7 +2,32 @@ export declare const APP_ID_HEADER_KEY = "X-Passflow-Clientid";
2
2
  export declare const AUTHORIZATION_HEADER_KEY = "Authorization";
3
3
  export declare const DEVICE_ID_HEADER_KEY = "X-Passflow-DeviceId";
4
4
  export declare const DEVICE_TYPE_HEADER_KEY = "X-Passflow-DeviceType";
5
+ /**
6
+ * SDK version from package.json.
7
+ * Useful for debugging and logging version information.
8
+ */
9
+ export declare const SDK_VERSION: string;
10
+ /**
11
+ * Minimal set of scopes for basic authentication.
12
+ * Includes only essential scopes: user ID, token refresh, and OpenID Connect.
13
+ * Use this for applications that need minimal permissions.
14
+ */
15
+ export declare const MINIMAL_DEFAULT_SCOPES: string[];
16
+ /**
17
+ * Default scopes used by the SDK.
18
+ * Includes comprehensive permissions: user ID, token refresh, tenant access, email, OIDC, and full tenant access.
19
+ * Note: 'access:tenant:all' is a very permissive scope and may not be appropriate for all applications.
20
+ * Consider using MINIMAL_DEFAULT_SCOPES or custom scopes for production applications.
21
+ */
5
22
  export declare const DEFAULT_SCOPES: string[];
6
23
  export declare const PASSFLOW_CLOUD_URL = "https://auth.passflow.cloud";
7
24
  export declare const DEFAULT_GROUP_NAME = "default";
25
+ export declare const POPUP_WIDTH = 500;
26
+ export declare const POPUP_HEIGHT = 600;
27
+ export declare const POPUP_POLL_INTERVAL_MS = 100;
28
+ export declare const POPUP_TIMEOUT_MS = 60000;
29
+ export declare const TOKEN_EXPIRY_BUFFER_SECONDS = 30;
30
+ export declare const USERNAME_MIN_LENGTH = 3;
31
+ export declare const USERNAME_MAX_LENGTH = 30;
32
+ export declare const ERROR_MESSAGE_MAX_LENGTH = 200;
8
33
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/constants/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AACvD,eAAO,MAAM,wBAAwB,kBAAkB,CAAC;AACxD,eAAO,MAAM,oBAAoB,wBAAwB,CAAC;AAC1D,eAAO,MAAM,sBAAsB,0BAA0B,CAAC;AAC9D,eAAO,MAAM,cAAc,UAA8E,CAAC;AAC1G,eAAO,MAAM,kBAAkB,gCAAgC,CAAC;AAChE,eAAO,MAAM,kBAAkB,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/constants/index.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AACvD,eAAO,MAAM,wBAAwB,kBAAkB,CAAC;AACxD,eAAO,MAAM,oBAAoB,wBAAwB,CAAC;AAC1D,eAAO,MAAM,sBAAsB,0BAA0B,CAAC;AAE9D;;;GAGG;AACH,eAAO,MAAM,WAAW,EAA0B,MAAM,CAAC;AAEzD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,UAA8B,CAAC;AAElE;;;;;GAKG;AACH,eAAO,MAAM,cAAc,UAA8E,CAAC;AAE1G,eAAO,MAAM,kBAAkB,gCAAgC,CAAC;AAChE,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAG5C,eAAO,MAAM,WAAW,MAAM,CAAC;AAC/B,eAAO,MAAM,YAAY,MAAM,CAAC;AAChC,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AAGtC,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAG9C,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AACtC,eAAO,MAAM,wBAAwB,MAAM,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Device Service
3
+ *
4
+ * Manages device identification for security and tracking purposes.
5
+ * Generates and persists unique device IDs using UUID v4.
6
+ * Used for device-based authentication and session management.
7
+ *
8
+ * @module device
9
+ */
10
+ import { StorageManager } from '../storage';
11
+ export declare class DeviceService {
12
+ private storageManager;
13
+ constructor(storageManager?: StorageManager);
14
+ getDeviceId(): string;
15
+ generateUniqueDeviceId(): string;
16
+ }
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/device/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,qBAAa,aAAa;IACxB,OAAO,CAAC,cAAc,CAAiB;gBAE3B,cAAc,CAAC,EAAE,cAAc;IAI3C,WAAW,IAAI,MAAM;IAUrB,sBAAsB,IAAI,MAAM;CAGjC"}
@@ -1,8 +1,15 @@
1
1
  export * from './api';
2
2
  export * from './constants';
3
- export * from './types';
4
- export { PassflowEvent, type PassflowSubscriber, type ErrorPayload, type PassflowEventPayload } from './store';
5
- export { isTokenExpired, parseToken, TokenType, type InvitationToken, type Token, type UserMembership, type TenantMembership, type GroupMembership, type Tenant, type Group, type RawUserMembership, } from './token-service';
6
3
  export { Passflow } from './passflow';
7
4
  export * from './services';
5
+ export { type ErrorPayload, PassflowEvent, type PassflowEventPayload, type PassflowSubscriber } from './store';
6
+ export { type Group, type GroupMembership, type InvitationToken, isTokenExpired, parseToken, type RawUserMembership, type Tenant, type TenantMembership, type Token, TokenType, type UserMembership, } from './token';
7
+ export * from './types';
8
+ export { isValidEmail, isValidJWTFormat, isValidPhoneNumber, isValidUsername, sanitizeErrorMessage } from './utils/validation';
9
+ export type { TwoFactorConfirmRequest, TwoFactorConfirmResponse, TwoFactorDisableRequest, TwoFactorDisableResponse, TwoFactorErrorCode, TwoFactorPolicy, TwoFactorRecoveryRequest, TwoFactorRecoveryResponse, TwoFactorRegenerateRequest, TwoFactorRegenerateResponse, TwoFactorSetupMagicLinkError, TwoFactorSetupMagicLinkErrorCode, TwoFactorSetupMagicLinkSession, TwoFactorSetupMagicLinkValidationResponse, TwoFactorSetupResponse, TwoFactorStatusResponse, TwoFactorVerifyRequest, TwoFactorVerifyResponse, } from './api/model';
10
+ export { TwoFactorApiClient } from './api/two-factor';
11
+ export { TwoFactorService } from './services/two-factor-service';
12
+ export { M2MClient, M2MError, M2MNetworkError, M2MTokenParseError, M2MConfigError, M2MErrorCodes, M2M_DEFAULTS } from './m2m';
13
+ export type { M2MClientConfig, M2MTokenRequestOptions, M2MTokenRequestInfo, M2MTokenResponse, M2MErrorResponse, M2MTokenClaims, M2MErrorCode, M2MTokenCache, RetryStrategy, M2MRateLimitInfo, } from './m2m';
14
+ export { TokenDeliveryMode, SessionState } from './types';
8
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":"AACA,cAAc,OAAO,CAAC;AAGtB,cAAc,aAAa,CAAC;AAG5B,cAAc,SAAS,CAAC;AAGxB,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,KAAK,YAAY,EAAE,KAAK,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAG/G,OAAO,EACL,cAAc,EACd,UAAU,EACV,SAAS,EACT,KAAK,eAAe,EACpB,KAAK,KAAK,EACV,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,MAAM,EACX,KAAK,KAAK,EACV,KAAK,iBAAiB,GACvB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":"AACA,cAAc,OAAO,CAAC;AAGtB,cAAc,aAAa,CAAC;AAE5B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,cAAc,YAAY,CAAC;AAE3B,OAAO,EAAE,KAAK,YAAY,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,KAAK,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAE/G,OAAO,EACL,KAAK,KAAK,EACV,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,cAAc,EACd,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,MAAM,EACX,KAAK,gBAAgB,EACrB,KAAK,KAAK,EACV,SAAS,EACT,KAAK,cAAc,GACpB,MAAM,SAAS,CAAC;AAEjB,cAAc,SAAS,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAG/H,YAAY,EACV,uBAAuB,EACvB,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,EACxB,kBAAkB,EAClB,eAAe,EACf,wBAAwB,EACxB,yBAAyB,EACzB,0BAA0B,EAC1B,2BAA2B,EAC3B,4BAA4B,EAC5B,gCAAgC,EAChC,8BAA8B,EAC9B,yCAAyC,EACzC,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,kBAAkB,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC9H,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,aAAa,EACb,aAAa,EACb,gBAAgB,GACjB,MAAM,OAAO,CAAC;AAGf,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,196 @@
1
+ /**
2
+ * M2M (Machine-to-Machine) Authentication Client
3
+ *
4
+ * OAuth 2.0 Client Credentials Grant implementation for server-to-server
5
+ * authentication without user involvement.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const m2m = new M2MClient({
10
+ * url: 'https://auth.yourapp.com',
11
+ * clientId: 'your-client-id',
12
+ * clientSecret: 'your-client-secret',
13
+ * scopes: ['users:read', 'orders:write'],
14
+ * });
15
+ *
16
+ * const token = await m2m.getToken();
17
+ * ```
18
+ */
19
+ import type { M2MClientConfig, M2MTokenClaims, M2MTokenRequestOptions, M2MTokenResponse } from './types';
20
+ /**
21
+ * M2M Authentication Client
22
+ *
23
+ * Implements OAuth 2.0 Client Credentials Grant for machine-to-machine
24
+ * authentication. Provides automatic token caching, refresh, and retry logic.
25
+ */
26
+ export declare class M2MClient {
27
+ private readonly config;
28
+ private readonly cache;
29
+ private readonly retryStrategy;
30
+ private readonly tokenEndpoint;
31
+ /**
32
+ * Create a new M2M client
33
+ *
34
+ * @param config - Client configuration
35
+ * @throws {M2MConfigError} If required configuration is missing
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * const m2m = new M2MClient({
40
+ * url: 'https://auth.yourapp.com',
41
+ * clientId: 'your-client-id',
42
+ * clientSecret: 'your-client-secret',
43
+ * });
44
+ * ```
45
+ */
46
+ constructor(config: M2MClientConfig);
47
+ /**
48
+ * Get the cache key for this client
49
+ */
50
+ private getCacheKey;
51
+ /**
52
+ * Request an access token from the authorization server
53
+ *
54
+ * @param options - Optional request overrides
55
+ * @returns Token response
56
+ * @throws {M2MError} On authentication failure
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * // Basic usage
61
+ * const token = await m2m.getToken();
62
+ *
63
+ * // With options
64
+ * const token = await m2m.getToken({
65
+ * scopes: ['users:read'],
66
+ * forceRefresh: true,
67
+ * });
68
+ * ```
69
+ */
70
+ getToken(options?: M2MTokenRequestOptions): Promise<M2MTokenResponse>;
71
+ /**
72
+ * Get a valid token, automatically refreshing if needed
73
+ *
74
+ * When autoRefresh is enabled, this will proactively refresh tokens
75
+ * that are about to expire (within refreshThreshold seconds).
76
+ *
77
+ * @returns Valid token response
78
+ * @throws {M2MError} On authentication failure
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * // Always returns a valid, non-expired token
83
+ * const token = await m2m.getValidToken();
84
+ * ```
85
+ */
86
+ getValidToken(): Promise<M2MTokenResponse>;
87
+ /**
88
+ * Request a new token from the authorization server
89
+ */
90
+ private requestToken;
91
+ /**
92
+ * Execute the actual HTTP request to the token endpoint
93
+ */
94
+ private doTokenRequest;
95
+ /**
96
+ * Execute a request with retry logic
97
+ */
98
+ private executeWithRetry;
99
+ /**
100
+ * Sleep for a given duration
101
+ */
102
+ private sleep;
103
+ /**
104
+ * Get the currently cached token without making a request
105
+ *
106
+ * @returns Cached token or null if not cached
107
+ *
108
+ * @example
109
+ * ```typescript
110
+ * const token = m2m.getCachedToken();
111
+ * if (token && !m2m.isTokenExpired(token)) {
112
+ * console.log('Using cached token');
113
+ * }
114
+ * ```
115
+ */
116
+ getCachedToken(): M2MTokenResponse | null;
117
+ /**
118
+ * Check if a token is expired or about to expire
119
+ *
120
+ * @param token - Token to check (uses issued_at + expires_in if available)
121
+ * @param threshold - Seconds before actual expiry to consider expired (default: 0)
122
+ * @returns true if expired or about to expire
123
+ *
124
+ * @example
125
+ * ```typescript
126
+ * if (m2m.isTokenExpired(token)) {
127
+ * console.log('Token is expired');
128
+ * }
129
+ *
130
+ * // Check if expiring within 5 minutes
131
+ * if (m2m.isTokenExpired(token, 300)) {
132
+ * console.log('Token expires soon');
133
+ * }
134
+ * ```
135
+ */
136
+ isTokenExpired(token?: M2MTokenResponse | null, threshold?: number): boolean;
137
+ /**
138
+ * Parse token claims from a JWT access token
139
+ *
140
+ * @param token - JWT access token string
141
+ * @returns Decoded token claims
142
+ * @throws {M2MTokenParseError} If token format is invalid
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * const token = await m2m.getToken();
147
+ * const claims = m2m.parseToken(token.access_token);
148
+ * console.log('Client ID:', claims.client_id);
149
+ * console.log('Scopes:', claims.scopes);
150
+ * ```
151
+ */
152
+ parseToken(token: string): M2MTokenClaims;
153
+ /**
154
+ * Clear the token cache, forcing a new request on next getToken()
155
+ *
156
+ * @example
157
+ * ```typescript
158
+ * m2m.clearCache();
159
+ * // Next getToken() will request a new token
160
+ * const token = await m2m.getToken();
161
+ * ```
162
+ */
163
+ clearCache(): void;
164
+ /**
165
+ * Revoke the current token
166
+ *
167
+ * Note: Requires the server to support token revocation (RFC 7009).
168
+ * Not all Passflow deployments may support this endpoint.
169
+ *
170
+ * @throws {M2MError} If revocation fails
171
+ *
172
+ * @example
173
+ * ```typescript
174
+ * await m2m.revokeToken();
175
+ * console.log('Token revoked');
176
+ * ```
177
+ */
178
+ revokeToken(): Promise<void>;
179
+ /**
180
+ * Get the configured URL
181
+ */
182
+ get url(): string;
183
+ /**
184
+ * Get the configured client ID
185
+ */
186
+ get clientId(): string;
187
+ /**
188
+ * Get the configured scopes
189
+ */
190
+ get scopes(): string[] | undefined;
191
+ /**
192
+ * Get the configured audience
193
+ */
194
+ get audience(): string[] | undefined;
195
+ }
196
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../lib/m2m/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EACV,eAAe,EAGf,cAAc,EACd,sBAAsB,EAEtB,gBAAgB,EAEjB,MAAM,SAAS,CAAC;AAwDjB;;;;;GAKG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAMnB;IAEJ,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IAEvC;;;;;;;;;;;;;;OAcG;gBACS,MAAM,EAAE,eAAe;IAsCnC;;OAEG;IACH,OAAO,CAAC,WAAW;IAMnB;;;;;;;;;;;;;;;;;;OAkBG;IACG,QAAQ,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAiB3E;;;;;;;;;;;;;;OAcG;IACG,aAAa,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAwBhD;;OAEG;YACW,YAAY;IA6C1B;;OAEG;YACW,cAAc;IAqF5B;;OAEG;YACW,gBAAgB;IA8B9B;;OAEG;IACH,OAAO,CAAC,KAAK;IAIb;;;;;;;;;;;;OAYG;IACH,cAAc,IAAI,gBAAgB,GAAG,IAAI;IAczC;;;;;;;;;;;;;;;;;;OAkBG;IACH,cAAc,CAAC,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,EAAE,SAAS,SAAI,GAAG,OAAO;IAUvE;;;;;;;;;;;;;;OAcG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc;IAgCzC;;;;;;;;;OASG;IACH,UAAU,IAAI,IAAI;IAKlB;;;;;;;;;;;;;OAaG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IA4ClC;;OAEG;IACH,IAAI,GAAG,IAAI,MAAM,CAEhB;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,EAAE,GAAG,SAAS,CAEjC;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,MAAM,EAAE,GAAG,SAAS,CAEnC;CACF"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * M2M Authentication Error Classes
3
+ *
4
+ * Custom error classes for M2M authentication failures with
5
+ * OAuth 2.0 compliant error codes and detailed information.
6
+ */
7
+ import type { M2MErrorCode, M2MRateLimitInfo } from './types';
8
+ /**
9
+ * M2M Authentication Error
10
+ *
11
+ * Thrown when M2M authentication fails. Contains OAuth 2.0 compliant
12
+ * error codes and additional debugging information.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * try {
17
+ * const token = await m2m.getToken();
18
+ * } catch (error) {
19
+ * if (error instanceof M2MError) {
20
+ * console.error(`Error: ${error.code} - ${error.message}`);
21
+ * if (error.code === 'rate_limit_exceeded') {
22
+ * console.log(`Retry after: ${error.rateLimitInfo?.reset}`);
23
+ * }
24
+ * }
25
+ * }
26
+ * ```
27
+ */
28
+ export declare class M2MError extends Error {
29
+ /** OAuth 2.0 error code */
30
+ readonly code: M2MErrorCode;
31
+ /** HTTP status code from the response */
32
+ readonly status: number;
33
+ /** URI with more information about the error (if provided) */
34
+ readonly errorUri?: string;
35
+ /** Rate limit information (if rate limited) */
36
+ readonly rateLimitInfo?: M2MRateLimitInfo;
37
+ /** Response headers from the server */
38
+ readonly headers?: Record<string, string>;
39
+ /** Original error (if this wraps another error) */
40
+ readonly cause?: Error;
41
+ /** Timestamp when the error occurred */
42
+ readonly timestamp: string;
43
+ constructor(options: {
44
+ code: M2MErrorCode;
45
+ message: string;
46
+ status?: number;
47
+ errorUri?: string;
48
+ rateLimitInfo?: M2MRateLimitInfo;
49
+ headers?: Record<string, string>;
50
+ cause?: Error;
51
+ });
52
+ /**
53
+ * Create an M2MError from an OAuth 2.0 error response
54
+ */
55
+ static fromOAuthError(errorResponse: {
56
+ error: M2MErrorCode;
57
+ error_description?: string;
58
+ error_uri?: string;
59
+ }, status: number, headers?: Record<string, string>): M2MError;
60
+ /**
61
+ * Create an M2MError from a network or other error
62
+ */
63
+ static fromError(error: Error, code?: M2MErrorCode): M2MError;
64
+ /**
65
+ * Parse rate limit headers from response
66
+ */
67
+ static parseRateLimitHeaders(headers: Record<string, string>): M2MRateLimitInfo | undefined;
68
+ /**
69
+ * Get default error message for an error code
70
+ */
71
+ static getDefaultMessage(code: M2MErrorCode): string;
72
+ /**
73
+ * Check if the error is retryable
74
+ */
75
+ isRetryable(): boolean;
76
+ /**
77
+ * Get suggested wait time before retry (in milliseconds)
78
+ */
79
+ getRetryAfter(): number;
80
+ /**
81
+ * Convert to JSON-serializable object
82
+ */
83
+ toJSON(): Record<string, unknown>;
84
+ /**
85
+ * Create a human-readable string representation
86
+ */
87
+ toString(): string;
88
+ }
89
+ /**
90
+ * Network error (connection failed, timeout, etc.)
91
+ */
92
+ export declare class M2MNetworkError extends M2MError {
93
+ constructor(message: string, cause?: Error);
94
+ }
95
+ /**
96
+ * Token parsing error (invalid JWT format)
97
+ */
98
+ export declare class M2MTokenParseError extends M2MError {
99
+ constructor(message: string, cause?: Error);
100
+ }
101
+ /**
102
+ * Configuration error (missing or invalid config)
103
+ */
104
+ export declare class M2MConfigError extends M2MError {
105
+ constructor(message: string);
106
+ }
107
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../lib/m2m/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,QAAS,SAAQ,KAAK;IACjC,2BAA2B;IAC3B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAE5B,yCAAyC;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE3B,+CAA+C;IAC/C,QAAQ,CAAC,aAAa,CAAC,EAAE,gBAAgB,CAAC;IAE1C,uCAAuC;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE1C,mDAAmD;IACnD,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IAEvB,wCAAwC;IACxC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,OAAO,EAAE;QACnB,IAAI,EAAE,YAAY,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,aAAa,CAAC,EAAE,gBAAgB,CAAC;QACjC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,KAAK,CAAC,EAAE,KAAK,CAAC;KACf;IAiBD;;OAEG;IACH,MAAM,CAAC,cAAc,CACnB,aAAa,EAAE;QACb,KAAK,EAAE,YAAY,CAAC;QACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,EACD,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,QAAQ;IAaX;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,GAAE,YAA6B,GAAG,QAAQ;IAS7E;;OAEG;IACH,MAAM,CAAC,qBAAqB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,gBAAgB,GAAG,SAAS;IAgB3F;;OAEG;IACH,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM;IAgBpD;;OAEG;IACH,WAAW,IAAI,OAAO;IAStB;;OAEG;IACH,aAAa,IAAI,MAAM;IAWvB;;OAEG;IACH,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAYjC;;OAEG;IACH,QAAQ,IAAI,MAAM;CAOnB;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,QAAQ;gBAC/B,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAS3C;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,QAAQ;gBAClC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAS3C;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,QAAQ;gBAC9B,OAAO,EAAE,MAAM;CAQ5B"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * M2M (Machine-to-Machine) Authentication Module
3
+ *
4
+ * OAuth 2.0 Client Credentials Grant implementation for server-to-server
5
+ * authentication without user involvement.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { M2MClient } from '@passflow/core';
10
+ *
11
+ * const m2m = new M2MClient({
12
+ * url: 'https://auth.yourapp.com',
13
+ * clientId: 'your-client-id',
14
+ * clientSecret: 'your-client-secret',
15
+ * scopes: ['users:read', 'orders:write'],
16
+ * });
17
+ *
18
+ * const token = await m2m.getToken();
19
+ * ```
20
+ *
21
+ * @packageDocumentation
22
+ */
23
+ export { M2MClient } from './client';
24
+ export { M2MError, M2MNetworkError, M2MTokenParseError, M2MConfigError } from './errors';
25
+ export type { M2MClientConfig, M2MTokenRequestOptions, M2MTokenRequestInfo, M2MTokenResponse, M2MErrorResponse, M2MTokenClaims, M2MErrorCode, M2MTokenCache, RetryStrategy, M2MRateLimitInfo, } from './types';
26
+ export { M2MErrorCodes, M2M_DEFAULTS } from './types';
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/m2m/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGrC,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAGzF,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,aAAa,EACb,aAAa,EACb,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC"}