@geekmidas/client 0.0.1 → 0.1.1

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.
package/README.md CHANGED
@@ -31,14 +31,20 @@ pnpm add @geekmidas/client @tanstack/react-query
31
31
  // Type-safe fetcher
32
32
  import { createTypedFetcher } from '@geekmidas/client';
33
33
 
34
- // React Query client
34
+ // Auth-aware fetcher with security schemes
35
+ import { createAuthAwareFetcher } from '@geekmidas/client/auth-fetcher';
36
+
37
+ // React Query hooks (endpoint-string based)
38
+ import { createEndpointHooks } from '@geekmidas/client/endpoint-hooks';
39
+
40
+ // React Query client (class-based)
35
41
  import { createTypedQueryClient } from '@geekmidas/client/react-query';
36
42
 
37
43
  // OpenAPI hooks generation
38
44
  import { generateReactQueryHooks } from '@geekmidas/client/openapi';
39
45
 
40
46
  // Type utilities
41
- import type { TypedFetcherOptions } from '@geekmidas/client/types';
47
+ import type { TypedApiFunction, FilteredRequestConfig } from '@geekmidas/client/types';
42
48
  ```
43
49
 
44
50
  ## Quick Start
@@ -226,6 +232,151 @@ function InfiniteUsersList() {
226
232
  }
227
233
  ```
228
234
 
235
+ ## Generated API Client (Recommended)
236
+
237
+ When using `@geekmidas/cli` to generate OpenAPI types, you get a fully configured `createApi` factory:
238
+
239
+ ```typescript
240
+ // Generated by: gkm openapi --output ./src/api.ts
241
+ import { createApi } from './api';
242
+
243
+ // Create API client with authentication
244
+ const api = createApi({
245
+ baseURL: 'https://api.example.com',
246
+ authStrategies: {
247
+ // Only strategies for schemes actually used in your API are required
248
+ jwt: {
249
+ type: 'bearer',
250
+ tokenProvider: async () => localStorage.getItem('token'),
251
+ },
252
+ },
253
+ });
254
+
255
+ // Imperative fetching - callable directly
256
+ const user = await api('GET /users/{id}', { params: { id: '123' } });
257
+
258
+ // React Query hooks - available as properties
259
+ function UserProfile({ id }: { id: string }) {
260
+ // Config is required when endpoint has path params
261
+ const { data, isLoading } = api.useQuery('GET /users/{id}', {
262
+ params: { id }
263
+ });
264
+
265
+ if (isLoading) return <div>Loading...</div>;
266
+ return <div>{data.name}</div>;
267
+ }
268
+
269
+ // Mutations
270
+ function CreateUser() {
271
+ const mutation = api.useMutation('POST /users');
272
+
273
+ return (
274
+ <button onClick={() => mutation.mutate({
275
+ body: { name: 'John', email: 'john@example.com' }
276
+ })}>
277
+ Create User
278
+ </button>
279
+ );
280
+ }
281
+ ```
282
+
283
+ ### Type-Safe Config Requirements
284
+
285
+ The generated client enforces config requirements at the type level:
286
+
287
+ ```typescript
288
+ // ✅ GET /health - no params, no body → config optional
289
+ await api('GET /health');
290
+
291
+ // ❌ GET /users/{id} - has params → config required
292
+ await api('GET /users/{id}'); // Type error!
293
+
294
+ // ✅ GET /users/{id} - with required params
295
+ await api('GET /users/{id}', { params: { id: '123' } });
296
+
297
+ // ❌ POST /users - has body → config required
298
+ await api('POST /users'); // Type error!
299
+
300
+ // ✅ POST /users - with required body
301
+ await api('POST /users', { body: { name: 'John', email: 'john@example.com' } });
302
+ ```
303
+
304
+ ### Authentication Strategies
305
+
306
+ The `authStrategies` option maps security scheme IDs to authentication handlers:
307
+
308
+ ```typescript
309
+ const api = createApi({
310
+ baseURL: 'https://api.example.com',
311
+ authStrategies: {
312
+ // Bearer token (JWT)
313
+ jwt: {
314
+ type: 'bearer',
315
+ tokenProvider: async () => getAccessToken(),
316
+ },
317
+
318
+ // API Key in header
319
+ apiKey: {
320
+ type: 'apiKey',
321
+ tokenProvider: async () => process.env.API_KEY,
322
+ },
323
+
324
+ // Custom authentication
325
+ custom: {
326
+ type: 'custom',
327
+ applyAuth: async (headers) => {
328
+ headers.set('X-Custom-Auth', await getCustomToken());
329
+ },
330
+ },
331
+ },
332
+ });
333
+ ```
334
+
335
+ ## Auth-Aware Fetcher
336
+
337
+ For manual setup without code generation, use `createAuthAwareFetcher`:
338
+
339
+ ```typescript
340
+ import { createAuthAwareFetcher } from '@geekmidas/client/auth-fetcher';
341
+ import { createEndpointHooks } from '@geekmidas/client/endpoint-hooks';
342
+ import type { paths } from './openapi-types';
343
+
344
+ // Define which endpoints use which auth
345
+ const endpointAuth = {
346
+ 'GET /users': 'jwt',
347
+ 'POST /users': 'jwt',
348
+ 'GET /health': null, // Public endpoint
349
+ } as const;
350
+
351
+ // Define security schemes
352
+ const securitySchemes = {
353
+ jwt: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT' },
354
+ } as const;
355
+
356
+ // Create auth-aware fetcher
357
+ const fetcher = createAuthAwareFetcher<
358
+ paths,
359
+ typeof endpointAuth,
360
+ typeof securitySchemes
361
+ >({
362
+ baseURL: 'https://api.example.com',
363
+ endpointAuth,
364
+ securitySchemes,
365
+ authStrategies: {
366
+ jwt: {
367
+ type: 'bearer',
368
+ tokenProvider: async () => localStorage.getItem('token'),
369
+ },
370
+ },
371
+ });
372
+
373
+ // Add React Query hooks
374
+ const hooks = createEndpointHooks<paths>(fetcher);
375
+
376
+ // Combine into single API object
377
+ const api = Object.assign(fetcher, hooks);
378
+ ```
379
+
229
380
  ## OpenAPI Code Generation
230
381
 
231
382
  Generate React Query hooks from OpenAPI specifications:
@@ -0,0 +1,78 @@
1
+ const require_fetcher = require('./fetcher-KdwHgdAl.cjs');
2
+
3
+ //#region src/auth-fetcher.ts
4
+ /**
5
+ * Creates an auth-aware fetcher that automatically applies the correct
6
+ * authentication based on the endpoint being called.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { endpointAuth, securitySchemes, paths } from './openapi';
11
+ * import { TokenClient } from '@geekmidas/auth/client';
12
+ *
13
+ * const tokenClient = new TokenClient({ ... });
14
+ *
15
+ * const api = createAuthAwareFetcher<paths>({
16
+ * baseURL: 'https://api.example.com',
17
+ * endpointAuth,
18
+ * securitySchemes,
19
+ * authStrategies: {
20
+ * bearer: { type: 'bearer', tokenProvider: tokenClient },
21
+ * iam: { type: 'iam', signer: awsSigner },
22
+ * },
23
+ * });
24
+ *
25
+ * // Bearer auth automatically applied
26
+ * const user = await api('GET /users/{id}', { params: { id: '123' } });
27
+ *
28
+ * // IAM SigV4 auth automatically applied
29
+ * const tenant = await api('POST /tenants', { body: { name: 'Acme' } });
30
+ * ```
31
+ */
32
+ function createAuthAwareFetcher(options) {
33
+ const { endpointAuth, securitySchemes, authStrategies, onRequest: userOnRequest,...fetcherOptions } = options;
34
+ const baseFetcher = new require_fetcher.TypedFetcher({
35
+ ...fetcherOptions,
36
+ onRequest: userOnRequest
37
+ });
38
+ const fetcher = async (endpoint, config) => {
39
+ const schemeName = endpointAuth[endpoint];
40
+ let authHeaders = {};
41
+ if (schemeName) {
42
+ const scheme = securitySchemes[schemeName];
43
+ const strategy = authStrategies[schemeName];
44
+ if (strategy) authHeaders = await resolveAuthHeaders(strategy, scheme);
45
+ }
46
+ const existingHeaders = config && "headers" in config && config.headers ? config.headers : {};
47
+ const mergedConfig = {
48
+ ...config,
49
+ headers: {
50
+ ...authHeaders,
51
+ ...existingHeaders
52
+ }
53
+ };
54
+ return baseFetcher.request(endpoint, mergedConfig);
55
+ };
56
+ return fetcher;
57
+ }
58
+ /**
59
+ * Resolves auth headers based on the strategy and scheme.
60
+ */
61
+ async function resolveAuthHeaders(strategy, scheme) {
62
+ switch (strategy.type) {
63
+ case "bearer": return strategy.tokenProvider.createValidAuthHeaders();
64
+ case "apiKey": {
65
+ const apiKey = await strategy.apiKeyProvider.getApiKey();
66
+ const headerName = strategy.headerName || scheme.name || "X-API-Key";
67
+ if (scheme.in === "header" || !scheme.in) return { [headerName]: apiKey };
68
+ return {};
69
+ }
70
+ case "iam": return {};
71
+ case "none":
72
+ default: return {};
73
+ }
74
+ }
75
+
76
+ //#endregion
77
+ exports.createAuthAwareFetcher = createAuthAwareFetcher;
78
+ //# sourceMappingURL=auth-fetcher.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-fetcher.cjs","names":["options: AuthFetcherOptions<EndpointAuth, SecuritySchemes> & {\n baseURL: string;\n }","TypedFetcher","endpoint: T","config?: FilteredRequestConfig<Paths, T>","authHeaders: Record<string, string>","strategy: AuthStrategy","scheme: SecuritySchemeObject"],"sources":["../src/auth-fetcher.ts"],"sourcesContent":["import { TypedFetcher } from './fetcher';\nimport type {\n ExtractEndpointResponse,\n FetcherOptions,\n FilteredRequestConfig,\n TypedApiFunction,\n TypedEndpoint,\n} from './types';\n\n/**\n * Security scheme object matching OpenAPI 3.1 specification.\n */\nexport interface SecuritySchemeObject {\n type: 'apiKey' | 'http' | 'mutualTLS' | 'oauth2' | 'openIdConnect';\n description?: string;\n name?: string;\n in?: 'query' | 'header' | 'cookie';\n scheme?: string;\n bearerFormat?: string;\n flows?: Record<string, unknown>;\n openIdConnectUrl?: string;\n [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 EndpointAuth 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 /**\n * Get a valid access token, refreshing if necessary.\n */\n getValidAccessToken(): Promise<string | null>;\n\n /**\n * Create Authorization headers from the current token.\n */\n createValidAuthHeaders(): Promise<Record<string, string>>;\n}\n\n/**\n * Interface for API key providers.\n */\nexport interface ApiKeyProvider {\n /**\n * Get the API key value.\n */\n getApiKey(): Promise<string> | string;\n}\n\n/**\n * Interface for AWS SigV4 request signing.\n */\nexport interface AwsSigner {\n /**\n * Sign a request with AWS SigV4.\n * @param url - The request URL\n * @param init - The request init object\n * @returns Headers to add to the request\n */\n sign(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 | { type: 'bearer'; tokenProvider: TokenProvider }\n | { type: 'apiKey'; apiKeyProvider: ApiKeyProvider; headerName?: string }\n | { type: 'iam'; signer: AwsSigner }\n | { 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 EndpointAuth extends Record<string, string | null>,\n SecuritySchemes extends Record<string, SecuritySchemeObject>,\n> extends Omit<FetcherOptions, 'onRequest'> {\n /**\n * Runtime map of endpoints to their required auth scheme.\n * Generated by `gkm openapi --ts`.\n */\n endpointAuth: EndpointAuth;\n\n /**\n * Security scheme definitions.\n * Generated by `gkm openapi --ts`.\n */\n securitySchemes: SecuritySchemes;\n\n /**\n * Auth strategies for security schemes that are actually used.\n * Only schemes referenced in endpointAuth are required.\n *\n * @example\n * ```typescript\n * // If endpointAuth has: { 'GET /users': 'jwt', 'POST /data': 'iam', 'GET /public': null }\n * // Then authStrategies must include strategies for 'jwt' and 'iam'\n * authStrategies: {\n * jwt: { type: 'bearer', tokenProvider },\n * iam: { type: 'iam', signer: awsSigner },\n * }\n * ```\n */\n authStrategies: Record<UsedSecuritySchemes<EndpointAuth>, AuthStrategy>;\n\n /**\n * Optional request interceptor (runs after auth headers are added).\n */\n onRequest?: (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 Paths,\n EndpointAuth extends Record<string, string | null> = Record<\n string,\n string | null\n >,\n SecuritySchemes extends Record<string, SecuritySchemeObject> = Record<\n string,\n SecuritySchemeObject\n >,\n>(\n options: AuthFetcherOptions<EndpointAuth, SecuritySchemes> & {\n baseURL: string;\n },\n): TypedApiFunction<Paths> {\n const {\n endpointAuth,\n securitySchemes,\n authStrategies,\n onRequest: userOnRequest,\n ...fetcherOptions\n } = options;\n\n // Create base fetcher with user's onRequest if provided\n const baseFetcher = new TypedFetcher<Paths>({\n ...fetcherOptions,\n onRequest: userOnRequest,\n });\n\n const fetcher = async <T extends TypedEndpoint<Paths>>(\n endpoint: T,\n config?: FilteredRequestConfig<Paths, T>,\n ): Promise<ExtractEndpointResponse<Paths, T>> => {\n // Look up auth requirement for this endpoint\n const schemeName = endpointAuth[endpoint as keyof EndpointAuth] as\n | string\n | null;\n\n let authHeaders: Record<string, string> = {};\n\n if (schemeName) {\n const scheme = securitySchemes[schemeName as keyof SecuritySchemes];\n // Since authStrategies is now required to have all used schemes,\n // we can safely access it - TypeScript ensures the strategy exists\n const strategy =\n authStrategies[schemeName as UsedSecuritySchemes<EndpointAuth>];\n\n if (strategy) {\n authHeaders = await resolveAuthHeaders(strategy, scheme);\n }\n }\n\n // Merge auth headers with config headers\n const existingHeaders =\n config && 'headers' in config && config.headers\n ? (config.headers as Record<string, string>)\n : {};\n\n const mergedConfig = {\n ...config,\n headers: {\n ...authHeaders,\n ...existingHeaders,\n },\n } as unknown as FilteredRequestConfig<Paths, T>;\n\n return baseFetcher.request(endpoint, mergedConfig);\n };\n\n return fetcher as TypedApiFunction<Paths>;\n}\n\n/**\n * Resolves auth headers based on the strategy and scheme.\n */\nasync function resolveAuthHeaders(\n strategy: AuthStrategy,\n scheme: SecuritySchemeObject,\n): Promise<Record<string, string>> {\n switch (strategy.type) {\n case 'bearer': {\n return strategy.tokenProvider.createValidAuthHeaders();\n }\n\n case 'apiKey': {\n const apiKey = await strategy.apiKeyProvider.getApiKey();\n const headerName = strategy.headerName || scheme.name || 'X-API-Key';\n\n if (scheme.in === 'header' || !scheme.in) {\n return { [headerName]: apiKey };\n }\n // Note: query and cookie API keys are handled differently\n // For now, we only support header-based API keys\n return {};\n }\n\n case 'iam': {\n // IAM signing requires the full URL and request config\n // This is a simplified version - full implementation would need\n // access to the complete request\n // For now, return empty - the actual signing should be done\n // in a custom onRequest interceptor if needed\n return {};\n }\n\n case 'none':\n default:\n return {};\n }\n}\n\n/**\n * Type helper to extract the security scheme ID from an endpoint.\n */\nexport type GetEndpointAuth<\n EndpointAuth extends Record<string, string | null>,\n Endpoint extends keyof EndpointAuth,\n> = EndpointAuth[Endpoint];\n\n/**\n * Type helper to get all authenticated endpoints.\n */\nexport type AuthenticatedEndpoints<\n EndpointAuth extends Record<string, string | null>,\n> = {\n [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 EndpointAuth extends Record<string, string | null>,\n> = {\n [K in keyof EndpointAuth]: EndpointAuth[K] extends null ? K : never;\n}[keyof EndpointAuth];\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwJA,SAAgB,uBAWdA,SAGyB;CACzB,MAAM,EACJ,cACA,iBACA,gBACA,WAAW,cACX,GAAG,gBACJ,GAAG;CAGJ,MAAM,cAAc,IAAIC,6BAAoB;EAC1C,GAAG;EACH,WAAW;CACZ;CAED,MAAM,UAAU,OACdC,UACAC,WAC+C;EAE/C,MAAM,aAAa,aAAa;EAIhC,IAAIC,cAAsC,CAAE;AAE5C,MAAI,YAAY;GACd,MAAM,SAAS,gBAAgB;GAG/B,MAAM,WACJ,eAAe;AAEjB,OAAI,SACF,eAAc,MAAM,mBAAmB,UAAU,OAAO;EAE3D;EAGD,MAAM,kBACJ,UAAU,aAAa,UAAU,OAAO,UACnC,OAAO,UACR,CAAE;EAER,MAAM,eAAe;GACnB,GAAG;GACH,SAAS;IACP,GAAG;IACH,GAAG;GACJ;EACF;AAED,SAAO,YAAY,QAAQ,UAAU,aAAa;CACnD;AAED,QAAO;AACR;;;;AAKD,eAAe,mBACbC,UACAC,QACiC;AACjC,SAAQ,SAAS,MAAjB;EACE,KAAK,SACH,QAAO,SAAS,cAAc,wBAAwB;EAGxD,KAAK,UAAU;GACb,MAAM,SAAS,MAAM,SAAS,eAAe,WAAW;GACxD,MAAM,aAAa,SAAS,cAAc,OAAO,QAAQ;AAEzD,OAAI,OAAO,OAAO,aAAa,OAAO,GACpC,QAAO,GAAG,aAAa,OAAQ;AAIjC,UAAO,CAAE;EACV;EAED,KAAK,MAMH,QAAO,CAAE;EAGX,KAAK;EACL,QACE,QAAO,CAAE;CACZ;AACF"}
@@ -0,0 +1,157 @@
1
+ import { FetcherOptions, TypedApiFunction } from "./types-D4OSWveN.cjs";
2
+
3
+ //#region src/auth-fetcher.d.ts
4
+
5
+ /**
6
+ * Security scheme object matching OpenAPI 3.1 specification.
7
+ */
8
+ interface SecuritySchemeObject {
9
+ type: 'apiKey' | 'http' | 'mutualTLS' | 'oauth2' | 'openIdConnect';
10
+ description?: string;
11
+ name?: string;
12
+ in?: 'query' | 'header' | 'cookie';
13
+ scheme?: string;
14
+ bearerFormat?: string;
15
+ flows?: Record<string, unknown>;
16
+ openIdConnectUrl?: string;
17
+ [key: string]: unknown;
18
+ }
19
+ /**
20
+ * Extract all non-null security scheme IDs that are actually used in the API.
21
+ * This gives us the union of scheme names that endpoints require.
22
+ */
23
+ type UsedSecuritySchemes<EndpointAuth extends Record<string, string | null>> = NonNullable<EndpointAuth[keyof EndpointAuth]>;
24
+ /**
25
+ * Interface for token storage and retrieval.
26
+ * Compatible with @geekmidas/auth TokenClient.
27
+ */
28
+ interface TokenProvider {
29
+ /**
30
+ * Get a valid access token, refreshing if necessary.
31
+ */
32
+ getValidAccessToken(): Promise<string | null>;
33
+ /**
34
+ * Create Authorization headers from the current token.
35
+ */
36
+ createValidAuthHeaders(): Promise<Record<string, string>>;
37
+ }
38
+ /**
39
+ * Interface for API key providers.
40
+ */
41
+ interface ApiKeyProvider {
42
+ /**
43
+ * Get the API key value.
44
+ */
45
+ getApiKey(): Promise<string> | string;
46
+ }
47
+ /**
48
+ * Interface for AWS SigV4 request signing.
49
+ */
50
+ interface AwsSigner {
51
+ /**
52
+ * Sign a request with AWS SigV4.
53
+ * @param url - The request URL
54
+ * @param init - The request init object
55
+ * @returns Headers to add to the request
56
+ */
57
+ sign(url: string, init: RequestInit): Promise<Record<string, string>>;
58
+ }
59
+ /**
60
+ * Auth strategy configuration for a specific security scheme type.
61
+ */
62
+ type AuthStrategy = {
63
+ type: 'bearer';
64
+ tokenProvider: TokenProvider;
65
+ } | {
66
+ type: 'apiKey';
67
+ apiKeyProvider: ApiKeyProvider;
68
+ headerName?: string;
69
+ } | {
70
+ type: 'iam';
71
+ signer: AwsSigner;
72
+ } | {
73
+ type: 'none';
74
+ };
75
+ /**
76
+ * Options for creating an auth-aware fetcher.
77
+ *
78
+ * @template EndpointAuth - Map of endpoint strings to their auth scheme (or null for public)
79
+ * @template SecuritySchemes - Available security scheme definitions
80
+ */
81
+ interface AuthFetcherOptions<EndpointAuth extends Record<string, string | null>, SecuritySchemes extends Record<string, SecuritySchemeObject>> extends Omit<FetcherOptions, 'onRequest'> {
82
+ /**
83
+ * Runtime map of endpoints to their required auth scheme.
84
+ * Generated by `gkm openapi --ts`.
85
+ */
86
+ endpointAuth: EndpointAuth;
87
+ /**
88
+ * Security scheme definitions.
89
+ * Generated by `gkm openapi --ts`.
90
+ */
91
+ securitySchemes: SecuritySchemes;
92
+ /**
93
+ * Auth strategies for security schemes that are actually used.
94
+ * Only schemes referenced in endpointAuth are required.
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * // If endpointAuth has: { 'GET /users': 'jwt', 'POST /data': 'iam', 'GET /public': null }
99
+ * // Then authStrategies must include strategies for 'jwt' and 'iam'
100
+ * authStrategies: {
101
+ * jwt: { type: 'bearer', tokenProvider },
102
+ * iam: { type: 'iam', signer: awsSigner },
103
+ * }
104
+ * ```
105
+ */
106
+ authStrategies: Record<UsedSecuritySchemes<EndpointAuth>, AuthStrategy>;
107
+ /**
108
+ * Optional request interceptor (runs after auth headers are added).
109
+ */
110
+ onRequest?: (config: RequestInit) => RequestInit | Promise<RequestInit>;
111
+ }
112
+ /**
113
+ * Creates an auth-aware fetcher that automatically applies the correct
114
+ * authentication based on the endpoint being called.
115
+ *
116
+ * @example
117
+ * ```typescript
118
+ * import { endpointAuth, securitySchemes, paths } from './openapi';
119
+ * import { TokenClient } from '@geekmidas/auth/client';
120
+ *
121
+ * const tokenClient = new TokenClient({ ... });
122
+ *
123
+ * const api = createAuthAwareFetcher<paths>({
124
+ * baseURL: 'https://api.example.com',
125
+ * endpointAuth,
126
+ * securitySchemes,
127
+ * authStrategies: {
128
+ * bearer: { type: 'bearer', tokenProvider: tokenClient },
129
+ * iam: { type: 'iam', signer: awsSigner },
130
+ * },
131
+ * });
132
+ *
133
+ * // Bearer auth automatically applied
134
+ * const user = await api('GET /users/{id}', { params: { id: '123' } });
135
+ *
136
+ * // IAM SigV4 auth automatically applied
137
+ * const tenant = await api('POST /tenants', { body: { name: 'Acme' } });
138
+ * ```
139
+ */
140
+ 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> & {
141
+ baseURL: string;
142
+ }): TypedApiFunction<Paths>;
143
+ /**
144
+ * Type helper to extract the security scheme ID from an endpoint.
145
+ */
146
+ type GetEndpointAuth<EndpointAuth extends Record<string, string | null>, Endpoint extends keyof EndpointAuth> = EndpointAuth[Endpoint];
147
+ /**
148
+ * Type helper to get all authenticated endpoints.
149
+ */
150
+ type AuthenticatedEndpoints<EndpointAuth extends Record<string, string | null>> = { [K in keyof EndpointAuth]: EndpointAuth[K] extends null ? never : K }[keyof EndpointAuth];
151
+ /**
152
+ * Type helper to get all public endpoints.
153
+ */
154
+ type PublicEndpoints<EndpointAuth extends Record<string, string | null>> = { [K in keyof EndpointAuth]: EndpointAuth[K] extends null ? K : never }[keyof EndpointAuth];
155
+ //#endregion
156
+ export { ApiKeyProvider, AuthFetcherOptions, AuthStrategy, AuthenticatedEndpoints, AwsSigner, GetEndpointAuth, PublicEndpoints, SecuritySchemeObject, TokenProvider, UsedSecuritySchemes, createAuthAwareFetcher };
157
+ //# sourceMappingURL=auth-fetcher.d.cts.map
@@ -0,0 +1,157 @@
1
+ import { FetcherOptions, TypedApiFunction } from "./types-Cdv1XAWr.mjs";
2
+
3
+ //#region src/auth-fetcher.d.ts
4
+
5
+ /**
6
+ * Security scheme object matching OpenAPI 3.1 specification.
7
+ */
8
+ interface SecuritySchemeObject {
9
+ type: 'apiKey' | 'http' | 'mutualTLS' | 'oauth2' | 'openIdConnect';
10
+ description?: string;
11
+ name?: string;
12
+ in?: 'query' | 'header' | 'cookie';
13
+ scheme?: string;
14
+ bearerFormat?: string;
15
+ flows?: Record<string, unknown>;
16
+ openIdConnectUrl?: string;
17
+ [key: string]: unknown;
18
+ }
19
+ /**
20
+ * Extract all non-null security scheme IDs that are actually used in the API.
21
+ * This gives us the union of scheme names that endpoints require.
22
+ */
23
+ type UsedSecuritySchemes<EndpointAuth extends Record<string, string | null>> = NonNullable<EndpointAuth[keyof EndpointAuth]>;
24
+ /**
25
+ * Interface for token storage and retrieval.
26
+ * Compatible with @geekmidas/auth TokenClient.
27
+ */
28
+ interface TokenProvider {
29
+ /**
30
+ * Get a valid access token, refreshing if necessary.
31
+ */
32
+ getValidAccessToken(): Promise<string | null>;
33
+ /**
34
+ * Create Authorization headers from the current token.
35
+ */
36
+ createValidAuthHeaders(): Promise<Record<string, string>>;
37
+ }
38
+ /**
39
+ * Interface for API key providers.
40
+ */
41
+ interface ApiKeyProvider {
42
+ /**
43
+ * Get the API key value.
44
+ */
45
+ getApiKey(): Promise<string> | string;
46
+ }
47
+ /**
48
+ * Interface for AWS SigV4 request signing.
49
+ */
50
+ interface AwsSigner {
51
+ /**
52
+ * Sign a request with AWS SigV4.
53
+ * @param url - The request URL
54
+ * @param init - The request init object
55
+ * @returns Headers to add to the request
56
+ */
57
+ sign(url: string, init: RequestInit): Promise<Record<string, string>>;
58
+ }
59
+ /**
60
+ * Auth strategy configuration for a specific security scheme type.
61
+ */
62
+ type AuthStrategy = {
63
+ type: 'bearer';
64
+ tokenProvider: TokenProvider;
65
+ } | {
66
+ type: 'apiKey';
67
+ apiKeyProvider: ApiKeyProvider;
68
+ headerName?: string;
69
+ } | {
70
+ type: 'iam';
71
+ signer: AwsSigner;
72
+ } | {
73
+ type: 'none';
74
+ };
75
+ /**
76
+ * Options for creating an auth-aware fetcher.
77
+ *
78
+ * @template EndpointAuth - Map of endpoint strings to their auth scheme (or null for public)
79
+ * @template SecuritySchemes - Available security scheme definitions
80
+ */
81
+ interface AuthFetcherOptions<EndpointAuth extends Record<string, string | null>, SecuritySchemes extends Record<string, SecuritySchemeObject>> extends Omit<FetcherOptions, 'onRequest'> {
82
+ /**
83
+ * Runtime map of endpoints to their required auth scheme.
84
+ * Generated by `gkm openapi --ts`.
85
+ */
86
+ endpointAuth: EndpointAuth;
87
+ /**
88
+ * Security scheme definitions.
89
+ * Generated by `gkm openapi --ts`.
90
+ */
91
+ securitySchemes: SecuritySchemes;
92
+ /**
93
+ * Auth strategies for security schemes that are actually used.
94
+ * Only schemes referenced in endpointAuth are required.
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * // If endpointAuth has: { 'GET /users': 'jwt', 'POST /data': 'iam', 'GET /public': null }
99
+ * // Then authStrategies must include strategies for 'jwt' and 'iam'
100
+ * authStrategies: {
101
+ * jwt: { type: 'bearer', tokenProvider },
102
+ * iam: { type: 'iam', signer: awsSigner },
103
+ * }
104
+ * ```
105
+ */
106
+ authStrategies: Record<UsedSecuritySchemes<EndpointAuth>, AuthStrategy>;
107
+ /**
108
+ * Optional request interceptor (runs after auth headers are added).
109
+ */
110
+ onRequest?: (config: RequestInit) => RequestInit | Promise<RequestInit>;
111
+ }
112
+ /**
113
+ * Creates an auth-aware fetcher that automatically applies the correct
114
+ * authentication based on the endpoint being called.
115
+ *
116
+ * @example
117
+ * ```typescript
118
+ * import { endpointAuth, securitySchemes, paths } from './openapi';
119
+ * import { TokenClient } from '@geekmidas/auth/client';
120
+ *
121
+ * const tokenClient = new TokenClient({ ... });
122
+ *
123
+ * const api = createAuthAwareFetcher<paths>({
124
+ * baseURL: 'https://api.example.com',
125
+ * endpointAuth,
126
+ * securitySchemes,
127
+ * authStrategies: {
128
+ * bearer: { type: 'bearer', tokenProvider: tokenClient },
129
+ * iam: { type: 'iam', signer: awsSigner },
130
+ * },
131
+ * });
132
+ *
133
+ * // Bearer auth automatically applied
134
+ * const user = await api('GET /users/{id}', { params: { id: '123' } });
135
+ *
136
+ * // IAM SigV4 auth automatically applied
137
+ * const tenant = await api('POST /tenants', { body: { name: 'Acme' } });
138
+ * ```
139
+ */
140
+ 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> & {
141
+ baseURL: string;
142
+ }): TypedApiFunction<Paths>;
143
+ /**
144
+ * Type helper to extract the security scheme ID from an endpoint.
145
+ */
146
+ type GetEndpointAuth<EndpointAuth extends Record<string, string | null>, Endpoint extends keyof EndpointAuth> = EndpointAuth[Endpoint];
147
+ /**
148
+ * Type helper to get all authenticated endpoints.
149
+ */
150
+ type AuthenticatedEndpoints<EndpointAuth extends Record<string, string | null>> = { [K in keyof EndpointAuth]: EndpointAuth[K] extends null ? never : K }[keyof EndpointAuth];
151
+ /**
152
+ * Type helper to get all public endpoints.
153
+ */
154
+ type PublicEndpoints<EndpointAuth extends Record<string, string | null>> = { [K in keyof EndpointAuth]: EndpointAuth[K] extends null ? K : never }[keyof EndpointAuth];
155
+ //#endregion
156
+ export { ApiKeyProvider, AuthFetcherOptions, AuthStrategy, AuthenticatedEndpoints, AwsSigner, GetEndpointAuth, PublicEndpoints, SecuritySchemeObject, TokenProvider, UsedSecuritySchemes, createAuthAwareFetcher };
157
+ //# sourceMappingURL=auth-fetcher.d.mts.map
@@ -0,0 +1,78 @@
1
+ import { TypedFetcher } from "./fetcher-DLDD_7Sa.mjs";
2
+
3
+ //#region src/auth-fetcher.ts
4
+ /**
5
+ * Creates an auth-aware fetcher that automatically applies the correct
6
+ * authentication based on the endpoint being called.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { endpointAuth, securitySchemes, paths } from './openapi';
11
+ * import { TokenClient } from '@geekmidas/auth/client';
12
+ *
13
+ * const tokenClient = new TokenClient({ ... });
14
+ *
15
+ * const api = createAuthAwareFetcher<paths>({
16
+ * baseURL: 'https://api.example.com',
17
+ * endpointAuth,
18
+ * securitySchemes,
19
+ * authStrategies: {
20
+ * bearer: { type: 'bearer', tokenProvider: tokenClient },
21
+ * iam: { type: 'iam', signer: awsSigner },
22
+ * },
23
+ * });
24
+ *
25
+ * // Bearer auth automatically applied
26
+ * const user = await api('GET /users/{id}', { params: { id: '123' } });
27
+ *
28
+ * // IAM SigV4 auth automatically applied
29
+ * const tenant = await api('POST /tenants', { body: { name: 'Acme' } });
30
+ * ```
31
+ */
32
+ function createAuthAwareFetcher(options) {
33
+ const { endpointAuth, securitySchemes, authStrategies, onRequest: userOnRequest,...fetcherOptions } = options;
34
+ const baseFetcher = new TypedFetcher({
35
+ ...fetcherOptions,
36
+ onRequest: userOnRequest
37
+ });
38
+ const fetcher = async (endpoint, config) => {
39
+ const schemeName = endpointAuth[endpoint];
40
+ let authHeaders = {};
41
+ if (schemeName) {
42
+ const scheme = securitySchemes[schemeName];
43
+ const strategy = authStrategies[schemeName];
44
+ if (strategy) authHeaders = await resolveAuthHeaders(strategy, scheme);
45
+ }
46
+ const existingHeaders = config && "headers" in config && config.headers ? config.headers : {};
47
+ const mergedConfig = {
48
+ ...config,
49
+ headers: {
50
+ ...authHeaders,
51
+ ...existingHeaders
52
+ }
53
+ };
54
+ return baseFetcher.request(endpoint, mergedConfig);
55
+ };
56
+ return fetcher;
57
+ }
58
+ /**
59
+ * Resolves auth headers based on the strategy and scheme.
60
+ */
61
+ async function resolveAuthHeaders(strategy, scheme) {
62
+ switch (strategy.type) {
63
+ case "bearer": return strategy.tokenProvider.createValidAuthHeaders();
64
+ case "apiKey": {
65
+ const apiKey = await strategy.apiKeyProvider.getApiKey();
66
+ const headerName = strategy.headerName || scheme.name || "X-API-Key";
67
+ if (scheme.in === "header" || !scheme.in) return { [headerName]: apiKey };
68
+ return {};
69
+ }
70
+ case "iam": return {};
71
+ case "none":
72
+ default: return {};
73
+ }
74
+ }
75
+
76
+ //#endregion
77
+ export { createAuthAwareFetcher };
78
+ //# sourceMappingURL=auth-fetcher.mjs.map