api-invoke 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1359 @@
1
+ /**
2
+ * Classified API errors with human/agent-readable suggestions.
3
+ * Each error has a `kind` for programmatic handling and `retryable` for retry logic.
4
+ */
5
+ /**
6
+ * Error classification constants. Use with {@link ApiInvokeError.kind} for programmatic error handling.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * if (error.kind === ErrorKind.RATE_LIMIT) {
11
+ * // Wait and retry
12
+ * }
13
+ * ```
14
+ */
15
+ declare const ErrorKind: {
16
+ readonly CORS: "cors";
17
+ readonly NETWORK: "network";
18
+ readonly AUTH: "auth";
19
+ readonly HTTP: "http";
20
+ readonly PARSE: "parse";
21
+ readonly RATE_LIMIT: "rate-limit";
22
+ readonly TIMEOUT: "timeout";
23
+ readonly GRAPHQL: "graphql";
24
+ };
25
+ type ErrorKind = (typeof ErrorKind)[keyof typeof ErrorKind];
26
+ /** Error name constant used on all ApiInvokeError instances. Useful for cross-realm `instanceof` checks. */
27
+ declare const API_INVOKE_ERROR_NAME: "ApiInvokeError";
28
+ /**
29
+ * Structured error thrown by api-invoke for all API failures.
30
+ * Includes a machine-readable `kind`, a human-readable `suggestion`, and a `retryable` flag.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * try {
35
+ * await client.execute('getUser', { userId: 123 })
36
+ * } catch (error) {
37
+ * if (error instanceof ApiInvokeError) {
38
+ * console.log(error.kind) // 'auth', 'network', 'rate-limit', etc.
39
+ * console.log(error.suggestion) // Human-readable recovery advice
40
+ * console.log(error.retryable) // Whether retrying might succeed
41
+ * }
42
+ * }
43
+ * ```
44
+ */
45
+ declare class ApiInvokeError extends Error {
46
+ /** Error classification for programmatic handling. */
47
+ readonly kind: ErrorKind | string;
48
+ /** HTTP status code, if the error originated from an HTTP response. */
49
+ readonly status?: number;
50
+ /** Human-readable suggestion for how to resolve this error. */
51
+ readonly suggestion: string;
52
+ /** Whether retrying the request might succeed (e.g. true for rate limits, network errors). */
53
+ readonly retryable: boolean;
54
+ /** Response body from the API (when available). May be parsed JSON, a string, or binary data depending on the response content type. */
55
+ readonly responseBody?: unknown;
56
+ constructor(opts: {
57
+ kind: ErrorKind | string;
58
+ message: string;
59
+ suggestion: string;
60
+ retryable?: boolean;
61
+ status?: number;
62
+ responseBody?: unknown;
63
+ });
64
+ }
65
+ /**
66
+ * Create a CORS error for when a browser request is blocked by the same-origin policy.
67
+ * @param url - The URL that was blocked
68
+ * @returns An `ApiInvokeError` with `kind: 'cors'` and `retryable: false`
69
+ */
70
+ declare function corsError(url: string): ApiInvokeError;
71
+ /**
72
+ * Create a network error for connection failures.
73
+ * @param url - The URL that failed to connect
74
+ * @returns An `ApiInvokeError` with `kind: 'network'` and `retryable: true`
75
+ */
76
+ declare function networkError(url: string): ApiInvokeError;
77
+ /**
78
+ * Create an authentication/authorization error (401 or 403).
79
+ * @param url - The URL that returned the error
80
+ * @param status - HTTP status code (401 or 403)
81
+ * @param responseBody - Parsed response body, if available
82
+ * @returns An `ApiInvokeError` with `kind: 'auth'` and `retryable: false`
83
+ */
84
+ declare function authError(url: string, status: 401 | 403, responseBody?: unknown): ApiInvokeError;
85
+ /**
86
+ * Create an HTTP error for non-2xx responses (excluding 401/403 which use {@link authError}).
87
+ * Status 429 is classified as `kind: 'rate-limit'`; all others as `kind: 'http'`.
88
+ * @param url - The URL that returned the error
89
+ * @param status - HTTP status code
90
+ * @param statusText - HTTP status text (e.g. 'Not Found')
91
+ * @param responseBody - Parsed response body, if available
92
+ * @returns An `ApiInvokeError` with `retryable: true` for 429 and 5xx status codes
93
+ */
94
+ declare function httpError(url: string, status: number, statusText: string, responseBody?: unknown): ApiInvokeError;
95
+ /**
96
+ * Create a parse error for when the response body cannot be read as the expected format.
97
+ * @param url - The URL that returned the unparseable response
98
+ * @param expectedType - The expected format (default: 'JSON')
99
+ * @returns An `ApiInvokeError` with `kind: 'parse'` and `retryable: false`
100
+ */
101
+ declare function parseError(url: string, expectedType?: string): ApiInvokeError;
102
+ /**
103
+ * Create a GraphQL error for when the response contains errors and no data (total failure).
104
+ * @param messages - Joined error messages from the GraphQL response
105
+ * @param status - HTTP status code (usually 200 for GraphQL)
106
+ * @param responseBody - Full GraphQL response body
107
+ * @returns An `ApiInvokeError` with `kind: 'graphql'` and `retryable: false`
108
+ */
109
+ declare function graphqlError(messages: string, status?: number, responseBody?: unknown): ApiInvokeError;
110
+ /**
111
+ * Create a timeout error for when a request exceeds the configured `timeoutMs`.
112
+ * @param url - The URL that timed out
113
+ * @returns An `ApiInvokeError` with `kind: 'timeout'` and `retryable: true`
114
+ */
115
+ declare function timeoutError(url: string): ApiInvokeError;
116
+
117
+ /**
118
+ * Core types for api-invoke.
119
+ * Spec-agnostic — these work with any API format (OpenAPI, GraphQL, raw URL, manual builder).
120
+ * All enums use `as const` objects for autocomplete + extensibility.
121
+ */
122
+
123
+ /** Standard HTTP methods supported by api-invoke. */
124
+ declare const HttpMethod: {
125
+ readonly GET: "GET";
126
+ readonly POST: "POST";
127
+ readonly PUT: "PUT";
128
+ readonly PATCH: "PATCH";
129
+ readonly DELETE: "DELETE";
130
+ readonly HEAD: "HEAD";
131
+ readonly OPTIONS: "OPTIONS";
132
+ };
133
+ type HttpMethod = (typeof HttpMethod)[keyof typeof HttpMethod];
134
+ /** Where a parameter is located in the HTTP request. */
135
+ declare const ParamLocation: {
136
+ readonly PATH: "path";
137
+ readonly QUERY: "query";
138
+ readonly HEADER: "header";
139
+ readonly COOKIE: "cookie";
140
+ };
141
+ type ParamLocation = (typeof ParamLocation)[keyof typeof ParamLocation];
142
+ /** Supported authentication types. */
143
+ declare const AuthType: {
144
+ readonly BEARER: "bearer";
145
+ readonly BASIC: "basic";
146
+ readonly API_KEY: "apiKey";
147
+ readonly QUERY_PARAM: "queryParam";
148
+ readonly OAUTH2: "oauth2";
149
+ readonly COOKIE: "cookie";
150
+ };
151
+ type AuthType = (typeof AuthType)[keyof typeof AuthType];
152
+ /** Detected API specification format. */
153
+ declare const SpecFormat: {
154
+ readonly OPENAPI_3: "openapi-3";
155
+ readonly OPENAPI_2: "openapi-2";
156
+ readonly RAW_URL: "raw-url";
157
+ readonly MANUAL: "manual";
158
+ readonly GRAPHQL: "graphql";
159
+ };
160
+ type SpecFormat = (typeof SpecFormat)[keyof typeof SpecFormat];
161
+ /** Well-known HTTP header names used internally. */
162
+ declare const HeaderName: {
163
+ readonly ACCEPT: "Accept";
164
+ readonly AUTHORIZATION: "Authorization";
165
+ readonly CONTENT_TYPE: "Content-Type";
166
+ readonly COOKIE: "Cookie";
167
+ };
168
+ type HeaderName = (typeof HeaderName)[keyof typeof HeaderName];
169
+ /**
170
+ * A parsed API specification, normalized into a spec-agnostic format.
171
+ * This is the central data model — all adapters (OpenAPI, GraphQL, raw URL, manual builder) produce this shape.
172
+ */
173
+ interface ParsedAPI {
174
+ /** Human-readable API title (e.g. 'Petstore API'). */
175
+ title: string;
176
+ /** API version string from the spec (e.g. '1.0.0'). */
177
+ version: string;
178
+ /** Base URL for all operations (e.g. 'https://api.example.com/v1'). */
179
+ baseUrl: string;
180
+ /** All available API operations extracted from the spec. */
181
+ operations: Operation[];
182
+ /** Authentication schemes declared in the spec. */
183
+ authSchemes: AuthScheme[];
184
+ /** Which adapter produced this ParsedAPI. */
185
+ specFormat: SpecFormat | string;
186
+ /** Raw spec version string from the spec (e.g. '3.0.3', '2.0'). Only set for OpenAPI specs. */
187
+ rawSpecVersion?: string;
188
+ }
189
+ /**
190
+ * A single API operation (endpoint + method).
191
+ * Produced by parsing a spec or using the manual builder.
192
+ */
193
+ interface Operation {
194
+ /** Unique identifier for this operation (e.g. 'listUsers', 'get_users'). */
195
+ id: string;
196
+ /** URL path template with placeholders (e.g. '/users/{userId}'). */
197
+ path: string;
198
+ /** HTTP method (e.g. 'GET', 'POST'). */
199
+ method: HttpMethod | string;
200
+ /** Short summary of what this operation does. */
201
+ summary?: string;
202
+ /** Longer description of the operation's behavior. */
203
+ description?: string;
204
+ /** Parameters accepted by this operation (path, query, header, cookie). */
205
+ parameters: Parameter[];
206
+ /** Request body definition, if the operation accepts one. */
207
+ requestBody?: RequestBody;
208
+ /** Primary response schema for the operation's success case. For OpenAPI specs, this is the first 2xx schema found (see parser for priority). Useful for code generation or validation. */
209
+ responseSchema?: unknown;
210
+ /** Success and default response schemas keyed by HTTP status code (e.g. '200', '201', 'default'). Codes without schemas (e.g. 204 No Content) are omitted. Error codes (4xx/5xx) are not extracted. */
211
+ responseSchemas?: Record<string, unknown>;
212
+ /** Primary response content type (e.g. 'application/json', 'application/xml'). Used as the default Accept header. */
213
+ responseContentType?: ContentType | string;
214
+ /** Error response descriptions keyed by HTTP status code (e.g. '404' → 'User not found'). Extracted from 4xx/5xx responses in the spec. */
215
+ errorHints?: Record<string, string>;
216
+ /** Tags for grouping operations (e.g. ['users', 'admin']). */
217
+ tags: string[];
218
+ /**
219
+ * Custom body builder for protocol adapters (e.g., GraphQL).
220
+ * When set and no explicit 'body' key is in args, the executor calls this instead of flat-arg assembly to construct the request body.
221
+ * Receives the full args map and returns the body data to be serialized.
222
+ */
223
+ buildBody?: (args: Record<string, unknown>) => unknown;
224
+ }
225
+ /**
226
+ * A parameter accepted by an API operation.
227
+ */
228
+ interface Parameter {
229
+ /** Parameter name as used in the request (e.g. 'userId', 'page'). */
230
+ name: string;
231
+ /** Where this parameter appears in the request. */
232
+ in: ParamLocation;
233
+ /** Whether this parameter must be provided. Path parameters are always required. */
234
+ required: boolean;
235
+ /** Human-readable description of the parameter. */
236
+ description: string;
237
+ /** Type and constraint information for this parameter. */
238
+ schema: ParameterSchema;
239
+ }
240
+ /**
241
+ * Type and constraint information for a parameter.
242
+ */
243
+ interface ParameterSchema {
244
+ /** Data type (e.g. 'string', 'integer', 'boolean', 'array'). */
245
+ type: string;
246
+ /** Format hint (e.g. 'int32', 'date-time', 'email', 'uuid'). */
247
+ format?: string;
248
+ /** Allowed values for this parameter. */
249
+ enum?: unknown[];
250
+ /** Default value used when the parameter is not provided. */
251
+ default?: unknown;
252
+ /** Example value for documentation and testing. */
253
+ example?: unknown;
254
+ /** Minimum value for numeric parameters. */
255
+ minimum?: number;
256
+ /** Maximum value for numeric parameters. */
257
+ maximum?: number;
258
+ /** Maximum length for string parameters. */
259
+ maxLength?: number;
260
+ /** Element schema for array parameters. */
261
+ items?: ParameterSchema;
262
+ }
263
+ /** Well-known MIME content types. */
264
+ declare const ContentType: {
265
+ readonly JSON: "application/json";
266
+ readonly FORM_URLENCODED: "application/x-www-form-urlencoded";
267
+ readonly MULTIPART: "multipart/form-data";
268
+ readonly XML: "application/xml";
269
+ readonly OCTET_STREAM: "application/octet-stream";
270
+ readonly TEXT: "text/plain";
271
+ readonly SSE: "text/event-stream";
272
+ };
273
+ type ContentType = (typeof ContentType)[keyof typeof ContentType];
274
+ /**
275
+ * Request body definition for an operation.
276
+ */
277
+ interface RequestBody {
278
+ /** Whether the request body is required for this operation. */
279
+ required: boolean;
280
+ /** Human-readable description of the request body. */
281
+ description?: string;
282
+ /** Content type for the request body (e.g. 'application/json'). */
283
+ contentType: ContentType | string;
284
+ /** Schema describing the request body structure. */
285
+ schema: RequestBodySchema;
286
+ }
287
+ /**
288
+ * Schema for a request body, with flattened top-level properties for easy access.
289
+ */
290
+ interface RequestBodySchema {
291
+ /** Top-level type (usually 'object'). */
292
+ type: string;
293
+ /** Original unprocessed schema from the spec. Useful for advanced use cases like code generation. */
294
+ raw: unknown;
295
+ /** Flattened top-level properties, keyed by property name. Only present when type is 'object'. */
296
+ properties?: Record<string, RequestBodyProperty>;
297
+ /** Names of required properties. */
298
+ required?: string[];
299
+ }
300
+ /**
301
+ * A single property within a request body schema.
302
+ */
303
+ interface RequestBodyProperty {
304
+ /** Data type (e.g. 'string', 'integer', 'boolean'). */
305
+ type: string;
306
+ /** Format hint (e.g. 'date-time', 'email'). */
307
+ format?: string;
308
+ /** Human-readable description of this property. */
309
+ description?: string;
310
+ /** Allowed values for this property. */
311
+ enum?: unknown[];
312
+ /** Default value for this property. */
313
+ default?: unknown;
314
+ /** Example value for documentation and testing. */
315
+ example?: unknown;
316
+ /** True when this property is an object or array with nested structure. Useful for UI rendering decisions. */
317
+ nested?: boolean;
318
+ }
319
+ /**
320
+ * An authentication scheme declared in the API spec.
321
+ * Describes how the API expects credentials to be provided, but does not contain actual credentials.
322
+ */
323
+ interface AuthScheme {
324
+ /** Scheme name from the spec (e.g. 'bearerAuth', 'api_key'). */
325
+ name: string;
326
+ /** Mapped auth type, or null if the scheme is unsupported. */
327
+ authType: AuthType | null;
328
+ /** Additional scheme-specific metadata (e.g. header name for API keys, OAuth2 URLs). */
329
+ metadata: Record<string, string>;
330
+ /** Human-readable description of the auth scheme. */
331
+ description: string;
332
+ }
333
+ /**
334
+ * Credentials for authenticating API requests.
335
+ * Discriminated union on `type` — use the `AuthType` constants to construct.
336
+ *
337
+ * @example
338
+ * // Bearer token
339
+ * const auth: Auth = { type: AuthType.BEARER, token: 'sk-...' }
340
+ *
341
+ * @example
342
+ * // API key in a header
343
+ * const auth: Auth = { type: AuthType.API_KEY, location: ParamLocation.HEADER, name: 'X-API-Key', value: 'my-key' }
344
+ */
345
+ type Auth = {
346
+ type: typeof AuthType.BEARER;
347
+ token: string;
348
+ } | {
349
+ type: typeof AuthType.BASIC;
350
+ username: string;
351
+ password: string;
352
+ } | {
353
+ type: typeof AuthType.API_KEY;
354
+ location: typeof ParamLocation.HEADER | typeof ParamLocation.QUERY;
355
+ name: string;
356
+ value: string;
357
+ } | {
358
+ type: typeof AuthType.OAUTH2;
359
+ accessToken: string;
360
+ refreshToken?: string;
361
+ tokenUrl?: string;
362
+ clientId?: string;
363
+ clientSecret?: string;
364
+ } | {
365
+ type: typeof AuthType.COOKIE;
366
+ name: string;
367
+ value: string;
368
+ };
369
+ /**
370
+ * A fully constructed HTTP request ready to be sent (or previewed).
371
+ * Produced by {@link buildRequest} and included in execution results for debugging.
372
+ */
373
+ interface BuiltRequest {
374
+ /** HTTP method (e.g. 'GET', 'POST'). */
375
+ method: HttpMethod | string;
376
+ /** Fully resolved URL with path and query parameters substituted. */
377
+ url: string;
378
+ /** Request headers including auth, content-type, and accept. */
379
+ headers: Record<string, string>;
380
+ /** Serialized request body, if present. String for JSON/form-urlencoded, FormData for multipart. */
381
+ body?: string | FormData;
382
+ }
383
+ /**
384
+ * Subset of {@link ErrorKind} that can appear on {@link ExecutionResult.errorKind}.
385
+ * Only HTTP-response errors — client-side errors (CORS, NETWORK, TIMEOUT) always throw regardless of `throwOnHttpError`.
386
+ */
387
+ type ResultErrorKind = typeof ErrorKind.AUTH | typeof ErrorKind.RATE_LIMIT | typeof ErrorKind.HTTP;
388
+ /**
389
+ * Result of executing an API operation.
390
+ * Contains the parsed response data, status, headers, timing, and the original request for debugging.
391
+ */
392
+ interface ExecutionResult {
393
+ /** HTTP status code (e.g. 200, 404, 500). */
394
+ status: number;
395
+ /** Parsed response body. JSON responses are parsed to objects; binary responses are ArrayBuffers; others attempt JSON parsing before falling back to strings. */
396
+ data: unknown;
397
+ /** Response content type from the Content-Type header (e.g. 'application/json', 'text/xml'). */
398
+ contentType: string;
399
+ /** Response headers as a flat key-value map. */
400
+ headers: Record<string, string>;
401
+ /** The request that was sent, useful for debugging and logging. */
402
+ request: BuiltRequest;
403
+ /** Request duration in milliseconds (from send to response headers received, before body parsing). */
404
+ elapsedMs: number;
405
+ /** Set when `throwOnHttpError` is false and the response is an error. Allows programmatic error classification without throwing. */
406
+ errorKind?: ResultErrorKind;
407
+ }
408
+ /**
409
+ * A parsed Server-Sent Event.
410
+ * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events
411
+ */
412
+ interface SSEEvent {
413
+ /** Event type (e.g. 'message', 'error'). Absent when no `event:` field was set in the stream. */
414
+ event?: string;
415
+ /** Event payload. For JSON-encoded events, this is the raw string — parse it with `JSON.parse()`. */
416
+ data: string;
417
+ /** Last event ID. Per spec, values containing U+0000 NULL are ignored by the parser. */
418
+ id?: string;
419
+ /** Reconnection time in milliseconds. Must be a non-negative integer per spec. */
420
+ retry?: number;
421
+ }
422
+ /**
423
+ * Result of a streaming API call. Errors always throw before this object is constructed,
424
+ * so `status` is guaranteed to be 2xx. The `stream` is single-use — iterating it twice
425
+ * will fail since the underlying ReadableStream reader can only be consumed once.
426
+ * Unlike `ExecutionResult`, `elapsedMs` measures time to receive the response headers (not total stream consumption time)
427
+ * and `errorKind` is absent (errors throw, no non-throwing mode for streams).
428
+ */
429
+ interface StreamingExecutionResult {
430
+ /** HTTP status code (guaranteed 2xx). */
431
+ status: number;
432
+ /** Async iterable of SSE events. Single-use — can only be iterated once. */
433
+ stream: AsyncIterable<SSEEvent>;
434
+ /** Response content type (expected: 'text/event-stream'). */
435
+ contentType: string;
436
+ /** Response headers as a flat key-value map. */
437
+ headers: Record<string, string>;
438
+ /** The request that was sent. */
439
+ request: BuiltRequest;
440
+ /** Time-to-first-byte in milliseconds (not total stream consumption time). */
441
+ elapsedMs: number;
442
+ }
443
+ /**
444
+ * Post-processing hook that transforms a ParsedAPI after parsing.
445
+ * Useful for adding custom operations, modifying base URLs, or injecting metadata.
446
+ */
447
+ interface Enricher {
448
+ /** Enricher name for identification in logs and debugging. */
449
+ readonly name: string;
450
+ /**
451
+ * Transform the parsed API. May return a new object or modify in place.
452
+ * Can be async for enrichers that need to fetch external data.
453
+ */
454
+ enrichAPI(api: ParsedAPI): ParsedAPI | Promise<ParsedAPI>;
455
+ }
456
+ /**
457
+ * Configuration options for {@link ApiInvokeClient} and {@link createClient}.
458
+ */
459
+ interface ClientOptions {
460
+ /** Original spec URL, used for base URL fallback when the spec has no servers/host field. */
461
+ specUrl?: string;
462
+ /** Default authentication credentials for all operations. Can be overridden per-call. */
463
+ auth?: Auth | Auth[];
464
+ /** Middleware pipeline applied to every request/response (e.g. logging, CORS proxy). */
465
+ middleware?: Middleware[];
466
+ /** Custom fetch implementation. Defaults to `globalThis.fetch`. Useful for testing or wrapping with {@link withRetry}. */
467
+ fetch?: typeof globalThis.fetch;
468
+ /** Post-parse enricher that transforms the ParsedAPI before client construction. */
469
+ enricher?: Enricher;
470
+ /** Default timeout in milliseconds for all operations. 0 = no timeout (default). */
471
+ timeoutMs?: number;
472
+ }
473
+ /**
474
+ * Middleware hook for intercepting requests and responses.
475
+ * All hooks are optional — implement only the ones you need.
476
+ */
477
+ interface Middleware {
478
+ /** Middleware name for identification in logs and debugging. */
479
+ name?: string;
480
+ /**
481
+ * Called before each request is sent. Can modify the URL and request init.
482
+ * Middleware runs in order — later middleware sees changes from earlier ones.
483
+ */
484
+ onRequest?(url: string, init: RequestInit): {
485
+ url: string;
486
+ init: RequestInit;
487
+ } | Promise<{
488
+ url: string;
489
+ init: RequestInit;
490
+ }>;
491
+ /**
492
+ * Called after receiving a response. Can transform or replace the response.
493
+ * Runs in order — later middleware sees the response from earlier ones.
494
+ */
495
+ onResponse?(response: Response): Response | Promise<Response>;
496
+ /**
497
+ * Called when a fetch error occurs (network failure, CORS, timeout).
498
+ * For logging/monitoring only — cannot recover from the error.
499
+ * Exceptions thrown by this handler are suppressed (logged as warnings).
500
+ */
501
+ onError?(error: Error): void;
502
+ }
503
+
504
+ /**
505
+ * Main client — the public API for api-invoke.
506
+ * Supports three tiers: full spec (OpenAPI/GraphQL), raw URL, and zero-spec execution.
507
+ */
508
+
509
+ /**
510
+ * High-level API client. Wraps a {@link ParsedAPI} and provides methods to execute operations by ID.
511
+ * Created via {@link createClient} (recommended) or by constructing directly with a `ParsedAPI`.
512
+ *
513
+ * @example
514
+ * ```ts
515
+ * const client = await createClient('https://petstore.swagger.io/v2/swagger.json')
516
+ * const result = await client.execute('getInventory')
517
+ * console.log(result.data)
518
+ * ```
519
+ */
520
+ declare class ApiInvokeClient {
521
+ /** The parsed API specification backing this client. */
522
+ readonly api: ParsedAPI;
523
+ private auth;
524
+ private middleware;
525
+ private fetchFn;
526
+ private timeoutMs;
527
+ /**
528
+ * @param api - Parsed API specification (from any adapter)
529
+ * @param options - Client configuration (auth, middleware, fetch, timeout)
530
+ */
531
+ constructor(api: ParsedAPI, options?: ClientOptions);
532
+ /** The resolved base URL for this API. */
533
+ get baseUrl(): string;
534
+ /** All available operations from the parsed spec. */
535
+ get operations(): Operation[];
536
+ /** Authentication schemes declared in the spec. Useful for building auth UIs. */
537
+ get authSchemes(): AuthScheme[];
538
+ /**
539
+ * Set authentication credentials for all subsequent requests.
540
+ * @param auth - Single credential or array for composing multiple schemes
541
+ */
542
+ setAuth(auth: Auth | Auth[]): void;
543
+ /**
544
+ * Clear authentication credentials.
545
+ */
546
+ clearAuth(): void;
547
+ /**
548
+ * Find an operation by its ID.
549
+ * @param operationId - The operation ID to search for (e.g. 'listUsers', 'get_users_userId')
550
+ * @returns The operation, or undefined if not found
551
+ */
552
+ findOperation(operationId: string): Operation | undefined;
553
+ /**
554
+ * Execute an operation by ID with arguments.
555
+ *
556
+ * @param operationId - The operation ID from the parsed spec
557
+ * @param args - Key-value pairs for path, query, header, and body parameters
558
+ * @param options - Per-call overrides for auth, accept header, error behavior, and redirect mode
559
+ * @returns The execution result with status, parsed data, and response metadata
560
+ * @throws {ApiInvokeError} For network, CORS, timeout, and (by default) HTTP errors
561
+ * @throws {Error} If the operation ID is not found
562
+ *
563
+ * @example
564
+ * ```ts
565
+ * const result = await client.execute('getUser', { userId: 123 })
566
+ * console.log(result.status, result.data)
567
+ * ```
568
+ */
569
+ execute(operationId: string, args?: Record<string, unknown>, options?: {
570
+ auth?: Auth | Auth[];
571
+ accept?: string;
572
+ throwOnHttpError?: boolean;
573
+ redirect?: RequestInit['redirect'];
574
+ }): Promise<ExecutionResult>;
575
+ /**
576
+ * Execute an operation as a stream, returning an async iterable of SSE events.
577
+ * Errors always throw (no non-throwing mode for streams).
578
+ *
579
+ * @param operationId - The operation ID from the parsed spec
580
+ * @param args - Key-value pairs for path, query, header, and body parameters
581
+ * @param options - Per-call overrides for auth, accept header, abort signal, and event callback. The client-level `timeoutMs` applies to the initial connection.
582
+ * @returns Streaming result with an async iterable `stream` property
583
+ * @throws {ApiInvokeError} For network, CORS, timeout, and HTTP errors
584
+ * @throws {Error} If the operation ID is not found
585
+ *
586
+ * @example
587
+ * ```ts
588
+ * const result = await client.executeStream('chatCompletion', {
589
+ * model: 'gpt-4', messages: [{ role: 'user', content: 'Hi' }], stream: true,
590
+ * })
591
+ * for await (const event of result.stream) {
592
+ * console.log(event.data)
593
+ * }
594
+ * ```
595
+ */
596
+ executeStream(operationId: string, args?: Record<string, unknown>, options?: {
597
+ auth?: Auth | Auth[];
598
+ accept?: string;
599
+ signal?: AbortSignal;
600
+ onEvent?: (event: SSEEvent) => void;
601
+ }): Promise<StreamingExecutionResult>;
602
+ }
603
+ /**
604
+ * Create a client from an OpenAPI spec URL, GraphQL endpoint, spec object, or raw API URL.
605
+ *
606
+ * Auto-detection logic:
607
+ * - OpenAPI spec URL (e.g. ends with `/openapi.json`) → parsed spec with all operations
608
+ * - GraphQL endpoint URL (path contains `/graphql`) → introspection query, one operation per field
609
+ * - Raw URL → attempts content-based spec detection, falls back to single-operation raw mode
610
+ * - GraphQL introspection object (`{ __schema }` or `{ data: { __schema } }`) → parsed directly
611
+ * - OpenAPI spec object (parsed JSON/YAML) → parsed directly
612
+ *
613
+ * @param input - OpenAPI spec URL, GraphQL endpoint URL, raw API URL, or pre-parsed spec/introspection object
614
+ * @param options - Client configuration (auth, middleware, fetch, enricher, timeout)
615
+ * @returns A configured {@link ApiInvokeClient} ready to execute operations
616
+ * @throws {Error} If the spec cannot be fetched or parsed
617
+ *
618
+ * @example
619
+ * ```ts
620
+ * // From OpenAPI spec URL
621
+ * const client = await createClient('https://petstore.swagger.io/v2/swagger.json')
622
+ *
623
+ * // From GraphQL endpoint
624
+ * const client = await createClient('https://countries.trevorblades.com/graphql')
625
+ *
626
+ * // From raw API URL
627
+ * const client = await createClient('https://api.example.com/users?page=1')
628
+ *
629
+ * // From spec object
630
+ * const client = await createClient(specJson, { auth: { type: 'bearer', token: 'sk-...' } })
631
+ * ```
632
+ */
633
+ declare function createClient(input: string | object, options?: ClientOptions): Promise<ApiInvokeClient>;
634
+
635
+ /**
636
+ * HTTP request execution with body serialization (JSON, form-urlencoded, multipart) and error classification.
637
+ * Pluggable: uses global fetch by default, can be overridden.
638
+ */
639
+
640
+ /**
641
+ * Options for {@link buildRequest} — only request-construction concerns, no runtime/execution options.
642
+ */
643
+ interface BuildRequestOptions {
644
+ /** Authentication credentials to inject into the request. */
645
+ auth?: Auth | Auth[];
646
+ /** Override the Accept header. Defaults to `operation.responseContentType` or `'application/json'`. */
647
+ accept?: string;
648
+ }
649
+ /**
650
+ * Options for {@link executeOperation} and {@link executeOperationStream}.
651
+ * Extends {@link BuildRequestOptions} with runtime and execution concerns.
652
+ */
653
+ interface ExecuteOptions extends BuildRequestOptions {
654
+ /** Middleware pipeline applied to the request/response. */
655
+ middleware?: Middleware[];
656
+ /** Custom fetch implementation. Defaults to `globalThis.fetch`. */
657
+ fetch?: typeof globalThis.fetch;
658
+ /** If false, return ExecutionResult for all HTTP errors instead of throwing. Client-side errors (CORS, network, timeout) always throw regardless. Default: true. */
659
+ throwOnHttpError?: boolean;
660
+ /** Timeout in milliseconds. 0 = no timeout (default). */
661
+ timeoutMs?: number;
662
+ /** AbortSignal to cancel the request. */
663
+ signal?: AbortSignal;
664
+ /** Redirect behavior passed to fetch. Unset by default (fetch implementations typically default to 'follow'). */
665
+ redirect?: RequestInit['redirect'];
666
+ /** Extra headers to merge into the request. Applied after buildRequest, so they override spec-derived headers. */
667
+ headers?: Record<string, string>;
668
+ }
669
+
670
+ /**
671
+ * Build a request without executing it (dry-run / preview).
672
+ * Validates parameters, assembles the body, and injects auth — but does not send.
673
+ *
674
+ * @param baseUrl - Base URL for the API (e.g. 'https://api.example.com/v1')
675
+ * @param operation - The operation to build a request for
676
+ * @param args - Key-value pairs for path, query, header, and body parameters
677
+ * @param options - Auth and accept header overrides
678
+ * @returns A fully constructed request ready to inspect or send manually
679
+ * @throws {Error} If required parameters are missing
680
+ * @throws {TypeError} If the URL is malformed when using query-based API key auth
681
+ */
682
+ declare function buildRequest(baseUrl: string, operation: Operation, args: Record<string, unknown>, options?: BuildRequestOptions): BuiltRequest;
683
+ /**
684
+ * Execute an API call for an operation with arguments.
685
+ * Builds the URL, injects auth, applies middleware, and classifies errors.
686
+ *
687
+ * @param baseUrl - Base URL for the API
688
+ * @param operation - The operation to execute
689
+ * @param args - Key-value pairs for path, query, header, and body parameters
690
+ * @param options - Execution options (auth, middleware, fetch, timeout, error behavior)
691
+ * @returns The execution result with parsed response data
692
+ * @throws {ApiInvokeError} For network, CORS, timeout, parse, and (by default) HTTP errors
693
+ */
694
+ declare function executeOperation(baseUrl: string, operation: Operation, args: Record<string, unknown>, options?: ExecuteOptions): Promise<ExecutionResult>;
695
+ /**
696
+ * Execute a raw HTTP request without an API spec (Tier 3: zero spec).
697
+ * Still provides error classification, response parsing, and timing.
698
+ *
699
+ * @param url - Full URL to request
700
+ * @param options - Request options (method, headers, body, auth, middleware)
701
+ * @returns The execution result with parsed response data
702
+ * @throws {ApiInvokeError} For network, CORS, timeout, parse, and (by default) HTTP errors
703
+ */
704
+ declare function executeRaw(url: string, options?: {
705
+ method?: string;
706
+ headers?: Record<string, string>;
707
+ body?: string;
708
+ auth?: Auth | Auth[];
709
+ middleware?: Middleware[];
710
+ fetch?: typeof globalThis.fetch;
711
+ timeoutMs?: number;
712
+ signal?: AbortSignal;
713
+ accept?: string;
714
+ redirect?: RequestInit['redirect'];
715
+ }): Promise<ExecutionResult>;
716
+ /**
717
+ * Execute an API call and return a streaming async iterable of SSE events.
718
+ * Errors always throw (no non-throwing mode for streams).
719
+ *
720
+ * @param baseUrl - Base URL for the API
721
+ * @param operation - The operation to execute
722
+ * @param args - Key-value pairs for path, query, header, and body parameters
723
+ * @param options - Execution options, plus optional `onEvent` callback for each SSE event
724
+ * @returns Streaming result with an async iterable `stream` property
725
+ * @throws {ApiInvokeError} For network, CORS, timeout, parse, and HTTP errors
726
+ */
727
+ declare function executeOperationStream(baseUrl: string, operation: Operation, args: Record<string, unknown>, options?: ExecuteOptions & {
728
+ onEvent?: (event: SSEEvent) => void;
729
+ }): Promise<StreamingExecutionResult>;
730
+ /**
731
+ * Execute a raw streaming HTTP request without an API spec (Tier 3: zero spec).
732
+ * Returns an async iterable of SSE events.
733
+ *
734
+ * @param url - Full URL to request
735
+ * @param options - Request options (method, headers, body, auth, middleware, onEvent callback)
736
+ * @returns Streaming result with an async iterable `stream` property
737
+ * @throws {ApiInvokeError} For network, CORS, timeout, parse, and HTTP errors
738
+ */
739
+ declare function executeRawStream(url: string, options?: {
740
+ method?: string;
741
+ headers?: Record<string, string>;
742
+ body?: string;
743
+ auth?: Auth | Auth[];
744
+ middleware?: Middleware[];
745
+ fetch?: typeof globalThis.fetch;
746
+ timeoutMs?: number;
747
+ signal?: AbortSignal;
748
+ accept?: string;
749
+ redirect?: RequestInit['redirect'];
750
+ onEvent?: (event: SSEEvent) => void;
751
+ }): Promise<StreamingExecutionResult>;
752
+
753
+ /**
754
+ * Parse a Server-Sent Events stream into an async iterable of events.
755
+ * Implements the WHATWG SSE parsing algorithm.
756
+ *
757
+ * @param body - ReadableStream from a fetch response (e.g. `response.body`)
758
+ * @returns Async generator yielding parsed {@link SSEEvent} objects
759
+ * @throws {Error} If the stream contains invalid UTF-8 data
760
+ * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream
761
+ */
762
+ declare function parseSSE(body: ReadableStream<Uint8Array>): AsyncGenerator<SSEEvent>;
763
+
764
+ /**
765
+ * Heuristics for detecting API spec formats from URLs and content.
766
+ * Used by `createClient()` for auto-detection and available for consumers
767
+ * that implement their own detection pipelines.
768
+ */
769
+ /**
770
+ * Detect if a URL likely points to an OpenAPI/Swagger spec by URL pattern.
771
+ * Checks for common spec file extensions and path patterns.
772
+ *
773
+ * @param url - Absolute URL to check
774
+ * @returns `true` if the URL matches a known spec URL pattern
775
+ */
776
+ declare function isSpecUrl(url: string): boolean;
777
+ /**
778
+ * Detect if a parsed JSON object is an OpenAPI/Swagger spec by checking
779
+ * for the required top-level `openapi` (3.x) or `swagger` (2.0) key.
780
+ *
781
+ * @param data - Parsed JSON value to check
782
+ * @returns `true` if the data looks like an OpenAPI/Swagger spec
783
+ */
784
+ declare function isSpecContent(data: unknown): data is Record<string, unknown>;
785
+ /**
786
+ * Detect if a URL likely points to a GraphQL endpoint by URL pattern.
787
+ * Checks for common GraphQL path suffixes.
788
+ *
789
+ * @param url - Absolute URL to check
790
+ * @returns `true` if the URL matches a known GraphQL endpoint pattern
791
+ */
792
+ declare function isGraphQLUrl(url: string): boolean;
793
+
794
+ /**
795
+ * URL and parameter construction utilities.
796
+ * Handles path parameter interpolation, query params, header params, cookie params, and slash normalization.
797
+ */
798
+
799
+ /**
800
+ * Build a full URL from base URL, operation path, and arguments.
801
+ * Handles path parameter interpolation, query parameter serialization, and slash normalization.
802
+ *
803
+ * @param baseUrl - Base URL for the API (e.g. 'https://api.example.com/v1')
804
+ * @param operation - The operation containing path template and parameter definitions
805
+ * @param args - Key-value pairs for path and query parameters
806
+ * @returns Fully resolved URL string with parameters substituted
807
+ */
808
+ declare function buildUrl(baseUrl: string, operation: Operation, args: Record<string, unknown>): string;
809
+ /**
810
+ * Derive a base URL from a spec URL by stripping the filename.
811
+ * e.g., `"https://api.example.com/v1/openapi.json"` → `"https://api.example.com/v1"`
812
+ *
813
+ * @param specUrl - URL pointing to an API spec file
814
+ * @returns Base URL with the filename removed, or empty string if the URL is invalid
815
+ */
816
+ declare function deriveBaseUrl(specUrl: string): string;
817
+
818
+ /**
819
+ * Authentication injection into HTTP requests.
820
+ * Supports Bearer, Basic, API Key (header/query), OAuth2, and Cookie.
821
+ */
822
+
823
+ /**
824
+ * A request with authentication applied (URL may be modified for query-based auth).
825
+ */
826
+ interface AuthenticatedRequest {
827
+ /** URL, potentially modified with query-based auth parameters. */
828
+ url: string;
829
+ /** Headers with auth credentials injected. */
830
+ headers: Record<string, string>;
831
+ }
832
+ /**
833
+ * Inject authentication credentials into a request URL and headers.
834
+ * Accepts a single Auth or an array for composing multiple schemes (e.g. API key + bearer).
835
+ *
836
+ * @param url - The request URL
837
+ * @param headers - Existing request headers (shallow-copied internally)
838
+ * @param auth - Credentials to inject (single or array)
839
+ * @returns New URL and headers with auth applied
840
+ */
841
+ declare function injectAuth(url: string, headers: Record<string, string>, auth: Auth | Auth[]): AuthenticatedRequest;
842
+ /** Result from an OAuth2 token refresh. */
843
+ interface OAuth2TokenResult {
844
+ /** The new access token. */
845
+ accessToken: string;
846
+ /** A new refresh token, if the server issued one. */
847
+ refreshToken?: string;
848
+ /** Token lifetime in seconds, if provided by the server. */
849
+ expiresIn?: number;
850
+ }
851
+ /**
852
+ * Exchange a refresh token for a new access token at the OAuth2 token endpoint.
853
+ *
854
+ * @param tokenUrl - The OAuth2 token endpoint URL
855
+ * @param refreshToken - The refresh token to exchange
856
+ * @param options - Optional client credentials, scopes, and custom fetch
857
+ * @returns The new token set
858
+ * @throws {ApiInvokeError} With `kind: 'auth'` if the token endpoint returns a non-OK response or the response is missing `access_token`
859
+ * @throws {ApiInvokeError} With `kind: 'parse'` if the response body is not valid JSON
860
+ */
861
+ declare function refreshOAuth2Token(tokenUrl: string, refreshToken: string, options?: {
862
+ clientId?: string;
863
+ clientSecret?: string;
864
+ scopes?: string[];
865
+ fetch?: typeof globalThis.fetch;
866
+ }): Promise<OAuth2TokenResult>;
867
+ /**
868
+ * Mask credential values for safe logging. Shows the auth type and a redacted value.
869
+ *
870
+ * @param auth - The auth credentials to mask
871
+ * @returns A human-readable string with sensitive values replaced by `***`
872
+ */
873
+ declare function maskAuth(auth: Auth): string;
874
+
875
+ /**
876
+ * Flat auth configuration for CLI consumers.
877
+ * Converts simple config objects (from CLI args, env vars, config files)
878
+ * into api-invoke's discriminated Auth union.
879
+ */
880
+
881
+ /** Simplified auth type constants for flat configuration (CLI, env vars, config files). */
882
+ declare const AuthConfigType: {
883
+ readonly BEARER: "bearer";
884
+ readonly HEADER: "header";
885
+ readonly API_KEY: "apikey";
886
+ readonly NONE: "none";
887
+ };
888
+ type AuthConfigType = (typeof AuthConfigType)[keyof typeof AuthConfigType];
889
+ /**
890
+ * Flat auth configuration for CLI consumers.
891
+ * Unlike {@link Auth}, this is a single object with optional fields rather than a discriminated union.
892
+ * Use {@link toAuth} to convert to the full `Auth` type.
893
+ */
894
+ interface AuthConfig {
895
+ /** Auth type to use. */
896
+ type: AuthConfigType;
897
+ /** Bearer token (used when `type` is 'bearer'). */
898
+ token?: string;
899
+ /** Custom header name (used when `type` is 'header'). */
900
+ headerName?: string;
901
+ /** Custom header value (used when `type` is 'header'). */
902
+ headerValue?: string;
903
+ /** Query parameter name (used when `type` is 'apikey'). */
904
+ paramName?: string;
905
+ /** Query parameter value (used when `type` is 'apikey'). */
906
+ paramValue?: string;
907
+ }
908
+ /**
909
+ * Convert a flat {@link AuthConfig} to api-invoke's {@link Auth} discriminated union.
910
+ * Returns undefined if required credentials are missing or type is `NONE`.
911
+ *
912
+ * @param config - Flat auth configuration
913
+ * @returns The `Auth` object, or undefined if credentials are incomplete
914
+ */
915
+ declare function toAuth(config: AuthConfig): Auth | undefined;
916
+
917
+ /**
918
+ * Retry fetch wrapper — exponential backoff with Retry-After header support.
919
+ *
920
+ * Works by wrapping the fetch function rather than using middleware hooks,
921
+ * since retry logic needs to re-execute the entire request.
922
+ */
923
+ interface RetryOptions {
924
+ /** Max retry attempts (default: 3) */
925
+ maxRetries?: number;
926
+ /** Initial delay in ms (default: 1000) */
927
+ initialDelayMs?: number;
928
+ /** Max delay in ms (default: 30000) */
929
+ maxDelayMs?: number;
930
+ /** Backoff multiplier (default: 2) */
931
+ multiplier?: number;
932
+ /** Jitter factor 0-1 (default: 0.1) */
933
+ jitter?: number;
934
+ /** Which status codes to retry (default: [429, 500, 502, 503, 504]) */
935
+ retryableStatuses?: number[];
936
+ /** Called on each retry with attempt info */
937
+ onRetry?: (attempt: number, delayMs: number, status?: number) => void;
938
+ }
939
+ /**
940
+ * Create a fetch wrapper that retries on transient failures.
941
+ * Implements exponential backoff with jitter, and respects the `Retry-After` header.
942
+ *
943
+ * @param options - Retry configuration (max retries, delays, retryable statuses)
944
+ * @param baseFetch - Base fetch function to wrap. Defaults to `globalThis.fetch`.
945
+ * @returns A fetch-compatible function with retry behavior
946
+ *
947
+ * @example
948
+ * ```ts
949
+ * const client = await createClient(url, {
950
+ * fetch: withRetry({ maxRetries: 3 }),
951
+ * })
952
+ * ```
953
+ *
954
+ * @example
955
+ * ```ts
956
+ * // Wrap a custom fetch
957
+ * const client = await createClient(url, {
958
+ * fetch: withRetry({ maxRetries: 3 }, myCustomFetch),
959
+ * })
960
+ * ```
961
+ */
962
+ declare function withRetry(options?: RetryOptions, baseFetch?: typeof globalThis.fetch): typeof globalThis.fetch;
963
+
964
+ /**
965
+ * CORS proxy middleware — rewrites request URLs through a proxy.
966
+ *
967
+ * Useful when APIs block browser CORS requests. Supports custom
968
+ * proxy URL patterns or the common `/api-proxy/{encodedUrl}` convention.
969
+ */
970
+
971
+ interface CorsProxyOptions {
972
+ /**
973
+ * URL rewrite function. Receives the original URL, returns the proxied URL.
974
+ * Default: `/api-proxy/{encodeURIComponent(url)}`
975
+ */
976
+ rewrite?: (url: string) => string;
977
+ /**
978
+ * Only proxy URLs matching this predicate.
979
+ * Default: proxies all absolute HTTP(S) URLs.
980
+ */
981
+ shouldProxy?: (url: string) => boolean;
982
+ }
983
+ /**
984
+ * Create a CORS proxy middleware that rewrites request URLs through a proxy server.
985
+ * Useful when APIs block browser CORS requests.
986
+ *
987
+ * @param options - Proxy configuration (custom rewrite function, proxy filter)
988
+ * @returns A {@link Middleware} that rewrites URLs through the proxy
989
+ *
990
+ * @example
991
+ * ```ts
992
+ * // Default: rewrites to /api-proxy/{encodedUrl}
993
+ * const client = await createClient(url, {
994
+ * middleware: [corsProxy()],
995
+ * })
996
+ * ```
997
+ *
998
+ * @example
999
+ * ```ts
1000
+ * // Custom proxy URL
1001
+ * const client = await createClient(url, {
1002
+ * middleware: [corsProxy({
1003
+ * rewrite: (url) => `https://my-proxy.com/?url=${encodeURIComponent(url)}`,
1004
+ * })],
1005
+ * })
1006
+ * ```
1007
+ */
1008
+ declare function corsProxy(options?: CorsProxyOptions): Middleware;
1009
+
1010
+ /**
1011
+ * Logging middleware — request/response logging with automatic secret masking.
1012
+ *
1013
+ * Masks Authorization headers, API keys in query strings, and other
1014
+ * sensitive values to prevent credential leakage in logs.
1015
+ */
1016
+
1017
+ interface LoggingOptions {
1018
+ /** Custom log function (default: console.log) */
1019
+ log?: (message: string) => void;
1020
+ /** Log response bodies (default: false) */
1021
+ logBody?: boolean;
1022
+ /** Additional header names to mask (always masks Authorization) */
1023
+ sensitiveHeaders?: string[];
1024
+ /** Query parameter names to mask (e.g., ['api_key', 'token']) */
1025
+ sensitiveParams?: string[];
1026
+ /** Label prefix for log messages (default: 'api-invoke') */
1027
+ prefix?: string;
1028
+ }
1029
+ /**
1030
+ * Create a logging middleware that logs requests and responses.
1031
+ * Automatically masks sensitive headers (Authorization, cookies) and query parameters.
1032
+ *
1033
+ * @param options - Logging configuration (custom logger, body logging, sensitive fields)
1034
+ * @returns A {@link Middleware} that logs request/response details
1035
+ *
1036
+ * @example
1037
+ * ```ts
1038
+ * const client = await createClient(url, {
1039
+ * middleware: [logging()],
1040
+ * })
1041
+ * ```
1042
+ *
1043
+ * @example
1044
+ * ```ts
1045
+ * // Custom logger
1046
+ * const client = await createClient(url, {
1047
+ * middleware: [logging({ log: myLogger.info })],
1048
+ * })
1049
+ * ```
1050
+ */
1051
+ declare function logging(options?: LoggingOptions): Middleware;
1052
+
1053
+ /**
1054
+ * OAuth2 token refresh fetch wrapper.
1055
+ * Intercepts 401 responses, refreshes the token, and retries the request.
1056
+ *
1057
+ * Note: Requests with `ReadableStream` bodies cannot be retried — if a stream body
1058
+ * is detected after a 401, the original response is returned with a warning.
1059
+ */
1060
+
1061
+ /** Configuration for the OAuth2 token refresh fetch wrapper ({@link withOAuthRefresh}). */
1062
+ interface OAuthRefreshOptions {
1063
+ /** OAuth2 token endpoint URL. */
1064
+ tokenUrl: string;
1065
+ /** Refresh token to exchange for a new access token. */
1066
+ refreshToken: string;
1067
+ /** OAuth2 client ID (if required by the token endpoint). */
1068
+ clientId?: string;
1069
+ /** OAuth2 client secret (if required by the token endpoint). */
1070
+ clientSecret?: string;
1071
+ /** OAuth2 scopes to request. */
1072
+ scopes?: string[];
1073
+ /** Called after a successful token refresh. Use this to persist the new tokens. May be async. */
1074
+ onTokenRefresh?: (tokens: OAuth2TokenResult) => void | Promise<void>;
1075
+ }
1076
+ /**
1077
+ * Create a fetch wrapper that auto-refreshes OAuth2 tokens on 401 responses.
1078
+ * On a 401, exchanges the refresh token for a new access token and retries the original request.
1079
+ * Concurrent 401s are deduplicated — only one refresh and one `onTokenRefresh` callback fire per refresh cycle.
1080
+ *
1081
+ * @param options - Refresh configuration (token URL, refresh token, client credentials)
1082
+ * @param baseFetch - Base fetch function to wrap. Defaults to `globalThis.fetch`.
1083
+ * @returns A fetch-compatible function with auto-refresh behavior
1084
+ *
1085
+ * @example
1086
+ * ```ts
1087
+ * const client = await createClient(specUrl, {
1088
+ * auth: { type: AuthType.OAUTH2, accessToken: 'current-token' },
1089
+ * fetch: withOAuthRefresh({
1090
+ * tokenUrl: 'https://auth.example.com/token',
1091
+ * refreshToken: 'rt_...',
1092
+ * onTokenRefresh: (tokens) => saveTokens(tokens),
1093
+ * }),
1094
+ * })
1095
+ * ```
1096
+ */
1097
+ declare function withOAuthRefresh(options: OAuthRefreshOptions, baseFetch?: typeof globalThis.fetch): typeof globalThis.fetch;
1098
+
1099
+ /**
1100
+ * Parse OpenAPI 2.0/3.x specs into the spec-agnostic ParsedAPI format.
1101
+ * Extracted and consolidated from api2aux/semantic-analysis.
1102
+ */
1103
+
1104
+ /**
1105
+ * Parse an OpenAPI 2.0 (Swagger) or 3.x spec into a spec-agnostic {@link ParsedAPI}.
1106
+ * Handles dereferencing, operation extraction, auth scheme mapping, and base URL resolution.
1107
+ *
1108
+ * @param specUrlOrObject - URL string pointing to a spec, or a pre-parsed spec object
1109
+ * @param options - Parse options
1110
+ * @param options.specUrl - Original spec URL (used for base URL fallback when spec has no servers/host field)
1111
+ * @returns A normalized ParsedAPI with all operations, auth schemes, and metadata
1112
+ * @throws {Error} If the spec cannot be fetched, parsed, or dereferenced
1113
+ */
1114
+ declare function parseOpenAPISpec(specUrlOrObject: string | object, options?: {
1115
+ specUrl?: string;
1116
+ }): Promise<ParsedAPI>;
1117
+
1118
+ /**
1119
+ * Raw URL adapter — creates a ParsedAPI from one or more plain URL endpoints (no spec).
1120
+ * Supports custom methods, IDs, and summaries per endpoint.
1121
+ * Auto-detects query parameters as configurable operation parameters.
1122
+ */
1123
+
1124
+ /**
1125
+ * A raw URL endpoint definition (no spec required).
1126
+ */
1127
+ interface RawEndpoint {
1128
+ /** Full URL for the endpoint (must be absolute). */
1129
+ url: string;
1130
+ /** HTTP method. Default: 'GET'. */
1131
+ method?: string;
1132
+ /** Custom operation ID. Auto-generated from method + path if omitted. */
1133
+ id?: string;
1134
+ /** Short summary. Defaults to `'{METHOD} {hostname}{path}'`. */
1135
+ summary?: string;
1136
+ }
1137
+ /**
1138
+ * Parse a raw URL into a {@link ParsedAPI} with a single operation.
1139
+ * Query parameters from the URL become configurable operation parameters.
1140
+ * Repeated keys (e.g. `?tags=a&tags=b`) and bracket notation (e.g. `?ids[]=1&ids[]=2`) produce array-typed parameters.
1141
+ *
1142
+ * @param url - Absolute URL (e.g. 'https://api.example.com/users?page=1')
1143
+ * @returns A ParsedAPI with a single operation (defaults to GET)
1144
+ * @throws {Error} If the URL is not a valid absolute URL
1145
+ */
1146
+ declare function parseRawUrl(url: string): ParsedAPI;
1147
+ /**
1148
+ * Parse multiple raw URL endpoints into a single {@link ParsedAPI}.
1149
+ * All endpoints must share the same origin. Query parameters become configurable operation parameters.
1150
+ * Repeated keys and bracket notation (e.g. `?ids[]=1&ids[]=2`) produce array-typed parameters.
1151
+ * Nested brackets (e.g. `[][]`) are flattened to a 1D array. Indexed brackets (e.g. `[0]`, `[1]`) are not recognized.
1152
+ *
1153
+ * @param endpoints - Array of raw endpoint definitions
1154
+ * @returns A ParsedAPI with one operation per endpoint
1155
+ * @throws {Error} If endpoints is empty, URLs are invalid, or origins don't match
1156
+ */
1157
+ declare function parseRawUrls(endpoints: RawEndpoint[]): ParsedAPI;
1158
+
1159
+ /**
1160
+ * Manual API definition builder — define APIs without writing a full OpenAPI spec.
1161
+ * Supports multiple endpoints, methods, parameters, and request bodies.
1162
+ *
1163
+ * @example
1164
+ * ```ts
1165
+ * const api = defineAPI('My API')
1166
+ * .baseUrl('https://api.example.com')
1167
+ * .get('/users', { id: 'listUsers', summary: 'List all users' })
1168
+ * .post('/users', {
1169
+ * id: 'createUser',
1170
+ * body: { contentType: 'application/json', properties: { name: 'string', email: 'string' } },
1171
+ * })
1172
+ * .build()
1173
+ * ```
1174
+ */
1175
+
1176
+ /**
1177
+ * Options for defining an endpoint in the manual builder.
1178
+ */
1179
+ interface EndpointOptions {
1180
+ /** Custom operation ID. Auto-generated from method + path if omitted (e.g. 'get_users'). */
1181
+ id?: string;
1182
+ /** Short summary of what this endpoint does. */
1183
+ summary?: string;
1184
+ /** Longer description of the endpoint's behavior. */
1185
+ description?: string;
1186
+ /** Parameter definitions. Keys are parameter names; values are type strings (shorthand) or full {@link ParamDef} objects. Path parameters from `{placeholders}` are auto-detected. */
1187
+ params?: Record<string, ParamDef | string>;
1188
+ /** Request body definition. */
1189
+ body?: BodyDef;
1190
+ /** Expected response content type. Used as the default Accept header. */
1191
+ responseContentType?: ContentType | string;
1192
+ /** Tags for grouping this endpoint. */
1193
+ tags?: string[];
1194
+ }
1195
+ /**
1196
+ * Parameter definition for the manual builder.
1197
+ * All fields are optional — defaults to a non-required query string parameter of type 'string'.
1198
+ */
1199
+ type ParamDef = {
1200
+ /** Where the parameter appears. Default: 'query' (path params are always forced to 'path'). */
1201
+ in?: ParamLocation;
1202
+ /** Whether this parameter is required. Default: false (path params are always required). */
1203
+ required?: boolean;
1204
+ /** Data type. Default: 'string'. */
1205
+ type?: string;
1206
+ /** Human-readable description. */
1207
+ description?: string;
1208
+ /** Default value when the parameter is not provided. */
1209
+ default?: unknown;
1210
+ };
1211
+ /**
1212
+ * Request body definition for the manual builder.
1213
+ */
1214
+ type BodyDef = {
1215
+ /** Content type for the body. Default: 'application/json'. */
1216
+ contentType?: string;
1217
+ /** Whether the body is required. Default: true. */
1218
+ required?: boolean;
1219
+ /** Body properties. Keys are property names; values are type strings (shorthand) or full {@link PropertyDef} objects. */
1220
+ properties?: Record<string, string | PropertyDef>;
1221
+ /** Names of required properties within the body. */
1222
+ requiredFields?: string[];
1223
+ };
1224
+ /**
1225
+ * Property definition within a request body.
1226
+ */
1227
+ type PropertyDef = {
1228
+ /** Data type (e.g. 'string', 'integer', 'boolean'). */
1229
+ type: string;
1230
+ /** Human-readable description. */
1231
+ description?: string;
1232
+ /** Format hint (e.g. 'date-time', 'email'). */
1233
+ format?: string;
1234
+ /** Allowed values for this property. */
1235
+ enum?: unknown[];
1236
+ };
1237
+ /**
1238
+ * Fluent builder for manually defining APIs without an OpenAPI spec.
1239
+ * Use {@link defineAPI} to create an instance.
1240
+ *
1241
+ * @example
1242
+ * ```ts
1243
+ * const api = defineAPI('Users API')
1244
+ * .baseUrl('https://api.example.com')
1245
+ * .get('/users', { id: 'listUsers' })
1246
+ * .get('/users/{userId}', { id: 'getUser' })
1247
+ * .post('/users', { id: 'createUser', body: { properties: { name: 'string' } } })
1248
+ * .build()
1249
+ * ```
1250
+ */
1251
+ declare class APIBuilder {
1252
+ private _title;
1253
+ private _version;
1254
+ private _baseUrl;
1255
+ private _operations;
1256
+ constructor(title: string);
1257
+ /**
1258
+ * Set the API version string.
1259
+ * @param v - Version string (e.g. '2.0.0'). Default: '1.0.0'.
1260
+ */
1261
+ version(v: string): this;
1262
+ /**
1263
+ * Set the base URL for all endpoints.
1264
+ * @param url - Base URL (e.g. 'https://api.example.com/v1'). Required before calling {@link build}.
1265
+ */
1266
+ baseUrl(url: string): this;
1267
+ /** Add a GET endpoint. */
1268
+ get(path: string, options?: EndpointOptions): this;
1269
+ /** Add a POST endpoint. */
1270
+ post(path: string, options?: EndpointOptions): this;
1271
+ /** Add a PUT endpoint. */
1272
+ put(path: string, options?: EndpointOptions): this;
1273
+ /** Add a PATCH endpoint. */
1274
+ patch(path: string, options?: EndpointOptions): this;
1275
+ /** Add a DELETE endpoint. */
1276
+ delete(path: string, options?: EndpointOptions): this;
1277
+ /**
1278
+ * Add an endpoint with any HTTP method.
1279
+ * Path parameters are auto-detected from `{placeholder}` segments.
1280
+ *
1281
+ * @param method - HTTP method (e.g. 'GET', 'POST')
1282
+ * @param path - URL path template (e.g. '/users/{userId}')
1283
+ * @param options - Endpoint configuration
1284
+ */
1285
+ endpoint(method: string, path: string, options?: EndpointOptions): this;
1286
+ /**
1287
+ * Build the {@link ParsedAPI} from the configured endpoints.
1288
+ * @returns A ParsedAPI ready to use with {@link ApiInvokeClient}
1289
+ * @throws {Error} If `baseUrl` is not set or no endpoints are defined
1290
+ */
1291
+ build(): ParsedAPI;
1292
+ }
1293
+ /**
1294
+ * Create a new API builder with a fluent interface.
1295
+ *
1296
+ * @param title - Human-readable API title
1297
+ * @returns A new {@link APIBuilder} instance
1298
+ *
1299
+ * @example
1300
+ * ```ts
1301
+ * const api = defineAPI('My API')
1302
+ * .baseUrl('https://api.example.com')
1303
+ * .get('/health', { id: 'healthCheck' })
1304
+ * .build()
1305
+ * ```
1306
+ */
1307
+ declare function defineAPI(title: string): APIBuilder;
1308
+
1309
+ /**
1310
+ * GraphQL adapter — parses introspection schemas into ParsedAPI.
1311
+ * Accepts a live endpoint URL (runs introspection) or an introspection JSON object.
1312
+ */
1313
+
1314
+ /** Options for parsing a GraphQL schema. */
1315
+ interface GraphQLParseOptions {
1316
+ /** GraphQL endpoint URL. Strongly recommended when input is introspection JSON — without it, baseUrl defaults to '/graphql' (a relative path). Inferred automatically when input is a URL string. */
1317
+ endpoint?: string;
1318
+ /** Custom fetch implementation for introspection queries. Defaults to `globalThis.fetch`. */
1319
+ fetch?: typeof globalThis.fetch;
1320
+ /** Maximum depth for auto-generated query selection sets. Default: 2. */
1321
+ maxDepth?: number;
1322
+ }
1323
+ /**
1324
+ * Parse a GraphQL schema into a ParsedAPI.
1325
+ *
1326
+ * @param input - Either an endpoint URL (string starting with http) or an introspection result object.
1327
+ * URL: runs introspection query against the endpoint.
1328
+ * Object: expects `{ data: { __schema: ... } }` or `{ __schema: ... }` shape.
1329
+ * @param options - Configuration options.
1330
+ * @returns A ParsedAPI with one operation per query/mutation/subscription field.
1331
+ */
1332
+ declare function parseGraphQLSchema(input: string | object, options?: GraphQLParseOptions): Promise<ParsedAPI>;
1333
+
1334
+ /**
1335
+ * GraphQL error detection and handling utilities.
1336
+ * GraphQL APIs return HTTP 200 even on errors — these helpers inspect the response body.
1337
+ */
1338
+
1339
+ /** A single GraphQL error from the response `errors` array. */
1340
+ interface GraphQLError {
1341
+ message: string;
1342
+ locations?: Array<{
1343
+ line: number;
1344
+ column: number;
1345
+ }>;
1346
+ path?: Array<string | number>;
1347
+ extensions?: Record<string, unknown>;
1348
+ }
1349
+ /** Check if an ExecutionResult contains GraphQL errors. Returns true for both total and partial errors. Use {@link throwOnGraphQLErrors} to throw only on total failures (when `data` is null). */
1350
+ declare function hasGraphQLErrors(result: ExecutionResult): boolean;
1351
+ /** Extract GraphQL errors from an ExecutionResult. Returns empty array if none. */
1352
+ declare function getGraphQLErrors(result: ExecutionResult): GraphQLError[];
1353
+ /**
1354
+ * Throw if the result has GraphQL errors and no data (total failure).
1355
+ * Partial errors (data + errors both present) do not throw — the caller decides how to handle them.
1356
+ */
1357
+ declare function throwOnGraphQLErrors(result: ExecutionResult): void;
1358
+
1359
+ export { APIBuilder, API_INVOKE_ERROR_NAME, ApiInvokeClient, ApiInvokeError, type Auth, type AuthConfig, AuthConfigType, type AuthScheme, AuthType, type AuthenticatedRequest, type BodyDef, type BuildRequestOptions, type BuiltRequest, type ClientOptions, ContentType, type CorsProxyOptions, type EndpointOptions, type Enricher, ErrorKind, type ExecuteOptions, type ExecutionResult, type GraphQLError, type GraphQLParseOptions, HeaderName, HttpMethod, type LoggingOptions, type Middleware, type OAuth2TokenResult, type OAuthRefreshOptions, type Operation, type ParamDef, ParamLocation, type Parameter, type ParameterSchema, type ParsedAPI, type PropertyDef, type RawEndpoint, type RequestBody, type RequestBodyProperty, type RequestBodySchema, type ResultErrorKind, type RetryOptions, type SSEEvent, SpecFormat, type StreamingExecutionResult, authError, buildRequest, buildUrl, corsError, corsProxy, createClient, defineAPI, deriveBaseUrl, executeOperation, executeOperationStream, executeRaw, executeRawStream, getGraphQLErrors, graphqlError, hasGraphQLErrors, httpError, injectAuth, isGraphQLUrl, isSpecContent, isSpecUrl, logging, maskAuth, networkError, parseError, parseGraphQLSchema, parseOpenAPISpec, parseRawUrl, parseRawUrls, parseSSE, refreshOAuth2Token, throwOnGraphQLErrors, timeoutError, toAuth, withOAuthRefresh, withRetry };