@sdk-it/typescript 0.39.0 → 0.40.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.
Files changed (64) hide show
  1. package/dist/index.js +155 -53
  2. package/dist/index.js.map +3 -3
  3. package/dist/lib/client.d.ts.map +1 -1
  4. package/dist/lib/emitters/zod.d.ts.map +1 -1
  5. package/dist/lib/generate.d.ts +3 -1
  6. package/dist/lib/generate.d.ts.map +1 -1
  7. package/dist/lib/generator.d.ts.map +1 -1
  8. package/dist/lib/options.d.ts +1 -0
  9. package/dist/lib/options.d.ts.map +1 -1
  10. package/dist/lib/sdk.d.ts +1 -1
  11. package/dist/lib/sdk.d.ts.map +1 -1
  12. package/dist/lib/server-urls.d.ts +3 -0
  13. package/dist/lib/server-urls.d.ts.map +1 -0
  14. package/dist/lib/status-map.d.ts.map +1 -1
  15. package/dist/lib/typescript-snippet.d.ts.map +1 -1
  16. package/package.json +4 -4
  17. package/dist/connect.d.ts +0 -1
  18. package/dist/connect.d.ts.map +0 -1
  19. package/dist/global.d.js +0 -1
  20. package/dist/global.d.js.map +0 -7
  21. package/dist/lib/connect.d.ts +0 -162
  22. package/dist/lib/connect.d.ts.map +0 -1
  23. package/dist/lib/readme-generator.d.ts +0 -8
  24. package/dist/lib/readme-generator.d.ts.map +0 -1
  25. package/dist/lib/statusMap.d.ts +0 -2
  26. package/dist/lib/statusMap.d.ts.map +0 -1
  27. package/dist/lib/utils.d.ts +0 -17
  28. package/dist/lib/utils.d.ts.map +0 -1
  29. package/dist/lib/watcher.d.ts +0 -2
  30. package/dist/lib/watcher.d.ts.map +0 -1
  31. package/dist/src/index.js +0 -5
  32. package/dist/src/index.js.map +0 -7
  33. package/dist/src/lib/agent/ai-sdk.js +0 -60
  34. package/dist/src/lib/agent/ai-sdk.js.map +0 -7
  35. package/dist/src/lib/agent/openai-agents.js +0 -42
  36. package/dist/src/lib/agent/openai-agents.js.map +0 -7
  37. package/dist/src/lib/client.js +0 -152
  38. package/dist/src/lib/client.js.map +0 -7
  39. package/dist/src/lib/emitters/interface.js +0 -169
  40. package/dist/src/lib/emitters/interface.js.map +0 -7
  41. package/dist/src/lib/emitters/snippet.js +0 -191
  42. package/dist/src/lib/emitters/snippet.js.map +0 -7
  43. package/dist/src/lib/emitters/zod.js +0 -271
  44. package/dist/src/lib/emitters/zod.js.map +0 -7
  45. package/dist/src/lib/generate.js +0 -382
  46. package/dist/src/lib/generate.js.map +0 -7
  47. package/dist/src/lib/generator.js +0 -268
  48. package/dist/src/lib/generator.js.map +0 -7
  49. package/dist/src/lib/import-utilities.js +0 -56
  50. package/dist/src/lib/import-utilities.js.map +0 -7
  51. package/dist/src/lib/options.js +0 -3
  52. package/dist/src/lib/options.js.map +0 -7
  53. package/dist/src/lib/readme/prop.emitter.js +0 -283
  54. package/dist/src/lib/readme/prop.emitter.js.map +0 -7
  55. package/dist/src/lib/readme/readme.js +0 -105
  56. package/dist/src/lib/readme/readme.js.map +0 -7
  57. package/dist/src/lib/sdk.js +0 -236
  58. package/dist/src/lib/sdk.js.map +0 -7
  59. package/dist/src/lib/status-map.js +0 -28
  60. package/dist/src/lib/status-map.js.map +0 -7
  61. package/dist/src/lib/style.js +0 -1
  62. package/dist/src/lib/style.js.map +0 -7
  63. package/dist/src/lib/typescript-snippet.js +0 -738
  64. package/dist/src/lib/typescript-snippet.js.map +0 -7
package/dist/index.js CHANGED
@@ -172,8 +172,10 @@ var ZodEmitter = class {
172
172
  */
173
173
  normal(type, schema, required = false, nullable = false) {
174
174
  switch (type) {
175
- case "string":
176
- return `${this.string(schema)}${this.#suffixes(JSON.stringify(schema.default), required, nullable)}`;
175
+ case "string": {
176
+ const defaultVal = schema.format === "date" && schema.default ? `new Date(${JSON.stringify(schema.default)})` : JSON.stringify(schema.default);
177
+ return `${this.string(schema)}${this.#suffixes(defaultVal, required, nullable)}`;
178
+ }
177
179
  case "number":
178
180
  case "integer": {
179
181
  const { base, defaultValue } = this.#number(schema);
@@ -415,17 +417,20 @@ var client_default = (spec) => {
415
417
  token = await Promise.resolve(token());
416
418
  }
417
419
  return \`Bearer \${token}\`;
418
- })`
420
+ }).describe('Bearer token for authentication. Can be a string or a function that returns a string.')`
419
421
  }
420
422
  } : {},
421
423
  fetch: {
422
- schema: "fetchType"
424
+ schema: `fetchType.describe('Custom fetch implementation. Defaults to globalThis.fetch.')`
423
425
  },
424
426
  baseUrl: {
425
- schema: spec.servers.length ? `z.enum(servers).default(servers[0])` : "z.string()"
427
+ schema: spec.servers.length ? `z.enum(servers).default(servers[0]).describe('Base URL of the API server.')` : `z.string().describe('Base URL of the API server.')`
426
428
  },
427
429
  headers: {
428
- schema: "z.record(z.string()).optional()"
430
+ schema: `z.record(z.string()).optional().describe('Default headers to include in all requests.')`
431
+ },
432
+ skipValidation: {
433
+ schema: `z.boolean().optional().describe('Skip request input validation. Client options and TypeScript types still enforce correct usage.')`
429
434
  }
430
435
  };
431
436
  return `import z from 'zod';
@@ -453,6 +458,7 @@ export class ${spec.name} {
453
458
  this.options = options;
454
459
  }
455
460
 
461
+ /** Sends a request and returns the unwrapped response data. Delegates to the standalone {@link request} function. */
456
462
  async request<const E extends keyof typeof schemas>(
457
463
  endpoint: E,
458
464
  input: z.input<(typeof schemas)[E]['schema']>,
@@ -466,32 +472,13 @@ export class ${spec.name} {
466
472
  });
467
473
  }
468
474
 
475
+ /** Builds a ready-to-send request without sending it. Delegates to the standalone {@link prepare} function. */
469
476
  async prepare<const E extends keyof typeof schemas>(
470
477
  endpoint: E,
471
478
  input: z.input<(typeof schemas)[E]['schema']>,
472
479
  options?: { headers?: HeadersInit },
473
- ): Promise<RequestConfig & {
474
- parse: (response: Response) => ReturnType<typeof parse>;
475
- }> {
476
- const clientOptions = await optionsSchema.parseAsync(this.options);
477
- const route = schemas[endpoint];
478
- const interceptors = [
479
- createHeadersInterceptor(
480
- await this.defaultHeaders(),
481
- options?.headers ?? {},
482
- ),
483
- createBaseUrlInterceptor(clientOptions.baseUrl),
484
- ];
485
- const parsedInput = parseInput(route.schema, input);
486
-
487
- let config = route.toRequest(parsedInput as never);
488
- for (const interceptor of interceptors) {
489
- if (interceptor.before) {
490
- config = await interceptor.before(config);
491
- }
492
- }
493
- const prepared = { ...config, parse: (response: Response) => parse(route.output, response, (d) => d) as never };
494
- return prepared as any;
480
+ ) {
481
+ return prepare(this, endpoint, input, options);
495
482
  }
496
483
 
497
484
  async defaultHeaders() {
@@ -516,34 +503,89 @@ export class ${spec.name} {
516
503
 
517
504
  }
518
505
 
506
+ /**
507
+ * Sends a validated request using the client's configuration and returns the parsed response.
508
+ * Merges the client's default inputs and headers before sending.
509
+ * Throws \`APIError\` on non-ok responses.
510
+ *
511
+ * @example
512
+ * \`\`\`ts
513
+ * const result = await request(client, 'GET /users', { limit: 10 });
514
+ * \`\`\`
515
+ */
519
516
  export async function request<const E extends keyof typeof schemas>(
520
517
  client: ${spec.name},
521
518
  endpoint: E,
522
519
  input: z.input<(typeof schemas)[E]['schema']>,
523
- options?: { signal?: AbortSignal; headers?: HeadersInit },
520
+ requestOptions?: { signal?: AbortSignal; headers?: HeadersInit },
524
521
  ): Promise<Awaited<ReturnType<(typeof schemas)[E]['dispatch']>>> {
525
522
  const route = schemas[endpoint];
523
+ const options = await optionsSchema.parseAsync(client.options);
526
524
  const withDefaultInputs = Object.assign(
527
525
  {},
528
- await client.defaultInputs(),
526
+ ${defaultInputs},
529
527
  input,
530
528
  );
531
- const parsedInput = parseInput(route.schema, withDefaultInputs);
532
- const clientOptions = await optionsSchema.parseAsync(client.options);
529
+ const parsedInput = options.skipValidation ? withDefaultInputs : parseInput(route.schema, withDefaultInputs);
533
530
  const result = await route.dispatch(parsedInput as never, {
534
- fetch: clientOptions.fetch,
531
+ fetch: options.fetch,
535
532
  interceptors: [
536
533
  createHeadersInterceptor(
537
- await client.defaultHeaders(),
538
- options?.headers ?? {},
534
+ { ...${defaultHeaders}, ...options.headers },
535
+ requestOptions?.headers ?? {},
539
536
  ),
540
- createBaseUrlInterceptor(clientOptions.baseUrl),
537
+ createBaseUrlInterceptor(options.baseUrl),
541
538
  ],
542
- signal: options?.signal,
539
+ signal: requestOptions?.signal,
543
540
  });
544
541
  return result as Awaited<ReturnType<(typeof schemas)[E]['dispatch']>>;
545
542
  }
546
543
 
544
+ /**
545
+ * Builds a validated \`RequestConfig\` (url + init) with a \`parse\` function attached, without sending.
546
+ * Use when you need control over the fetch call \u2014 framework integration (Next.js, SvelteKit),
547
+ * custom retry/logging, request batching, or testing.
548
+ *
549
+ * @example
550
+ * \`\`\`ts
551
+ * const { url, init, parse } = await prepare(client, 'GET /users', { limit: 10 });
552
+ * const response = await fetch(new Request(url, init));
553
+ * const result = await parse(response);
554
+ * \`\`\`
555
+ */
556
+ export async function prepare<const E extends keyof typeof schemas>(
557
+ client: ${spec.name},
558
+ endpoint: E,
559
+ input: z.input<(typeof schemas)[E]['schema']>,
560
+ requestOptions?: { headers?: HeadersInit },
561
+ ): Promise<RequestConfig & {
562
+ parse: (response: Response) => ReturnType<typeof parse>;
563
+ }> {
564
+ const route = schemas[endpoint];
565
+ const options = await optionsSchema.parseAsync(client.options);
566
+ const withDefaultInputs = Object.assign(
567
+ {},
568
+ ${defaultInputs},
569
+ input,
570
+ );
571
+ const parsedInput = options.skipValidation ? withDefaultInputs : parseInput(route.schema, withDefaultInputs);
572
+ const interceptors = [
573
+ createHeadersInterceptor(
574
+ { ...${defaultHeaders}, ...options.headers },
575
+ requestOptions?.headers ?? {},
576
+ ),
577
+ createBaseUrlInterceptor(options.baseUrl),
578
+ ];
579
+
580
+ let config = route.toRequest(parsedInput as never);
581
+ for (const interceptor of interceptors) {
582
+ if (interceptor.before) {
583
+ config = await interceptor.before(config);
584
+ }
585
+ }
586
+ return { ...config, parse: (response: Response) => parse(route.output as never, response, (d) => d) as never } as any;
587
+ }
588
+
547
589
 
548
590
  `;
549
591
  };
@@ -728,6 +770,8 @@ import {
728
770
  import { camelcase as camelcase3 } from "stringcase";
729
771
  import { isEmpty, pascalcase as pascalcase3 } from "@sdk-it/core";
730
772
  import {
773
+ isBinaryContentType,
774
+ isSseContentType,
731
775
  isStreamingContentType,
732
776
  isTextContentType,
733
777
  parseJsonContentType,
@@ -754,6 +798,7 @@ var status_map_default = {
754
798
  "412": "PreconditionFailed",
755
799
  "413": "PayloadTooLarge",
756
800
  "410": "Gone",
801
+ "415": "UnsupportedMediaType",
757
802
  "422": "UnprocessableEntity",
758
803
  "429": "TooManyRequests",
759
804
  "500": "InternalServerError",
@@ -928,16 +973,31 @@ function fromContentType(spec, typeScriptDeserialzer, response) {
928
973
  if ((response.headers ?? {})["Transfer-Encoding"]) {
929
974
  return streamedOutput();
930
975
  }
976
+ const hasContentDisposition = hasHeader(response, "Content-Disposition");
931
977
  for (const type in response.content) {
932
- if (isStreamingContentType(type)) {
978
+ const isStreaming = isStreamingContentType(type);
979
+ const isBinary = isBinaryContentType(type) || isStreaming && hasContentDisposition;
980
+ if (isStreaming && !hasContentDisposition) {
933
981
  return streamedOutput();
934
982
  }
983
+ if (isBinary) {
984
+ return {
985
+ parser: "buffered",
986
+ responseSchema: response.content[type].schema ? typeScriptDeserialzer.handle(response.content[type].schema, true) : "Blob"
987
+ };
988
+ }
935
989
  if (parseJsonContentType(type)) {
936
990
  return {
937
991
  parser: "buffered",
938
992
  responseSchema: response.content[type].schema ? typeScriptDeserialzer.handle(response.content[type].schema, true) : "void"
939
993
  };
940
994
  }
995
+ if (isSseContentType(type)) {
996
+ return {
997
+ parser: "sse",
998
+ responseSchema: "SSEListener"
999
+ };
1000
+ }
941
1001
  if (isTextContentType(type)) {
942
1002
  return {
943
1003
  parser: "buffered",
@@ -947,6 +1007,11 @@ function fromContentType(spec, typeScriptDeserialzer, response) {
947
1007
  }
948
1008
  return streamedOutput();
949
1009
  }
1010
+ function hasHeader(response, name) {
1011
+ const headers = response.headers ?? {};
1012
+ const target = name.toLowerCase();
1013
+ return Object.keys(headers).some((key) => key.toLowerCase() === target);
1014
+ }
950
1015
  function streamedOutput() {
951
1016
  return {
952
1017
  parser: "chunked",
@@ -1108,6 +1173,7 @@ ${allSchemas.map((it) => it.use).join(",\n")}
1108
1173
  `import * as outputs from '${config.makeImport("../outputs/index")}';`,
1109
1174
  `import { toRequest, json, urlencoded, empty, formdata, type HeadersInit } from '${config.makeImport("../http/request")}';`,
1110
1175
  `import { chunked, buffered } from "${config.makeImport("../http/parse-response")}";`,
1176
+ `import { sse } from "${config.makeImport("../http/sse")}";`,
1111
1177
  `import * as ${camelcase4(name)} from '../inputs/${config.makeImport(spinalcase2(name))}';`,
1112
1178
  `import { createBaseUrlInterceptor, createHeadersInterceptor, type Interceptor } from '${config.makeImport("../http/interceptors")}';`,
1113
1179
  `import { Dispatcher, fetchType, type InstanceType } from '${config.makeImport("../http/dispatcher")}';`,
@@ -1236,13 +1302,13 @@ function operationSchema(ir, operation, type) {
1236
1302
  }
1237
1303
 
1238
1304
  // packages/typescript/src/lib/http/dispatcher.txt
1239
- 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\ntype ResponseData<T extends OutputType[]> =\n Extract<InstanceType<T>, SuccessfulResponse> extends SuccessfulResponse<\n infer P\n >\n ? P\n : unknown;\n\ntype ResponseMapper<T extends OutputType[], R> = (data: ResponseData<T>) => R;\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[], R = ResponseData<T>>(\n outputs: T,\n response: Response,\n mapper: ResponseMapper<T, R>,\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 if (response.ok) {\n const apiresponse = (output || APIResponse).create(\n response.status,\n response.headers,\n mapper((await parser(response)) as ResponseData<T>),\n );\n\n return apiresponse as RebindSuccessPayload<Extract<InstanceType<T>, SuccessfulResponse<unknown>>, R>;\n }\n\n throw (output || APIError).create(\n response.status,\n response.headers,\n await parser(response),\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[], R = ResponseData<T>>(\n config: RequestConfig,\n outputs: T,\n signal?: AbortSignal,\n mapper?: ResponseMapper<T, R>,\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(\n outputs,\n response,\n mapper ?? ((data: ResponseData<T>) => data as unknown as R),\n );\n }\n}\n";
1305
+ 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\ntype ResponseData<T extends OutputType[]> =\n Extract<InstanceType<T>, SuccessfulResponse> extends SuccessfulResponse<\n infer P\n >\n ? P\n : unknown;\n\ntype ResponseMapper<T extends OutputType[], R> = (data: ResponseData<T>) => R;\n\nexport interface Type<T> {\n new (...args: any[]): T;\n}\nexport type Parser = (\n response: Response,\n) => Promise<unknown> | ReadableStream<any> | SSEListener;\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[], R = ResponseData<T>>(\n outputs: T,\n response: Response,\n mapper: ResponseMapper<T, R>,\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 if (response.ok) {\n const apiresponse = (output || APIResponse).create(\n response.status,\n response.headers,\n mapper((await parser(response)) as ResponseData<T>),\n );\n\n return apiresponse as RebindSuccessPayload<Extract<InstanceType<T>, SuccessfulResponse<unknown>>, R>;\n }\n\n throw (output || APIError).create(\n response.status,\n response.headers,\n await parser(response),\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[], R = ResponseData<T>>(\n config: RequestConfig,\n outputs: T,\n signal?: AbortSignal,\n mapper?: ResponseMapper<T, R>,\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(\n outputs,\n response,\n mapper ?? ((data: ResponseData<T>) => data as unknown as R),\n );\n }\n}\n";
1240
1306
 
1241
1307
  // packages/typescript/src/lib/http/interceptors.txt
1242
1308
  var interceptors_default = "export interface Interceptor {\n before?: (config: RequestConfig) => Promise<RequestConfig> | RequestConfig;\n after?: (response: Response) => Promise<Response> | Response;\n}\n\nexport const createHeadersInterceptor = (\n headers: Record<string, string | undefined>,\n requestHeaders: HeadersInit,\n):Interceptor => {\n return {\n before({init, url}) {\n // Priority Levels\n // 1. Headers Input\n // 2. Request Headers\n // 3. Default Headers\n\n for (const [key, value] of new Headers(requestHeaders)) {\n // Only set the header if it doesn't already exist and has a value\n // even though these headers are passed at operation level\n // still they are lower priority compared to the headers input\n if (value !== undefined && !init.headers.has(key)) {\n init.headers.set(key, value);\n }\n }\n\n for (const [key, value] of Object.entries(headers)) {\n // Only set the header if it doesn't already exist and has a value\n if (value !== undefined && !init.headers.has(key)) {\n init.headers.set(key, value);\n }\n }\n\n return {init, url};\n },\n };\n};\n\nexport const createBaseUrlInterceptor = (baseUrl: string): Interceptor => {\n return {\n before({ init, url }) {\n if (url.protocol === 'local:') {\n return {\n init,\n url: new URL(url.href.replace('local://', baseUrl))\n };\n }\n return { init, url };\n },\n };\n};\n\nexport const logInterceptor: Interceptor = {\n before({ url, init }) {\n console.log('Request:', { url, init });\n return { url, init };\n },\n after(response) {\n console.log('Response:', response);\n return response;\n },\n};\n\n/**\n * Creates an interceptor that logs detailed information about requests and responses.\n * @param options Configuration options for the logger\n * @returns An interceptor object with before and after handlers\n */\nexport const createDetailedLogInterceptor = (options?: {\n logLevel?: 'debug' | 'info' | 'warn' | 'error';\n includeRequestBody?: boolean;\n includeResponseBody?: boolean;\n}) => {\n const logLevel = options?.logLevel || 'info';\n const includeRequestBody = options?.includeRequestBody || false;\n const includeResponseBody = options?.includeResponseBody || false;\n\n return {\n async before(request: Request) {\n const logData = {\n url: request.url,\n method: request.method,\n contentType: request.headers.get('Content-Type'),\n headers: Object.fromEntries([...request.headers.entries()]),\n };\n\n console[logLevel]('\u{1F680} Outgoing Request:', logData);\n\n if (includeRequestBody) {\n try {\n // Clone the request to avoid consuming the body stream\n const clonedRequest = request.clone();\n if (clonedRequest.headers.get('Content-Type')?.includes('application/json')) {\n const body = await clonedRequest.json().catch(() => null);\n console[logLevel]('Request Body:', body);\n } else {\n const body = await clonedRequest.text().catch(() => null);\n console[logLevel]('Request Body:', body);\n }\n } catch (error) {\n console.error('Could not log request body:', error);\n }\n }\n\n return request;\n },\n\n async after(response: Response) {\n const logData = {\n status: response.status,\n statusText: response.statusText,\n url: response.url,\n headers: Object.fromEntries([...response.headers.entries()]),\n };\n\n console[logLevel]('\u{1F4E5} Incoming Response:', logData);\n\n if (includeResponseBody && response.body) {\n try {\n // Clone the response to avoid consuming the body stream\n const clonedResponse = response.clone();\n if (clonedResponse.headers.get('Content-Type')?.includes('application/json')) {\n const body = await clonedResponse.json().catch(() => null);\n console[logLevel]('Response Body:', body);\n } else {\n const body = await clonedResponse.text().catch(() => null);\n if (body) {\n console[logLevel]('Response Body:', body.substring(0, 500) + (body.length > 500 ? '...' : ''));\n } else {\n console[logLevel]('No response body');\n }\n }\n } catch (error) {\n console.error('Could not log response body:', error);\n }\n }\n\n return response;\n },\n };\n};\n";
1243
1309
 
1244
1310
  // packages/typescript/src/lib/http/parse-response.txt
1245
- var parse_response_default = 'import { parse } from "fast-content-type-parse";\n\nasync function handleChunkedResponse(response: Response, contentType: string) {\n const { type } = parse(contentType);\n\n switch (type) {\n case "application/json": {\n let buffer = "";\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value);\n }\n return JSON.parse(buffer);\n }\n case "text/html":\n case "text/plain": {\n let buffer = "";\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value);\n }\n return buffer;\n }\n default:\n return response.body;\n }\n}\n\nexport function chunked(response: Response) {\n return response.body!;\n}\n\nexport async function buffered(response: Response) {\n const contentType = response.headers.get("Content-Type");\n if (!contentType) {\n throw new Error("Content-Type header is missing");\n }\n\n if (response.status === 204) {\n return null;\n }\n\n const { type } = parse(contentType);\n switch (type) {\n case "application/json":\n return response.json();\n case "text/plain":\n return response.text();\n case "text/html":\n return response.text();\n case "text/xml":\n case "application/xml":\n return response.text();\n case "application/x-www-form-urlencoded": {\n const text = await response.text();\n return Object.fromEntries(new URLSearchParams(text));\n }\n case "multipart/form-data":\n return response.formData();\n default:\n throw new Error(`Unsupported content type: ${contentType}`);\n }\n}\n';
1311
+ var parse_response_default = 'import { parse } from "fast-content-type-parse";\n\nfunction isBinaryContentType(contentType: string) {\n const type = contentType.toLowerCase();\n if (type.startsWith("image/")) {\n return true;\n }\n if (type.startsWith("audio/")) {\n return true;\n }\n if (type.startsWith("video/")) {\n return true;\n }\n switch (type) {\n case "application/pdf":\n case "application/zip":\n case "application/gzip":\n case "application/x-7z-compressed":\n case "application/x-tar":\n case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":\n case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":\n case "application/vnd.openxmlformats-officedocument.presentationml.presentation":\n case "application/vnd.ms-excel":\n case "application/vnd.ms-powerpoint":\n case "application/msword":\n case "application/octet-stream":\n return true;\n default:\n return false;\n }\n}\n\nasync function handleChunkedResponse(response: Response, contentType: string) {\n const { type } = parse(contentType);\n\n switch (type) {\n case "application/json": {\n let buffer = "";\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value);\n }\n return JSON.parse(buffer);\n }\n case "text/html":\n case "text/plain": {\n let buffer = "";\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value);\n }\n return buffer;\n }\n default:\n return response.body;\n }\n}\n\nexport function chunked(response: Response) {\n return response.body!;\n}\n\nexport async function buffered(response: Response) {\n const contentType = response.headers.get("Content-Type");\n if (!contentType) {\n throw new Error("Content-Type header is missing");\n }\n\n if (response.status === 204) {\n return null;\n }\n\n const { type } = parse(contentType);\n if (isBinaryContentType(type)) {\n return response.blob();\n }\n if (type.startsWith("text/")) {\n return response.text();\n }\n switch (type) {\n case "application/json":\n return response.json();\n case "application/xml":\n return response.text();\n case "application/x-www-form-urlencoded": {\n const text = await response.text();\n return Object.fromEntries(new URLSearchParams(text));\n }\n case "multipart/form-data":\n return response.formData();\n default:\n throw new Error(`Unsupported content type: ${contentType}`);\n }\n}\n';
1246
1312
 
1247
1313
  // packages/typescript/src/lib/http/parser.txt
1248
1314
  var parser_default = "import { z } from 'zod';\n\nexport class ParseError<T extends z.ZodType<any, any, any>> extends Error {\n public data: z.typeToFlattenedError<T, z.ZodIssue>;\n constructor(data: z.typeToFlattenedError<T, z.ZodIssue>) {\n super('Validation failed');\n this.name = 'ParseError';\n this.data = data;\n }\n}\n\nexport function parseInput<T extends z.ZodType<any, any, any>>(\n schema: T,\n input: unknown,\n): z.infer<T> {\n const result = schema.safeParse(input);\n if (!result.success) {\n const error = result.error.flatten((issue) => issue);\n throw new ParseError(error);\n }\n return result.data as z.infer<T>;\n}\n";
@@ -1253,6 +1319,9 @@ var request_default = "type Init = Omit<RequestInit, 'headers'> & { headers: Hea
1253
1319
  // packages/typescript/src/lib/http/response.txt
1254
1320
  var response_default = "export class APIResponse<Body = unknown, Status extends number = number> {\n static readonly status: number;\n readonly status: Status;\n data: Body;\n readonly headers: Headers;\n\n constructor(status: Status, headers: Headers, data: Body) {\n this.status = status;\n this.headers = headers;\n this.data = data;\n }\n\n static create<Body = unknown>(status: number, headers: Headers, data: Body) {\n return new this(status, headers, data);\n }\n}\n\nexport class APIError<Body, Status extends number = number> extends APIResponse<\n Body,\n Status\n> {\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(status, headers, data);\n }\n}\n\n// 2xx Success\nexport class Ok<T> extends APIResponse<T, 200> {\n static override readonly status = 200 as const;\n constructor(headers: Headers, data: T) {\n super(Ok.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\n\nexport class Created<T> extends APIResponse<T, 201> {\n static override status = 201 as const;\n constructor(headers: Headers, data: T) {\n super(Created.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class Accepted<T> extends APIResponse<T, 202> {\n static override status = 202 as const;\n constructor(headers: Headers, data: T) {\n super(Accepted.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class NoContent extends APIResponse<never, 204> {\n static override status = 204 as const;\n constructor(headers: Headers) {\n super(NoContent.status, headers, null as never);\n }\n static override create(status: number, headers: Headers): NoContent {\n return new this(headers);\n }\n}\n\n// 4xx Client Errors\nexport class BadRequest<T> extends APIError<T, 400> {\n static override status = 400 as const;\n constructor(headers: Headers, data: T) {\n super(BadRequest.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class Unauthorized<T = { message: string }> extends APIError<T, 401> {\n static override status = 401 as const;\n constructor(headers: Headers, data: T) {\n super(Unauthorized.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class PaymentRequired<T = { message: string }> extends APIError<T, 402> {\n static override status = 402 as const;\n constructor(headers: Headers, data: T) {\n super(PaymentRequired.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class Forbidden<T = { message: string }> extends APIError<T, 403> {\n static override status = 403 as const;\n constructor(headers: Headers, data: T) {\n super(Forbidden.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class NotFound<T = { message: string }> extends APIError<T, 404> {\n static override status = 404 as const;\n constructor(headers: Headers, data: T) {\n super(NotFound.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class MethodNotAllowed<T = { message: string }> extends APIError<\n T,\n 405\n> {\n static override status = 405 as const;\n constructor(headers: Headers, data: T) {\n super(MethodNotAllowed.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class NotAcceptable<T = { message: string }> extends APIError<T, 406> {\n static override status = 406 as const;\n constructor(headers: Headers, data: T) {\n super(NotAcceptable.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class Conflict<T = { message: string }> extends APIError<T, 409> {\n static override status = 409 as const;\n constructor(headers: Headers, data: T) {\n super(Conflict.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class Gone<T = { message: string }> extends APIError<T, 410> {\n static override status = 410 as const;\n constructor(headers: Headers, data: T) {\n super(Gone.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class PreconditionFailed<T = { message: string }> extends APIError<\n T,\n 412\n> {\n static override status = 412 as const;\n constructor(headers: Headers, data: T) {\n super(PreconditionFailed.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class UnprocessableEntity<\n T = { message: string; errors?: Record<string, string[]> },\n> extends APIError<T, 422> {\n static override status = 422 as const;\n constructor(headers: Headers, data: T) {\n super(UnprocessableEntity.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class TooManyRequests<\n T = { message: string; retryAfter?: string },\n> extends APIError<T, 429> {\n static override status = 429 as const;\n constructor(headers: Headers, data: T) {\n super(TooManyRequests.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class PayloadTooLarge<T = { message: string }> extends APIError<T, 413> {\n static override status = 413 as const;\n constructor(headers: Headers, data: T) {\n super(PayloadTooLarge.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class UnsupportedMediaType<T = { message: string }> extends APIError<\n T,\n 415\n> {\n static override status = 415 as const;\n constructor(headers: Headers, data: T) {\n super(UnsupportedMediaType.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\n\n// 5xx Server Errors\nexport class InternalServerError<T = { message: string }> extends APIError<\n T,\n 500\n> {\n static override status = 500 as const;\n constructor(headers: Headers, data: T) {\n super(InternalServerError.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class NotImplemented<T = { message: string }> extends APIError<T, 501> {\n static override status = 501 as const;\n constructor(headers: Headers, data: T) {\n super(NotImplemented.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class BadGateway<T = { message: string }> extends APIError<T, 502> {\n static override status = 502 as const;\n constructor(headers: Headers, data: T) {\n super(BadGateway.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class ServiceUnavailable<\n T = { message: string; retryAfter?: string },\n> extends APIError<T, 503> {\n static override status = 503 as const;\n constructor(headers: Headers, data: T) {\n super(ServiceUnavailable.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\nexport class GatewayTimeout<T = { message: string }> extends APIError<T, 504> {\n static override status = 504 as const;\n constructor(headers: Headers, data: T) {\n super(GatewayTimeout.status, headers, data);\n }\n static override create<T>(status: number, headers: Headers, data: T) {\n return new this(headers, data);\n }\n}\n\nexport type ClientError =\n | BadRequest<unknown>\n | Unauthorized<unknown>\n | PaymentRequired<unknown>\n | Forbidden<unknown>\n | NotFound<unknown>\n | MethodNotAllowed<unknown>\n | NotAcceptable<unknown>\n | Conflict<unknown>\n | Gone<unknown>\n | PreconditionFailed<unknown>\n | PayloadTooLarge<unknown>\n | UnsupportedMediaType<unknown>\n | UnprocessableEntity<unknown>\n | TooManyRequests<unknown>;\n\nexport type ServerError =\n | InternalServerError<unknown>\n | NotImplemented<unknown>\n | BadGateway<unknown>\n | ServiceUnavailable<unknown>\n | GatewayTimeout<unknown>;\n\nexport type ProblematicResponse = ClientError | ServerError;\n\nexport type SuccessfulResponse<T = unknown> =\n | Ok<T>\n | Created<T>\n | Accepted<T>\n | NoContent;\n\nexport type RebindSuccessPayload<Resp, New> =\n Resp extends Ok<infer _>\n ? Ok<New>\n : Resp extends Created<infer _>\n ? Created<New>\n : Resp extends Accepted<infer _>\n ? Accepted<New>\n : Resp extends NoContent\n ? NoContent\n : Resp extends SuccessfulResponse<infer _>\n ? APIResponse<New, Resp['status']>\n : never;\n";
1255
1321
 
1322
+ // packages/typescript/src/lib/http/sse.txt
1323
+ var sse_default = 'export type SSEListener = (eventType: string) => AsyncIterable<string>;\n\nexport function sse(response: Response): SSEListener {\n const subscribers = new Map<\n string,\n { queue: string[]; resolve: (() => void) | null }\n >();\n let started = false;\n let streamDone = false;\n\n function dispatch(eventType: string, data: string) {\n const sub = subscribers.get(eventType);\n if (sub) {\n sub.queue.push(data);\n sub.resolve?.();\n sub.resolve = null;\n }\n }\n\n function endAll() {\n streamDone = true;\n for (const sub of subscribers.values()) {\n sub.resolve?.();\n }\n }\n\n function startReading() {\n if (started) return;\n started = true;\n const decoder = new TextDecoder();\n let buffer = "";\n\n (async () => {\n try {\n for await (const value of response.body!) {\n buffer += decoder.decode(value, { stream: true });\n const parts = buffer.split("\\n\\n");\n buffer = parts.pop()!;\n\n for (const part of parts) {\n if (!part.trim()) continue;\n let eventType = "message";\n let data = "";\n for (const line of part.split("\\n")) {\n if (line.startsWith("event:")) {\n eventType = line.slice(6).trim();\n } else if (line.startsWith("data:")) {\n data += (data ? "\\n" : "") + line.slice(5).trim();\n }\n }\n if (data) dispatch(eventType, data);\n }\n }\n } catch {}\n endAll();\n })();\n }\n\n return function listen(eventType: string): AsyncIterable<string> {\n if (!subscribers.has(eventType)) {\n subscribers.set(eventType, { queue: [], resolve: null });\n }\n const sub = subscribers.get(eventType)!;\n startReading();\n\n return {\n [Symbol.asyncIterator]() {\n return {\n async next(): Promise<IteratorResult<string>> {\n while (sub.queue.length === 0) {\n if (streamDone) return { value: undefined as any, done: true };\n const { promise, resolve } = Promise.withResolvers<void>();\n sub.resolve = resolve;\n await promise;\n }\n return { value: sub.queue.shift()!, done: false };\n },\n async return(): Promise<IteratorResult<string>> {\n return { value: undefined as any, done: true };\n },\n };\n },\n };\n };\n}\n';
1324
+
1256
1325
  // packages/typescript/src/lib/paginations/cursor-pagination.txt
1257
1326
  var cursor_pagination_default = "type CursorPaginationParams = {\n cursor?: string;\n};\n\ninterface CursorMetadata extends Metadata {\n nextCursor?: string;\n}\n\ninterface Metadata {\n hasMore?: boolean;\n}\n\ntype PaginationResult<T, M extends CursorMetadata> = {\n data: T[];\n meta: M;\n};\n\ntype FetchFn<T, M extends CursorMetadata> = (\n input: CursorPaginationParams,\n) => Promise<PaginationResult<T, M>>;\n\n/**\n * @experimental\n */\nexport class CursorPagination<T, M extends CursorMetadata> {\n #meta: PaginationResult<T, M>['meta'] | null = null;\n #params: CursorPaginationParams;\n #currentPage: Page<T> | null = null;\n readonly #fetchFn: FetchFn<T, M>;\n\n constructor(\n initialParams: PartialNullable<CursorPaginationParams>,\n fetchFn: FetchFn<T, M>,\n ) {\n this.#fetchFn = fetchFn;\n this.#params = {\n cursor: initialParams.cursor ?? undefined,\n };\n }\n\n async getNextPage() {\n const result = await this.#fetchFn(this.#params);\n this.#currentPage = new Page(result.data);\n this.#meta = result.meta;\n this.#params = {\n ...this.#params,\n cursor: result.meta.nextCursor,\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() {\n if (!this.#currentPage) {\n yield await this.getNextPage();\n }\n\n while (this.hasMore) {\n yield await this.getNextPage();\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\ntype PartialNullable<T> = {\n [K in keyof T]?: T[K] | null;\n};\n";
1258
1327
 
@@ -1647,6 +1716,32 @@ ${l}`));
1647
1716
  return markdown.join("\n\n");
1648
1717
  }
1649
1718
 
1719
+ // packages/typescript/src/lib/server-urls.ts
1720
+ function expandServerUrls(servers) {
1721
+ return servers.flatMap((server) => {
1722
+ const variables = server.variables;
1723
+ if (!variables || Object.keys(variables).length === 0) {
1724
+ return [server.url];
1725
+ }
1726
+ const entries = Object.entries(variables);
1727
+ const valueSets = entries.map(([, variable]) => {
1728
+ const enumValues = variable.enum?.map(String);
1729
+ return enumValues?.length ? enumValues : [String(variable.default)];
1730
+ });
1731
+ const combinations = valueSets.reduce(
1732
+ (acc, values) => acc.flatMap((combo) => values.map((v) => [...combo, v])),
1733
+ [[]]
1734
+ );
1735
+ return combinations.map((combo) => {
1736
+ let url = server.url;
1737
+ for (let i = 0; i < entries.length; i++) {
1738
+ url = url.replaceAll(`{${entries[i][0]}}`, combo[i]);
1739
+ }
1740
+ return url;
1741
+ });
1742
+ });
1743
+ }
1744
+
1650
1745
  // packages/typescript/src/lib/typescript-snippet.ts
1651
1746
  import { camelcase as camelcase5, spinalcase as spinalcase3 } from "stringcase";
1652
1747
  import { isEmpty as isEmpty4, pascalcase as pascalcase4, resolveRef as resolveRef3 } from "@sdk-it/core";
@@ -2000,7 +2095,7 @@ var TypeScriptSnippet = class {
2000
2095
  }
2001
2096
  client() {
2002
2097
  const options = {
2003
- baseUrl: this.#spec.servers?.[0]?.url ?? "http://localhost:3000"
2098
+ baseUrl: expandServerUrls(this.#spec.servers ?? [])[0] ?? "http://localhost:3000"
2004
2099
  };
2005
2100
  const authOptions = this.#authentication();
2006
2101
  if (!isEmpty4(authOptions)) {
@@ -2041,7 +2136,7 @@ ${client.use}`;
2041
2136
  const hasServers = Boolean(
2042
2137
  this.#spec.servers && this.#spec.servers.length > 0
2043
2138
  );
2044
- const baseUrl = this.#spec.servers?.[0]?.url || "https://api.example.com";
2139
+ const baseUrl = expandServerUrls(this.#spec.servers ?? [])[0] || "https://api.example.com";
2045
2140
  const authOptions = this.#authentication();
2046
2141
  const hasApiKey = !isEmpty4(authOptions);
2047
2142
  sections.push("### Configuration Options");
@@ -2457,7 +2552,7 @@ ${client.use}`;
2457
2552
  );
2458
2553
  sections.push("");
2459
2554
  const bearerAuthClient = this.#constructClient({
2460
- [optionName]: "sk_live_51234567890abcdef1234567890abcdef"
2555
+ [optionName]: "test_51234567890abcdef1234567890abcdef"
2461
2556
  });
2462
2557
  sections.push(createCodeBlock("typescript", [bearerAuthClient.use]));
2463
2558
  sections.push("");
@@ -2466,7 +2561,7 @@ ${client.use}`;
2466
2561
  sections.push(`${headingLevel} ${apiKeyHeading}`);
2467
2562
  sections.push("");
2468
2563
  const apiKeyAuthClient = this.#constructClient({
2469
- [optionName]: "api_key_1234567890abcdef1234567890abcdef"
2564
+ [optionName]: "test_api_key_1234567890abcdef1234567890abcdef"
2470
2565
  });
2471
2566
  sections.push(createCodeBlock("typescript", [apiKeyAuthClient.use]));
2472
2567
  sections.push("");
@@ -2475,7 +2570,7 @@ ${client.use}`;
2475
2570
  sections.push(`${headingLevel} ${queryParamHeading}`);
2476
2571
  sections.push("");
2477
2572
  const queryParamAuthClient = this.#constructClient({
2478
- [optionName]: "qp_key_1234567890abcdef1234567890abcdef"
2573
+ [optionName]: "test_qp_key_1234567890abcdef1234567890abcdef"
2479
2574
  });
2480
2575
  sections.push(
2481
2576
  createCodeBlock("typescript", [queryParamAuthClient.use])
@@ -2486,7 +2581,7 @@ ${client.use}`;
2486
2581
  sections.push(`${headingLevel} ${genericAuthHeading}`);
2487
2582
  sections.push("");
2488
2583
  const genericAuthClient = this.#constructClient({
2489
- [optionName]: "auth_token_1234567890abcdef1234567890abcdef"
2584
+ [optionName]: "test_auth_token_1234567890abcdef1234567890abcdef"
2490
2585
  });
2491
2586
  sections.push(createCodeBlock("typescript", [genericAuthClient.use]));
2492
2587
  sections.push("");
@@ -2513,7 +2608,7 @@ ${client.use}`;
2513
2608
  if (!isEmpty4(authOptions)) {
2514
2609
  const [primaryAuth] = authOptions;
2515
2610
  const authOptionName = primaryAuth["x-optionName"] ?? primaryAuth.name;
2516
- initialClientOptions[authOptionName] = "prod_sk_1234567890abcdef";
2611
+ initialClientOptions[authOptionName] = "YOUR_PRODUCTION_TOKEN";
2517
2612
  }
2518
2613
  const initialClientSetup = this.#constructClient(initialClientOptions);
2519
2614
  const configurationUpdateCode = [
@@ -2527,9 +2622,7 @@ ${client.use}`;
2527
2622
  if (!isEmpty4(authOptions)) {
2528
2623
  const [primaryAuth] = authOptions;
2529
2624
  const authOptionName = primaryAuth["x-optionName"] ?? primaryAuth.name;
2530
- configurationUpdateCode.push(
2531
- ` ${authOptionName}: 'staging_sk_abcdef1234567890'`
2532
- );
2625
+ configurationUpdateCode.push(` ${authOptionName}: 'YOUR_STAGING_TOKEN'`);
2533
2626
  }
2534
2627
  configurationUpdateCode.push("});");
2535
2628
  sections.push(createCodeBlock("typescript", configurationUpdateCode));
@@ -2634,7 +2727,7 @@ async function generate(openapi, settings) {
2634
2727
  makeImport
2635
2728
  });
2636
2729
  const clientName = pascalcase5((settings.name || "client").trim());
2637
- const packageName = settings.name ? `@${spinalcase4(settings.name.trim().toLowerCase())}/sdk` : "sdk";
2730
+ const packageName = settings.packageName ?? (settings.name ? `@${spinalcase4(settings.name.trim().toLowerCase())}/sdk` : "sdk");
2638
2731
  const inputs = toInputs(groups, commonZod, makeImport);
2639
2732
  const models = serializeModels(spec);
2640
2733
  await settings.writer(output, {
@@ -2647,10 +2740,12 @@ async function generate(openapi, settings) {
2647
2740
  "response.ts": response_default,
2648
2741
  "parser.ts": parser_default,
2649
2742
  "request.ts": request_default,
2743
+ "sse.ts": sse_default,
2650
2744
  "dispatcher.ts": `import z from 'zod';
2651
2745
  import { type Interceptor } from '${makeImport("../http/interceptors")}';
2652
2746
  import { type RequestConfig } from '${makeImport("../http/request")}';
2653
2747
  import { buffered } from '${makeImport("./parse-response")}';
2748
+ import { type SSEListener } from '${makeImport("./sse")}';
2654
2749
  import { APIError, APIResponse, type SuccessfulResponse, type RebindSuccessPayload } from '${makeImport("./response")}';
2655
2750
 
2656
2751
  ${template2(dispatcher_default, {})()}`,
@@ -2661,7 +2756,7 @@ ${template2(dispatcher_default, {})()}`,
2661
2756
  await settings.writer(output, {
2662
2757
  "client.ts": client_default({
2663
2758
  name: clientName,
2664
- servers: (spec.servers ?? []).map((server) => server.url) || [],
2759
+ servers: expandServerUrls(spec.servers ?? []),
2665
2760
  options: security(spec),
2666
2761
  makeImport
2667
2762
  }),
@@ -2821,6 +2916,7 @@ ${utils_default}`
2821
2916
  output,
2822
2917
  env: npmRunPathEnv()
2823
2918
  });
2919
+ return { packageName };
2824
2920
  }
2825
2921
  function serializeModels(spec) {
2826
2922
  const filesMap = {};
@@ -2834,12 +2930,18 @@ function serializeModels(spec) {
2834
2930
  continue;
2835
2931
  }
2836
2932
  const folder = isResponseBody ? "outputs" : "models";
2837
- let typeContent = "ReadableStream";
2933
+ const isSse = schema["x-sse"];
2934
+ let typeContent = isSse ? "SSEListener" : "ReadableStream";
2838
2935
  if (!stream) {
2839
2936
  const serializer = new TypeScriptEmitter(spec);
2840
2937
  typeContent = serializer.handle(schema, true);
2841
2938
  }
2939
+ const imports = [];
2940
+ if (isSse) {
2941
+ imports.push(`import type { SSEListener } from '../http/sse.ts';`);
2942
+ }
2842
2943
  const fileContent = [
2944
+ ...imports,
2843
2945
  `
2844
2946
  ${schema.description ? `
2845
2947
  /**