@geekmidas/client 10.0.0-alpha.2 → 10.0.0-alpha.21

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 (103) hide show
  1. package/README.md +39 -57
  2. package/dist/auth-fetcher.cjs +78 -3
  3. package/dist/auth-fetcher.cjs.map +1 -0
  4. package/dist/auth-fetcher.d.cts +155 -3
  5. package/dist/auth-fetcher.d.cts.map +1 -0
  6. package/dist/auth-fetcher.d.mts +155 -3
  7. package/dist/auth-fetcher.d.mts.map +1 -0
  8. package/dist/auth-fetcher.mjs +77 -3
  9. package/dist/auth-fetcher.mjs.map +1 -0
  10. package/dist/endpoint-hooks.cjs +11 -15
  11. package/dist/endpoint-hooks.cjs.map +1 -1
  12. package/dist/endpoint-hooks.d.cts +4 -7
  13. package/dist/endpoint-hooks.d.cts.map +1 -1
  14. package/dist/endpoint-hooks.d.mts +4 -7
  15. package/dist/endpoint-hooks.d.mts.map +1 -1
  16. package/dist/endpoint-hooks.mjs +5 -9
  17. package/dist/endpoint-hooks.mjs.map +1 -1
  18. package/dist/fetcher.cjs +111 -3
  19. package/dist/fetcher.cjs.map +1 -0
  20. package/dist/fetcher.d.cts +23 -3
  21. package/dist/fetcher.d.cts.map +1 -0
  22. package/dist/fetcher.d.mts +23 -3
  23. package/dist/fetcher.d.mts.map +1 -0
  24. package/dist/fetcher.mjs +86 -2
  25. package/dist/fetcher.mjs.map +1 -0
  26. package/dist/index.cjs +9 -6
  27. package/dist/index.d.cts +6 -5
  28. package/dist/index.d.mts +6 -5
  29. package/dist/index.mjs +6 -6
  30. package/dist/infer.cjs +0 -1
  31. package/dist/infer.d.cts +130 -2
  32. package/dist/infer.d.cts.map +1 -0
  33. package/dist/infer.d.mts +130 -2
  34. package/dist/infer.d.mts.map +1 -0
  35. package/dist/infer.mjs +1 -1
  36. package/dist/methods.cjs +21 -0
  37. package/dist/methods.cjs.map +1 -0
  38. package/dist/methods.d.cts +23 -0
  39. package/dist/methods.d.cts.map +1 -0
  40. package/dist/methods.d.mts +23 -0
  41. package/dist/methods.d.mts.map +1 -0
  42. package/dist/methods.mjs +19 -0
  43. package/dist/methods.mjs.map +1 -0
  44. package/dist/openapi-hooks.cjs +13 -16
  45. package/dist/openapi-hooks.cjs.map +1 -1
  46. package/dist/openapi-hooks.d.cts +8 -11
  47. package/dist/openapi-hooks.d.cts.map +1 -1
  48. package/dist/openapi-hooks.d.mts +8 -11
  49. package/dist/openapi-hooks.d.mts.map +1 -1
  50. package/dist/openapi-hooks.mjs +9 -12
  51. package/dist/openapi-hooks.mjs.map +1 -1
  52. package/dist/openapi-types.d.cts +5 -6
  53. package/dist/openapi-types.d.cts.map +1 -1
  54. package/dist/openapi-types.d.mts +5 -6
  55. package/dist/openapi-types.d.mts.map +1 -1
  56. package/dist/react-query.cjs +17 -16
  57. package/dist/react-query.cjs.map +1 -1
  58. package/dist/react-query.d.cts +12 -17
  59. package/dist/react-query.d.cts.map +1 -1
  60. package/dist/react-query.d.mts +12 -17
  61. package/dist/react-query.d.mts.map +1 -1
  62. package/dist/react-query.mjs +10 -9
  63. package/dist/react-query.mjs.map +1 -1
  64. package/dist/types.cjs +0 -1
  65. package/dist/types.d.cts +114 -2
  66. package/dist/types.d.cts.map +1 -0
  67. package/dist/types.d.mts +114 -2
  68. package/dist/types.d.mts.map +1 -0
  69. package/dist/types.mjs +1 -1
  70. package/package.json +14 -14
  71. package/dist/auth-fetcher-CBYuL6rx.d.cts +0 -158
  72. package/dist/auth-fetcher-CBYuL6rx.d.cts.map +0 -1
  73. package/dist/auth-fetcher-DOj0iz21.mjs +0 -77
  74. package/dist/auth-fetcher-DOj0iz21.mjs.map +0 -1
  75. package/dist/auth-fetcher-DxS8zOLc.d.mts +0 -158
  76. package/dist/auth-fetcher-DxS8zOLc.d.mts.map +0 -1
  77. package/dist/auth-fetcher-HILABmws.cjs +0 -82
  78. package/dist/auth-fetcher-HILABmws.cjs.map +0 -1
  79. package/dist/chunk-CUT6urMc.cjs +0 -30
  80. package/dist/fetcher-C1xtCKpT.d.mts +0 -25
  81. package/dist/fetcher-C1xtCKpT.d.mts.map +0 -1
  82. package/dist/fetcher-CakjC9C7.mjs +0 -88
  83. package/dist/fetcher-CakjC9C7.mjs.map +0 -1
  84. package/dist/fetcher-CwnSqc4D.cjs +0 -100
  85. package/dist/fetcher-CwnSqc4D.cjs.map +0 -1
  86. package/dist/fetcher-cDrfwN-Y.d.cts +0 -25
  87. package/dist/fetcher-cDrfwN-Y.d.cts.map +0 -1
  88. package/dist/infer-6KKCgmg1.cjs +0 -0
  89. package/dist/infer-DfRq5kIb.d.cts +0 -133
  90. package/dist/infer-DfRq5kIb.d.cts.map +0 -1
  91. package/dist/infer-bTirNeNW.d.mts +0 -133
  92. package/dist/infer-bTirNeNW.d.mts.map +0 -1
  93. package/dist/infer-uCUq1whM.mjs +0 -0
  94. package/dist/openapi.cjs +0 -526
  95. package/dist/openapi.cjs.map +0 -1
  96. package/dist/openapi.mjs +0 -501
  97. package/dist/openapi.mjs.map +0 -1
  98. package/dist/types-BH8WgGrm.mjs +0 -0
  99. package/dist/types-BMGM6sZc.d.mts +0 -110
  100. package/dist/types-BMGM6sZc.d.mts.map +0 -1
  101. package/dist/types-DMQMHePI.d.cts +0 -110
  102. package/dist/types-DMQMHePI.d.cts.map +0 -1
  103. package/dist/types-a8gm_IaQ.cjs +0 -0
package/README.md CHANGED
@@ -40,8 +40,8 @@ import { createEndpointHooks } from '@geekmidas/client/endpoint-hooks';
40
40
  // React Query client (class-based)
41
41
  import { createTypedQueryClient } from '@geekmidas/client/react-query';
42
42
 
43
- // OpenAPI hooks generation
44
- import { generateReactQueryHooks } from '@geekmidas/client/openapi';
43
+ // OpenAPI hooks from a paths type
44
+ import { createOpenAPIHooks } from '@geekmidas/client/openapi';
45
45
 
46
46
  // Type utilities
47
47
  import type { TypedApiFunction, FilteredRequestConfig } from '@geekmidas/client/types';
@@ -76,7 +76,7 @@ interface API {
76
76
  email: string;
77
77
  };
78
78
  };
79
- 'GET /users/:id': {
79
+ 'GET /users/{id}': {
80
80
  params: {
81
81
  id: string;
82
82
  };
@@ -102,7 +102,7 @@ const user = await api('POST /users', {
102
102
  });
103
103
  // user is typed as { id: string; name: string; email: string }
104
104
 
105
- const singleUser = await api('GET /users/:id', {
105
+ const singleUser = await api('GET /users/{id}', {
106
106
  params: { id: '123' }
107
107
  });
108
108
  // singleUser is typed as { id: string; name: string; email: string }
@@ -280,6 +280,26 @@ function CreateUser() {
280
280
  }
281
281
  ```
282
282
 
283
+ ### Method Calls
284
+
285
+ Every client also answers by method — the same request as
286
+ `api('POST /users', …)`, with the method as the call:
287
+
288
+ ```typescript
289
+ await api.get('/health'); // declares nothing → no second argument
290
+ await api.get('/users/{id}', { params: { id: '123' } }); // path params → argument required
291
+ await api.post('/users', { body: { name: 'Ada', email } }); // body → argument required
292
+ await api.get('/search', { query: { q: 'ada' } }); // required query key → required
293
+ await api.get('/users', { query: { page: 2 } }); // optional query → optional
294
+
295
+ await api.post('/users', { body: { name: 'Ada' } }); // ❌ `email` is missing
296
+ await api.get('/health', { body: {} }); // ❌ GET /health takes no body
297
+ await api.post('/health'); // ❌ /health has no POST
298
+ ```
299
+
300
+ The route autocompletes per method — only routes with a `POST` appear in
301
+ `api.post` — and the second argument has only the keys the endpoint declares.
302
+
283
303
  ### Type-Safe Config Requirements
284
304
 
285
305
  The generated client enforces config requirements at the type level:
@@ -379,48 +399,10 @@ const api = Object.assign(fetcher, hooks);
379
399
 
380
400
  ## OpenAPI Code Generation
381
401
 
382
- Generate React Query hooks from OpenAPI specifications:
383
-
384
- ```bash
385
- # Using CLI
386
- pnpm gkm generate:react-query --input api-docs.json --output ./src/api
387
-
388
- # Programmatic usage
389
- import { generateReactQueryHooks } from '@geekmidas/client/openapi';
390
- import fs from 'fs/promises';
391
-
392
- const spec = JSON.parse(await fs.readFile('api-docs.json', 'utf-8'));
393
- const code = await generateReactQueryHooks(spec);
394
- await fs.writeFile('./src/api/generated.ts', code);
395
- ```
396
-
397
- Generated hooks example:
398
-
399
- ```typescript
400
- // Generated from OpenAPI spec
401
- export const api = createTypedQueryClient<{
402
- 'GET /users': {
403
- response: User[];
404
- };
405
- 'POST /users': {
406
- body: CreateUserRequest;
407
- response: User;
408
- };
409
- // ... all your endpoints
410
- }>({
411
- baseUrl: process.env.REACT_APP_API_URL
412
- });
413
-
414
- // Use generated hooks
415
- function MyComponent() {
416
- const { data: users } = api.useQuery('GET /users');
417
- const createUser = api.useMutation('POST /users');
418
-
419
- return (
420
- // Your component
421
- );
422
- }
423
- ```
402
+ Each surface's typed client is written by `gkm build` (and kept current by
403
+ `gkm dev`) to `.gkm/openapi/<surface>.ts`: its `createApi()` returns a typed
404
+ fetcher with React Query hooks, built from the endpoints themselves rather
405
+ than from a spec file.
424
406
 
425
407
  ## Advanced Features
426
408
 
@@ -433,14 +415,14 @@ Type-safe cache invalidation:
433
415
  await api.invalidateQueries('GET /users');
434
416
 
435
417
  // Invalidate with params
436
- await api.invalidateQueries('GET /users/:id', {
418
+ await api.invalidateQueries('GET /users/{id}', {
437
419
  params: { id: '123' }
438
420
  });
439
421
 
440
422
  // Invalidate multiple queries
441
423
  await Promise.all([
442
424
  api.invalidateQueries('GET /users'),
443
- api.invalidateQueries('GET /users/:id')
425
+ api.invalidateQueries('GET /users/{id}')
444
426
  ]);
445
427
  ```
446
428
 
@@ -449,20 +431,20 @@ await Promise.all([
449
431
  Implement optimistic UI updates:
450
432
 
451
433
  ```typescript
452
- const updateUser = api.useMutation('PUT /users/:id', {
434
+ const updateUser = api.useMutation('PUT /users/{id}', {
453
435
  onMutate: async (variables) => {
454
436
  // Cancel outgoing refetches
455
- await api.cancelQueries('GET /users/:id', {
437
+ await api.cancelQueries('GET /users/{id}', {
456
438
  params: { id: variables.params.id }
457
439
  });
458
440
 
459
441
  // Snapshot previous value
460
- const previousUser = api.getQueryData('GET /users/:id', {
442
+ const previousUser = api.getQueryData('GET /users/{id}', {
461
443
  params: { id: variables.params.id }
462
444
  });
463
445
 
464
446
  // Optimistically update
465
- api.setQueryData('GET /users/:id', {
447
+ api.setQueryData('GET /users/{id}', {
466
448
  params: { id: variables.params.id }
467
449
  }, variables.body);
468
450
 
@@ -471,14 +453,14 @@ const updateUser = api.useMutation('PUT /users/:id', {
471
453
  onError: (err, variables, context) => {
472
454
  // Rollback on error
473
455
  if (context?.previousUser) {
474
- api.setQueryData('GET /users/:id', {
456
+ api.setQueryData('GET /users/{id}', {
475
457
  params: { id: variables.params.id }
476
458
  }, context.previousUser);
477
459
  }
478
460
  },
479
461
  onSettled: (data, error, variables) => {
480
462
  // Refetch after mutation
481
- api.invalidateQueries('GET /users/:id', {
463
+ api.invalidateQueries('GET /users/{id}', {
482
464
  params: { id: variables.params.id }
483
465
  });
484
466
  }
@@ -499,7 +481,7 @@ const api = createTypedFetcher<API>({
499
481
  });
500
482
 
501
483
  // Per-request headers
502
- const user = await api('GET /users/:id', {
484
+ const user = await api('GET /users/{id}', {
503
485
  params: { id: '123' },
504
486
  headers: {
505
487
  'X-Request-ID': requestId
@@ -515,7 +497,7 @@ Handle errors with full type safety:
515
497
  import { HttpError } from '@geekmidas/errors';
516
498
 
517
499
  try {
518
- const user = await api('GET /users/:id', {
500
+ const user = await api('GET /users/{id}', {
519
501
  params: { id: '123' }
520
502
  });
521
503
  } catch (error) {
@@ -575,7 +557,7 @@ function UsersList() {
575
557
 
576
558
  const handleUserHover = (userId: string) => {
577
559
  // Prefetch user details on hover
578
- api.prefetchQuery('GET /users/:id', {
560
+ api.prefetchQuery('GET /users/{id}', {
579
561
  params: { id: userId }
580
562
  });
581
563
  };
@@ -1,4 +1,79 @@
1
- require('./fetcher-CwnSqc4D.cjs');
2
- const require_auth_fetcher = require('./auth-fetcher-HILABmws.cjs');
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_methods = require("./methods.cjs");
3
+ const require_fetcher = require("./fetcher.cjs");
4
+ //#region src/auth-fetcher.ts
5
+ /**
6
+ * Creates an auth-aware fetcher that automatically applies the correct
7
+ * authentication based on the endpoint being called.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { endpointAuth, securitySchemes, paths } from './openapi';
12
+ * import { TokenClient } from '@geekmidas/auth/client';
13
+ *
14
+ * const tokenClient = new TokenClient({ ... });
15
+ *
16
+ * const api = createAuthAwareFetcher<paths>({
17
+ * baseURL: 'https://api.example.com',
18
+ * endpointAuth,
19
+ * securitySchemes,
20
+ * authStrategies: {
21
+ * bearer: { type: 'bearer', tokenProvider: tokenClient },
22
+ * iam: { type: 'iam', signer: awsSigner },
23
+ * },
24
+ * });
25
+ *
26
+ * // Bearer auth automatically applied
27
+ * const user = await api('GET /users/{id}', { params: { id: '123' } });
28
+ *
29
+ * // IAM SigV4 auth automatically applied
30
+ * const tenant = await api('POST /tenants', { body: { name: 'Acme' } });
31
+ * ```
32
+ */
33
+ function createAuthAwareFetcher(options) {
34
+ const { endpointAuth, securitySchemes, authStrategies, onRequest: userOnRequest, ...fetcherOptions } = options;
35
+ const baseFetcher = new require_fetcher.TypedFetcher({
36
+ ...fetcherOptions,
37
+ onRequest: userOnRequest
38
+ });
39
+ const fetcher = async (endpoint, config) => {
40
+ const schemeName = endpointAuth[endpoint];
41
+ let authHeaders = {};
42
+ if (schemeName) {
43
+ const scheme = securitySchemes[schemeName];
44
+ const strategy = authStrategies[schemeName];
45
+ if (strategy && scheme) authHeaders = await resolveAuthHeaders(strategy, scheme);
46
+ }
47
+ const existingHeaders = config && "headers" in config && config.headers ? config.headers : {};
48
+ const mergedConfig = {
49
+ ...config,
50
+ headers: {
51
+ ...authHeaders,
52
+ ...existingHeaders
53
+ }
54
+ };
55
+ return baseFetcher.request(endpoint, mergedConfig);
56
+ };
57
+ const api = fetcher;
58
+ return Object.assign(api, require_methods.methodCalls(api));
59
+ }
60
+ /**
61
+ * Resolves auth headers based on the strategy and scheme.
62
+ */
63
+ async function resolveAuthHeaders(strategy, scheme) {
64
+ switch (strategy.type) {
65
+ case "bearer": return strategy.tokenProvider.createValidAuthHeaders();
66
+ case "apiKey": {
67
+ const apiKey = await strategy.apiKeyProvider.getApiKey();
68
+ const headerName = strategy.headerName || scheme.name || "X-API-Key";
69
+ if (scheme.in === "header" || !scheme.in) return { [headerName]: apiKey };
70
+ return {};
71
+ }
72
+ case "iam": return {};
73
+ default: return {};
74
+ }
75
+ }
76
+ //#endregion
77
+ exports.createAuthAwareFetcher = createAuthAwareFetcher;
3
78
 
4
- exports.createAuthAwareFetcher = require_auth_fetcher.createAuthAwareFetcher;
79
+ //# sourceMappingURL=auth-fetcher.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-fetcher.cjs","names":["TypedFetcher","methodCalls"],"sources":["../src/auth-fetcher.ts"],"sourcesContent":["import { TypedFetcher } from './fetcher';\nimport { methodCalls } from './methods';\nimport type {\n\tExtractEndpointResponse,\n\tFetcherOptions,\n\tFilteredRequestConfig,\n\tTypedApiFunction,\n\tTypedEndpoint,\n} from './types';\n\nexport type { FetcherOptions } from './types';\n\n/**\n * Security scheme object matching OpenAPI 3.1 specification.\n */\nexport interface SecuritySchemeObject {\n\ttype: 'apiKey' | 'http' | 'mutualTLS' | 'oauth2' | 'openIdConnect';\n\tdescription?: string;\n\tname?: string;\n\tin?: 'query' | 'header' | 'cookie';\n\tscheme?: string;\n\tbearerFormat?: string;\n\tflows?: Record<string, unknown>;\n\topenIdConnectUrl?: string;\n\t[key: string]: unknown;\n}\n\n/**\n * Extract all non-null security scheme IDs that are actually used in the API.\n * This gives us the union of scheme names that endpoints require.\n */\nexport type UsedSecuritySchemes<\n\tEndpointAuth extends Record<string, string | null>,\n> = NonNullable<EndpointAuth[keyof EndpointAuth]>;\n\n/**\n * Interface for token storage and retrieval.\n * Compatible with @geekmidas/auth TokenClient.\n */\nexport interface TokenProvider {\n\t/**\n\t * Get a valid access token, refreshing if necessary.\n\t */\n\tgetValidAccessToken(): Promise<string | null>;\n\n\t/**\n\t * Create Authorization headers from the current token.\n\t */\n\tcreateValidAuthHeaders(): Promise<Record<string, string>>;\n}\n\n/**\n * Interface for API key providers.\n */\nexport interface ApiKeyProvider {\n\t/**\n\t * Get the API key value.\n\t */\n\tgetApiKey(): Promise<string> | string;\n}\n\n/**\n * Interface for AWS SigV4 request signing.\n */\nexport interface AwsSigner {\n\t/**\n\t * Sign a request with AWS SigV4.\n\t * @param url - The request URL\n\t * @param init - The request init object\n\t * @returns Headers to add to the request\n\t */\n\tsign(url: string, init: RequestInit): Promise<Record<string, string>>;\n}\n\n/**\n * Auth strategy configuration for a specific security scheme type.\n */\nexport type AuthStrategy =\n\t| { type: 'bearer'; tokenProvider: TokenProvider }\n\t| { type: 'apiKey'; apiKeyProvider: ApiKeyProvider; headerName?: string }\n\t| { type: 'iam'; signer: AwsSigner }\n\t| { type: 'none' };\n\n/**\n * Options for creating an auth-aware fetcher.\n *\n * @template EndpointAuth - Map of endpoint strings to their auth scheme (or null for public)\n * @template SecuritySchemes - Available security scheme definitions\n */\nexport interface AuthFetcherOptions<\n\tEndpointAuth extends Record<string, string | null>,\n\tSecuritySchemes extends Record<string, SecuritySchemeObject>,\n> extends Omit<FetcherOptions, 'onRequest'> {\n\t/**\n\t * Runtime map of endpoints to their required auth scheme.\n\t * Generated by `gkm openapi --ts`.\n\t */\n\tendpointAuth: EndpointAuth;\n\n\t/**\n\t * Security scheme definitions.\n\t * Generated by `gkm openapi --ts`.\n\t */\n\tsecuritySchemes: SecuritySchemes;\n\n\t/**\n\t * Auth strategies for security schemes that are actually used.\n\t * Only schemes referenced in endpointAuth are required.\n\t *\n\t * @example\n\t * ```typescript\n\t * // If endpointAuth has: { 'GET /users': 'jwt', 'POST /data': 'iam', 'GET /public': null }\n\t * // Then authStrategies must include strategies for 'jwt' and 'iam'\n\t * authStrategies: {\n\t * jwt: { type: 'bearer', tokenProvider },\n\t * iam: { type: 'iam', signer: awsSigner },\n\t * }\n\t * ```\n\t */\n\tauthStrategies: Record<UsedSecuritySchemes<EndpointAuth>, AuthStrategy>;\n\n\t/**\n\t * Optional request interceptor (runs after auth headers are added).\n\t */\n\tonRequest?: (config: RequestInit) => RequestInit | Promise<RequestInit>;\n}\n\n/**\n * Creates an auth-aware fetcher that automatically applies the correct\n * authentication based on the endpoint being called.\n *\n * @example\n * ```typescript\n * import { endpointAuth, securitySchemes, paths } from './openapi';\n * import { TokenClient } from '@geekmidas/auth/client';\n *\n * const tokenClient = new TokenClient({ ... });\n *\n * const api = createAuthAwareFetcher<paths>({\n * baseURL: 'https://api.example.com',\n * endpointAuth,\n * securitySchemes,\n * authStrategies: {\n * bearer: { type: 'bearer', tokenProvider: tokenClient },\n * iam: { type: 'iam', signer: awsSigner },\n * },\n * });\n *\n * // Bearer auth automatically applied\n * const user = await api('GET /users/{id}', { params: { id: '123' } });\n *\n * // IAM SigV4 auth automatically applied\n * const tenant = await api('POST /tenants', { body: { name: 'Acme' } });\n * ```\n */\nexport function createAuthAwareFetcher<\n\tPaths,\n\tEndpointAuth extends Record<string, string | null> = Record<\n\t\tstring,\n\t\tstring | null\n\t>,\n\tSecuritySchemes extends Record<string, SecuritySchemeObject> = Record<\n\t\tstring,\n\t\tSecuritySchemeObject\n\t>,\n>(\n\toptions: AuthFetcherOptions<EndpointAuth, SecuritySchemes> & {\n\t\tbaseURL: string;\n\t},\n): TypedApiFunction<Paths> {\n\tconst {\n\t\tendpointAuth,\n\t\tsecuritySchemes,\n\t\tauthStrategies,\n\t\tonRequest: userOnRequest,\n\t\t...fetcherOptions\n\t} = options;\n\n\t// Create base fetcher with user's onRequest if provided\n\tconst baseFetcher = new TypedFetcher<Paths>({\n\t\t...fetcherOptions,\n\t\tonRequest: userOnRequest,\n\t});\n\n\tconst fetcher = async <T extends TypedEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\tconfig?: FilteredRequestConfig<Paths, T>,\n\t): Promise<ExtractEndpointResponse<Paths, T>> => {\n\t\t// Look up auth requirement for this endpoint\n\t\tconst schemeName = endpointAuth[endpoint as keyof EndpointAuth] as\n\t\t\t| string\n\t\t\t| null;\n\n\t\tlet authHeaders: Record<string, string> = {};\n\n\t\tif (schemeName) {\n\t\t\tconst scheme = securitySchemes[schemeName as keyof SecuritySchemes];\n\t\t\t// Since authStrategies is now required to have all used schemes,\n\t\t\t// we can safely access it - TypeScript ensures the strategy exists\n\t\t\tconst strategy =\n\t\t\t\tauthStrategies[schemeName as UsedSecuritySchemes<EndpointAuth>];\n\n\t\t\tif (strategy && scheme) {\n\t\t\t\tauthHeaders = await resolveAuthHeaders(strategy, scheme);\n\t\t\t}\n\t\t}\n\n\t\t// Merge auth headers with config headers\n\t\tconst existingHeaders =\n\t\t\tconfig && 'headers' in config && config.headers\n\t\t\t\t? (config.headers as Record<string, string>)\n\t\t\t\t: {};\n\n\t\tconst mergedConfig = {\n\t\t\t...config,\n\t\t\theaders: {\n\t\t\t\t...authHeaders,\n\t\t\t\t...existingHeaders,\n\t\t\t},\n\t\t} as unknown as FilteredRequestConfig<Paths, T>;\n\n\t\treturn baseFetcher.request(endpoint, mergedConfig);\n\t};\n\n\tconst api = fetcher as TypedApiFunction<Paths>;\n\treturn Object.assign(api, methodCalls<Paths>(api));\n}\n\n/**\n * Resolves auth headers based on the strategy and scheme.\n */\nasync function resolveAuthHeaders(\n\tstrategy: AuthStrategy,\n\tscheme: SecuritySchemeObject,\n): Promise<Record<string, string>> {\n\tswitch (strategy.type) {\n\t\tcase 'bearer': {\n\t\t\treturn strategy.tokenProvider.createValidAuthHeaders();\n\t\t}\n\n\t\tcase 'apiKey': {\n\t\t\tconst apiKey = await strategy.apiKeyProvider.getApiKey();\n\t\t\tconst headerName = strategy.headerName || scheme.name || 'X-API-Key';\n\n\t\t\tif (scheme.in === 'header' || !scheme.in) {\n\t\t\t\treturn { [headerName]: apiKey };\n\t\t\t}\n\t\t\t// Note: query and cookie API keys are handled differently\n\t\t\t// For now, we only support header-based API keys\n\t\t\treturn {};\n\t\t}\n\n\t\tcase 'iam': {\n\t\t\t// IAM signing requires the full URL and request config\n\t\t\t// This is a simplified version - full implementation would need\n\t\t\t// access to the complete request\n\t\t\t// For now, return empty - the actual signing should be done\n\t\t\t// in a custom onRequest interceptor if needed\n\t\t\treturn {};\n\t\t}\n\t\tdefault:\n\t\t\treturn {};\n\t}\n}\n\n/**\n * Type helper to extract the security scheme ID from an endpoint.\n */\nexport type GetEndpointAuth<\n\tEndpointAuth extends Record<string, string | null>,\n\tEndpoint extends keyof EndpointAuth,\n> = EndpointAuth[Endpoint];\n\n/**\n * Type helper to get all authenticated endpoints.\n */\nexport type AuthenticatedEndpoints<\n\tEndpointAuth extends Record<string, string | null>,\n> = {\n\t[K in keyof EndpointAuth]: EndpointAuth[K] extends null ? never : K;\n}[keyof EndpointAuth];\n\n/**\n * Type helper to get all public endpoints.\n */\nexport type PublicEndpoints<\n\tEndpointAuth extends Record<string, string | null>,\n> = {\n\t[K in keyof EndpointAuth]: EndpointAuth[K] extends null ? K : never;\n}[keyof EndpointAuth];\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2JA,SAAgB,uBAWf,SAG0B;CAC1B,MAAM,EACL,cACA,iBACA,gBACA,WAAW,eACX,GAAG,mBACA;CAGJ,MAAM,cAAc,IAAIA,gBAAAA,aAAoB;EAC3C,GAAG;EACH,WAAW;CACZ,CAAC;CAED,MAAM,UAAU,OACf,UACA,WACgD;EAEhD,MAAM,aAAa,aAAa;EAIhC,IAAI,cAAsC,CAAC;EAE3C,IAAI,YAAY;GACf,MAAM,SAAS,gBAAgB;GAG/B,MAAM,WACL,eAAe;GAEhB,IAAI,YAAY,QACf,cAAc,MAAM,mBAAmB,UAAU,MAAM;EAEzD;EAGA,MAAM,kBACL,UAAU,aAAa,UAAU,OAAO,UACpC,OAAO,UACR,CAAC;EAEL,MAAM,eAAe;GACpB,GAAG;GACH,SAAS;IACR,GAAG;IACH,GAAG;GACJ;EACD;EAEA,OAAO,YAAY,QAAQ,UAAU,YAAY;CAClD;CAEA,MAAM,MAAM;CACZ,OAAO,OAAO,OAAO,KAAKC,gBAAAA,YAAmB,GAAG,CAAC;AAClD;;;;AAKA,eAAe,mBACd,UACA,QACkC;CAClC,QAAQ,SAAS,MAAjB;EACC,KAAK,UACJ,OAAO,SAAS,cAAc,uBAAuB;EAGtD,KAAK,UAAU;GACd,MAAM,SAAS,MAAM,SAAS,eAAe,UAAU;GACvD,MAAM,aAAa,SAAS,cAAc,OAAO,QAAQ;GAEzD,IAAI,OAAO,OAAO,YAAY,CAAC,OAAO,IACrC,OAAO,GAAG,aAAa,OAAO;GAI/B,OAAO,CAAC;EACT;EAEA,KAAK,OAMJ,OAAO,CAAC;EAET,SACC,OAAO,CAAC;CACV;AACD"}
@@ -1,3 +1,155 @@
1
- import { FetcherOptions } from "./types-DMQMHePI.cjs";
2
- import { ApiKeyProvider, AuthFetcherOptions, AuthStrategy, AuthenticatedEndpoints, AwsSigner, GetEndpointAuth, PublicEndpoints, SecuritySchemeObject, TokenProvider, UsedSecuritySchemes, createAuthAwareFetcher } from "./auth-fetcher-CBYuL6rx.cjs";
3
- export { ApiKeyProvider, AuthFetcherOptions, AuthStrategy, AuthenticatedEndpoints, AwsSigner, FetcherOptions, GetEndpointAuth, PublicEndpoints, SecuritySchemeObject, TokenProvider, UsedSecuritySchemes, createAuthAwareFetcher };
1
+ import { FetcherOptions, TypedApiFunction } from "./types.cjs";
2
+ //#region src/auth-fetcher.d.ts
3
+ /**
4
+ * Security scheme object matching OpenAPI 3.1 specification.
5
+ */
6
+ export interface SecuritySchemeObject {
7
+ type: 'apiKey' | 'http' | 'mutualTLS' | 'oauth2' | 'openIdConnect';
8
+ description?: string;
9
+ name?: string;
10
+ in?: 'query' | 'header' | 'cookie';
11
+ scheme?: string;
12
+ bearerFormat?: string;
13
+ flows?: Record<string, unknown>;
14
+ openIdConnectUrl?: string;
15
+ [key: string]: unknown;
16
+ }
17
+ /**
18
+ * Extract all non-null security scheme IDs that are actually used in the API.
19
+ * This gives us the union of scheme names that endpoints require.
20
+ */
21
+ export type UsedSecuritySchemes<EndpointAuth extends Record<string, string | null>> = NonNullable<EndpointAuth[keyof EndpointAuth]>;
22
+ /**
23
+ * Interface for token storage and retrieval.
24
+ * Compatible with @geekmidas/auth TokenClient.
25
+ */
26
+ export interface TokenProvider {
27
+ /**
28
+ * Get a valid access token, refreshing if necessary.
29
+ */
30
+ getValidAccessToken(): Promise<string | null>;
31
+ /**
32
+ * Create Authorization headers from the current token.
33
+ */
34
+ createValidAuthHeaders(): Promise<Record<string, string>>;
35
+ }
36
+ /**
37
+ * Interface for API key providers.
38
+ */
39
+ export interface ApiKeyProvider {
40
+ /**
41
+ * Get the API key value.
42
+ */
43
+ getApiKey(): Promise<string> | string;
44
+ }
45
+ /**
46
+ * Interface for AWS SigV4 request signing.
47
+ */
48
+ export interface AwsSigner {
49
+ /**
50
+ * Sign a request with AWS SigV4.
51
+ * @param url - The request URL
52
+ * @param init - The request init object
53
+ * @returns Headers to add to the request
54
+ */
55
+ sign(url: string, init: RequestInit): Promise<Record<string, string>>;
56
+ }
57
+ /**
58
+ * Auth strategy configuration for a specific security scheme type.
59
+ */
60
+ export type AuthStrategy = {
61
+ type: 'bearer';
62
+ tokenProvider: TokenProvider;
63
+ } | {
64
+ type: 'apiKey';
65
+ apiKeyProvider: ApiKeyProvider;
66
+ headerName?: string;
67
+ } | {
68
+ type: 'iam';
69
+ signer: AwsSigner;
70
+ } | {
71
+ type: 'none';
72
+ };
73
+ /**
74
+ * Options for creating an auth-aware fetcher.
75
+ *
76
+ * @template EndpointAuth - Map of endpoint strings to their auth scheme (or null for public)
77
+ * @template SecuritySchemes - Available security scheme definitions
78
+ */
79
+ export interface AuthFetcherOptions<EndpointAuth extends Record<string, string | null>, SecuritySchemes extends Record<string, SecuritySchemeObject>> extends Omit<FetcherOptions, 'onRequest'> {
80
+ /**
81
+ * Runtime map of endpoints to their required auth scheme.
82
+ * Generated by `gkm openapi --ts`.
83
+ */
84
+ endpointAuth: EndpointAuth;
85
+ /**
86
+ * Security scheme definitions.
87
+ * Generated by `gkm openapi --ts`.
88
+ */
89
+ securitySchemes: SecuritySchemes;
90
+ /**
91
+ * Auth strategies for security schemes that are actually used.
92
+ * Only schemes referenced in endpointAuth are required.
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * // If endpointAuth has: { 'GET /users': 'jwt', 'POST /data': 'iam', 'GET /public': null }
97
+ * // Then authStrategies must include strategies for 'jwt' and 'iam'
98
+ * authStrategies: {
99
+ * jwt: { type: 'bearer', tokenProvider },
100
+ * iam: { type: 'iam', signer: awsSigner },
101
+ * }
102
+ * ```
103
+ */
104
+ authStrategies: Record<UsedSecuritySchemes<EndpointAuth>, AuthStrategy>;
105
+ /**
106
+ * Optional request interceptor (runs after auth headers are added).
107
+ */
108
+ onRequest?: (config: RequestInit) => RequestInit | Promise<RequestInit>;
109
+ }
110
+ /**
111
+ * Creates an auth-aware fetcher that automatically applies the correct
112
+ * authentication based on the endpoint being called.
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * import { endpointAuth, securitySchemes, paths } from './openapi';
117
+ * import { TokenClient } from '@geekmidas/auth/client';
118
+ *
119
+ * const tokenClient = new TokenClient({ ... });
120
+ *
121
+ * const api = createAuthAwareFetcher<paths>({
122
+ * baseURL: 'https://api.example.com',
123
+ * endpointAuth,
124
+ * securitySchemes,
125
+ * authStrategies: {
126
+ * bearer: { type: 'bearer', tokenProvider: tokenClient },
127
+ * iam: { type: 'iam', signer: awsSigner },
128
+ * },
129
+ * });
130
+ *
131
+ * // Bearer auth automatically applied
132
+ * const user = await api('GET /users/{id}', { params: { id: '123' } });
133
+ *
134
+ * // IAM SigV4 auth automatically applied
135
+ * const tenant = await api('POST /tenants', { body: { name: 'Acme' } });
136
+ * ```
137
+ */
138
+ export declare function createAuthAwareFetcher<Paths, EndpointAuth extends Record<string, string | null> = Record<string, string | null>, SecuritySchemes extends Record<string, SecuritySchemeObject> = Record<string, SecuritySchemeObject>>(options: AuthFetcherOptions<EndpointAuth, SecuritySchemes> & {
139
+ baseURL: string;
140
+ }): TypedApiFunction<Paths>;
141
+ /**
142
+ * Type helper to extract the security scheme ID from an endpoint.
143
+ */
144
+ export type GetEndpointAuth<EndpointAuth extends Record<string, string | null>, Endpoint extends keyof EndpointAuth> = EndpointAuth[Endpoint];
145
+ /**
146
+ * Type helper to get all authenticated endpoints.
147
+ */
148
+ export type AuthenticatedEndpoints<EndpointAuth extends Record<string, string | null>> = { [K in keyof EndpointAuth]: EndpointAuth[K] extends null ? never : K; }[keyof EndpointAuth];
149
+ /**
150
+ * Type helper to get all public endpoints.
151
+ */
152
+ export type PublicEndpoints<EndpointAuth extends Record<string, string | null>> = { [K in keyof EndpointAuth]: EndpointAuth[K] extends null ? K : never; }[keyof EndpointAuth];
153
+ //#endregion
154
+ export type { FetcherOptions };
155
+ //# sourceMappingURL=auth-fetcher.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-fetcher.d.cts","names":[],"sources":["../src/auth-fetcher.ts"],"mappings":";;;;;iBAeiB;EAChB;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR;GACC;;;;;;YAOU,oBACX,qBAAqB,iCAClB,YAAY,mBAAmB;;;;;iBAMlB;;;;EAIhB,uBAAuB;;;;EAKvB,0BAA0B,QAAQ;;;;;iBAMlB;;;;EAIhB,aAAa;;;;;iBAMG;;;;;;;EAOhB,KAAK,aAAa,MAAM,cAAc,QAAQ;;;;;YAMnC;EACP;EAAgB,eAAe;;EAC/B;EAAgB,gBAAgB;EAAgB;;EAChD;EAAa,QAAQ;;EACrB;;;;;;;;iBAQY,mBAChB,qBAAqB,+BACrB,wBAAwB,eAAe,+BAC9B,KAAK;;;;;EAKd,cAAc;;;;;EAMd,iBAAiB;;;;;;;;;;;;;;;EAgBjB,gBAAgB,OAAO,oBAAoB,eAAe;;;;EAK1D,aAAa,QAAQ,gBAAgB,cAAc,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA+B5C,uBACf,OACA,qBAAqB,gCAAgC,+BAIrD,wBAAwB,eAAe,wBAAwB,eAE9D,uBAGD,SAAS,mBAAmB,cAAc;EACzC;IAEC,iBAAiB;;;;YAmGR,gBACX,qBAAqB,+BACrB,uBAAuB,gBACpB,aAAa;;;;YAKL,uBACX,qBAAqB,oCAEpB,WAAW,eAAe,aAAa,0BAA0B,WAC3D;;;;YAKI,gBACX,qBAAqB,oCAEpB,WAAW,eAAe,aAAa,kBAAkB,mBACnD"}
@@ -1,3 +1,155 @@
1
- import { FetcherOptions } from "./types-BMGM6sZc.mjs";
2
- import { ApiKeyProvider, AuthFetcherOptions, AuthStrategy, AuthenticatedEndpoints, AwsSigner, GetEndpointAuth, PublicEndpoints, SecuritySchemeObject, TokenProvider, UsedSecuritySchemes, createAuthAwareFetcher } from "./auth-fetcher-DxS8zOLc.mjs";
3
- export { ApiKeyProvider, AuthFetcherOptions, AuthStrategy, AuthenticatedEndpoints, AwsSigner, FetcherOptions, GetEndpointAuth, PublicEndpoints, SecuritySchemeObject, TokenProvider, UsedSecuritySchemes, createAuthAwareFetcher };
1
+ import { FetcherOptions, TypedApiFunction } from "./types.mjs";
2
+ //#region src/auth-fetcher.d.ts
3
+ /**
4
+ * Security scheme object matching OpenAPI 3.1 specification.
5
+ */
6
+ export interface SecuritySchemeObject {
7
+ type: 'apiKey' | 'http' | 'mutualTLS' | 'oauth2' | 'openIdConnect';
8
+ description?: string;
9
+ name?: string;
10
+ in?: 'query' | 'header' | 'cookie';
11
+ scheme?: string;
12
+ bearerFormat?: string;
13
+ flows?: Record<string, unknown>;
14
+ openIdConnectUrl?: string;
15
+ [key: string]: unknown;
16
+ }
17
+ /**
18
+ * Extract all non-null security scheme IDs that are actually used in the API.
19
+ * This gives us the union of scheme names that endpoints require.
20
+ */
21
+ export type UsedSecuritySchemes<EndpointAuth extends Record<string, string | null>> = NonNullable<EndpointAuth[keyof EndpointAuth]>;
22
+ /**
23
+ * Interface for token storage and retrieval.
24
+ * Compatible with @geekmidas/auth TokenClient.
25
+ */
26
+ export interface TokenProvider {
27
+ /**
28
+ * Get a valid access token, refreshing if necessary.
29
+ */
30
+ getValidAccessToken(): Promise<string | null>;
31
+ /**
32
+ * Create Authorization headers from the current token.
33
+ */
34
+ createValidAuthHeaders(): Promise<Record<string, string>>;
35
+ }
36
+ /**
37
+ * Interface for API key providers.
38
+ */
39
+ export interface ApiKeyProvider {
40
+ /**
41
+ * Get the API key value.
42
+ */
43
+ getApiKey(): Promise<string> | string;
44
+ }
45
+ /**
46
+ * Interface for AWS SigV4 request signing.
47
+ */
48
+ export interface AwsSigner {
49
+ /**
50
+ * Sign a request with AWS SigV4.
51
+ * @param url - The request URL
52
+ * @param init - The request init object
53
+ * @returns Headers to add to the request
54
+ */
55
+ sign(url: string, init: RequestInit): Promise<Record<string, string>>;
56
+ }
57
+ /**
58
+ * Auth strategy configuration for a specific security scheme type.
59
+ */
60
+ export type AuthStrategy = {
61
+ type: 'bearer';
62
+ tokenProvider: TokenProvider;
63
+ } | {
64
+ type: 'apiKey';
65
+ apiKeyProvider: ApiKeyProvider;
66
+ headerName?: string;
67
+ } | {
68
+ type: 'iam';
69
+ signer: AwsSigner;
70
+ } | {
71
+ type: 'none';
72
+ };
73
+ /**
74
+ * Options for creating an auth-aware fetcher.
75
+ *
76
+ * @template EndpointAuth - Map of endpoint strings to their auth scheme (or null for public)
77
+ * @template SecuritySchemes - Available security scheme definitions
78
+ */
79
+ export interface AuthFetcherOptions<EndpointAuth extends Record<string, string | null>, SecuritySchemes extends Record<string, SecuritySchemeObject>> extends Omit<FetcherOptions, 'onRequest'> {
80
+ /**
81
+ * Runtime map of endpoints to their required auth scheme.
82
+ * Generated by `gkm openapi --ts`.
83
+ */
84
+ endpointAuth: EndpointAuth;
85
+ /**
86
+ * Security scheme definitions.
87
+ * Generated by `gkm openapi --ts`.
88
+ */
89
+ securitySchemes: SecuritySchemes;
90
+ /**
91
+ * Auth strategies for security schemes that are actually used.
92
+ * Only schemes referenced in endpointAuth are required.
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * // If endpointAuth has: { 'GET /users': 'jwt', 'POST /data': 'iam', 'GET /public': null }
97
+ * // Then authStrategies must include strategies for 'jwt' and 'iam'
98
+ * authStrategies: {
99
+ * jwt: { type: 'bearer', tokenProvider },
100
+ * iam: { type: 'iam', signer: awsSigner },
101
+ * }
102
+ * ```
103
+ */
104
+ authStrategies: Record<UsedSecuritySchemes<EndpointAuth>, AuthStrategy>;
105
+ /**
106
+ * Optional request interceptor (runs after auth headers are added).
107
+ */
108
+ onRequest?: (config: RequestInit) => RequestInit | Promise<RequestInit>;
109
+ }
110
+ /**
111
+ * Creates an auth-aware fetcher that automatically applies the correct
112
+ * authentication based on the endpoint being called.
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * import { endpointAuth, securitySchemes, paths } from './openapi';
117
+ * import { TokenClient } from '@geekmidas/auth/client';
118
+ *
119
+ * const tokenClient = new TokenClient({ ... });
120
+ *
121
+ * const api = createAuthAwareFetcher<paths>({
122
+ * baseURL: 'https://api.example.com',
123
+ * endpointAuth,
124
+ * securitySchemes,
125
+ * authStrategies: {
126
+ * bearer: { type: 'bearer', tokenProvider: tokenClient },
127
+ * iam: { type: 'iam', signer: awsSigner },
128
+ * },
129
+ * });
130
+ *
131
+ * // Bearer auth automatically applied
132
+ * const user = await api('GET /users/{id}', { params: { id: '123' } });
133
+ *
134
+ * // IAM SigV4 auth automatically applied
135
+ * const tenant = await api('POST /tenants', { body: { name: 'Acme' } });
136
+ * ```
137
+ */
138
+ export declare function createAuthAwareFetcher<Paths, EndpointAuth extends Record<string, string | null> = Record<string, string | null>, SecuritySchemes extends Record<string, SecuritySchemeObject> = Record<string, SecuritySchemeObject>>(options: AuthFetcherOptions<EndpointAuth, SecuritySchemes> & {
139
+ baseURL: string;
140
+ }): TypedApiFunction<Paths>;
141
+ /**
142
+ * Type helper to extract the security scheme ID from an endpoint.
143
+ */
144
+ export type GetEndpointAuth<EndpointAuth extends Record<string, string | null>, Endpoint extends keyof EndpointAuth> = EndpointAuth[Endpoint];
145
+ /**
146
+ * Type helper to get all authenticated endpoints.
147
+ */
148
+ export type AuthenticatedEndpoints<EndpointAuth extends Record<string, string | null>> = { [K in keyof EndpointAuth]: EndpointAuth[K] extends null ? never : K; }[keyof EndpointAuth];
149
+ /**
150
+ * Type helper to get all public endpoints.
151
+ */
152
+ export type PublicEndpoints<EndpointAuth extends Record<string, string | null>> = { [K in keyof EndpointAuth]: EndpointAuth[K] extends null ? K : never; }[keyof EndpointAuth];
153
+ //#endregion
154
+ export type { FetcherOptions };
155
+ //# sourceMappingURL=auth-fetcher.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-fetcher.d.mts","names":[],"sources":["../src/auth-fetcher.ts"],"mappings":";;;;;iBAeiB;EAChB;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR;GACC;;;;;;YAOU,oBACX,qBAAqB,iCAClB,YAAY,mBAAmB;;;;;iBAMlB;;;;EAIhB,uBAAuB;;;;EAKvB,0BAA0B,QAAQ;;;;;iBAMlB;;;;EAIhB,aAAa;;;;;iBAMG;;;;;;;EAOhB,KAAK,aAAa,MAAM,cAAc,QAAQ;;;;;YAMnC;EACP;EAAgB,eAAe;;EAC/B;EAAgB,gBAAgB;EAAgB;;EAChD;EAAa,QAAQ;;EACrB;;;;;;;;iBAQY,mBAChB,qBAAqB,+BACrB,wBAAwB,eAAe,+BAC9B,KAAK;;;;;EAKd,cAAc;;;;;EAMd,iBAAiB;;;;;;;;;;;;;;;EAgBjB,gBAAgB,OAAO,oBAAoB,eAAe;;;;EAK1D,aAAa,QAAQ,gBAAgB,cAAc,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA+B5C,uBACf,OACA,qBAAqB,gCAAgC,+BAIrD,wBAAwB,eAAe,wBAAwB,eAE9D,uBAGD,SAAS,mBAAmB,cAAc;EACzC;IAEC,iBAAiB;;;;YAmGR,gBACX,qBAAqB,+BACrB,uBAAuB,gBACpB,aAAa;;;;YAKL,uBACX,qBAAqB,oCAEpB,WAAW,eAAe,aAAa,0BAA0B,WAC3D;;;;YAKI,gBACX,qBAAqB,oCAEpB,WAAW,eAAe,aAAa,kBAAkB,mBACnD"}