@sdk-it/typescript 0.28.0 → 0.29.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.
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +224 -250
- package/dist/index.js.map +4 -4
- package/dist/lib/agent/ai-sdk.d.ts +3 -0
- package/dist/lib/agent/ai-sdk.d.ts.map +1 -0
- package/dist/lib/agent/openai-agents.d.ts +3 -0
- package/dist/lib/agent/openai-agents.d.ts.map +1 -0
- package/dist/lib/generate.d.ts +0 -2
- package/dist/lib/generate.d.ts.map +1 -1
- package/dist/lib/generator.d.ts +7 -3
- package/dist/lib/generator.d.ts.map +1 -1
- package/dist/lib/sdk.d.ts +10 -14
- package/dist/lib/sdk.d.ts.map +1 -1
- package/dist/lib/typescript-snippet.d.ts +1 -1
- package/dist/lib/typescript-snippet.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { template as template2 } from "lodash-es";
|
|
|
3
3
|
import { readdir } from "node:fs/promises";
|
|
4
4
|
import { join as join2 } from "node:path";
|
|
5
5
|
import { npmRunPathEnv } from "npm-run-path";
|
|
6
|
-
import { camelcase as
|
|
6
|
+
import { camelcase as camelcase5, spinalcase as spinalcase4 } from "stringcase";
|
|
7
7
|
import { methods, pascalcase as pascalcase5, toLitObject as toLitObject2 } from "@sdk-it/core";
|
|
8
8
|
import {
|
|
9
9
|
createWriterProxy,
|
|
@@ -13,12 +13,50 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
augmentSpec,
|
|
15
15
|
cleanFiles,
|
|
16
|
-
forEachOperation as forEachOperation4,
|
|
17
16
|
readWriteMetadata,
|
|
18
17
|
sanitizeTag as sanitizeTag4,
|
|
19
18
|
securityToOptions as securityToOptions2
|
|
20
19
|
} from "@sdk-it/spec";
|
|
21
20
|
|
|
21
|
+
// packages/typescript/src/lib/agent/ai-sdk.ts
|
|
22
|
+
import { camelcase, spinalcase } from "stringcase";
|
|
23
|
+
import {
|
|
24
|
+
forEachOperation
|
|
25
|
+
} from "@sdk-it/spec";
|
|
26
|
+
function generateAISDKTools(spec) {
|
|
27
|
+
const groups = {};
|
|
28
|
+
forEachOperation(spec, (entry, operation) => {
|
|
29
|
+
groups[entry.tag] ??= [];
|
|
30
|
+
groups[entry.tag].push(createTool(entry, operation));
|
|
31
|
+
});
|
|
32
|
+
const imports = [
|
|
33
|
+
`import { z } from 'zod';`,
|
|
34
|
+
`import { tool } from 'ai';`,
|
|
35
|
+
`import * as schemas from './inputs/index.ts';`
|
|
36
|
+
];
|
|
37
|
+
const tools = Object.entries(groups).map(([group, tools2]) => {
|
|
38
|
+
return `export const ${spinalcase(group)} = (context: { client: any }) => ({ ${tools2.join(", ")} });`;
|
|
39
|
+
});
|
|
40
|
+
return [...imports, ...tools].join("\n\n");
|
|
41
|
+
}
|
|
42
|
+
function createTool(entry, operation) {
|
|
43
|
+
const schemaName = camelcase(`${operation.operationId} schema`);
|
|
44
|
+
return `'${operation["x-fn-name"]}': tool({
|
|
45
|
+
description: \`${operation.description || operation.summary}\`,
|
|
46
|
+
type: 'function',
|
|
47
|
+
inputSchema: schemas.${schemaName},
|
|
48
|
+
execute: async (input) => {
|
|
49
|
+
console.log('Executing ${operation.operationId} tool with input:', input);
|
|
50
|
+
const client = context.client;
|
|
51
|
+
const response = await client.request(
|
|
52
|
+
'${entry.method.toUpperCase()} ${entry.path}' ,
|
|
53
|
+
input as any,
|
|
54
|
+
);
|
|
55
|
+
return JSON.stringify(response);
|
|
56
|
+
},
|
|
57
|
+
})`;
|
|
58
|
+
}
|
|
59
|
+
|
|
22
60
|
// packages/typescript/src/lib/agent/utils.txt
|
|
23
61
|
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.ZodTypeAny>;\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._def.innerType.nullable().optional();\n } else {\n // Keep non-optional properties as they are\n newShape[key] = value;\n }\n }\n\n return z.object(newShape);\n}";
|
|
24
62
|
|
|
@@ -588,58 +626,25 @@ function appendOptional2(type, isRequired) {
|
|
|
588
626
|
// packages/typescript/src/lib/generator.ts
|
|
589
627
|
import { merge, template } from "lodash-es";
|
|
590
628
|
import { join } from "node:path";
|
|
591
|
-
import { camelcase as
|
|
629
|
+
import { camelcase as camelcase3, spinalcase as spinalcase2 } from "stringcase";
|
|
592
630
|
import { followRef as followRef3, isEmpty as isEmpty2, isRef as isRef3, resolveRef } from "@sdk-it/core";
|
|
593
|
-
import {
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
import { removeDuplicates } from "@sdk-it/core";
|
|
597
|
-
function mergeImports(...imports) {
|
|
598
|
-
const merged = {};
|
|
599
|
-
for (const it of imports) {
|
|
600
|
-
merged[it.moduleSpecifier] = merged[it.moduleSpecifier] ?? {
|
|
601
|
-
moduleSpecifier: it.moduleSpecifier,
|
|
602
|
-
defaultImport: it.defaultImport,
|
|
603
|
-
namespaceImport: it.namespaceImport,
|
|
604
|
-
namedImports: []
|
|
605
|
-
};
|
|
606
|
-
for (const named of it.namedImports) {
|
|
607
|
-
if (!merged[it.moduleSpecifier].namedImports.some(
|
|
608
|
-
(x) => x.name === named.name
|
|
609
|
-
)) {
|
|
610
|
-
merged[it.moduleSpecifier].namedImports.push(named);
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
return Object.values(merged);
|
|
615
|
-
}
|
|
616
|
-
function importsToString(...imports) {
|
|
617
|
-
return imports.map((it) => {
|
|
618
|
-
if (it.defaultImport) {
|
|
619
|
-
return `import ${it.defaultImport} from '${it.moduleSpecifier}'`;
|
|
620
|
-
}
|
|
621
|
-
if (it.namespaceImport) {
|
|
622
|
-
return `import * as ${it.namespaceImport} from '${it.moduleSpecifier}'`;
|
|
623
|
-
}
|
|
624
|
-
if (it.namedImports) {
|
|
625
|
-
return `import {${removeDuplicates(it.namedImports, (it2) => it2.name).map((n) => `${n.isTypeOnly ? "type" : ""} ${n.name}`).join(", ")}} from '${it.moduleSpecifier}'`;
|
|
626
|
-
}
|
|
627
|
-
throw new Error(`Invalid import ${JSON.stringify(it)}`);
|
|
628
|
-
});
|
|
629
|
-
}
|
|
631
|
+
import {
|
|
632
|
+
forEachOperation as forEachOperation2
|
|
633
|
+
} from "@sdk-it/spec";
|
|
630
634
|
|
|
631
635
|
// packages/typescript/src/lib/sdk.ts
|
|
632
|
-
import { camelcase } from "stringcase";
|
|
636
|
+
import { camelcase as camelcase2 } from "stringcase";
|
|
633
637
|
import { isEmpty, pascalcase as pascalcase3 } from "@sdk-it/core";
|
|
634
638
|
import {
|
|
635
|
-
isErrorStatusCode,
|
|
636
639
|
isStreamingContentType,
|
|
637
|
-
isSuccessStatusCode,
|
|
638
640
|
isTextContentType,
|
|
639
641
|
parseJsonContentType,
|
|
640
642
|
sanitizeTag as sanitizeTag3
|
|
641
643
|
} from "@sdk-it/spec";
|
|
642
644
|
|
|
645
|
+
// packages/typescript/src/lib/import-utilities.ts
|
|
646
|
+
import { removeDuplicates } from "@sdk-it/core";
|
|
647
|
+
|
|
643
648
|
// packages/typescript/src/lib/status-map.ts
|
|
644
649
|
var status_map_default = {
|
|
645
650
|
"200": "Ok",
|
|
@@ -668,52 +673,25 @@ var status_map_default = {
|
|
|
668
673
|
|
|
669
674
|
// packages/typescript/src/lib/sdk.ts
|
|
670
675
|
function toEndpoint(groupName, spec, specOperation, operation, utils) {
|
|
671
|
-
const schemaName =
|
|
672
|
-
const schemaRef = `${
|
|
673
|
-
const inputHeaders = [];
|
|
674
|
-
const inputQuery = [];
|
|
675
|
-
const inputBody = [];
|
|
676
|
-
const inputParams = [];
|
|
676
|
+
const schemaName = camelcase2(`${specOperation.operationId} schema`);
|
|
677
|
+
const schemaRef = `${camelcase2(groupName)}.${schemaName}`;
|
|
677
678
|
const schemas = [];
|
|
678
|
-
const responses = [];
|
|
679
|
-
for (const [name, prop] of Object.entries(operation.inputs)) {
|
|
680
|
-
if (prop.in === "headers" || prop.in === "header") {
|
|
681
|
-
inputHeaders.push(`"${name}"`);
|
|
682
|
-
} else if (prop.in === "query") {
|
|
683
|
-
inputQuery.push(`"${name}"`);
|
|
684
|
-
} else if (prop.in === "body") {
|
|
685
|
-
inputBody.push(`"${name}"`);
|
|
686
|
-
} else if (prop.in === "path") {
|
|
687
|
-
inputParams.push(`"${name}"`);
|
|
688
|
-
} else if (prop.in === "internal") {
|
|
689
|
-
continue;
|
|
690
|
-
} else {
|
|
691
|
-
throw new Error(
|
|
692
|
-
`Unknown source ${prop.in} in ${name} ${JSON.stringify(
|
|
693
|
-
prop
|
|
694
|
-
)} in ${operation.name}`
|
|
695
|
-
);
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
679
|
specOperation.responses ??= {};
|
|
699
|
-
const outputs =
|
|
700
|
-
|
|
701
|
-
const handled = handleResponse(
|
|
680
|
+
const outputs = Object.keys(specOperation.responses).flatMap(
|
|
681
|
+
(status) => toHttpOutput(
|
|
702
682
|
spec,
|
|
703
|
-
|
|
683
|
+
specOperation.operationId,
|
|
704
684
|
status,
|
|
705
|
-
specOperation.responses[status]
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
responses.push(handled);
|
|
709
|
-
outputs.push(...handled.outputs);
|
|
710
|
-
}
|
|
685
|
+
specOperation.responses[status]
|
|
686
|
+
)
|
|
687
|
+
);
|
|
711
688
|
const addTypeParser = Object.keys(operation.schemas).length > 1;
|
|
712
689
|
for (const type in operation.schemas ?? {}) {
|
|
713
690
|
let typePrefix = "";
|
|
714
691
|
if (addTypeParser && type !== "json") {
|
|
715
692
|
typePrefix = `${type} `;
|
|
716
693
|
}
|
|
694
|
+
const paths = inputToPath(specOperation, operation.inputs);
|
|
717
695
|
const endpoint = `${typePrefix}${operation.method.toUpperCase()} ${operation.path}`;
|
|
718
696
|
schemas.push(
|
|
719
697
|
`"${endpoint}": {
|
|
@@ -721,10 +699,10 @@ function toEndpoint(groupName, spec, specOperation, operation, utils) {
|
|
|
721
699
|
output:[${outputs.join(",")}],
|
|
722
700
|
toRequest(input: z.infer<typeof ${schemaRef}${addTypeParser ? `.${type}` : ""}>) {
|
|
723
701
|
return toRequest('${endpoint}', ${operation.outgoingContentType || "empty"}(input, {
|
|
724
|
-
inputHeaders: [${inputHeaders}],
|
|
725
|
-
inputQuery: [${inputQuery}],
|
|
726
|
-
inputBody: [${inputBody}],
|
|
727
|
-
inputParams: [${inputParams}],
|
|
702
|
+
inputHeaders: [${paths.inputHeaders}],
|
|
703
|
+
inputQuery: [${paths.inputQuery}],
|
|
704
|
+
inputBody: [${paths.inputBody}],
|
|
705
|
+
inputParams: [${paths.inputParams}],
|
|
728
706
|
}));},
|
|
729
707
|
async dispatch(input: z.infer<typeof ${schemaRef}${addTypeParser ? `.${type}` : ""}>,options: {
|
|
730
708
|
signal?: AbortSignal;
|
|
@@ -733,7 +711,7 @@ function toEndpoint(groupName, spec, specOperation, operation, utils) {
|
|
|
733
711
|
})${specOperation["x-pagination"] ? paginationOperation(specOperation, utils.style) : normalOperation(utils.style)}`
|
|
734
712
|
);
|
|
735
713
|
}
|
|
736
|
-
return {
|
|
714
|
+
return { schemas };
|
|
737
715
|
}
|
|
738
716
|
function normalOperation(style) {
|
|
739
717
|
return `{
|
|
@@ -819,32 +797,10 @@ function paginationOperation(operation, style) {
|
|
|
819
797
|
}
|
|
820
798
|
return normalOperation(style);
|
|
821
799
|
}
|
|
822
|
-
function
|
|
823
|
-
const schemas = {};
|
|
824
|
-
const imports = {};
|
|
825
|
-
const endpointImports = {
|
|
826
|
-
ParseError: {
|
|
827
|
-
defaultImport: void 0,
|
|
828
|
-
isTypeOnly: false,
|
|
829
|
-
moduleSpecifier: utils.makeImport(`../http/parser`),
|
|
830
|
-
namedImports: [{ isTypeOnly: false, name: "ParseError" }],
|
|
831
|
-
namespaceImport: void 0
|
|
832
|
-
}
|
|
833
|
-
};
|
|
834
|
-
const responses = [];
|
|
835
|
-
const outputs = [];
|
|
800
|
+
function toHttpOutput(spec, operationName, status, response, withGenerics = true) {
|
|
836
801
|
const typeScriptDeserialzer = new TypeScriptEmitter(spec);
|
|
837
|
-
const statusCode = +status;
|
|
838
|
-
const statusName = `http.${status_map_default[status] || "APIResponse"}`;
|
|
839
802
|
const interfaceName = pascalcase3(sanitizeTag3(response["x-response-name"]));
|
|
840
|
-
|
|
841
|
-
if (isEmpty(response.content)) {
|
|
842
|
-
responses.push({
|
|
843
|
-
name: interfaceName,
|
|
844
|
-
schema: "void",
|
|
845
|
-
description: response.description
|
|
846
|
-
});
|
|
847
|
-
} else {
|
|
803
|
+
if (!isEmpty(response.content)) {
|
|
848
804
|
const contentTypeResult = fromContentType(
|
|
849
805
|
spec,
|
|
850
806
|
typeScriptDeserialzer,
|
|
@@ -855,33 +811,27 @@ function handleResponse(spec, operationName, status, response, utils) {
|
|
|
855
811
|
`No recognizable content type for response ${status} in operation ${operationName}`
|
|
856
812
|
);
|
|
857
813
|
}
|
|
858
|
-
parser = contentTypeResult.parser;
|
|
859
|
-
const
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
});
|
|
865
|
-
if (isErrorStatusCode(statusCode)) {
|
|
866
|
-
endpointImports[status_map_default[status] ?? "APIError"] = {
|
|
867
|
-
moduleSpecifier: utils.makeImport("../http/response"),
|
|
868
|
-
namedImports: [{ name: status_map_default[status] ?? "APIError" }]
|
|
869
|
-
};
|
|
870
|
-
} else if (isSuccessStatusCode(statusCode)) {
|
|
871
|
-
}
|
|
872
|
-
}
|
|
873
|
-
if (statusCode === 204) {
|
|
874
|
-
outputs.push(statusName);
|
|
875
|
-
} else {
|
|
876
|
-
if (status.endsWith("XX")) {
|
|
877
|
-
outputs.push(`http.APIError<outputs.${interfaceName}>`);
|
|
814
|
+
const parser = contentTypeResult.parser || "buffered";
|
|
815
|
+
const outputs = [];
|
|
816
|
+
const statusName = `http.${status_map_default[status] || "APIResponse"}`;
|
|
817
|
+
const statusCode = +status;
|
|
818
|
+
if (statusCode === 204) {
|
|
819
|
+
outputs.push(statusName);
|
|
878
820
|
} else {
|
|
879
|
-
outputs
|
|
880
|
-
|
|
881
|
-
|
|
821
|
+
const generic = withGenerics ? `<outputs.${interfaceName}>` : "";
|
|
822
|
+
if (status.endsWith("XX")) {
|
|
823
|
+
outputs.push(`http.APIError${generic}`);
|
|
824
|
+
} else {
|
|
825
|
+
if (parser !== "buffered") {
|
|
826
|
+
outputs.push(`{type: ${statusName}${generic}, parser: ${parser}}`);
|
|
827
|
+
} else {
|
|
828
|
+
outputs.push(`${statusName}${generic}`);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
882
831
|
}
|
|
832
|
+
return outputs;
|
|
883
833
|
}
|
|
884
|
-
return
|
|
834
|
+
return [];
|
|
885
835
|
}
|
|
886
836
|
function fromContentType(spec, typeScriptDeserialzer, response) {
|
|
887
837
|
if ((response.headers ?? {})["Transfer-Encoding"]) {
|
|
@@ -912,11 +862,71 @@ function streamedOutput() {
|
|
|
912
862
|
responseSchema: "ReadableStream"
|
|
913
863
|
};
|
|
914
864
|
}
|
|
865
|
+
function inputToPath(operation, inputs) {
|
|
866
|
+
const inputHeaders = [];
|
|
867
|
+
const inputQuery = [];
|
|
868
|
+
const inputBody = [];
|
|
869
|
+
const inputParams = [];
|
|
870
|
+
for (const [name, prop] of Object.entries(inputs)) {
|
|
871
|
+
if (prop.in === "headers" || prop.in === "header") {
|
|
872
|
+
inputHeaders.push(`"${name}"`);
|
|
873
|
+
} else if (prop.in === "query") {
|
|
874
|
+
inputQuery.push(`"${name}"`);
|
|
875
|
+
} else if (prop.in === "body") {
|
|
876
|
+
inputBody.push(`"${name}"`);
|
|
877
|
+
} else if (prop.in === "path") {
|
|
878
|
+
inputParams.push(`"${name}"`);
|
|
879
|
+
} else if (prop.in === "internal") {
|
|
880
|
+
continue;
|
|
881
|
+
} else {
|
|
882
|
+
throw new Error(
|
|
883
|
+
`Unknown source ${prop.in} in ${name} ${JSON.stringify(
|
|
884
|
+
prop
|
|
885
|
+
)} in ${operation.operationId}`
|
|
886
|
+
);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
return {
|
|
890
|
+
inputHeaders,
|
|
891
|
+
inputQuery,
|
|
892
|
+
inputBody,
|
|
893
|
+
inputParams
|
|
894
|
+
};
|
|
895
|
+
}
|
|
915
896
|
|
|
916
897
|
// packages/typescript/src/lib/styles/github/endpoints.txt
|
|
917
898
|
var endpoints_default = "type EndpointOutput<K extends keyof typeof schemas> = Extract<\n Unionize<(typeof schemas)[K]['output']>,\n SuccessfulResponse\n>;\n\ntype EndpointError<K extends keyof typeof schemas> = Extract<\n Unionize<(typeof schemas)[K]['output']>,\n ProblematicResponse\n>;\n\nexport type Endpoints = {\n [K in keyof typeof schemas]: {\n input: z.infer<(typeof schemas)[K]['schema']>;\n output: <% if (outputType === 'default') { %>EndpointOutput<K>['data']<% } else { %>EndpointOutput<K><% } %>;\n error: EndpointError<K> | ParseError<(typeof schemas)[K]['schema']>;\n };\n};";
|
|
918
899
|
|
|
919
900
|
// packages/typescript/src/lib/generator.ts
|
|
901
|
+
function coearceRequestInput(spec, operation, type) {
|
|
902
|
+
let objectSchema = resolveRef(
|
|
903
|
+
spec,
|
|
904
|
+
operation.requestBody.content[type].schema
|
|
905
|
+
);
|
|
906
|
+
const xProperties = objectSchema["x-properties"] ?? {};
|
|
907
|
+
const xRequired = objectSchema["x-required"] ?? [];
|
|
908
|
+
if (type === "application/empty") {
|
|
909
|
+
objectSchema = {
|
|
910
|
+
type: "object",
|
|
911
|
+
additionalProperties: isEmpty2(xProperties)
|
|
912
|
+
};
|
|
913
|
+
} else {
|
|
914
|
+
if (objectSchema.type !== "object") {
|
|
915
|
+
objectSchema = {
|
|
916
|
+
type: "object",
|
|
917
|
+
required: [operation.requestBody.required ? "$body" : ""],
|
|
918
|
+
properties: {
|
|
919
|
+
$body: objectSchema
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
return {
|
|
925
|
+
objectSchema,
|
|
926
|
+
xProperties,
|
|
927
|
+
xRequired
|
|
928
|
+
};
|
|
929
|
+
}
|
|
920
930
|
function generateCode(config) {
|
|
921
931
|
const commonZod = /* @__PURE__ */ new Map();
|
|
922
932
|
const commonZodImports = [];
|
|
@@ -932,11 +942,10 @@ function generateCode(config) {
|
|
|
932
942
|
});
|
|
933
943
|
const groups = {};
|
|
934
944
|
const endpoints = {};
|
|
935
|
-
|
|
945
|
+
forEachOperation2(config.spec, (entry, operation) => {
|
|
936
946
|
console.log(`Processing ${entry.method} ${entry.path}`);
|
|
937
947
|
groups[entry.tag] ??= [];
|
|
938
948
|
endpoints[entry.tag] ??= [];
|
|
939
|
-
const inputs = {};
|
|
940
949
|
const schemas = {};
|
|
941
950
|
const shortContenTypeMap = {
|
|
942
951
|
"application/json": "json",
|
|
@@ -949,30 +958,12 @@ function generateCode(config) {
|
|
|
949
958
|
"application/xml": "xml",
|
|
950
959
|
"text/plain": "text"
|
|
951
960
|
};
|
|
952
|
-
let outgoingContentType = "empty";
|
|
953
961
|
for (const type in operation.requestBody.content) {
|
|
954
|
-
|
|
962
|
+
const { objectSchema, xProperties, xRequired } = coearceRequestInput(
|
|
955
963
|
config.spec,
|
|
956
|
-
operation
|
|
964
|
+
operation,
|
|
965
|
+
type
|
|
957
966
|
);
|
|
958
|
-
const xProperties = objectSchema["x-properties"] ?? {};
|
|
959
|
-
const xRequired = objectSchema["x-required"] ?? [];
|
|
960
|
-
if (type === "application/empty") {
|
|
961
|
-
objectSchema = {
|
|
962
|
-
type: "object",
|
|
963
|
-
additionalProperties: isEmpty2(xProperties)
|
|
964
|
-
};
|
|
965
|
-
} else {
|
|
966
|
-
if (objectSchema.type !== "object") {
|
|
967
|
-
objectSchema = {
|
|
968
|
-
type: "object",
|
|
969
|
-
required: [operation.requestBody.required ? "$body" : ""],
|
|
970
|
-
properties: {
|
|
971
|
-
$body: objectSchema
|
|
972
|
-
}
|
|
973
|
-
};
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
967
|
const additionalProperties = {};
|
|
977
968
|
for (const [name, prop] of Object.entries(xProperties)) {
|
|
978
969
|
additionalProperties[name] = {
|
|
@@ -981,10 +972,6 @@ function generateCode(config) {
|
|
|
981
972
|
schema: prop,
|
|
982
973
|
in: prop["x-in"]
|
|
983
974
|
};
|
|
984
|
-
inputs[name] = {
|
|
985
|
-
in: prop["x-in"],
|
|
986
|
-
schema: ""
|
|
987
|
-
};
|
|
988
975
|
}
|
|
989
976
|
const schema = merge({}, objectSchema, {
|
|
990
977
|
required: Object.values(additionalProperties).filter((p) => p.required).map((p) => p.name),
|
|
@@ -993,43 +980,36 @@ function generateCode(config) {
|
|
|
993
980
|
{}
|
|
994
981
|
)
|
|
995
982
|
});
|
|
996
|
-
Object.assign(inputs, bodyInputs(config.spec, objectSchema));
|
|
997
983
|
schemas[shortContenTypeMap[type]] = zodDeserialzer.handle(schema, true);
|
|
998
984
|
}
|
|
999
|
-
|
|
1000
|
-
outgoingContentType = "json";
|
|
1001
|
-
} else if (operation.requestBody.content["application/x-www-form-urlencoded"]) {
|
|
1002
|
-
outgoingContentType = "urlencoded";
|
|
1003
|
-
} else if (operation.requestBody.content["multipart/form-data"]) {
|
|
1004
|
-
outgoingContentType = "formdata";
|
|
1005
|
-
}
|
|
985
|
+
const details = buildInput(config.spec, operation);
|
|
1006
986
|
const endpoint = toEndpoint(
|
|
1007
987
|
entry.tag,
|
|
1008
988
|
config.spec,
|
|
1009
989
|
operation,
|
|
1010
990
|
{
|
|
1011
|
-
outgoingContentType,
|
|
1012
|
-
name: operation.operationId,
|
|
1013
991
|
method: entry.method,
|
|
1014
992
|
path: entry.path,
|
|
993
|
+
operationId: operation.operationId,
|
|
1015
994
|
schemas,
|
|
1016
|
-
|
|
995
|
+
outgoingContentType: details.outgoingContentType,
|
|
996
|
+
inputs: details.inputs
|
|
1017
997
|
},
|
|
1018
|
-
|
|
998
|
+
config
|
|
1019
999
|
);
|
|
1020
1000
|
endpoints[entry.tag].push(endpoint);
|
|
1021
1001
|
groups[entry.tag].push({
|
|
1022
|
-
name: operation.operationId,
|
|
1023
|
-
inputs,
|
|
1024
|
-
outgoingContentType,
|
|
1025
|
-
schemas,
|
|
1026
1002
|
method: entry.method,
|
|
1027
|
-
path: entry.path
|
|
1003
|
+
path: entry.path,
|
|
1004
|
+
operationId: operation.operationId,
|
|
1005
|
+
schemas,
|
|
1006
|
+
outgoingContentType: details.outgoingContentType,
|
|
1007
|
+
inputs: details.inputs
|
|
1028
1008
|
});
|
|
1029
1009
|
});
|
|
1030
1010
|
const allSchemas = Object.keys(endpoints).map((it) => ({
|
|
1031
|
-
import: `import ${
|
|
1032
|
-
use: ` ...${
|
|
1011
|
+
import: `import ${camelcase3(it)} from './${config.makeImport(spinalcase2(it))}';`,
|
|
1012
|
+
use: ` ...${camelcase3(it)}`
|
|
1033
1013
|
}));
|
|
1034
1014
|
return {
|
|
1035
1015
|
groups,
|
|
@@ -1056,26 +1036,16 @@ ${allSchemas.map((it) => it.use).join(",\n")}
|
|
|
1056
1036
|
`.trim(),
|
|
1057
1037
|
...Object.fromEntries(
|
|
1058
1038
|
Object.entries(endpoints).map(([name, endpoint]) => {
|
|
1059
|
-
const imps = importsToString(
|
|
1060
|
-
...mergeImports(
|
|
1061
|
-
...endpoint.flatMap(
|
|
1062
|
-
(it) => it.responses.flatMap(
|
|
1063
|
-
(it2) => Object.values(it2.endpointImports)
|
|
1064
|
-
)
|
|
1065
|
-
)
|
|
1066
|
-
)
|
|
1067
|
-
);
|
|
1068
1039
|
return [
|
|
1069
1040
|
[
|
|
1070
|
-
join("api", `${
|
|
1041
|
+
join("api", `${spinalcase2(name)}.ts`),
|
|
1071
1042
|
`${[
|
|
1072
|
-
...imps,
|
|
1073
1043
|
`import z from 'zod';`,
|
|
1074
1044
|
`import * as http from '${config.makeImport("../http/response")}';`,
|
|
1075
1045
|
`import * as outputs from '${config.makeImport("../outputs/index")}';`,
|
|
1076
1046
|
`import { toRequest, json, urlencoded, empty, formdata, createUrl, type HeadersInit } from '${config.makeImport("../http/request")}';`,
|
|
1077
1047
|
`import { chunked, buffered } from "${config.makeImport("../http/parse-response")}";`,
|
|
1078
|
-
`import * as ${
|
|
1048
|
+
`import * as ${camelcase3(name)} from '../inputs/${config.makeImport(spinalcase2(name))}';`,
|
|
1079
1049
|
`import { createBaseUrlInterceptor, createHeadersInterceptor, type Interceptor } from '${config.makeImport("../http/interceptors")}';`,
|
|
1080
1050
|
`import { Dispatcher, fetchType, type InstanceType } from '${config.makeImport("../http/dispatcher")}';`,
|
|
1081
1051
|
`import { Pagination, OffsetPagination, CursorPagination } from "${config.makeImport("../pagination/index")}";`
|
|
@@ -1137,6 +1107,40 @@ function bodyInputs(spec, ctSchema) {
|
|
|
1137
1107
|
{}
|
|
1138
1108
|
);
|
|
1139
1109
|
}
|
|
1110
|
+
var contentTypeMap = {
|
|
1111
|
+
"application/json": "json",
|
|
1112
|
+
"application/x-www-form-urlencoded": "urlencoded",
|
|
1113
|
+
"multipart/form-data": "formdata",
|
|
1114
|
+
"application/xml": "xml",
|
|
1115
|
+
"text/plain": "text",
|
|
1116
|
+
"application/empty": "empty"
|
|
1117
|
+
};
|
|
1118
|
+
function buildInput(spec, operation) {
|
|
1119
|
+
const inputs = {};
|
|
1120
|
+
let outgoingContentType = "empty";
|
|
1121
|
+
for (const [ct, value] of Object.entries(contentTypeMap)) {
|
|
1122
|
+
if (operation.requestBody.content[ct]) {
|
|
1123
|
+
outgoingContentType = value;
|
|
1124
|
+
const { objectSchema, xProperties } = coearceRequestInput(
|
|
1125
|
+
spec,
|
|
1126
|
+
operation,
|
|
1127
|
+
ct
|
|
1128
|
+
);
|
|
1129
|
+
for (const [name, prop] of Object.entries(xProperties)) {
|
|
1130
|
+
inputs[name] = {
|
|
1131
|
+
in: prop["x-in"],
|
|
1132
|
+
schema: ""
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1135
|
+
Object.assign(inputs, bodyInputs(spec, objectSchema));
|
|
1136
|
+
break;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
return {
|
|
1140
|
+
inputs,
|
|
1141
|
+
outgoingContentType
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1140
1144
|
|
|
1141
1145
|
// packages/typescript/src/lib/http/dispatcher.txt
|
|
1142
1146
|
var dispatcher_default = "export type Unionize<T> = T extends [infer Single extends OutputType]\n ? InstanceType<Single>\n : T extends readonly [...infer Tuple extends OutputType[]]\n ? { [I in keyof Tuple]: InstanceType<Tuple[I]> }[number]\n : never;\n\nexport type InstanceType<T> =\n T extends Type<infer U>\n ? U\n : T extends { type: Type<infer U> }\n ? U\n : T extends Array<unknown>\n ? Unionize<T>\n : never;\n\nexport interface Type<T> {\n new (...args: any[]): T;\n}\nexport type Parser = (\n response: Response,\n) => Promise<unknown> | ReadableStream<any>;\nexport type OutputType =\n | Type<APIResponse>\n | { parser: Parser; type: Type<APIResponse> };\n\nexport const fetchType = z\n .function()\n .args(z.instanceof(Request))\n .returns(z.promise(z.instanceof(Response)))\n .optional();\n\nexport async function parse<T extends OutputType[]>(\n outputs: T,\n response: Response,\n) <% if(!throwError) { %>\n: Promise<\n [\n Extract<InstanceType<T>, SuccessfulResponse>['data'],\n Extract<InstanceType<T>, ProblematicResponse>['data'],\n ]\n>\n <% } %>\n\n\n\n {\n let output: typeof APIResponse | null = null;\n let parser: Parser = buffered;\n for (const outputType of outputs) {\n if ('parser' in outputType) {\n parser = outputType.parser;\n if (isTypeOf(outputType.type, APIResponse)) {\n if (response.status === outputType.type.status) {\n output = outputType.type;\n break;\n }\n }\n } else if (isTypeOf(outputType, APIResponse)) {\n if (response.status === outputType.status) {\n output = outputType;\n break;\n }\n }\n }\n\n\n if (response.ok) {\n const apiresponse = (output || APIResponse).create(\n response.status,\n await parser(response),\n );\n <% if(throwError) { %>\n return <% if (outputType === 'default') { %>apiresponse as Extract<InstanceType<T>, SuccessfulResponse><% } else { %>apiresponse as Extract<InstanceType<T>, SuccessfulResponse>;<% } %>;\n <% } else { %>\n return [<% if (outputType === 'default') { %>apiresponse.data as Extract<InstanceType<T>, SuccessfulResponse>['data']<% } else { %>apiresponse as Extract<InstanceType<T>, SuccessfulResponse><% } %>, null] as const;\n <% } %>\n }\n<% if(throwError) { %>\n throw (output || APIError).create(\n response.status,\n await parser(response),\n );\n<% } else { %>\n const data = (output || APIError).create(\n response.status,\n await parser(response),\n );\n return [null, data] as const;\n<% } %>\n}\n\nexport function isTypeOf<T extends Type<APIResponse>>(\n instance: any,\n baseType: T,\n): instance is T {\n if (instance === baseType) {\n return true;\n }\n const prototype = Object.getPrototypeOf(instance);\n if (prototype === null) {\n return false;\n }\n return isTypeOf(prototype, baseType);\n}\n\nexport class Dispatcher {\n #interceptors: Interceptor[] = [];\n #fetch: z.infer<typeof fetchType>;\n constructor(interceptors: Interceptor[], fetch?: z.infer<typeof fetchType>) {\n this.#interceptors = interceptors;\n this.#fetch = fetch;\n }\n\n async send<T extends OutputType[]>(\n config: RequestConfig,\n outputs: T,\n signal?: AbortSignal,\n ) {\n for (const interceptor of this.#interceptors) {\n if (interceptor.before) {\n config = await interceptor.before(config);\n }\n }\n\n let response = await (this.#fetch ?? fetch)(\n new Request(config.url, config.init),\n {\n ...config.init,\n signal: signal,\n },\n );\n\n for (let i = this.#interceptors.length - 1; i >= 0; i--) {\n const interceptor = this.#interceptors[i];\n if (interceptor.after) {\n response = await interceptor.after(response.clone());\n }\n }\n\n return await parse(outputs, response);\n }\n}\n";
|
|
@@ -1599,7 +1603,7 @@ var page_pagination_default = "type InferPage<T> = T extends Page<infer U> ? U :
|
|
|
1599
1603
|
|
|
1600
1604
|
// packages/typescript/src/lib/readme/readme.ts
|
|
1601
1605
|
import { isEmpty as isEmpty3 } from "@sdk-it/core";
|
|
1602
|
-
import { forEachOperation as
|
|
1606
|
+
import { forEachOperation as forEachOperation3 } from "@sdk-it/spec";
|
|
1603
1607
|
|
|
1604
1608
|
// packages/typescript/src/lib/readme/prop.emitter.ts
|
|
1605
1609
|
import { followRef as followRef4, isRef as isRef4 } from "@sdk-it/core";
|
|
@@ -1889,7 +1893,7 @@ function toReadme(spec, generator) {
|
|
|
1889
1893
|
markdown.push(`# ${spec.info.title} TypeScript SDK`);
|
|
1890
1894
|
markdown.push("");
|
|
1891
1895
|
markdown.push(
|
|
1892
|
-
"A fully-typed TypeScript SDK with comprehensive IntelliSense support, automatic request/response validation, and modern async/await patterns. Built for seamless integration with TypeScript and JavaScript projects."
|
|
1896
|
+
"A fully-typed TypeScript SDK with comprehensive IntelliSense support, automatic request/response validation, and modern async/await patterns. Built for seamless integration with TypeScript and JavaScript projects. Each endpoint includes a brief description, example usage, and details about request and response formats."
|
|
1893
1897
|
);
|
|
1894
1898
|
markdown.push("");
|
|
1895
1899
|
markdown.push(generator.clientSetupDocs());
|
|
@@ -1910,7 +1914,7 @@ function toReadme(spec, generator) {
|
|
|
1910
1914
|
markdown.push("");
|
|
1911
1915
|
markdown.push("## API Reference");
|
|
1912
1916
|
markdown.push("");
|
|
1913
|
-
|
|
1917
|
+
forEachOperation3(spec, (entry, operation) => {
|
|
1914
1918
|
const { method, path } = entry;
|
|
1915
1919
|
markdown.push(
|
|
1916
1920
|
`### ${operation["x-fn-name"]} | ${`_${method.toUpperCase()} ${path}_`}`
|
|
@@ -1983,11 +1987,11 @@ ${l}`));
|
|
|
1983
1987
|
}
|
|
1984
1988
|
|
|
1985
1989
|
// packages/typescript/src/lib/typescript-snippet.ts
|
|
1986
|
-
import { camelcase as
|
|
1990
|
+
import { camelcase as camelcase4, spinalcase as spinalcase3 } from "stringcase";
|
|
1987
1991
|
import { isEmpty as isEmpty4, pascalcase as pascalcase4, resolveRef as resolveRef3 } from "@sdk-it/core";
|
|
1988
1992
|
import "@sdk-it/readme";
|
|
1989
1993
|
import {
|
|
1990
|
-
forEachOperation as
|
|
1994
|
+
forEachOperation as forEachOperation4,
|
|
1991
1995
|
patchParameters,
|
|
1992
1996
|
securityToOptions
|
|
1993
1997
|
} from "@sdk-it/spec";
|
|
@@ -2038,11 +2042,11 @@ var SnippetEmitter = class {
|
|
|
2038
2042
|
switch (schema.format) {
|
|
2039
2043
|
case "date-time":
|
|
2040
2044
|
case "datetime":
|
|
2041
|
-
return
|
|
2045
|
+
return `2025-07-17T09:08:00.097Z`;
|
|
2042
2046
|
case "date":
|
|
2043
|
-
return
|
|
2047
|
+
return `2025-07-17`;
|
|
2044
2048
|
case "time":
|
|
2045
|
-
return
|
|
2049
|
+
return `09:08:00.097Z`;
|
|
2046
2050
|
case "email":
|
|
2047
2051
|
return "user@example.com";
|
|
2048
2052
|
case "uuid":
|
|
@@ -2182,7 +2186,7 @@ var SnippetEmitter = class {
|
|
|
2182
2186
|
};
|
|
2183
2187
|
|
|
2184
2188
|
// packages/typescript/src/lib/typescript-snippet.ts
|
|
2185
|
-
var
|
|
2189
|
+
var TypeScriptSnippet = class {
|
|
2186
2190
|
#spec;
|
|
2187
2191
|
#settings;
|
|
2188
2192
|
#snippetEmitter;
|
|
@@ -2193,7 +2197,7 @@ var TypeScriptGenerator = class {
|
|
|
2193
2197
|
this.#settings = settings;
|
|
2194
2198
|
this.#snippetEmitter = new SnippetEmitter(spec);
|
|
2195
2199
|
this.#clientName = settings.name?.trim() ? pascalcase4(settings.name) : "Client";
|
|
2196
|
-
this.#packageName = settings.name ? `@${
|
|
2200
|
+
this.#packageName = settings.name ? `@${spinalcase3(this.#clientName.toLowerCase())}/sdk` : "sdk";
|
|
2197
2201
|
}
|
|
2198
2202
|
succinct(entry, operation, values) {
|
|
2199
2203
|
let payload = "{}";
|
|
@@ -2312,7 +2316,7 @@ var TypeScriptGenerator = class {
|
|
|
2312
2316
|
};
|
|
2313
2317
|
}
|
|
2314
2318
|
#toRequest(entry, payload) {
|
|
2315
|
-
return `await ${
|
|
2319
|
+
return `await ${camelcase4(this.#clientName)}.request('${entry.method.toUpperCase()} ${entry.path}', ${payload});`;
|
|
2316
2320
|
}
|
|
2317
2321
|
snippet(entry, operation, config = {}) {
|
|
2318
2322
|
const payload = this.succinct(entry, operation, config);
|
|
@@ -2353,7 +2357,7 @@ ${client.use}`;
|
|
|
2353
2357
|
#constructClient(options = {}) {
|
|
2354
2358
|
return {
|
|
2355
2359
|
import: `import { ${this.#clientName} } from '${this.#packageName}';`,
|
|
2356
|
-
use: `const ${
|
|
2360
|
+
use: `const ${camelcase4(this.#clientName)} = new ${this.#clientName}({
|
|
2357
2361
|
${Object.entries(
|
|
2358
2362
|
options
|
|
2359
2363
|
).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(",\n ")}
|
|
@@ -2888,7 +2892,7 @@ function availablePaginationTypes(spec) {
|
|
|
2888
2892
|
let offset = false;
|
|
2889
2893
|
let page = false;
|
|
2890
2894
|
let cursor = false;
|
|
2891
|
-
|
|
2895
|
+
forEachOperation4(spec, (entry, operation) => {
|
|
2892
2896
|
if (operation["x-pagination"]) {
|
|
2893
2897
|
switch (operation["x-pagination"].type) {
|
|
2894
2898
|
case "offset":
|
|
@@ -2945,7 +2949,6 @@ async function generate(openapi, settings) {
|
|
|
2945
2949
|
},
|
|
2946
2950
|
false
|
|
2947
2951
|
);
|
|
2948
|
-
const generator = new TypeScriptGenerator(spec, settings);
|
|
2949
2952
|
const style = Object.assign(
|
|
2950
2953
|
{},
|
|
2951
2954
|
{
|
|
@@ -2980,7 +2983,7 @@ async function generate(openapi, settings) {
|
|
|
2980
2983
|
makeImport
|
|
2981
2984
|
});
|
|
2982
2985
|
const clientName = pascalcase5((settings.name || "client").trim());
|
|
2983
|
-
const packageName = settings.name ? `@${
|
|
2986
|
+
const packageName = settings.name ? `@${spinalcase4(settings.name.trim().toLowerCase())}/sdk` : "sdk";
|
|
2984
2987
|
const inputs = toInputs(groups, commonZod, makeImport);
|
|
2985
2988
|
const models = serializeModels(spec);
|
|
2986
2989
|
await settings.writer(output, {
|
|
@@ -3082,8 +3085,9 @@ ${template2(dispatcher_default, {})({ throwError: !style.errorAsValue, outputTyp
|
|
|
3082
3085
|
});
|
|
3083
3086
|
if (settings.agentTools) {
|
|
3084
3087
|
await settings.writer(output, {
|
|
3085
|
-
"agents.ts": `${
|
|
3088
|
+
"agents.ts": `${generateAISDKTools(spec)}
|
|
3086
3089
|
${utils_default}`
|
|
3090
|
+
// 'agents.ts': `${generateOpenAIAgentTools(spec)}\n${utilsTxt}`,
|
|
3087
3091
|
});
|
|
3088
3092
|
}
|
|
3089
3093
|
await settings.writer(output, {
|
|
@@ -3092,7 +3096,7 @@ ${utils_default}`
|
|
|
3092
3096
|
settings.readFolder,
|
|
3093
3097
|
settings.useTsExtension,
|
|
3094
3098
|
["ts"],
|
|
3095
|
-
(config) => config.fileName.endsWith("pagination")
|
|
3099
|
+
(config) => config.fileName.endsWith("pagination") || config.fileName.endsWith("agents")
|
|
3096
3100
|
)
|
|
3097
3101
|
});
|
|
3098
3102
|
if (settings.mode === "full") {
|
|
@@ -3154,7 +3158,7 @@ ${utils_default}`
|
|
|
3154
3158
|
}
|
|
3155
3159
|
if (settings.readme) {
|
|
3156
3160
|
await settings.writer(settings.mode === "full" ? settings.output : output, {
|
|
3157
|
-
"README.md": toReadme(spec,
|
|
3161
|
+
"README.md": toReadme(spec, new TypeScriptSnippet(spec, settings))
|
|
3158
3162
|
});
|
|
3159
3163
|
}
|
|
3160
3164
|
await settings.formatCode?.({
|
|
@@ -3188,7 +3192,7 @@ ${schema.description ? `
|
|
|
3188
3192
|
` : ""}`,
|
|
3189
3193
|
`export type ${pascalcase5(sanitizeTag4(name))} = ${typeContent};`
|
|
3190
3194
|
];
|
|
3191
|
-
const fileName = responseGroup ? join2(folder, `${
|
|
3195
|
+
const fileName = responseGroup ? join2(folder, `${spinalcase4(responseGroup)}.ts`) : join2(folder, `${spinalcase4(name)}.ts`);
|
|
3192
3196
|
filesMap[fileName] ??= [];
|
|
3193
3197
|
filesMap[fileName].push(fileContent.join("\n"));
|
|
3194
3198
|
}
|
|
@@ -3209,18 +3213,18 @@ function toInputs(operationsSet, commonZod, makeImport) {
|
|
|
3209
3213
|
const output = [];
|
|
3210
3214
|
const imports = /* @__PURE__ */ new Set(['import { z } from "zod";']);
|
|
3211
3215
|
for (const operation of operations) {
|
|
3212
|
-
const schemaName =
|
|
3216
|
+
const schemaName = camelcase5(`${operation.operationId} schema`);
|
|
3213
3217
|
const schema = `export const ${schemaName} = ${Object.keys(operation.schemas).length === 1 ? Object.values(operation.schemas)[0] : toLitObject2(operation.schemas)};`;
|
|
3214
3218
|
for (const it of commonImports) {
|
|
3215
3219
|
if (schema.includes(it)) {
|
|
3216
3220
|
imports.add(
|
|
3217
|
-
`import { ${it} } from './schemas/${makeImport(
|
|
3221
|
+
`import { ${it} } from './schemas/${makeImport(spinalcase4(it))}';`
|
|
3218
3222
|
);
|
|
3219
3223
|
}
|
|
3220
3224
|
}
|
|
3221
3225
|
output.push(schema);
|
|
3222
3226
|
}
|
|
3223
|
-
inputs[`inputs/${
|
|
3227
|
+
inputs[`inputs/${spinalcase4(name)}.ts`] = [...imports, ...output].join("\n") + "\n";
|
|
3224
3228
|
}
|
|
3225
3229
|
const schemas = commonZod.entries().reduce((acc, [name, schema]) => {
|
|
3226
3230
|
const output = [`import { z } from 'zod';`];
|
|
@@ -3229,13 +3233,13 @@ function toInputs(operationsSet, commonZod, makeImport) {
|
|
|
3229
3233
|
const preciseMatch = new RegExp(`\\b${schema2}\\b`);
|
|
3230
3234
|
if (preciseMatch.test(content) && schema2 !== name) {
|
|
3231
3235
|
output.push(
|
|
3232
|
-
`import { ${schema2} } from './${makeImport(
|
|
3236
|
+
`import { ${schema2} } from './${makeImport(spinalcase4(schema2))}';`
|
|
3233
3237
|
);
|
|
3234
3238
|
}
|
|
3235
3239
|
}
|
|
3236
3240
|
output.push(content);
|
|
3237
3241
|
return [
|
|
3238
|
-
[`inputs/schemas/${
|
|
3242
|
+
[`inputs/schemas/${spinalcase4(name)}.ts`, output.join("\n")],
|
|
3239
3243
|
...acc
|
|
3240
3244
|
];
|
|
3241
3245
|
}, []);
|
|
@@ -3244,44 +3248,14 @@ function toInputs(operationsSet, commonZod, makeImport) {
|
|
|
3244
3248
|
...inputs
|
|
3245
3249
|
};
|
|
3246
3250
|
}
|
|
3247
|
-
function generateAgentTools(spec) {
|
|
3248
|
-
const groups = {};
|
|
3249
|
-
forEachOperation4(spec, (entry, operation) => {
|
|
3250
|
-
groups[entry.tag] ??= [];
|
|
3251
|
-
groups[entry.tag].push(createTool(entry, operation));
|
|
3252
|
-
});
|
|
3253
|
-
const imports = [
|
|
3254
|
-
`import { z } from 'zod';`,
|
|
3255
|
-
`import { tool } from '@openai/agents';`,
|
|
3256
|
-
`import * as schemas from './inputs/index.ts';`
|
|
3257
|
-
];
|
|
3258
|
-
const tools = Object.entries(groups).map(([group, tools2]) => {
|
|
3259
|
-
return `export const ${spinalcase3(group)} = [${tools2.join(", ")}];`;
|
|
3260
|
-
});
|
|
3261
|
-
return [...imports, ...tools].join("\n\n");
|
|
3262
|
-
}
|
|
3263
|
-
function createTool(entry, operation) {
|
|
3264
|
-
const schemaName = camelcase4(`${operation.operationId} schema`);
|
|
3265
|
-
return `tool({
|
|
3266
|
-
description: \`${operation.description || operation.summary}\`,
|
|
3267
|
-
name: '${operation["x-fn-name"]}',
|
|
3268
|
-
parameters: makeOptionalPropsNullable(schemas.${schemaName}),
|
|
3269
|
-
execute: async (input, maybeContext) => {
|
|
3270
|
-
console.log('Executing ${operation.operationId} tool with input:', input);
|
|
3271
|
-
const context = coerceContext(maybeContext?.context);
|
|
3272
|
-
const client = context.client;
|
|
3273
|
-
const response = await client.request(
|
|
3274
|
-
'${entry.method.toUpperCase()} ${entry.path}' ,
|
|
3275
|
-
input as any,
|
|
3276
|
-
);
|
|
3277
|
-
return JSON.stringify(response);
|
|
3278
|
-
},
|
|
3279
|
-
})`;
|
|
3280
|
-
}
|
|
3281
3251
|
export {
|
|
3282
|
-
|
|
3252
|
+
TypeScriptSnippet,
|
|
3253
|
+
buildInput,
|
|
3283
3254
|
generate,
|
|
3284
|
-
|
|
3255
|
+
generateCode,
|
|
3256
|
+
inputToPath,
|
|
3257
|
+
toEndpoint,
|
|
3258
|
+
toHttpOutput,
|
|
3285
3259
|
toInputs
|
|
3286
3260
|
};
|
|
3287
3261
|
//# sourceMappingURL=index.js.map
|