zod-codegen 1.5.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/.github/workflows/ci.yml +6 -0
  2. package/.github/workflows/release.yml +3 -3
  3. package/CHANGELOG.md +37 -0
  4. package/CONTRIBUTING.md +1 -1
  5. package/EXAMPLES.md +91 -12
  6. package/README.md +11 -4
  7. package/dist/scripts/add-js-extensions.d.ts +2 -0
  8. package/dist/scripts/add-js-extensions.d.ts.map +1 -0
  9. package/dist/scripts/add-js-extensions.js +66 -0
  10. package/dist/scripts/update-manifest.d.ts +14 -0
  11. package/dist/scripts/update-manifest.d.ts.map +1 -0
  12. package/dist/scripts/update-manifest.js +33 -0
  13. package/dist/src/assets/manifest.json +1 -1
  14. package/dist/src/cli.js +3 -3
  15. package/dist/src/generator.d.ts +46 -4
  16. package/dist/src/generator.d.ts.map +1 -1
  17. package/dist/src/generator.js +43 -1
  18. package/dist/src/interfaces/code-generator.d.ts +1 -1
  19. package/dist/src/interfaces/code-generator.d.ts.map +1 -1
  20. package/dist/src/services/code-generator.service.d.ts +5 -3
  21. package/dist/src/services/code-generator.service.d.ts.map +1 -1
  22. package/dist/src/services/code-generator.service.js +69 -1
  23. package/dist/src/services/file-reader.service.d.ts +2 -2
  24. package/dist/src/services/file-reader.service.d.ts.map +1 -1
  25. package/dist/src/services/file-writer.service.d.ts +1 -1
  26. package/dist/src/services/file-writer.service.d.ts.map +1 -1
  27. package/dist/src/services/import-builder.service.d.ts +1 -1
  28. package/dist/src/services/import-builder.service.d.ts.map +1 -1
  29. package/dist/src/services/import-builder.service.js +1 -1
  30. package/dist/src/services/type-builder.service.d.ts +1 -1
  31. package/dist/src/services/type-builder.service.d.ts.map +1 -1
  32. package/dist/src/types/generator-options.d.ts +1 -1
  33. package/dist/src/types/generator-options.d.ts.map +1 -1
  34. package/dist/src/utils/error-handler.d.ts +3 -2
  35. package/dist/src/utils/error-handler.d.ts.map +1 -1
  36. package/dist/src/utils/error-handler.js +4 -4
  37. package/dist/src/utils/reporter.d.ts +3 -2
  38. package/dist/src/utils/reporter.d.ts.map +1 -1
  39. package/dist/src/utils/reporter.js +7 -5
  40. package/dist/src/utils/signal-handler.d.ts +3 -2
  41. package/dist/src/utils/signal-handler.d.ts.map +1 -1
  42. package/dist/src/utils/signal-handler.js +4 -4
  43. package/examples/README.md +10 -1
  44. package/examples/petstore/README.md +6 -6
  45. package/examples/petstore/authenticated-usage.ts +1 -1
  46. package/examples/petstore/basic-usage.ts +1 -1
  47. package/examples/petstore/retry-handler-usage.ts +173 -0
  48. package/examples/petstore/server-variables-usage.ts +1 -1
  49. package/examples/petstore/type.ts +68 -47
  50. package/examples/pokeapi/README.md +3 -3
  51. package/examples/pokeapi/basic-usage.ts +1 -1
  52. package/examples/pokeapi/custom-client.ts +1 -1
  53. package/generated/type.ts +323 -0
  54. package/package.json +10 -13
  55. package/scripts/add-js-extensions.ts +79 -0
  56. package/scripts/update-manifest.ts +4 -2
  57. package/src/assets/manifest.json +1 -1
  58. package/src/cli.ts +7 -7
  59. package/src/generator.ts +51 -9
  60. package/src/interfaces/code-generator.ts +1 -1
  61. package/src/services/code-generator.service.ts +114 -8
  62. package/src/services/file-reader.service.ts +3 -3
  63. package/src/services/file-writer.service.ts +1 -1
  64. package/src/services/import-builder.service.ts +2 -2
  65. package/src/services/type-builder.service.ts +1 -1
  66. package/src/types/generator-options.ts +1 -1
  67. package/src/utils/error-handler.ts +6 -5
  68. package/src/utils/reporter.ts +6 -3
  69. package/src/utils/signal-handler.ts +10 -8
  70. package/tests/integration/cli-comprehensive.test.ts +123 -0
  71. package/tests/integration/cli.test.ts +2 -2
  72. package/tests/integration/error-scenarios.test.ts +240 -0
  73. package/tests/integration/snapshots.test.ts +131 -0
  74. package/tests/unit/code-generator-edge-cases.test.ts +551 -0
  75. package/tests/unit/code-generator.test.ts +385 -2
  76. package/tests/unit/file-reader.test.ts +16 -1
  77. package/tests/unit/generator.test.ts +19 -2
  78. package/tests/unit/naming-convention.test.ts +30 -1
  79. package/tests/unit/reporter.test.ts +63 -0
  80. package/tests/unit/type-builder.test.ts +131 -0
  81. package/tsconfig.json +3 -3
  82. package/dist/src/http/fetch-client.d.ts +0 -15
  83. package/dist/src/http/fetch-client.d.ts.map +0 -1
  84. package/dist/src/http/fetch-client.js +0 -140
  85. package/dist/src/polyfills/fetch.d.ts +0 -5
  86. package/dist/src/polyfills/fetch.d.ts.map +0 -1
  87. package/dist/src/polyfills/fetch.js +0 -18
  88. package/dist/src/types/http.d.ts +0 -25
  89. package/dist/src/types/http.d.ts.map +0 -1
  90. package/dist/src/types/http.js +0 -10
  91. package/dist/src/utils/manifest.d.ts +0 -8
  92. package/dist/src/utils/manifest.d.ts.map +0 -1
  93. package/dist/src/utils/manifest.js +0 -9
  94. package/dist/src/utils/tty.d.ts +0 -2
  95. package/dist/src/utils/tty.d.ts.map +0 -1
  96. package/dist/src/utils/tty.js +0 -3
  97. package/src/http/fetch-client.ts +0 -181
  98. package/src/polyfills/fetch.ts +0 -26
  99. package/src/types/http.ts +0 -35
  100. package/src/utils/manifest.ts +0 -17
  101. package/src/utils/tty.ts +0 -3
package/tsconfig.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "isolatedModules": true,
13
13
  "lib": ["ES2022", "DOM"],
14
14
  "module": "ESNext",
15
- "moduleResolution": "Bundler",
15
+ "moduleResolution": "bundler",
16
16
  "declaration": true,
17
17
  "declarationMap": true,
18
18
  "noEmit": false,
@@ -39,8 +39,8 @@
39
39
  "target": "ES2022",
40
40
  "typeRoots": ["./node_modules/@types"],
41
41
  "useUnknownInCatchVariables": true,
42
- "verbatimModuleSyntax": true
42
+ "verbatimModuleSyntax": false
43
43
  },
44
- "exclude": ["node_modules", "dist", "build", "examples/**/*.ts", "tests/**/*.ts", "scripts/**/*.ts"],
44
+ "exclude": ["node_modules", "dist", "build", "examples/**/*.ts", "tests/**/*.ts"],
45
45
  "include": ["src/**/*.ts", "scripts/**/*.ts", "tests/**/*.ts", "vitest.config.ts"]
46
46
  }
@@ -1,15 +0,0 @@
1
- import type { HttpClient, HttpRequestConfig, HttpResponse } from '../types/http.js';
2
- export declare class FetchHttpClient implements HttpClient {
3
- private readonly baseUrl;
4
- private readonly defaultHeaders;
5
- private readonly fetch;
6
- private readonly Headers;
7
- constructor(baseUrl?: string, defaultHeaders?: Record<string, string>);
8
- request<TResponse = unknown, TRequest = unknown>(config: HttpRequestConfig<TRequest>): Promise<HttpResponse<TResponse>>;
9
- private buildUrl;
10
- private buildHeaders;
11
- private buildBody;
12
- private extractHeaders;
13
- private parseResponse;
14
- }
15
- //# sourceMappingURL=fetch-client.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fetch-client.d.ts","sourceRoot":"","sources":["../../../src/http/fetch-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAE,iBAAiB,EAAE,YAAY,EAAC,MAAM,kBAAkB,CAAC;AAclF,qBAAa,eAAgB,YAAW,UAAU;IAK9C,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,cAAc;IALjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;gBAG1B,OAAO,SAAK,EACZ,cAAc,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM;IAoBxD,OAAO,CAAC,SAAS,GAAG,OAAO,EAAE,QAAQ,GAAG,OAAO,EACnD,MAAM,EAAE,iBAAiB,CAAC,QAAQ,CAAC,GAClC,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IA4DnC,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,SAAS;IAqBjB,OAAO,CAAC,cAAc;YAQR,aAAa;CAkB5B"}
@@ -1,140 +0,0 @@
1
- import { HttpError } from '../types/http.js';
2
- export class FetchHttpClient {
3
- baseUrl;
4
- defaultHeaders;
5
- fetch;
6
- Headers;
7
- constructor(baseUrl = '', defaultHeaders = {}) {
8
- this.baseUrl = baseUrl;
9
- this.defaultHeaders = defaultHeaders;
10
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
11
- if (typeof globalThis.fetch === 'function' && globalThis.Headers) {
12
- this.fetch = globalThis.fetch.bind(globalThis);
13
- this.Headers = globalThis.Headers;
14
- return;
15
- }
16
- if (typeof window !== 'undefined' && typeof window.fetch === 'function') {
17
- this.fetch = window.fetch.bind(window);
18
- this.Headers = window.Headers;
19
- return;
20
- }
21
- throw new Error("Fetch API is not available. Please ensure you're running in a compatible environment or polyfill fetch.");
22
- }
23
- async request(config) {
24
- const url = this.buildUrl(config.url, config.params);
25
- const headers = this.buildHeaders(config.headers);
26
- const body = this.buildBody(config.data, headers);
27
- const controller = new AbortController();
28
- const timeoutId = config.timeout
29
- ? setTimeout(() => {
30
- controller.abort();
31
- }, config.timeout)
32
- : undefined;
33
- try {
34
- const response = await this.fetch(url, {
35
- method: config.method,
36
- headers,
37
- body,
38
- signal: controller.signal,
39
- });
40
- const responseHeaders = this.extractHeaders(response.headers);
41
- const data = await this.parseResponse(response);
42
- if (!response.ok) {
43
- throw new HttpError(`HTTP ${String(response.status)}: ${response.statusText}`, response.status, {
44
- data,
45
- status: response.status,
46
- statusText: response.statusText,
47
- headers: responseHeaders,
48
- url: response.url,
49
- });
50
- }
51
- return {
52
- data,
53
- status: response.status,
54
- statusText: response.statusText,
55
- headers: responseHeaders,
56
- url: response.url,
57
- };
58
- }
59
- catch (error) {
60
- if (error instanceof HttpError) {
61
- throw error;
62
- }
63
- if (error instanceof Error) {
64
- if (error.name === 'AbortError') {
65
- throw new HttpError('Request timeout', 408);
66
- }
67
- throw new HttpError(`Network error: ${error.message}`, 0);
68
- }
69
- throw new HttpError('Unknown network error', 0);
70
- }
71
- finally {
72
- if (timeoutId) {
73
- clearTimeout(timeoutId);
74
- }
75
- }
76
- }
77
- buildUrl(path, params) {
78
- const url = new URL(path, this.baseUrl || 'http://localhost');
79
- if (params) {
80
- Object.entries(params).forEach(([key, value]) => {
81
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
82
- if (value !== undefined && value !== null) {
83
- url.searchParams.set(key, String(value));
84
- }
85
- });
86
- }
87
- return url.toString();
88
- }
89
- buildHeaders(customHeaders) {
90
- const headers = new this.Headers();
91
- Object.entries(this.defaultHeaders).forEach(([key, value]) => {
92
- headers.set(key, value);
93
- });
94
- if (customHeaders) {
95
- Object.entries(customHeaders).forEach(([key, value]) => {
96
- headers.set(key, value);
97
- });
98
- }
99
- return headers;
100
- }
101
- buildBody(data, headers) {
102
- if (!data) {
103
- return null;
104
- }
105
- const contentType = headers?.get('content-type') ?? 'application/json';
106
- if (contentType.includes('application/json')) {
107
- if (!headers?.has('content-type')) {
108
- headers?.set('content-type', 'application/json');
109
- }
110
- return JSON.stringify(data);
111
- }
112
- if (typeof data === 'string') {
113
- return data;
114
- }
115
- return JSON.stringify(data);
116
- }
117
- extractHeaders(headers) {
118
- const result = {};
119
- headers.forEach((value, key) => {
120
- result[key.toLowerCase()] = value;
121
- });
122
- return result;
123
- }
124
- async parseResponse(response) {
125
- const contentType = response.headers.get('content-type') ?? '';
126
- if (contentType.includes('application/json')) {
127
- return (await response.json());
128
- }
129
- if (contentType.includes('text/')) {
130
- return (await response.text());
131
- }
132
- try {
133
- const text = await response.text();
134
- return text ? JSON.parse(text) : {};
135
- }
136
- catch {
137
- return {};
138
- }
139
- }
140
- }
@@ -1,5 +0,0 @@
1
- export interface FetchPolyfillOptions {
2
- enableNodejsPolyfill?: boolean;
3
- }
4
- export declare function setupFetchPolyfill(options?: FetchPolyfillOptions): Promise<void>;
5
- //# sourceMappingURL=fetch.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../../src/polyfills/fetch.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,wBAAsB,kBAAkB,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB1F"}
@@ -1,18 +0,0 @@
1
- export async function setupFetchPolyfill(options = {}) {
2
- if (typeof fetch === 'function') {
3
- return;
4
- }
5
- if (typeof window !== 'undefined' && typeof window.fetch === 'function') {
6
- return;
7
- }
8
- if (options.enableNodejsPolyfill && typeof process !== 'undefined' && process.versions.node) {
9
- try {
10
- await import('undici');
11
- return;
12
- }
13
- catch {
14
- // Fall through to error
15
- }
16
- }
17
- throw new Error('Fetch API is not available. ' + 'For Node.js environments, please install undici: npm install undici');
18
- }
@@ -1,25 +0,0 @@
1
- export interface HttpRequestConfig<TData = unknown> {
2
- readonly url: string;
3
- readonly method: HttpMethod;
4
- readonly headers?: Record<string, string>;
5
- readonly params?: Record<string, string | number | boolean>;
6
- readonly data?: TData;
7
- readonly timeout?: number;
8
- }
9
- export interface HttpResponse<TData = unknown> {
10
- readonly data: TData;
11
- readonly status: number;
12
- readonly statusText: string;
13
- readonly headers: Record<string, string>;
14
- readonly url: string;
15
- }
16
- export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
17
- export interface HttpClient {
18
- request<TResponse = unknown, TRequest = unknown>(config: HttpRequestConfig<TRequest>): Promise<HttpResponse<TResponse>>;
19
- }
20
- export declare class HttpError extends Error {
21
- readonly status: number;
22
- readonly response?: HttpResponse | undefined;
23
- constructor(message: string, status: number, response?: HttpResponse | undefined);
24
- }
25
- //# sourceMappingURL=http.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../src/types/http.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB,CAAC,KAAK,GAAG,OAAO;IAChD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IAC5D,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY,CAAC,KAAK,GAAG,OAAO;IAC3C,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1F,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,SAAS,GAAG,OAAO,EAAE,QAAQ,GAAG,OAAO,EAC7C,MAAM,EAAE,iBAAiB,CAAC,QAAQ,CAAC,GAClC,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC;CACrC;AAED,qBAAa,SAAU,SAAQ,KAAK;aAGhB,MAAM,EAAE,MAAM;aACd,QAAQ,CAAC,EAAE,YAAY;gBAFvC,OAAO,EAAE,MAAM,EACC,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,YAAY,YAAA;CAK1C"}
@@ -1,10 +0,0 @@
1
- export class HttpError extends Error {
2
- status;
3
- response;
4
- constructor(message, status, response) {
5
- super(message);
6
- this.status = status;
7
- this.response = response;
8
- this.name = 'HttpError';
9
- }
10
- }
@@ -1,8 +0,0 @@
1
- interface Manifest {
2
- readonly name: string;
3
- readonly version: string;
4
- readonly description: string;
5
- }
6
- export declare function isManifest(input: unknown): input is Manifest;
7
- export {};
8
- //# sourceMappingURL=manifest.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/utils/manifest.ts"],"names":[],"mappings":"AAEA,UAAU,QAAQ;IAChB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAQD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D"}
@@ -1,9 +0,0 @@
1
- import { z } from 'zod';
2
- const ManifestSchema = z.object({
3
- name: z.string().min(1),
4
- version: z.string().min(1),
5
- description: z.string().min(1),
6
- });
7
- export function isManifest(input) {
8
- return ManifestSchema.safeParse(input).success;
9
- }
@@ -1,2 +0,0 @@
1
- export declare function isTTY(process: NodeJS.Process): boolean;
2
- //# sourceMappingURL=tty.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tty.d.ts","sourceRoot":"","sources":["../../../src/utils/tty.ts"],"names":[],"mappings":"AAAA,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAEtD"}
@@ -1,3 +0,0 @@
1
- export function isTTY(process) {
2
- return process.stdout.isTTY || false;
3
- }
@@ -1,181 +0,0 @@
1
- import type {HttpClient, HttpRequestConfig, HttpResponse} from '../types/http.js';
2
- import {HttpError} from '../types/http.js';
3
-
4
- declare const globalThis: typeof global & {
5
- fetch?: typeof fetch;
6
- Headers?: typeof Headers;
7
- Request?: typeof Request;
8
- Response?: typeof Response;
9
- };
10
-
11
- type FetchFunction = (input: string | Request, init?: RequestInit) => Promise<Response>;
12
-
13
- type HeadersConstructor = new (init?: HeadersInit) => Headers;
14
-
15
- export class FetchHttpClient implements HttpClient {
16
- private readonly fetch: FetchFunction;
17
- private readonly Headers: HeadersConstructor;
18
-
19
- constructor(
20
- private readonly baseUrl = '',
21
- private readonly defaultHeaders: Record<string, string> = {},
22
- ) {
23
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
24
- if (typeof globalThis.fetch === 'function' && globalThis.Headers) {
25
- this.fetch = globalThis.fetch.bind(globalThis);
26
- this.Headers = globalThis.Headers;
27
- return;
28
- }
29
-
30
- if (typeof window !== 'undefined' && typeof window.fetch === 'function') {
31
- this.fetch = window.fetch.bind(window);
32
- this.Headers = window.Headers;
33
- return;
34
- }
35
-
36
- throw new Error(
37
- "Fetch API is not available. Please ensure you're running in a compatible environment or polyfill fetch.",
38
- );
39
- }
40
-
41
- async request<TResponse = unknown, TRequest = unknown>(
42
- config: HttpRequestConfig<TRequest>,
43
- ): Promise<HttpResponse<TResponse>> {
44
- const url = this.buildUrl(config.url, config.params);
45
- const headers = this.buildHeaders(config.headers);
46
- const body = this.buildBody(config.data, headers);
47
-
48
- const controller = new AbortController();
49
- const timeoutId = config.timeout
50
- ? setTimeout(() => {
51
- controller.abort();
52
- }, config.timeout)
53
- : undefined;
54
-
55
- try {
56
- const response = await this.fetch(url, {
57
- method: config.method,
58
- headers,
59
- body,
60
- signal: controller.signal,
61
- });
62
-
63
- const responseHeaders = this.extractHeaders(response.headers);
64
- const data = await this.parseResponse<TResponse>(response);
65
-
66
- if (!response.ok) {
67
- throw new HttpError(`HTTP ${String(response.status)}: ${response.statusText}`, response.status, {
68
- data,
69
- status: response.status,
70
- statusText: response.statusText,
71
- headers: responseHeaders,
72
- url: response.url,
73
- });
74
- }
75
-
76
- return {
77
- data,
78
- status: response.status,
79
- statusText: response.statusText,
80
- headers: responseHeaders,
81
- url: response.url,
82
- };
83
- } catch (error) {
84
- if (error instanceof HttpError) {
85
- throw error;
86
- }
87
-
88
- if (error instanceof Error) {
89
- if (error.name === 'AbortError') {
90
- throw new HttpError('Request timeout', 408);
91
- }
92
- throw new HttpError(`Network error: ${error.message}`, 0);
93
- }
94
-
95
- throw new HttpError('Unknown network error', 0);
96
- } finally {
97
- if (timeoutId) {
98
- clearTimeout(timeoutId);
99
- }
100
- }
101
- }
102
-
103
- private buildUrl(path: string, params?: Record<string, string | number | boolean>): string {
104
- const url = new URL(path, this.baseUrl || 'http://localhost');
105
-
106
- if (params) {
107
- Object.entries(params).forEach(([key, value]) => {
108
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
109
- if (value !== undefined && value !== null) {
110
- url.searchParams.set(key, String(value));
111
- }
112
- });
113
- }
114
-
115
- return url.toString();
116
- }
117
-
118
- private buildHeaders(customHeaders?: Record<string, string>): Headers {
119
- const headers = new this.Headers();
120
-
121
- Object.entries(this.defaultHeaders).forEach(([key, value]) => {
122
- headers.set(key, value);
123
- });
124
-
125
- if (customHeaders) {
126
- Object.entries(customHeaders).forEach(([key, value]) => {
127
- headers.set(key, value);
128
- });
129
- }
130
-
131
- return headers;
132
- }
133
-
134
- private buildBody(data?: unknown, headers?: Headers): string | null {
135
- if (!data) {
136
- return null;
137
- }
138
-
139
- const contentType = headers?.get('content-type') ?? 'application/json';
140
-
141
- if (contentType.includes('application/json')) {
142
- if (!headers?.has('content-type')) {
143
- headers?.set('content-type', 'application/json');
144
- }
145
- return JSON.stringify(data);
146
- }
147
-
148
- if (typeof data === 'string') {
149
- return data;
150
- }
151
-
152
- return JSON.stringify(data);
153
- }
154
-
155
- private extractHeaders(headers: Headers): Record<string, string> {
156
- const result: Record<string, string> = {};
157
- headers.forEach((value, key) => {
158
- result[key.toLowerCase()] = value;
159
- });
160
- return result;
161
- }
162
-
163
- private async parseResponse<TResponse>(response: Response): Promise<TResponse> {
164
- const contentType = response.headers.get('content-type') ?? '';
165
-
166
- if (contentType.includes('application/json')) {
167
- return (await response.json()) as TResponse;
168
- }
169
-
170
- if (contentType.includes('text/')) {
171
- return (await response.text()) as TResponse;
172
- }
173
-
174
- try {
175
- const text = await response.text();
176
- return text ? (JSON.parse(text) as TResponse) : ({} as TResponse);
177
- } catch {
178
- return {} as TResponse;
179
- }
180
- }
181
- }
@@ -1,26 +0,0 @@
1
- export interface FetchPolyfillOptions {
2
- enableNodejsPolyfill?: boolean;
3
- }
4
-
5
- export async function setupFetchPolyfill(options: FetchPolyfillOptions = {}): Promise<void> {
6
- if (typeof fetch === 'function') {
7
- return;
8
- }
9
-
10
- if (typeof window !== 'undefined' && typeof window.fetch === 'function') {
11
- return;
12
- }
13
-
14
- if (options.enableNodejsPolyfill && typeof process !== 'undefined' && process.versions.node) {
15
- try {
16
- await import('undici');
17
- return;
18
- } catch {
19
- // Fall through to error
20
- }
21
- }
22
-
23
- throw new Error(
24
- 'Fetch API is not available. ' + 'For Node.js environments, please install undici: npm install undici',
25
- );
26
- }
package/src/types/http.ts DELETED
@@ -1,35 +0,0 @@
1
- export interface HttpRequestConfig<TData = unknown> {
2
- readonly url: string;
3
- readonly method: HttpMethod;
4
- readonly headers?: Record<string, string>;
5
- readonly params?: Record<string, string | number | boolean>;
6
- readonly data?: TData;
7
- readonly timeout?: number;
8
- }
9
-
10
- export interface HttpResponse<TData = unknown> {
11
- readonly data: TData;
12
- readonly status: number;
13
- readonly statusText: string;
14
- readonly headers: Record<string, string>;
15
- readonly url: string;
16
- }
17
-
18
- export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
19
-
20
- export interface HttpClient {
21
- request<TResponse = unknown, TRequest = unknown>(
22
- config: HttpRequestConfig<TRequest>,
23
- ): Promise<HttpResponse<TResponse>>;
24
- }
25
-
26
- export class HttpError extends Error {
27
- constructor(
28
- message: string,
29
- public readonly status: number,
30
- public readonly response?: HttpResponse,
31
- ) {
32
- super(message);
33
- this.name = 'HttpError';
34
- }
35
- }
@@ -1,17 +0,0 @@
1
- import {z} from 'zod';
2
-
3
- interface Manifest {
4
- readonly name: string;
5
- readonly version: string;
6
- readonly description: string;
7
- }
8
-
9
- const ManifestSchema = z.object({
10
- name: z.string().min(1),
11
- version: z.string().min(1),
12
- description: z.string().min(1),
13
- });
14
-
15
- export function isManifest(input: unknown): input is Manifest {
16
- return ManifestSchema.safeParse(input).success;
17
- }
package/src/utils/tty.ts DELETED
@@ -1,3 +0,0 @@
1
- export function isTTY(process: NodeJS.Process): boolean {
2
- return process.stdout.isTTY || false;
3
- }