@sdk-it/typescript 0.45.0 → 0.46.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 +75 -57
- package/dist/index.js +39 -25
- package/dist/index.js.map +3 -3
- package/dist/lib/emitters/interface.d.ts +1 -1
- package/dist/lib/emitters/interface.d.ts.map +1 -1
- package/dist/lib/emitters/zod.d.ts.map +1 -1
- package/dist/lib/generate.d.ts.map +1 -1
- package/dist/lib/pagination-emit.d.ts.map +1 -1
- package/dist/lib/sdk.d.ts.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,103 +1,121 @@
|
|
|
1
1
|
# @sdk-it/typescript
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Generate a fully typed TypeScript client from an OpenAPI document. Generated
|
|
4
|
+
clients work in Node.js, browsers, and other JavaScript runtimes with `fetch`.
|
|
4
5
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
This package transforms OpenAPI specifications into
|
|
8
|
-
|
|
9
|
-
- a fully-typed TypeScript client
|
|
10
|
-
- that works in Node.js, browsers, and any JavaScript runtime
|
|
11
|
-
- with the ability to control the structure, style, and formatting of generated code
|
|
12
|
-
|
|
13
|
-
## Installation
|
|
6
|
+
## Install
|
|
14
7
|
|
|
15
8
|
```bash
|
|
16
|
-
npm install @sdk-it/typescript
|
|
9
|
+
npm install --save-dev @sdk-it/typescript
|
|
10
|
+
npm install zod fast-content-type-parse
|
|
17
11
|
```
|
|
18
12
|
|
|
19
|
-
|
|
13
|
+
`zod` and `fast-content-type-parse` are runtime dependencies of clients
|
|
14
|
+
generated in `minimal` mode.
|
|
20
15
|
|
|
21
|
-
|
|
16
|
+
## Generate from an OpenAPI document
|
|
22
17
|
|
|
23
18
|
```typescript
|
|
24
19
|
import { generate } from '@sdk-it/typescript';
|
|
25
20
|
|
|
26
|
-
|
|
21
|
+
const spec = await fetch('https://api.openstatus.dev/v1/openapi').then(
|
|
22
|
+
(response) => response.json(),
|
|
23
|
+
);
|
|
27
24
|
|
|
28
25
|
await generate(spec, {
|
|
29
|
-
output: './
|
|
30
|
-
|
|
26
|
+
output: './src/generated/openstatus',
|
|
27
|
+
mode: 'minimal',
|
|
28
|
+
name: 'OpenStatus',
|
|
31
29
|
});
|
|
32
30
|
```
|
|
33
31
|
|
|
34
|
-
|
|
32
|
+
`name` controls the generated client class name. `minimal` mode writes client
|
|
33
|
+
source files directly to `output`.
|
|
34
|
+
|
|
35
|
+
## Use the generated client
|
|
35
36
|
|
|
36
37
|
```typescript
|
|
37
|
-
import {
|
|
38
|
+
import { OpenStatus } from './src/generated/openstatus/index.ts';
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
);
|
|
40
|
+
const client = new OpenStatus({
|
|
41
|
+
baseUrl: 'https://api.openstatus.dev/v1',
|
|
42
|
+
'x-openstatus-key': process.env.OPENSTATUS_API_KEY,
|
|
43
|
+
});
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
const reports = await client.request('GET /status_report', {});
|
|
46
|
+
console.log(reports);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`request` returns unwrapped response data. It throws `ParseError` when input
|
|
50
|
+
validation fails and an `APIError` subclass when the server returns a
|
|
51
|
+
non-successful response:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import {
|
|
55
|
+
APIError,
|
|
56
|
+
OpenStatus,
|
|
57
|
+
ParseError,
|
|
58
|
+
} from './src/generated/openstatus/index.ts';
|
|
59
|
+
|
|
60
|
+
const client = new OpenStatus({
|
|
61
|
+
baseUrl: 'https://api.openstatus.dev/v1',
|
|
62
|
+
'x-openstatus-key': process.env.OPENSTATUS_API_KEY,
|
|
48
63
|
});
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const report = await client.request('GET /status_report/{id}', { id: '42' });
|
|
67
|
+
console.log(report);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (error instanceof ParseError) {
|
|
70
|
+
console.error(error.data);
|
|
71
|
+
} else if (error instanceof APIError) {
|
|
72
|
+
console.error(error.status, error.data);
|
|
73
|
+
} else {
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
49
77
|
```
|
|
50
78
|
|
|
51
|
-
|
|
79
|
+
## Format generated code
|
|
52
80
|
|
|
53
|
-
|
|
81
|
+
`formatCode` runs after generation and receives the actual source directory plus
|
|
82
|
+
an environment with local package executables on `PATH`:
|
|
54
83
|
|
|
55
84
|
```typescript
|
|
85
|
+
import { execFile } from 'node:child_process';
|
|
86
|
+
import { promisify } from 'node:util';
|
|
87
|
+
|
|
56
88
|
import { generate } from '@sdk-it/typescript';
|
|
57
89
|
|
|
90
|
+
const execFileAsync = promisify(execFile);
|
|
58
91
|
const spec = await fetch('https://petstore.swagger.io/v2/swagger.json').then(
|
|
59
|
-
(
|
|
92
|
+
(response) => response.json(),
|
|
60
93
|
);
|
|
61
94
|
|
|
62
|
-
// Format generated code using Prettier
|
|
63
95
|
await generate(spec, {
|
|
64
|
-
output:
|
|
65
|
-
|
|
66
|
-
|
|
96
|
+
output: './src/generated/petstore',
|
|
97
|
+
name: 'PetStore',
|
|
98
|
+
formatCode: async ({ output, env }) => {
|
|
99
|
+
await execFileAsync('prettier', [output, '--write'], { env });
|
|
67
100
|
},
|
|
68
101
|
});
|
|
69
102
|
```
|
|
70
103
|
|
|
71
|
-
|
|
104
|
+
## Generate a standalone project
|
|
72
105
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
node ./openapi.ts
|
|
76
|
-
|
|
77
|
-
# using node < 22
|
|
78
|
-
npx tsx ./openapi.ts
|
|
79
|
-
|
|
80
|
-
# using bun
|
|
81
|
-
bun ./openapi.ts
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
- Use the generated SDK
|
|
106
|
+
`full` mode adds `package.json` and `tsconfig.json`, places generated source
|
|
107
|
+
under `<output>/src`, and records the generated client's runtime dependencies:
|
|
85
108
|
|
|
86
109
|
```typescript
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
110
|
+
await generate(spec, {
|
|
111
|
+
output: './generated/petstore',
|
|
112
|
+
mode: 'full',
|
|
113
|
+
name: 'PetStore',
|
|
114
|
+
packageName: '@acme/petstore',
|
|
91
115
|
});
|
|
92
|
-
|
|
93
|
-
const [result, error] = await client.request('GET /status_report', {});
|
|
94
116
|
```
|
|
95
117
|
|
|
96
|
-
##
|
|
97
|
-
|
|
98
|
-
The SDK works on its own, but you might want native integration with your frameworks:
|
|
118
|
+
## Framework integrations
|
|
99
119
|
|
|
100
120
|
- [React Query](../../docs/react-query.md)
|
|
101
121
|
- [Angular](../../docs/angular.md)
|
|
102
|
-
|
|
103
|
-
Let us know what you're using, and we'll help you integrate it.
|
package/dist/index.js
CHANGED
|
@@ -66,7 +66,7 @@ function createTool(entry, operation) {
|
|
|
66
66
|
inputSchema: schemas.${schemaName},
|
|
67
67
|
execute: async (input, options) => {
|
|
68
68
|
console.log('Executing ${operation.operationId} tool with input:', input);
|
|
69
|
-
const context = coerceContext(options.
|
|
69
|
+
const context = coerceContext(options.context);
|
|
70
70
|
const response = await context.client.request(
|
|
71
71
|
'${entry.method.toUpperCase()} ${entry.path}' ,
|
|
72
72
|
input,
|
|
@@ -117,13 +117,13 @@ function createTool2(entry, operation) {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
// packages/typescript/src/lib/agent/utils.txt
|
|
120
|
-
var utils_default = "function coerceContext(context?: any) {\n if (!context) {\n throw new Error('Context is required');\n }\n return context as {\n client: any\n };\n}\n/**\n * Takes a Zod object schema and makes all optional properties nullable as well.\n * This is useful for APIs where optional fields can be explicitly set to null.\n *\n * @param schema - The Zod object schema to transform\n * @returns A new Zod schema with optional properties made nullable\n */\nfunction makeOptionalPropsNullable<T extends z.ZodRawShape>(\n schema: z.ZodObject<T>,\n) {\n const shape = schema.shape;\n const newShape = {} as Record<string, z.ZodType>;\n\n for (const [key, value] of Object.entries(shape)) {\n if (value instanceof z.ZodOptional) {\n // Make optional properties also nullable\n newShape[key] = value.
|
|
120
|
+
var utils_default = "function coerceContext(context?: any) {\n if (!context) {\n throw new Error('Context is required');\n }\n return context as {\n client: any\n };\n}\n/**\n * Takes a Zod object schema and makes all optional properties nullable as well.\n * This is useful for APIs where optional fields can be explicitly set to null.\n *\n * @param schema - The Zod object schema to transform\n * @returns A new Zod schema with optional properties made nullable\n */\nfunction makeOptionalPropsNullable<T extends z.ZodRawShape>(\n schema: z.ZodObject<T>,\n) {\n const shape = schema.shape;\n const newShape = {} as Record<string, z.ZodType>;\n\n for (const [key, value] of Object.entries(shape) as [string, z.ZodType][]) {\n if (value instanceof z.ZodOptional) {\n // Make optional properties also nullable\n newShape[key] = value.nullable();\n } else {\n // Keep non-optional properties as they are\n newShape[key] = value;\n }\n }\n\n return z.object(newShape);\n}\n";
|
|
121
121
|
|
|
122
122
|
// packages/typescript/src/lib/client.ts
|
|
123
123
|
import { toLitObject } from "@sdk-it/core";
|
|
124
124
|
|
|
125
125
|
// packages/typescript/src/lib/emitters/zod.ts
|
|
126
|
-
import { followRef, isRef, parseRef, pascalcase } from "@sdk-it/core";
|
|
126
|
+
import { followRef, isEmpty, isRef, parseRef, pascalcase } from "@sdk-it/core";
|
|
127
127
|
import { isPrimitiveSchema, sanitizeTag } from "@sdk-it/spec";
|
|
128
128
|
var ZodEmitter = class {
|
|
129
129
|
#generatedRefs = /* @__PURE__ */ new Set();
|
|
@@ -344,6 +344,9 @@ var ZodEmitter = class {
|
|
|
344
344
|
if (isRef(schema)) {
|
|
345
345
|
return `${this.#ref(schema.$ref, true)}${appendOptional(required)}`;
|
|
346
346
|
}
|
|
347
|
+
if (schema.not && isEmpty(schema.not)) {
|
|
348
|
+
return `z.never()${appendOptional(required)}`;
|
|
349
|
+
}
|
|
347
350
|
if (schema.allOf && Array.isArray(schema.allOf)) {
|
|
348
351
|
return this.allOf(schema.allOf ?? [], required);
|
|
349
352
|
}
|
|
@@ -619,7 +622,14 @@ export async function prepare<const E extends keyof typeof schemas>(
|
|
|
619
622
|
};
|
|
620
623
|
|
|
621
624
|
// packages/typescript/src/lib/emitters/interface.ts
|
|
622
|
-
import {
|
|
625
|
+
import {
|
|
626
|
+
followRef as followRef2,
|
|
627
|
+
isEmpty as isEmpty2,
|
|
628
|
+
isRef as isRef2,
|
|
629
|
+
parseRef as parseRef2,
|
|
630
|
+
pascalcase as pascalcase2,
|
|
631
|
+
resolveRef
|
|
632
|
+
} from "@sdk-it/core";
|
|
623
633
|
import { isPrimitiveSchema as isPrimitiveSchema2, sanitizeTag as sanitizeTag2 } from "@sdk-it/spec";
|
|
624
634
|
var TypeScriptEmitter = class {
|
|
625
635
|
#spec;
|
|
@@ -629,7 +639,7 @@ var TypeScriptEmitter = class {
|
|
|
629
639
|
#stringifyKey = (value) => {
|
|
630
640
|
return `'${value}'`;
|
|
631
641
|
};
|
|
632
|
-
object(schema,
|
|
642
|
+
object(schema, _required = false) {
|
|
633
643
|
const properties = schema.properties || {};
|
|
634
644
|
const propEntries = Object.entries(properties).map(([key, propSchema]) => {
|
|
635
645
|
const isRequired = (schema.required ?? []).includes(key);
|
|
@@ -649,7 +659,7 @@ var TypeScriptEmitter = class {
|
|
|
649
659
|
/**
|
|
650
660
|
* Handle arrays (items could be a single schema or a tuple)
|
|
651
661
|
*/
|
|
652
|
-
#array(schema,
|
|
662
|
+
#array(schema, _required = false) {
|
|
653
663
|
const { items } = schema;
|
|
654
664
|
if (!items) {
|
|
655
665
|
return "any[]";
|
|
@@ -759,6 +769,9 @@ var TypeScriptEmitter = class {
|
|
|
759
769
|
if (isRef2(schema)) {
|
|
760
770
|
return this.#ref(schema.$ref, required);
|
|
761
771
|
}
|
|
772
|
+
if (schema.not && isEmpty2(schema.not)) {
|
|
773
|
+
return appendOptional2("never", required);
|
|
774
|
+
}
|
|
762
775
|
if (schema.allOf && Array.isArray(schema.allOf)) {
|
|
763
776
|
return this.allOf(schema.allOf);
|
|
764
777
|
}
|
|
@@ -801,14 +814,14 @@ function appendOptional2(type, isRequired) {
|
|
|
801
814
|
import { merge, template } from "lodash-es";
|
|
802
815
|
import { join } from "node:path";
|
|
803
816
|
import { camelcase as camelcase4, spinalcase as spinalcase2 } from "stringcase";
|
|
804
|
-
import { followRef as followRef3, isEmpty as
|
|
817
|
+
import { followRef as followRef3, isEmpty as isEmpty4, isRef as isRef3, resolveRef as resolveRef2, sortArray } from "@sdk-it/core";
|
|
805
818
|
import {
|
|
806
819
|
forEachOperation as forEachOperation3
|
|
807
820
|
} from "@sdk-it/spec";
|
|
808
821
|
|
|
809
822
|
// packages/typescript/src/lib/sdk.ts
|
|
810
823
|
import { camelcase as camelcase3 } from "stringcase";
|
|
811
|
-
import { isEmpty, pascalcase as pascalcase3 } from "@sdk-it/core";
|
|
824
|
+
import { isEmpty as isEmpty3, pascalcase as pascalcase3 } from "@sdk-it/core";
|
|
812
825
|
import {
|
|
813
826
|
isBinaryContentType,
|
|
814
827
|
isSseContentType,
|
|
@@ -855,9 +868,7 @@ function describe(p) {
|
|
|
855
868
|
nextPageMapping: `${p.pageNumberParamName}: nextPageParams.page, ${p.pageSizeParamName}: nextPageParams.pageSize`
|
|
856
869
|
};
|
|
857
870
|
}
|
|
858
|
-
throw new Error(
|
|
859
|
-
`Unknown pagination type: ${p.type}`
|
|
860
|
-
);
|
|
871
|
+
throw new Error(`Unknown pagination type: ${p.type}`);
|
|
861
872
|
}
|
|
862
873
|
function paginationOperation(pagination) {
|
|
863
874
|
const shape = describe(pagination);
|
|
@@ -963,7 +974,7 @@ function normalOperation() {
|
|
|
963
974
|
function toHttpOutput(spec, operationName, status, response, withGenerics = true) {
|
|
964
975
|
const typeScriptDeserialzer = new TypeScriptEmitter(spec);
|
|
965
976
|
const interfaceName = pascalcase3(sanitizeTag3(response["x-response-name"]));
|
|
966
|
-
if (!
|
|
977
|
+
if (!isEmpty3(response.content)) {
|
|
967
978
|
const contentTypeResult = fromContentType(typeScriptDeserialzer, response);
|
|
968
979
|
if (!contentTypeResult) {
|
|
969
980
|
throw new Error(
|
|
@@ -1086,7 +1097,7 @@ function coearceRequestInput(spec, operation, type) {
|
|
|
1086
1097
|
if (type === "application/empty") {
|
|
1087
1098
|
objectSchema = {
|
|
1088
1099
|
type: "object",
|
|
1089
|
-
additionalProperties:
|
|
1100
|
+
additionalProperties: isEmpty4(xProperties)
|
|
1090
1101
|
};
|
|
1091
1102
|
} else {
|
|
1092
1103
|
if (objectSchema.type !== "object") {
|
|
@@ -1356,7 +1367,7 @@ var offset_pagination_default = "type OffsetPaginationParams = {\n offset: numb
|
|
|
1356
1367
|
var page_pagination_default = "type InferPage<T> = T extends Page<infer U> ? U : never;\ntype PaginationParams<P extends number | bigint, S extends number | bigint> = {\n page?: P;\n pageSize?: S;\n};\n\ninterface Metadata {\n hasMore?: boolean;\n}\n\ntype PaginationRequestOptions = {\n signal?: AbortSignal;\n};\n\ntype PaginationResult<T, M extends Metadata> = {\n data: T[];\n meta: M;\n};\n\ntype FetchFn<\n T,\n M extends Metadata,\n P extends number | bigint,\n S extends number | bigint,\n> = (\n input: Partial<PaginationParams<P, S>>,\n requestOptions?: PaginationRequestOptions,\n) => Promise<PaginationResult<T, M>>;\n\n/**\n * @experimental\n */\nexport class Pagination<\n T,\n M extends Metadata,\n P extends number | bigint,\n S extends number | bigint,\n> {\n #meta: PaginationResult<T, M>['meta'] | null = null;\n #params: PaginationParams<P, S>;\n #currentPage: Page<T> | null = null;\n readonly #fetchFn: FetchFn<T, M, P, S>;\n readonly #requestOptions: PaginationRequestOptions;\n\n constructor(\n initialParams: Partial<PaginationParams<P, S>>,\n fetchFn: FetchFn<T, M, P, S>,\n requestOptions: PaginationRequestOptions = {},\n ) {\n this.#fetchFn = fetchFn;\n this.#requestOptions = requestOptions;\n this.#params = { ...initialParams, page: initialParams.page };\n }\n\n async getNextPage(requestOptions?: PaginationRequestOptions) {\n const result = await this.#fetchFn(this.#params, {\n ...this.#requestOptions,\n ...requestOptions,\n });\n this.#currentPage = new Page(result.data);\n this.#meta = result.meta;\n this.#params = {\n ...this.#params,\n page: (((this.#params.page as number) || 0) + 1) as never,\n };\n return this;\n }\n\n getCurrentPage() {\n if (!this.#currentPage) {\n throw new Error(\n 'No page data available. Please call getNextPage() first.',\n );\n }\n return this.#currentPage;\n }\n\n get hasMore() {\n if (!this.#meta) {\n throw new Error(\n 'No meta data available. Please call getNextPage() first.',\n );\n }\n return this.#meta.hasMore;\n }\n\n async *[Symbol.asyncIterator]() {\n for await (const page of this.iter()) {\n yield page.getCurrentPage();\n }\n }\n\n async *iter(requestOptions?: PaginationRequestOptions) {\n if (!this.#currentPage) {\n yield await this.getNextPage(requestOptions);\n }\n\n while (this.hasMore) {\n yield await this.getNextPage(requestOptions);\n }\n }\n\n get metadata() {\n if (!this.#meta) {\n throw new Error(\n 'No meta data available. Please call getNextPage() first.',\n );\n }\n return this.#meta;\n }\n}\n\nclass Page<T> {\n data: T[];\n constructor(data: T[]) {\n this.data = data;\n }\n}\n";
|
|
1357
1368
|
|
|
1358
1369
|
// packages/typescript/src/lib/readme/readme.ts
|
|
1359
|
-
import { isEmpty as
|
|
1370
|
+
import { isEmpty as isEmpty5 } from "@sdk-it/core";
|
|
1360
1371
|
import { forEachOperation as forEachOperation4 } from "@sdk-it/spec";
|
|
1361
1372
|
|
|
1362
1373
|
// packages/typescript/src/lib/readme/prop.emitter.ts
|
|
@@ -1684,7 +1695,7 @@ function toReadme(spec, generator) {
|
|
|
1684
1695
|
markdown.push(`#### Output`);
|
|
1685
1696
|
for (const status in operation.responses) {
|
|
1686
1697
|
const response = operation.responses[status];
|
|
1687
|
-
if (!
|
|
1698
|
+
if (!isEmpty5(response.content)) {
|
|
1688
1699
|
const contentEntries = Object.entries(response.content);
|
|
1689
1700
|
if (contentEntries.length === 1) {
|
|
1690
1701
|
const [contentType, mediaType] = contentEntries[0];
|
|
@@ -1768,7 +1779,7 @@ function expandServerUrls(servers) {
|
|
|
1768
1779
|
|
|
1769
1780
|
// packages/typescript/src/lib/typescript-snippet.ts
|
|
1770
1781
|
import { camelcase as camelcase5, spinalcase as spinalcase3 } from "stringcase";
|
|
1771
|
-
import { isEmpty as
|
|
1782
|
+
import { isEmpty as isEmpty6, pascalcase as pascalcase4, resolveRef as resolveRef4 } from "@sdk-it/core";
|
|
1772
1783
|
import "@sdk-it/readme";
|
|
1773
1784
|
import {
|
|
1774
1785
|
forEachOperation as forEachOperation5,
|
|
@@ -1979,7 +1990,7 @@ var TypeScriptSnippet = class {
|
|
|
1979
1990
|
}
|
|
1980
1991
|
succinct(entry, operation, values) {
|
|
1981
1992
|
let payload = "{}";
|
|
1982
|
-
if (!
|
|
1993
|
+
if (!isEmpty6(operation.requestBody)) {
|
|
1983
1994
|
const contentTypes = Object.keys(operation.requestBody.content || {});
|
|
1984
1995
|
const schema = resolveRef4(
|
|
1985
1996
|
this.#spec,
|
|
@@ -2041,7 +2052,7 @@ var TypeScriptSnippet = class {
|
|
|
2041
2052
|
return this.#streamDownload(entry, payload);
|
|
2042
2053
|
}
|
|
2043
2054
|
}
|
|
2044
|
-
if (!
|
|
2055
|
+
if (!isEmpty6(operation["x-pagination"])) {
|
|
2045
2056
|
return this.#pagination(operation, entry, payload);
|
|
2046
2057
|
}
|
|
2047
2058
|
return this.#normal(entry, payload);
|
|
@@ -2125,7 +2136,7 @@ const result = await ${camelcase5(this.#clientName)}.request('${entry.method.toU
|
|
|
2125
2136
|
baseUrl: expandServerUrls(this.#spec.servers ?? [])[0] ?? "http://localhost:3000"
|
|
2126
2137
|
};
|
|
2127
2138
|
const authOptions = this.#authentication();
|
|
2128
|
-
if (!
|
|
2139
|
+
if (!isEmpty6(authOptions)) {
|
|
2129
2140
|
const [firstAuth] = authOptions;
|
|
2130
2141
|
const optionName = firstAuth["x-optionName"] ?? firstAuth.name;
|
|
2131
2142
|
options[optionName] = firstAuth.example;
|
|
@@ -2165,7 +2176,7 @@ ${client.use}`;
|
|
|
2165
2176
|
);
|
|
2166
2177
|
const baseUrl = expandServerUrls(this.#spec.servers ?? [])[0] || "https://api.example.com";
|
|
2167
2178
|
const authOptions = this.#authentication();
|
|
2168
|
-
const hasApiKey = !
|
|
2179
|
+
const hasApiKey = !isEmpty6(authOptions);
|
|
2169
2180
|
sections.push("### Configuration Options");
|
|
2170
2181
|
sections.push("");
|
|
2171
2182
|
sections.push("| Option | Type | Required | Description |");
|
|
@@ -2550,7 +2561,7 @@ ${client.use}`;
|
|
|
2550
2561
|
}
|
|
2551
2562
|
authenticationDocs() {
|
|
2552
2563
|
const authOptions = this.#authentication();
|
|
2553
|
-
if (
|
|
2564
|
+
if (isEmpty6(authOptions)) {
|
|
2554
2565
|
return "";
|
|
2555
2566
|
}
|
|
2556
2567
|
const sections = [];
|
|
@@ -2632,7 +2643,7 @@ ${client.use}`;
|
|
|
2632
2643
|
const initialClientOptions = {
|
|
2633
2644
|
baseUrl: "https://api.production-service.com"
|
|
2634
2645
|
};
|
|
2635
|
-
if (!
|
|
2646
|
+
if (!isEmpty6(authOptions)) {
|
|
2636
2647
|
const [primaryAuth] = authOptions;
|
|
2637
2648
|
const authOptionName = primaryAuth["x-optionName"] ?? primaryAuth.name;
|
|
2638
2649
|
initialClientOptions[authOptionName] = "YOUR_PRODUCTION_TOKEN";
|
|
@@ -2646,7 +2657,7 @@ ${client.use}`;
|
|
|
2646
2657
|
"client.setOptions({",
|
|
2647
2658
|
" baseUrl: 'https://api.staging-service.com',"
|
|
2648
2659
|
];
|
|
2649
|
-
if (!
|
|
2660
|
+
if (!isEmpty6(authOptions)) {
|
|
2650
2661
|
const [primaryAuth] = authOptions;
|
|
2651
2662
|
const authOptionName = primaryAuth["x-optionName"] ?? primaryAuth.name;
|
|
2652
2663
|
configurationUpdateCode.push(` ${authOptionName}: 'YOUR_STAGING_TOKEN'`);
|
|
@@ -2695,7 +2706,7 @@ function availablePaginationTypes(spec) {
|
|
|
2695
2706
|
|
|
2696
2707
|
// packages/typescript/src/lib/generate.ts
|
|
2697
2708
|
async function generate(openapi, settings) {
|
|
2698
|
-
const spec = toIR(
|
|
2709
|
+
const spec = await toIR(
|
|
2699
2710
|
{
|
|
2700
2711
|
spec: openapi,
|
|
2701
2712
|
responses: { flattenErrorResponses: true },
|
|
@@ -2860,6 +2871,7 @@ ${utils_default}`
|
|
|
2860
2871
|
name: packageName,
|
|
2861
2872
|
version: "0.0.1",
|
|
2862
2873
|
type: "module",
|
|
2874
|
+
...settings.agentTools === "ai-sdk" ? { engines: { node: ">=22" } } : {},
|
|
2863
2875
|
main: "./src/index.ts",
|
|
2864
2876
|
module: "./src/index.ts",
|
|
2865
2877
|
types: "./src/index.ts",
|
|
@@ -2876,7 +2888,9 @@ ${utils_default}`
|
|
|
2876
2888
|
},
|
|
2877
2889
|
dependencies: {
|
|
2878
2890
|
"fast-content-type-parse": "^3.0.0",
|
|
2879
|
-
zod: "^4.3.0"
|
|
2891
|
+
zod: "^4.3.0",
|
|
2892
|
+
...settings.agentTools === "ai-sdk" ? { ai: "^7.0.29" } : {},
|
|
2893
|
+
...settings.agentTools === "openai-agents" ? { "@openai/agents": "^0.13.4" } : {}
|
|
2880
2894
|
}
|
|
2881
2895
|
},
|
|
2882
2896
|
null,
|