@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.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 camelcase4, spinalcase as spinalcase3 } from "stringcase";
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 camelcase2, spinalcase } from "stringcase";
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 { forEachOperation } from "@sdk-it/spec";
594
-
595
- // packages/typescript/src/lib/import-utilities.ts
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 = camelcase(`${operation.name} schema`);
672
- const schemaRef = `${camelcase(groupName)}.${schemaName}`;
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
- for (const status in specOperation.responses) {
701
- const handled = handleResponse(
680
+ const outputs = Object.keys(specOperation.responses).flatMap(
681
+ (status) => toHttpOutput(
702
682
  spec,
703
- operation.name,
683
+ specOperation.operationId,
704
684
  status,
705
- specOperation.responses[status],
706
- utils
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 { responses, schemas };
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 handleResponse(spec, operationName, status, response, utils) {
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
- let parser = "buffered";
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 responseSchema = contentTypeResult.responseSchema;
860
- responses.push({
861
- name: interfaceName,
862
- schema: responseSchema,
863
- description: response.description
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.push(
880
- parser !== "buffered" ? `{type: ${statusName}<outputs.${interfaceName}>, parser: ${parser}}` : `${statusName}<outputs.${interfaceName}>`
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 { schemas, imports, endpointImports, responses, outputs };
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
- forEachOperation(config.spec, (entry, operation) => {
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
- let objectSchema = resolveRef(
962
+ const { objectSchema, xProperties, xRequired } = coearceRequestInput(
955
963
  config.spec,
956
- operation.requestBody.content[type].schema
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
- if (operation.requestBody.content["application/json"]) {
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
- inputs
995
+ outgoingContentType: details.outgoingContentType,
996
+ inputs: details.inputs
1017
997
  },
1018
- { makeImport: config.makeImport, style: config.style }
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 ${camelcase2(it)} from './${config.makeImport(spinalcase(it))}';`,
1032
- use: ` ...${camelcase2(it)}`
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", `${spinalcase(name)}.ts`),
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 ${camelcase2(name)} from '../inputs/${config.makeImport(spinalcase(name))}';`,
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 forEachOperation2 } from "@sdk-it/spec";
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
- forEachOperation2(spec, (entry, operation) => {
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 camelcase3, spinalcase as spinalcase2 } from "stringcase";
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 forEachOperation3,
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 (/* @__PURE__ */ new Date()).toISOString();
2045
+ return `2025-07-17T09:08:00.097Z`;
2042
2046
  case "date":
2043
- return (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
2047
+ return `2025-07-17`;
2044
2048
  case "time":
2045
- return (/* @__PURE__ */ new Date()).toISOString().split("T")[1];
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 TypeScriptGenerator = class {
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 ? `@${spinalcase2(this.#clientName.toLowerCase())}/sdk` : "sdk";
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 ${camelcase3(this.#clientName)}.request('${entry.method.toUpperCase()} ${entry.path}', ${payload});`;
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 ${camelcase3(this.#clientName)} = new ${this.#clientName}({
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
- forEachOperation3(spec, (entry, operation) => {
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 ? `@${spinalcase3(settings.name.trim().toLowerCase())}/sdk` : "sdk";
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": `${generateAgentTools(spec)}
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, generator)
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, `${spinalcase3(responseGroup)}.ts`) : join2(folder, `${spinalcase3(name)}.ts`);
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 = camelcase4(`${operation.name} schema`);
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(spinalcase3(it))}';`
3221
+ `import { ${it} } from './schemas/${makeImport(spinalcase4(it))}';`
3218
3222
  );
3219
3223
  }
3220
3224
  }
3221
3225
  output.push(schema);
3222
3226
  }
3223
- inputs[`inputs/${spinalcase3(name)}.ts`] = [...imports, ...output].join("\n") + "\n";
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(spinalcase3(schema2))}';`
3236
+ `import { ${schema2} } from './${makeImport(spinalcase4(schema2))}';`
3233
3237
  );
3234
3238
  }
3235
3239
  }
3236
3240
  output.push(content);
3237
3241
  return [
3238
- [`inputs/schemas/${spinalcase3(name)}.ts`, output.join("\n")],
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
- TypeScriptGenerator,
3252
+ TypeScriptSnippet,
3253
+ buildInput,
3283
3254
  generate,
3284
- generateAgentTools,
3255
+ generateCode,
3256
+ inputToPath,
3257
+ toEndpoint,
3258
+ toHttpOutput,
3285
3259
  toInputs
3286
3260
  };
3287
3261
  //# sourceMappingURL=index.js.map