@owox/idp-owox-better-auth 0.18.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 (156) hide show
  1. package/README.md +119 -0
  2. package/dist/client/IdentityOwoxClient.d.ts +41 -0
  3. package/dist/client/IdentityOwoxClient.d.ts.map +1 -0
  4. package/dist/client/IdentityOwoxClient.js +128 -0
  5. package/dist/client/dto/authFlowDto.d.ts +27 -0
  6. package/dist/client/dto/authFlowDto.d.ts.map +1 -0
  7. package/dist/client/dto/authFlowDto.js +5 -0
  8. package/dist/client/dto/idpOwoxPayloadDto.d.ts +29 -0
  9. package/dist/client/dto/idpOwoxPayloadDto.d.ts.map +1 -0
  10. package/dist/client/dto/idpOwoxPayloadDto.js +28 -0
  11. package/dist/client/dto/index.d.ts +11 -0
  12. package/dist/client/dto/index.d.ts.map +1 -0
  13. package/dist/client/dto/index.js +10 -0
  14. package/dist/client/dto/introspectionDto.d.ts +70 -0
  15. package/dist/client/dto/introspectionDto.d.ts.map +1 -0
  16. package/dist/client/dto/introspectionDto.js +15 -0
  17. package/dist/client/dto/jwksDto.d.ts +102 -0
  18. package/dist/client/dto/jwksDto.d.ts.map +1 -0
  19. package/dist/client/dto/jwksDto.js +18 -0
  20. package/dist/client/dto/revocationDto.d.ts +11 -0
  21. package/dist/client/dto/revocationDto.d.ts.map +1 -0
  22. package/dist/client/dto/revocationDto.js +1 -0
  23. package/dist/client/dto/tokenDto.d.ts +33 -0
  24. package/dist/client/dto/tokenDto.d.ts.map +1 -0
  25. package/dist/client/dto/tokenDto.js +9 -0
  26. package/dist/client/dto/tokenType.d.ts +5 -0
  27. package/dist/client/dto/tokenType.d.ts.map +1 -0
  28. package/dist/client/dto/tokenType.js +1 -0
  29. package/dist/client/index.d.ts +6 -0
  30. package/dist/client/index.d.ts.map +1 -0
  31. package/dist/client/index.js +5 -0
  32. package/dist/config/idp-better-auth-config.d.ts +9 -0
  33. package/dist/config/idp-better-auth-config.d.ts.map +1 -0
  34. package/dist/config/idp-better-auth-config.js +101 -0
  35. package/dist/config/idp-owox-config.d.ts +195 -0
  36. package/dist/config/idp-owox-config.d.ts.map +1 -0
  37. package/dist/config/idp-owox-config.js +252 -0
  38. package/dist/config/index.d.ts +6 -0
  39. package/dist/config/index.d.ts.map +1 -0
  40. package/dist/config/index.js +5 -0
  41. package/dist/core/constants.d.ts +14 -0
  42. package/dist/core/constants.d.ts.map +1 -0
  43. package/dist/core/constants.js +13 -0
  44. package/dist/core/exceptions.d.ts +27 -0
  45. package/dist/core/exceptions.d.ts.map +1 -0
  46. package/dist/core/exceptions.js +36 -0
  47. package/dist/core/logger.d.ts +17 -0
  48. package/dist/core/logger.d.ts.map +1 -0
  49. package/dist/core/logger.js +66 -0
  50. package/dist/core/pkce.d.ts +21 -0
  51. package/dist/core/pkce.d.ts.map +1 -0
  52. package/dist/core/pkce.js +27 -0
  53. package/dist/facades/owox-token-facade.d.ts +27 -0
  54. package/dist/facades/owox-token-facade.d.ts.map +1 -0
  55. package/dist/facades/owox-token-facade.js +117 -0
  56. package/dist/index.d.ts +13 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +13 -0
  59. package/dist/jwt/jwksCache.d.ts +24 -0
  60. package/dist/jwt/jwksCache.d.ts.map +1 -0
  61. package/dist/jwt/jwksCache.js +41 -0
  62. package/dist/jwt/parseToken.d.ts +15 -0
  63. package/dist/jwt/parseToken.d.ts.map +1 -0
  64. package/dist/jwt/parseToken.js +26 -0
  65. package/dist/jwt/verifyJwt.d.ts +13 -0
  66. package/dist/jwt/verifyJwt.d.ts.map +1 -0
  67. package/dist/jwt/verifyJwt.js +23 -0
  68. package/dist/mappers/client-payload-mapper.d.ts +6 -0
  69. package/dist/mappers/client-payload-mapper.d.ts.map +1 -0
  70. package/dist/mappers/client-payload-mapper.js +17 -0
  71. package/dist/mappers/user-info-payload-builder.d.ts +11 -0
  72. package/dist/mappers/user-info-payload-builder.d.ts.map +1 -0
  73. package/dist/mappers/user-info-payload-builder.js +28 -0
  74. package/dist/owox-better-auth-idp.d.ts +40 -0
  75. package/dist/owox-better-auth-idp.d.ts.map +1 -0
  76. package/dist/owox-better-auth-idp.js +239 -0
  77. package/dist/resources/templates/layouts/auth.ejs +29 -0
  78. package/dist/resources/templates/pages/sign-in.ejs +66 -0
  79. package/dist/resources/templates/pages/sign-up.ejs +65 -0
  80. package/dist/resources/templates/partials/brand-panel.ejs +24 -0
  81. package/dist/resources/templates/partials/footer.ejs +10 -0
  82. package/dist/resources/templates/partials/head.ejs +64 -0
  83. package/dist/resources/templates/partials/header.ejs +7 -0
  84. package/dist/services/auth/better-auth-session-service.d.ts +28 -0
  85. package/dist/services/auth/better-auth-session-service.d.ts.map +1 -0
  86. package/dist/services/auth/better-auth-session-service.js +121 -0
  87. package/dist/services/auth/pkce-flow-orchestrator.d.ts +33 -0
  88. package/dist/services/auth/pkce-flow-orchestrator.d.ts.map +1 -0
  89. package/dist/services/auth/pkce-flow-orchestrator.js +134 -0
  90. package/dist/services/auth/platform-auth-flow-client.d.ts +16 -0
  91. package/dist/services/auth/platform-auth-flow-client.d.ts.map +1 -0
  92. package/dist/services/auth/platform-auth-flow-client.js +32 -0
  93. package/dist/services/core/token-service.d.ts +25 -0
  94. package/dist/services/core/token-service.d.ts.map +1 -0
  95. package/dist/services/core/token-service.js +56 -0
  96. package/dist/services/core/user-context-service.d.ts +23 -0
  97. package/dist/services/core/user-context-service.d.ts.map +1 -0
  98. package/dist/services/core/user-context-service.js +54 -0
  99. package/dist/services/middleware/middleware-service.d.ts +19 -0
  100. package/dist/services/middleware/middleware-service.d.ts.map +1 -0
  101. package/dist/services/middleware/middleware-service.js +62 -0
  102. package/dist/services/middleware/request-handler-service.d.ts +18 -0
  103. package/dist/services/middleware/request-handler-service.d.ts.map +1 -0
  104. package/dist/services/middleware/request-handler-service.js +131 -0
  105. package/dist/services/rendering/page-service.d.ts +11 -0
  106. package/dist/services/rendering/page-service.d.ts.map +1 -0
  107. package/dist/services/rendering/page-service.js +26 -0
  108. package/dist/services/rendering/template-service.d.ts +17 -0
  109. package/dist/services/rendering/template-service.d.ts.map +1 -0
  110. package/dist/services/rendering/template-service.js +52 -0
  111. package/dist/social/google-provider.d.ts +35 -0
  112. package/dist/social/google-provider.d.ts.map +1 -0
  113. package/dist/social/google-provider.js +55 -0
  114. package/dist/social/social-provider.d.ts +23 -0
  115. package/dist/social/social-provider.d.ts.map +1 -0
  116. package/dist/social/social-provider.js +1 -0
  117. package/dist/store/database-store-factory.d.ts +8 -0
  118. package/dist/store/database-store-factory.d.ts.map +1 -0
  119. package/dist/store/database-store-factory.js +38 -0
  120. package/dist/store/database-store.d.ts +20 -0
  121. package/dist/store/database-store.d.ts.map +1 -0
  122. package/dist/store/database-store.js +1 -0
  123. package/dist/store/mysql-database-store.d.ts +40 -0
  124. package/dist/store/mysql-database-store.d.ts.map +1 -0
  125. package/dist/store/mysql-database-store.js +213 -0
  126. package/dist/store/sqlite-database-store.d.ts +32 -0
  127. package/dist/store/sqlite-database-store.d.ts.map +1 -0
  128. package/dist/store/sqlite-database-store.js +205 -0
  129. package/dist/store/store-result.d.ts +16 -0
  130. package/dist/store/store-result.d.ts.map +1 -0
  131. package/dist/store/store-result.js +25 -0
  132. package/dist/types/auth-request-context.d.ts +15 -0
  133. package/dist/types/auth-request-context.d.ts.map +1 -0
  134. package/dist/types/auth-request-context.js +12 -0
  135. package/dist/types/auth-session.d.ts +25 -0
  136. package/dist/types/auth-session.d.ts.map +1 -0
  137. package/dist/types/auth-session.js +1 -0
  138. package/dist/types/database-models.d.ts +39 -0
  139. package/dist/types/database-models.d.ts.map +1 -0
  140. package/dist/types/database-models.js +1 -0
  141. package/dist/types/index.d.ts +45 -0
  142. package/dist/types/index.d.ts.map +1 -0
  143. package/dist/types/index.js +2 -0
  144. package/dist/utils/cookie-policy.d.ts +16 -0
  145. package/dist/utils/cookie-policy.d.ts.map +1 -0
  146. package/dist/utils/cookie-policy.js +27 -0
  147. package/dist/utils/platform-redirect-builder.d.ts +29 -0
  148. package/dist/utils/platform-redirect-builder.d.ts.map +1 -0
  149. package/dist/utils/platform-redirect-builder.js +86 -0
  150. package/dist/utils/request-utils.d.ts +87 -0
  151. package/dist/utils/request-utils.d.ts.map +1 -0
  152. package/dist/utils/request-utils.js +171 -0
  153. package/dist/utils/string-utils.d.ts +13 -0
  154. package/dist/utils/string-utils.d.ts.map +1 -0
  155. package/dist/utils/string-utils.js +21 -0
  156. package/package.json +71 -0
package/README.md ADDED
@@ -0,0 +1,119 @@
1
+ # @owox/idp-owox-better-auth
2
+
3
+ Better Auth IDP provider for OWOX Data Marts authentication.
4
+
5
+ ## Setup
6
+
7
+ ### 1. Environment Configuration
8
+
9
+ ```env
10
+ # OWOX IDP
11
+ IDP_PROVIDER=owox-better-auth
12
+
13
+ IDP_OWOX_DB_TYPE=sqlite
14
+
15
+ ## MySQL Config
16
+ # IDP_OWOX_DB_TYPE=mysql
17
+ # IDP_OWOX_MYSQL_HOST=localhost
18
+ # IDP_OWOX_MYSQL_USER=root
19
+ # IDP_OWOX_MYSQL_PASSWORD=your-password
20
+ # IDP_OWOX_MYSQL_DB=idp_owox
21
+ # IDP_OWOX_MYSQL_PORT=3306
22
+ # IDP_OWOX_MYSQL_SSL=true
23
+
24
+ IDP_OWOX_CLIENT_BASE_URL=https://idp.example.com
25
+ IDP_OWOX_CLIENT_BACKCHANNEL_PREFIX=/your-custom-prefix
26
+ IDP_OWOX_C2C_SERVICE_ACCOUNT=service-account@example.com
27
+ IDP_OWOX_C2C_TARGET_AUDIENCE=audience-string
28
+ IDP_OWOX_CLIENT_ID=your-client-id
29
+ IDP_OWOX_PLATFORM_SIGN_IN_URL=https://platform.example.com/auth/sign-in
30
+ IDP_OWOX_PLATFORM_SIGN_UP_URL=https://platform.example.com/auth/sign-up
31
+ IDP_OWOX_SIGN_OUT_REDIRECT_URL=https://platform.example.com/auth/signed-out
32
+ IDP_OWOX_JWT_ISSUER=https://idp.example.com
33
+
34
+ # Better Auth IDP
35
+ IDP_BETTER_AUTH_SECRET=your-super-secret-key-at-least-32-characters-long
36
+
37
+ # Social login (Google)
38
+ # IDP_BETTER_AUTH_GOOGLE_CLIENT_ID=xx
39
+ # IDP_BETTER_AUTH_GOOGLE_CLIENT_SECRET=xx
40
+ ```
41
+
42
+ ## Configuration Reference
43
+
44
+ | Variable | Required | Default | Description |
45
+ | -------------------------------------- | :------: | :-----------------------------------------: | ----------------------------------------------------- |
46
+ | `IDP_PROVIDER` | **Yes** | – | Set to `owox-better-auth` |
47
+ | `IDP_OWOX_DB_TYPE` | No | `sqlite` | Database type: `sqlite` or `mysql` |
48
+ | `IDP_OWOX_SQLITE_DB_PATH` | No | `<app data>/sqlite/idp/owox-better-auth.db` | SQLite database file path |
49
+ | `IDP_OWOX_MYSQL_HOST` | No | – | MySQL host |
50
+ | `IDP_OWOX_MYSQL_USER` | No | – | MySQL user |
51
+ | `IDP_OWOX_MYSQL_PASSWORD` | No | – | MySQL password |
52
+ | `IDP_OWOX_MYSQL_DB` | No | – | MySQL database |
53
+ | `IDP_OWOX_MYSQL_PORT` | No | `3306` | MySQL port |
54
+ | `IDP_OWOX_MYSQL_SSL` | No | `false` | Enable SSL: `true`, JSON, or string |
55
+ | `IDP_OWOX_CLIENT_BASE_URL` | **Yes** | – | Identity client base URL |
56
+ | `IDP_OWOX_CLIENT_BACKCHANNEL_PREFIX` | **Yes** | – | Identity client path prefix for backchannel endpoints |
57
+ | `IDP_OWOX_C2C_SERVICE_ACCOUNT` | **Yes** | – | Service account email for C2C impersonation |
58
+ | `IDP_OWOX_C2C_TARGET_AUDIENCE` | **Yes** | – | Target audience for C2C impersonation |
59
+ | `IDP_OWOX_CLIENT_ID` | **Yes** | – | Client id for PKCE |
60
+ | `IDP_OWOX_PLATFORM_SIGN_IN_URL` | **Yes** | – | Platform sign-in URL (redirect target) |
61
+ | `IDP_OWOX_PLATFORM_SIGN_UP_URL` | **Yes** | – | Platform sign-up URL (redirect target) |
62
+ | `IDP_OWOX_SIGN_OUT_REDIRECT_URL` | No | `/auth/sign-in` | Custom redirect after sign-out |
63
+ | `IDP_OWOX_ALLOWED_REDIRECT_ORIGINS` | No | origins from platform sign-in/up URLs | Allowlist for redirect-to/app-redirect-to |
64
+ | `IDP_OWOX_JWT_ISSUER` | **Yes** | – | Expected JWT issuer |
65
+ | `IDP_OWOX_JWT_CACHE_TTL` | No | `1h` | JWKS cache TTL |
66
+ | `IDP_OWOX_JWT_CLOCK_TOLERANCE` | No | `5s` | Clock skew tolerance |
67
+ | `IDP_BETTER_AUTH_SECRET` | **Yes** | – | Secret key for signing (min. 32 characters) |
68
+ | `PUBLIC_ORIGIN` | No | `http://localhost:3000` | Base URL for callbacks |
69
+ | `IDP_BETTER_AUTH_SESSION_MAX_AGE` | No | `1800` (30 mins) | Session duration (seconds) |
70
+ | `IDP_BETTER_AUTH_TRUSTED_ORIGINS` | No | `PUBLIC_ORIGIN` | Trusted origins for auth service |
71
+ | `IDP_BETTER_AUTH_GOOGLE_CLIENT_ID` | No | – | Google OAuth client id (enables Google) |
72
+ | `IDP_BETTER_AUTH_GOOGLE_CLIENT_SECRET` | No | – | Google OAuth client secret |
73
+
74
+ ## Troubleshooting
75
+
76
+ ### "IDP_BETTER_AUTH_SECRET is not set" Error
77
+
78
+ Make sure your `.env` file contains a valid `IDP_BETTER_AUTH_SECRET` with at least 32 characters.
79
+
80
+ ### Database Connection Issues
81
+
82
+ For MySQL, verify your connection settings and ensure the database exists.
83
+
84
+ ### Permission Denied
85
+
86
+ Ensure the user has permission for the action they're trying to perform.
87
+
88
+ ## Customizing the auth UI
89
+
90
+ ### How it works
91
+
92
+ - Rendering goes through `TemplateService`, which stitches layout + page: `renderSignIn()` and `renderSignUp()` inject `pageTitle` and `heading` and place the page body into `layouts/auth.ejs`.
93
+ - The service first looks for templates in `dist/resources/templates`, and if missing, falls back to `src/resources/templates`. After changing files in `src`, run `npm run build` to refresh `dist`.
94
+ - Templates are EJS and styled with Tailwind via CDN (`partials/head.ejs` contains the Tailwind config with OWOX brand colors).
95
+
96
+ ### Where the files live
97
+
98
+ - Layout: `src/resources/templates/layouts/auth.ejs` — splits the screen into brand panel + content and pulls in header/footer.
99
+ - Pages: `pages/sign-in.ejs`, `pages/sign-up.ejs` — Google buttons, copy, and the social-login start script.
100
+ - Partials:
101
+ - `head.ejs` — `<head>`, Tailwind include, color palette.
102
+ - `header.ejs` — page heading (receives `heading`).
103
+ - `brand-panel.ejs` — left panel with background and logo.
104
+ - `footer.ejs` — terms and privacy links.
105
+
106
+ ### What and how to change
107
+
108
+ - Text/links: edit the relevant `pages/*.ejs` or `partials/footer.ejs`.
109
+ - Page heading: adjust `heading` in `TemplateService.renderSignIn|renderSignUp`, or edit `partials/header.ejs` if you need a different look.
110
+ - Buttons and social-login logic: in `pages/sign-in.ejs` and `pages/sign-up.ejs` (the `fetch` handler to `/auth/better-auth/sign-in/social`).
111
+ - Styles/colors: tweak the Tailwind config in `partials/head.ejs` or utility classes in each section.
112
+ - Branding (background, logo, tagline): in `partials/brand-panel.ejs`.
113
+
114
+ ### Quick steps
115
+
116
+ 1. Edit the needed `.ejs` in `src/resources/templates/**`.
117
+ 2. Check rendering locally (via the app that consumes this package).
118
+ 3. Run `npm run build` to update `dist/resources/templates`.
119
+ 4. Commit changes in `src` (and `dist` if you ship built artifacts).
@@ -0,0 +1,41 @@
1
+ import { Projects } from '@owox/idp-protocol';
2
+ import { IdentityOwoxClientConfig } from '../config/idp-owox-config.js';
3
+ import { AuthFlowRequest, AuthFlowResponse, IntrospectionRequest, IntrospectionResponse, JwksResponse, RevocationRequest, RevocationResponse, TokenRequest, TokenResponse } from './dto/index.js';
4
+ /**
5
+ * Represents a client for interacting with the Identity OWOX API.
6
+ * Provides methods for token management, validation, and retrieval of key sets.
7
+ */
8
+ export declare class IdentityOwoxClient {
9
+ private readonly http;
10
+ private readonly impersonatedIdTokenFetcher?;
11
+ private readonly c2cServiceAccountEmail?;
12
+ private readonly c2cTargetAudience?;
13
+ private readonly clientBackchannelPrefix;
14
+ constructor(config: IdentityOwoxClientConfig);
15
+ /**
16
+ * POST /api/idp/token
17
+ */
18
+ getToken(req: TokenRequest): Promise<TokenResponse>;
19
+ /**
20
+ * POST /api/idp/revocation
21
+ */
22
+ revokeToken(req: RevocationRequest): Promise<RevocationResponse>;
23
+ /**
24
+ * GET /api/idp/introspection
25
+ */
26
+ introspectToken(req: IntrospectionRequest): Promise<IntrospectionResponse>;
27
+ /**
28
+ * GET /api/idp/projects
29
+ */
30
+ getProjects(accessToken: string): Promise<Projects>;
31
+ /**
32
+ * GET /api/idp/.well-known/jwks.json
33
+ */
34
+ getJwks(): Promise<JwksResponse>;
35
+ /**
36
+ * Completes auth flow by exchanging user info for a one-time authorization code.
37
+ * Requires service account authentication for the private internal endpoint.
38
+ */
39
+ completeAuthFlow(request: AuthFlowRequest): Promise<AuthFlowResponse>;
40
+ }
41
+ //# sourceMappingURL=IdentityOwoxClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IdentityOwoxClient.d.ts","sourceRoot":"","sources":["../../src/client/IdentityOwoxClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAkB,MAAM,oBAAoB,CAAC;AAI9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAExE,OAAO,EACL,eAAe,EACf,gBAAgB,EAEhB,oBAAoB,EACpB,qBAAqB,EAErB,YAAY,EAEZ,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,EACZ,aAAa,EAEd,MAAM,gBAAgB,CAAC;AAExB;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAC,CAA6B;IACzE,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAS;IACjD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAS;IAC5C,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAS;gBAErC,MAAM,EAAE,wBAAwB;IAsB5C;;OAEG;IACG,QAAQ,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAyBzD;;OAEG;IACG,WAAW,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAKtE;;OAEG;IACG,eAAe,CAAC,GAAG,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAUhF;;OAEG;IACG,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAUzD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,YAAY,CAAC;IAKtC;;;OAGG;IACG,gBAAgB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;CA4C5E"}
@@ -0,0 +1,128 @@
1
+ import { ProjectsSchema } from '@owox/idp-protocol';
2
+ import { ImpersonatedIdTokenFetcher } from '@owox/internal-helpers';
3
+ import axios from 'axios';
4
+ import ms from 'ms';
5
+ import { AuthenticationException, IdpFailedException } from '../core/exceptions.js';
6
+ import { AuthFlowResponseSchema, IntrospectionResponseSchema, JwksResponseSchema, TokenResponseSchema, } from './dto/index.js';
7
+ /**
8
+ * Represents a client for interacting with the Identity OWOX API.
9
+ * Provides methods for token management, validation, and retrieval of key sets.
10
+ */
11
+ export class IdentityOwoxClient {
12
+ http;
13
+ impersonatedIdTokenFetcher;
14
+ c2cServiceAccountEmail;
15
+ c2cTargetAudience;
16
+ clientBackchannelPrefix;
17
+ constructor(config) {
18
+ const timeout = typeof config.clientTimeout === 'number' ? config.clientTimeout : ms(config.clientTimeout);
19
+ this.http = axios.create({
20
+ baseURL: config.clientBaseUrl,
21
+ timeout,
22
+ headers: {
23
+ 'Content-Type': 'application/json',
24
+ ...(config.defaultHeaders ?? {}),
25
+ },
26
+ });
27
+ this.clientBackchannelPrefix = config.clientBackchannelPrefix;
28
+ // Initialize service account authentication if configured
29
+ if (config.c2cServiceAccountEmail && config.c2cTargetAudience) {
30
+ this.impersonatedIdTokenFetcher = new ImpersonatedIdTokenFetcher();
31
+ this.c2cServiceAccountEmail = config.c2cServiceAccountEmail;
32
+ this.c2cTargetAudience = config.c2cTargetAudience;
33
+ }
34
+ }
35
+ /**
36
+ * POST /api/idp/token
37
+ */
38
+ async getToken(req) {
39
+ try {
40
+ const { data } = await this.http.post('/api/idp/token', req);
41
+ return TokenResponseSchema.parse(data);
42
+ }
43
+ catch (err) {
44
+ if (axios.isAxiosError(err)) {
45
+ const status = err.response?.status;
46
+ if (status === 401) {
47
+ throw new AuthenticationException('Invalid or expired credentials', {
48
+ cause: err,
49
+ context: { req },
50
+ });
51
+ }
52
+ throw new IdpFailedException(`Failed to get token: ${status}`, {
53
+ cause: err,
54
+ context: { req },
55
+ });
56
+ }
57
+ throw err;
58
+ }
59
+ }
60
+ /**
61
+ * POST /api/idp/revocation
62
+ */
63
+ async revokeToken(req) {
64
+ const resp = await this.http.post('/api/idp/revocation', req);
65
+ return { success: resp.status >= 200 && resp.status < 300 };
66
+ }
67
+ /**
68
+ * GET /api/idp/introspection
69
+ */
70
+ async introspectToken(req) {
71
+ const { data } = await this.http.get('/api/idp/introspection', {
72
+ headers: {
73
+ Authorization: req.token,
74
+ },
75
+ });
76
+ return IntrospectionResponseSchema.parse(data);
77
+ }
78
+ /**
79
+ * GET /api/idp/projects
80
+ */
81
+ async getProjects(accessToken) {
82
+ const { data } = await this.http.get('/api/idp/projects', {
83
+ headers: {
84
+ Authorization: accessToken,
85
+ },
86
+ });
87
+ return ProjectsSchema.parse(data);
88
+ }
89
+ /**
90
+ * GET /api/idp/.well-known/jwks.json
91
+ */
92
+ async getJwks() {
93
+ const { data } = await this.http.get('/api/idp/.well-known/jwks.json');
94
+ return JwksResponseSchema.parse(data);
95
+ }
96
+ /**
97
+ * Completes auth flow by exchanging user info for a one-time authorization code.
98
+ * Requires service account authentication for the private internal endpoint.
99
+ */
100
+ async completeAuthFlow(request) {
101
+ if (!this.impersonatedIdTokenFetcher ||
102
+ !this.c2cServiceAccountEmail ||
103
+ !this.c2cTargetAudience) {
104
+ throw new IdpFailedException('Service account authentication is not configured. Cannot complete auth flow.', { context: { hasRequest: Boolean(request) } });
105
+ }
106
+ try {
107
+ const idToken = await this.impersonatedIdTokenFetcher.getIdToken(this.c2cServiceAccountEmail, this.c2cTargetAudience);
108
+ const { data } = await this.http.post(`${this.clientBackchannelPrefix}/idp/auth-flow/complete`, request, {
109
+ headers: {
110
+ Authorization: `Bearer ${idToken}`,
111
+ },
112
+ });
113
+ // Validate and return response
114
+ return AuthFlowResponseSchema.parse(data);
115
+ }
116
+ catch (err) {
117
+ if (axios.isAxiosError(err)) {
118
+ const status = err.response?.status;
119
+ const responseData = err.response?.data;
120
+ throw new IdpFailedException(`Failed to complete auth flow: ${status}`, {
121
+ cause: err,
122
+ context: { request, status, responseData },
123
+ });
124
+ }
125
+ throw err;
126
+ }
127
+ }
128
+ }
@@ -0,0 +1,27 @@
1
+ import { z } from 'zod';
2
+ /** User information and state for auth flow completion. */
3
+ export interface AuthFlowRequest {
4
+ state: string;
5
+ userInfo: {
6
+ uid: string;
7
+ signinProvider: string;
8
+ email: string;
9
+ firstName?: string;
10
+ lastName?: string;
11
+ fullName?: string;
12
+ avatar?: string;
13
+ };
14
+ }
15
+ /** One-time authorization code response. */
16
+ export interface AuthFlowResponse {
17
+ code: string;
18
+ }
19
+ /** Validates auth flow response structure. */
20
+ export declare const AuthFlowResponseSchema: z.ZodObject<{
21
+ code: z.ZodString;
22
+ }, "strip", z.ZodTypeAny, {
23
+ code: string;
24
+ }, {
25
+ code: string;
26
+ }>;
27
+ //# sourceMappingURL=authFlowDto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authFlowDto.d.ts","sourceRoot":"","sources":["../../../src/client/dto/authFlowDto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,2DAA2D;AAC3D,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QACR,GAAG,EAAE,MAAM,CAAC;QACZ,cAAc,EAAE,MAAM,CAAC;QACvB,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,4CAA4C;AAC5C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,8CAA8C;AAC9C,eAAO,MAAM,sBAAsB;;;;;;EAEjC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { z } from 'zod';
2
+ /** Validates auth flow response structure. */
3
+ export const AuthFlowResponseSchema = z.object({
4
+ code: z.string().min(1, 'Authorization code is required'),
5
+ });
@@ -0,0 +1,29 @@
1
+ import { z } from 'zod';
2
+ /** Payload schema returned by Identity OWOX introspection. */
3
+ export declare const IdpOwoxPayloadSchema: z.ZodObject<{
4
+ userId: z.ZodString;
5
+ projectId: z.ZodString;
6
+ userEmail: z.ZodString;
7
+ userFullName: z.ZodString;
8
+ userAvatar: z.ZodNullable<z.ZodString>;
9
+ roles: z.ZodEffects<z.ZodEffects<z.ZodArray<z.ZodEnum<["admin", "editor", "viewer"]>, "atleastone">, ("admin" | "editor" | "viewer")[], ["admin" | "editor" | "viewer", ...("admin" | "editor" | "viewer")[]]>, ("admin" | "editor" | "viewer")[], unknown>;
10
+ projectTitle: z.ZodString;
11
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
12
+ userId: z.ZodString;
13
+ projectId: z.ZodString;
14
+ userEmail: z.ZodString;
15
+ userFullName: z.ZodString;
16
+ userAvatar: z.ZodNullable<z.ZodString>;
17
+ roles: z.ZodEffects<z.ZodEffects<z.ZodArray<z.ZodEnum<["admin", "editor", "viewer"]>, "atleastone">, ("admin" | "editor" | "viewer")[], ["admin" | "editor" | "viewer", ...("admin" | "editor" | "viewer")[]]>, ("admin" | "editor" | "viewer")[], unknown>;
18
+ projectTitle: z.ZodString;
19
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
20
+ userId: z.ZodString;
21
+ projectId: z.ZodString;
22
+ userEmail: z.ZodString;
23
+ userFullName: z.ZodString;
24
+ userAvatar: z.ZodNullable<z.ZodString>;
25
+ roles: z.ZodEffects<z.ZodEffects<z.ZodArray<z.ZodEnum<["admin", "editor", "viewer"]>, "atleastone">, ("admin" | "editor" | "viewer")[], ["admin" | "editor" | "viewer", ...("admin" | "editor" | "viewer")[]]>, ("admin" | "editor" | "viewer")[], unknown>;
26
+ projectTitle: z.ZodString;
27
+ }, z.ZodTypeAny, "passthrough">>;
28
+ export type IdpOwoxPayload = z.infer<typeof IdpOwoxPayloadSchema>;
29
+ //# sourceMappingURL=idpOwoxPayloadDto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idpOwoxPayloadDto.d.ts","sourceRoot":"","sources":["../../../src/client/dto/idpOwoxPayloadDto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,8DAA8D;AAC9D,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;gCA2BjB,CAAC;AAEjB,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { z } from 'zod';
2
+ import { RoleEnum } from '@owox/idp-protocol';
3
+ /** Payload schema returned by Identity OWOX introspection. */
4
+ export const IdpOwoxPayloadSchema = z
5
+ .object({
6
+ userId: z.string().min(1, 'userId is required'),
7
+ projectId: z.string().min(1, 'projectId is required'),
8
+ userEmail: z.string().email(),
9
+ userFullName: z.string().min(1, 'userFullName is required'),
10
+ userAvatar: z.string().url().nullable(),
11
+ roles: z.preprocess(val => {
12
+ if (typeof val === 'string') {
13
+ return val
14
+ .split(',')
15
+ .map(r => r.trim().toLowerCase())
16
+ .filter(Boolean);
17
+ }
18
+ if (Array.isArray(val)) {
19
+ return val.map(r => String(r).trim().toLowerCase()).filter(Boolean);
20
+ }
21
+ return [];
22
+ }, z
23
+ .array(RoleEnum)
24
+ .nonempty()
25
+ .transform(arr => Array.from(new Set(arr)))),
26
+ projectTitle: z.string().min(1, 'projectTitle is required'),
27
+ })
28
+ .passthrough();
@@ -0,0 +1,11 @@
1
+ /**
2
+ * DTO schema exports for Identity OWOX API.
3
+ */
4
+ export * from './authFlowDto.js';
5
+ export * from './idpOwoxPayloadDto.js';
6
+ export * from './introspectionDto.js';
7
+ export * from './jwksDto.js';
8
+ export * from './revocationDto.js';
9
+ export * from './tokenDto.js';
10
+ export * from './tokenType.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/dto/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * DTO schema exports for Identity OWOX API.
3
+ */
4
+ export * from './authFlowDto.js';
5
+ export * from './idpOwoxPayloadDto.js';
6
+ export * from './introspectionDto.js';
7
+ export * from './jwksDto.js';
8
+ export * from './revocationDto.js';
9
+ export * from './tokenDto.js';
10
+ export * from './tokenType.js';
@@ -0,0 +1,70 @@
1
+ import { z } from 'zod';
2
+ /** Token introspection request payload. */
3
+ export interface IntrospectionRequest {
4
+ token: string;
5
+ }
6
+ /** Token introspection response schema. */
7
+ export declare const IntrospectionResponseSchema: z.ZodDiscriminatedUnion<"isActive", [z.ZodObject<{
8
+ userId: z.ZodString;
9
+ projectId: z.ZodString;
10
+ userEmail: z.ZodString;
11
+ userFullName: z.ZodString;
12
+ userAvatar: z.ZodNullable<z.ZodString>;
13
+ roles: z.ZodEffects<z.ZodEffects<z.ZodArray<z.ZodEnum<["admin", "editor", "viewer"]>, "atleastone">, ("admin" | "editor" | "viewer")[], ["admin" | "editor" | "viewer", ...("admin" | "editor" | "viewer")[]]>, ("admin" | "editor" | "viewer")[], unknown>;
14
+ projectTitle: z.ZodString;
15
+ } & {
16
+ isActive: z.ZodLiteral<true>;
17
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
18
+ userId: z.ZodString;
19
+ projectId: z.ZodString;
20
+ userEmail: z.ZodString;
21
+ userFullName: z.ZodString;
22
+ userAvatar: z.ZodNullable<z.ZodString>;
23
+ roles: z.ZodEffects<z.ZodEffects<z.ZodArray<z.ZodEnum<["admin", "editor", "viewer"]>, "atleastone">, ("admin" | "editor" | "viewer")[], ["admin" | "editor" | "viewer", ...("admin" | "editor" | "viewer")[]]>, ("admin" | "editor" | "viewer")[], unknown>;
24
+ projectTitle: z.ZodString;
25
+ } & {
26
+ isActive: z.ZodLiteral<true>;
27
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
28
+ userId: z.ZodString;
29
+ projectId: z.ZodString;
30
+ userEmail: z.ZodString;
31
+ userFullName: z.ZodString;
32
+ userAvatar: z.ZodNullable<z.ZodString>;
33
+ roles: z.ZodEffects<z.ZodEffects<z.ZodArray<z.ZodEnum<["admin", "editor", "viewer"]>, "atleastone">, ("admin" | "editor" | "viewer")[], ["admin" | "editor" | "viewer", ...("admin" | "editor" | "viewer")[]]>, ("admin" | "editor" | "viewer")[], unknown>;
34
+ projectTitle: z.ZodString;
35
+ } & {
36
+ isActive: z.ZodLiteral<true>;
37
+ }, z.ZodTypeAny, "passthrough">>, z.ZodObject<{
38
+ [x: string]: z.ZodNull;
39
+ userId: z.ZodNull;
40
+ projectId: z.ZodNull;
41
+ userEmail: z.ZodNull;
42
+ userFullName: z.ZodNull;
43
+ userAvatar: z.ZodNull;
44
+ roles: z.ZodNull;
45
+ projectTitle: z.ZodNull;
46
+ } & {
47
+ isActive: z.ZodLiteral<false>;
48
+ }, "strict", z.ZodTypeAny, {
49
+ [x: string]: null;
50
+ userId?: unknown;
51
+ projectId?: unknown;
52
+ userEmail?: unknown;
53
+ userFullName?: unknown;
54
+ userAvatar?: unknown;
55
+ roles?: unknown;
56
+ projectTitle?: unknown;
57
+ isActive?: unknown;
58
+ }, {
59
+ [x: string]: null;
60
+ userId?: unknown;
61
+ projectId?: unknown;
62
+ userEmail?: unknown;
63
+ userFullName?: unknown;
64
+ userAvatar?: unknown;
65
+ roles?: unknown;
66
+ projectTitle?: unknown;
67
+ isActive?: unknown;
68
+ }>]>;
69
+ export type IntrospectionResponse = z.infer<typeof IntrospectionResponseSchema>;
70
+ //# sourceMappingURL=introspectionDto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"introspectionDto.d.ts","sourceRoot":"","sources":["../../../src/client/dto/introspectionDto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,2CAA2C;AAC3C,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;CACf;AAgBD,2CAA2C;AAC3C,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAGtC,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { z } from 'zod';
2
+ import { IdpOwoxPayloadSchema } from './idpOwoxPayloadDto.js';
3
+ const ActiveSchema = IdpOwoxPayloadSchema.extend({
4
+ isActive: z.literal(true),
5
+ });
6
+ const inactiveShape = Object.fromEntries(Object.keys(IdpOwoxPayloadSchema.shape).map(k => [k, z.null()]));
7
+ const InactiveSchema = z
8
+ .object(inactiveShape)
9
+ .strict()
10
+ .extend({ isActive: z.literal(false) });
11
+ /** Token introspection response schema. */
12
+ export const IntrospectionResponseSchema = z.discriminatedUnion('isActive', [
13
+ ActiveSchema,
14
+ InactiveSchema,
15
+ ]);
@@ -0,0 +1,102 @@
1
+ import { z } from 'zod';
2
+ import { JWK } from 'jose';
3
+ /** JSON Web Key schema used in JWKS responses. */
4
+ export declare const JsonWebKeySchema: z.ZodObject<{
5
+ kty: z.ZodString;
6
+ use: z.ZodString;
7
+ alg: z.ZodString;
8
+ kid: z.ZodString;
9
+ n: z.ZodString;
10
+ e: z.ZodString;
11
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
12
+ kty: z.ZodString;
13
+ use: z.ZodString;
14
+ alg: z.ZodString;
15
+ kid: z.ZodString;
16
+ n: z.ZodString;
17
+ e: z.ZodString;
18
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
19
+ kty: z.ZodString;
20
+ use: z.ZodString;
21
+ alg: z.ZodString;
22
+ kid: z.ZodString;
23
+ n: z.ZodString;
24
+ e: z.ZodString;
25
+ }, z.ZodTypeAny, "passthrough">>;
26
+ /** JWKS response schema. */
27
+ export declare const JwksResponseSchema: z.ZodEffects<z.ZodObject<{
28
+ keys: z.ZodArray<z.ZodObject<{
29
+ kty: z.ZodString;
30
+ use: z.ZodString;
31
+ alg: z.ZodString;
32
+ kid: z.ZodString;
33
+ n: z.ZodString;
34
+ e: z.ZodString;
35
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
36
+ kty: z.ZodString;
37
+ use: z.ZodString;
38
+ alg: z.ZodString;
39
+ kid: z.ZodString;
40
+ n: z.ZodString;
41
+ e: z.ZodString;
42
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
43
+ kty: z.ZodString;
44
+ use: z.ZodString;
45
+ alg: z.ZodString;
46
+ kid: z.ZodString;
47
+ n: z.ZodString;
48
+ e: z.ZodString;
49
+ }, z.ZodTypeAny, "passthrough">>, "atleastone">;
50
+ }, "strip", z.ZodTypeAny, {
51
+ keys: [z.objectOutputType<{
52
+ kty: z.ZodString;
53
+ use: z.ZodString;
54
+ alg: z.ZodString;
55
+ kid: z.ZodString;
56
+ n: z.ZodString;
57
+ e: z.ZodString;
58
+ }, z.ZodTypeAny, "passthrough">, ...z.objectOutputType<{
59
+ kty: z.ZodString;
60
+ use: z.ZodString;
61
+ alg: z.ZodString;
62
+ kid: z.ZodString;
63
+ n: z.ZodString;
64
+ e: z.ZodString;
65
+ }, z.ZodTypeAny, "passthrough">[]];
66
+ }, {
67
+ keys: [z.objectInputType<{
68
+ kty: z.ZodString;
69
+ use: z.ZodString;
70
+ alg: z.ZodString;
71
+ kid: z.ZodString;
72
+ n: z.ZodString;
73
+ e: z.ZodString;
74
+ }, z.ZodTypeAny, "passthrough">, ...z.objectInputType<{
75
+ kty: z.ZodString;
76
+ use: z.ZodString;
77
+ alg: z.ZodString;
78
+ kid: z.ZodString;
79
+ n: z.ZodString;
80
+ e: z.ZodString;
81
+ }, z.ZodTypeAny, "passthrough">[]];
82
+ }>, {
83
+ keys: JWK[];
84
+ }, {
85
+ keys: [z.objectInputType<{
86
+ kty: z.ZodString;
87
+ use: z.ZodString;
88
+ alg: z.ZodString;
89
+ kid: z.ZodString;
90
+ n: z.ZodString;
91
+ e: z.ZodString;
92
+ }, z.ZodTypeAny, "passthrough">, ...z.objectInputType<{
93
+ kty: z.ZodString;
94
+ use: z.ZodString;
95
+ alg: z.ZodString;
96
+ kid: z.ZodString;
97
+ n: z.ZodString;
98
+ e: z.ZodString;
99
+ }, z.ZodTypeAny, "passthrough">[]];
100
+ }>;
101
+ export type JwksResponse = z.infer<typeof JwksResponseSchema>;
102
+ //# sourceMappingURL=jwksDto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwksDto.d.ts","sourceRoot":"","sources":["../../../src/client/dto/jwksDto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAE3B,kDAAkD;AAClD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;gCASb,CAAC;AAEjB,4BAA4B;AAC5B,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAIiB,GAAG,EAAE;;;;;;;;;;;;;;;;;EAAI,CAAC;AAE1D,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { z } from 'zod';
2
+ /** JSON Web Key schema used in JWKS responses. */
3
+ export const JsonWebKeySchema = z
4
+ .object({
5
+ kty: z.string(),
6
+ use: z.string(),
7
+ alg: z.string(),
8
+ kid: z.string(),
9
+ n: z.string(),
10
+ e: z.string(),
11
+ })
12
+ .passthrough();
13
+ /** JWKS response schema. */
14
+ export const JwksResponseSchema = z
15
+ .object({
16
+ keys: z.array(JsonWebKeySchema).nonempty(),
17
+ })
18
+ .transform(v => ({ keys: v.keys }));
@@ -0,0 +1,11 @@
1
+ import { TokenType } from './tokenType.js';
2
+ /** Token revocation request payload. */
3
+ export interface RevocationRequest {
4
+ token: string;
5
+ tokenType?: TokenType;
6
+ }
7
+ /** Token revocation response payload. */
8
+ export interface RevocationResponse {
9
+ success: boolean;
10
+ }
11
+ //# sourceMappingURL=revocationDto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revocationDto.d.ts","sourceRoot":"","sources":["../../../src/client/dto/revocationDto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,wCAAwC;AACxC,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,yCAAyC;AACzC,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;CAClB"}
@@ -0,0 +1 @@
1
+ export {};