@blimu/codegen 0.1.1 → 0.2.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.
@@ -0,0 +1,8 @@
1
+ {
2
+ "semi": true,
3
+ "trailingComma": "es5",
4
+ "singleQuote": true,
5
+ "printWidth": 80,
6
+ "tabWidth": 2,
7
+ "useTabs": false
8
+ }
@@ -19,13 +19,16 @@ import { {{pascal Client.name}}Client } from '{{Client.packageName}}';
19
19
  const client = new {{pascal Client.name}}Client({
20
20
  baseURL: '{{Client.defaultBaseURL}}',
21
21
  timeoutMs: 10000,
22
- retry: { retries: 2, backoffMs: 300, retryOn: [429, 500, 502, 503, 504] },
23
- // Environment-based baseURL (optional)
24
- env: 'sandbox',
25
- envBaseURLs: { sandbox: 'https://api-sandbox.example.com', production: 'https://api.example.com' },
26
- // Auth (generic API Key or Bearer header)
27
- accessToken: process.env.API_TOKEN,
28
- headerName: 'access_token', // or 'Authorization' (defaults to Authorization: Bearer <token>)
22
+ retry: { retries: 2, strategy: 'exponential', backoffMs: 300, retryOn: [429, 500, 502, 503, 504] },
23
+ // Auth configuration
24
+ auth: {
25
+ strategies: [
26
+ {
27
+ type: 'bearer',
28
+ token: process.env.API_TOKEN,
29
+ },
30
+ ],
31
+ },
29
32
  });
30
33
 
31
34
  {{#each IR.services}}
@@ -1,17 +1,6 @@
1
- {{~#if IR.securitySchemes~}}
2
- export type ClientOption = {
3
- baseURL?: string;
4
- headers?: Record<string, string>;
5
- timeoutMs?: number;
6
- retry?: { retries: number; backoffMs: number; retryOn?: number[] };
7
- onRequest?: (ctx: { url: string; init: RequestInit & { path: string; method: string; query?: Record<string, any>; headers: Headers }; attempt: number }) => void | Promise<void>;
8
- onResponse?: (ctx: { url: string; init: RequestInit & { path: string; method: string; query?: Record<string, any>; headers: Headers }; attempt: number; response: Response }) => void | Promise<void>;
9
- onError?: (err: unknown, ctx: { url: string; init: RequestInit & { path: string; method: string; query?: Record<string, any> }; attempt: number }) => void | Promise<void>;
10
- // Environment & Auth
11
- env?: 'sandbox' | 'production';
12
- envBaseURLs?: { sandbox: string; production: string };
13
- accessToken?: string | undefined | (() => string | undefined | Promise<string | undefined>);
14
- headerName?: string;
1
+ import { FetchClient, FetchError, type FetchClientConfig, type AuthStrategy } from "@blimu/fetch";
2
+
3
+ export type ClientOption = FetchClientConfig & {
15
4
  {{~#each IR.securitySchemes~}}
16
5
  {{~#if (eq this.type "http")~}}
17
6
  {{~#if (eq this.scheme "bearer")~}}
@@ -23,200 +12,134 @@ export type ClientOption = {
23
12
  {{camel this.key}}?: string;
24
13
  {{~/if~}}
25
14
  {{~/each~}}
26
- fetch?: typeof fetch;
27
- credentials?: RequestCredentials;
15
+ // Generic accessToken support (alias for bearer auth)
16
+ accessToken?: string | (() => string | undefined | Promise<string | undefined>);
28
17
  };
29
18
 
30
- export class FetchError<T = unknown> extends Error {
31
- constructor(
32
- message: string,
33
- readonly status: number,
34
- readonly data?: T,
35
- readonly headers?: Headers,
36
- ) {
37
- super(message);
38
- this.name = "FetchError";
39
- }
40
- }
19
+ // Re-export FetchError for backward compatibility
20
+ export { FetchError };
41
21
 
42
- export class CoreClient {
43
- constructor(private cfg: ClientOption = {}) {
44
- // Set default base URL if not provided
45
- if (!this.cfg.baseURL) {
46
- if (this.cfg.env && this.cfg.envBaseURLs) {
47
- this.cfg.baseURL = this.cfg.env === 'production' ? this.cfg.envBaseURLs.production : this.cfg.envBaseURLs.sandbox;
48
- } else {
49
- this.cfg.baseURL = "{{Client.defaultBaseURL}}";
50
- }
51
- }
52
- }
53
- setAccessToken(token: string | undefined | (() => string | undefined | Promise<string | undefined>)) {
54
- this.cfg.accessToken = token;
55
- }
56
- async request(
57
- init: RequestInit & {
58
- path: string;
59
- method: string;
60
- query?: Record<string, any>;
61
- }
62
- ) {
63
- let normalizedPath = init.path || "";
64
- if (normalizedPath.length > 1 && normalizedPath.endsWith('/')) {
65
- normalizedPath = normalizedPath.slice(0, -1);
66
- }
67
- const url = new URL((this.cfg.baseURL || "") + normalizedPath);
68
- if (init.query) {
69
- Object.entries(init.query).forEach(([k, v]) => {
70
- if (v === undefined || v === null) return;
71
- if (Array.isArray(v))
72
- v.forEach((vv) => url.searchParams.append(k, String(vv)));
73
- else url.searchParams.set(k, String(v));
74
- });
75
- }
22
+ export class CoreClient extends FetchClient {
23
+ constructor(cfg: ClientOption = {}) {
24
+ // Build auth strategies from OpenAPI security schemes
25
+ const authStrategies: AuthStrategy[] = [];
26
+
76
27
  {{~#each IR.securitySchemes~}}
77
- {{~#if (and (eq this.type "apiKey") (eq this.in "query"))~}}
78
- if (this.cfg.{{camel this.key}}) {
79
- url.searchParams.set("{{this.name}}", String(this.cfg.{{camel this.key}}));
28
+ {{~#if (eq this.type "http")~}}
29
+ {{~#if (eq this.scheme "bearer")~}}
30
+ if (cfg.{{camel this.key}}) {
31
+ const {{camel this.key}}Value = cfg.{{camel this.key}};
32
+ authStrategies.push({
33
+ type: "bearer",
34
+ token: () => {{camel this.key}}Value,
35
+ });
80
36
  }
37
+ {{~/if~}}
81
38
  {{~/if~}}
82
39
  {{~/each~}}
83
- const headers = new Headers({
84
- ...(this.cfg.headers || {}),
85
- ...(init.headers as any),
86
- });
87
- // Generic access token support (optional)
88
- if (this.cfg.accessToken) {
89
- const token = typeof this.cfg.accessToken === 'function' ? await this.cfg.accessToken() : this.cfg.accessToken;
90
- // Only set header if token is not nullish
91
- if (token != null) {
92
- const name = this.cfg.headerName || 'Authorization';
93
- if (name.toLowerCase() === 'authorization') headers.set(name, `Bearer ${String(token)}`);
94
- else headers.set(name, String(token));
40
+ // Support accessToken as an alias for bearer auth (only if no bearer auth was already added)
41
+ if (!authStrategies.some((s: any) => s.type === "bearer") && cfg.accessToken) {
42
+ const accessTokenValue = cfg.accessToken;
43
+ if (typeof accessTokenValue === "string") {
44
+ authStrategies.push({
45
+ type: "bearer",
46
+ token: () => accessTokenValue,
47
+ });
48
+ } else if (typeof accessTokenValue === "function") {
49
+ authStrategies.push({
50
+ type: "bearer",
51
+ token: accessTokenValue as () => string | undefined | Promise<string | undefined>,
52
+ });
95
53
  }
96
54
  }
55
+
97
56
  {{~#each IR.securitySchemes~}}
98
57
  {{~#if (eq this.type "http")~}}
99
- {{~#if (eq this.scheme "bearer")~}}
100
- const {{camel this.key}}Key = "{{camel this.key}}";
101
- if (this.cfg[{{camel this.key}}Key])
102
- headers.set("Authorization", `Bearer ${this.cfg[{{camel this.key}}Key]}`);
103
- {{~else if (eq this.scheme "basic")~}}
104
- const {{camel this.key}}Key = "{{camel this.key}}";
105
- if (this.cfg[{{camel this.key}}Key]) {
106
- const u = this.cfg[{{camel this.key}}Key].username;
107
- const p = this.cfg[{{camel this.key}}Key].password;
108
- const encoded = typeof btoa !== 'undefined' ? btoa(`${u}:${p}`) : (typeof Buffer !== 'undefined' ? Buffer.from(`${u}:${p}`).toString('base64') : '' );
109
- if (encoded) headers.set("Authorization", `Basic ${encoded}`);
58
+ {{~#if (eq this.scheme "basic")~}}
59
+ if (cfg.{{camel this.key}}) {
60
+ authStrategies.push({
61
+ type: "basic",
62
+ username: cfg.{{camel this.key}}.username,
63
+ password: cfg.{{camel this.key}}.password,
64
+ });
110
65
  }
111
66
  {{~/if~}}
112
- {{~else if (eq this.type "apiKey")~}}
67
+ {{~else if (eq this.type "apiKey")~}}
113
68
  {{~#if (eq this.in "header")~}}
114
- if (this.cfg?.{{camel this.key}})
115
- headers.set("{{this.name}}", String(this.cfg?.{{camel this.key}}));
69
+ if (cfg?.{{camel this.key}}) {
70
+ const {{camel this.key}}Value = cfg.{{camel this.key}};
71
+ authStrategies.push({
72
+ type: "apiKey",
73
+ key: () => {{camel this.key}}Value,
74
+ location: "header",
75
+ name: "{{this.name}}",
76
+ });
77
+ }
78
+ {{~else if (eq this.in "query")~}}
79
+ if (cfg?.{{camel this.key}}) {
80
+ const {{camel this.key}}Value = cfg.{{camel this.key}};
81
+ authStrategies.push({
82
+ type: "apiKey",
83
+ key: () => {{camel this.key}}Value,
84
+ location: "query",
85
+ name: "{{this.name}}",
86
+ });
87
+ }
116
88
  {{~else if (eq this.in "cookie")~}}
117
- if (this.cfg?.{{camel this.key}})
118
- headers.set("Cookie", `${"{{this.name}}"}=${String(this.cfg?.{{camel this.key}})}`);
89
+ if (cfg?.{{camel this.key}}) {
90
+ const {{camel this.key}}Value = cfg.{{camel this.key}};
91
+ authStrategies.push({
92
+ type: "apiKey",
93
+ key: () => {{camel this.key}}Value,
94
+ location: "cookie",
95
+ name: "{{this.name}}",
96
+ });
97
+ }
119
98
  {{~/if~}}
120
99
  {{~/if~}}
121
100
  {{~/each~}}
122
101
 
123
- const doFetch = async (attempt: number) => {
124
- // Clone init to prevent mutations from affecting concurrent requests
125
- // Create a new Headers object for each request to avoid sharing references
126
- const requestHeaders = new Headers(headers);
127
- const fetchInit: RequestInit & {
128
- path: string;
129
- method: string;
130
- query?: Record<string, any>;
131
- headers: Headers;
132
- } = {
133
- ...init,
134
- headers: requestHeaders,
135
- };
136
- // Set credentials from config if provided (can be overridden by onRequest)
137
- if (this.cfg.credentials !== undefined) {
138
- fetchInit.credentials = this.cfg.credentials;
139
- }
140
- if (this.cfg.onRequest) await this.cfg.onRequest({ url: url.toString(), init: fetchInit, attempt });
141
- let controller: AbortController | undefined;
142
- let timeoutId: any;
143
- const existingSignal = fetchInit.signal;
144
-
145
- if (this.cfg.timeoutMs && typeof AbortController !== 'undefined') {
146
- controller = new AbortController();
147
-
148
- // If there's an existing signal, combine it with the timeout signal
149
- // The combined controller will abort when either signal aborts
150
- if (existingSignal) {
151
- // If existing signal is already aborted, abort the new controller immediately
152
- if (existingSignal.aborted) {
153
- controller.abort();
154
- } else {
155
- // Listen to the existing signal and abort the combined controller when it aborts
156
- existingSignal.addEventListener('abort', () => {
157
- controller?.abort();
158
- });
102
+ // Extract accessToken, auth, and security scheme properties to avoid passing them to FetchClient
103
+ const {
104
+ accessToken,
105
+ auth: _existingAuth{{~#each IR.securitySchemes~}},
106
+ {{camel this.key}}{{~/each~}},
107
+ ...restCfg
108
+ } = cfg;
109
+
110
+ // Build final auth config (merge existing with new strategies)
111
+ const finalAuthStrategies = [
112
+ ...(_existingAuth?.strategies || []),
113
+ ...authStrategies,
114
+ ];
115
+
116
+ // Build fetchConfig, ensuring auth comes after restCfg spread to override any existing auth
117
+ const fetchConfig: FetchClientConfig = {
118
+ ...restCfg,
119
+ baseURL: cfg.baseURL ?? "{{Client.defaultBaseURL}}",
120
+ // Explicitly set auth after restCfg to ensure it's not overwritten
121
+ // (restCfg might have an auth property that we want to replace)
122
+ ...(finalAuthStrategies.length > 0
123
+ ? {
124
+ auth: {
125
+ strategies: finalAuthStrategies,
126
+ },
159
127
  }
160
- }
161
-
162
- fetchInit.signal = controller.signal;
163
- timeoutId = setTimeout(() => controller?.abort(), this.cfg.timeoutMs);
164
- }
165
- try {
166
- const res = await (this.cfg.fetch || fetch)(url.toString(), fetchInit);
167
- if (this.cfg.onResponse) await this.cfg.onResponse({ url: url.toString(), init: fetchInit, attempt, response: res });
168
- const ct = res.headers.get("content-type") || "";
169
- let parsed: any;
170
- if (ct.includes("application/json")) {
171
- parsed = await res.json();
172
- } else if (ct.startsWith("text/")) {
173
- parsed = await res.text();
174
- } else {
175
- // binary or unknown -> ArrayBuffer
176
- parsed = await res.arrayBuffer();
177
- }
178
- if (!res.ok) {
179
- throw new FetchError(
180
- parsed?.message || `HTTP ${res.status}`,
181
- res.status,
182
- parsed,
183
- res.headers,
184
- );
185
- }
186
- return parsed as any;
187
- } catch (err) {
188
- if (this.cfg.onError) await this.cfg.onError(err, { url: url.toString(), init, attempt });
189
- throw err;
190
- } finally {
191
- if (timeoutId) clearTimeout(timeoutId);
192
- }
128
+ : {}),
129
+ // Hooks are passed through directly from FetchClientConfig (no mapping needed)
193
130
  };
194
131
 
195
- const retries = this.cfg.retry?.retries ?? 0;
196
- const baseBackoff = this.cfg.retry?.backoffMs ?? 300;
197
- const retryOn = this.cfg.retry?.retryOn ?? [429, 500, 502, 503, 504];
132
+ super(fetchConfig);
133
+ }
198
134
 
199
- let lastError: unknown;
200
- for (let attempt = 0; attempt <= retries; attempt++) {
201
- try {
202
- return await doFetch(attempt);
203
- } catch (err: any) {
204
- // Retry on network errors or configured status errors
205
- const status = err?.status as number | undefined;
206
- const shouldRetry = status ? retryOn.includes(status) : true;
207
- if (attempt < retries && shouldRetry) {
208
- const delay = baseBackoff * Math.pow(2, attempt);
209
- await new Promise((r) => setTimeout(r, delay));
210
- lastError = err;
211
- continue;
212
- }
213
- if (err instanceof DOMException) throw err;
214
- if (err instanceof FetchError) throw err;
215
- if (typeof err === 'string') throw new FetchError(err, status ?? 0);
216
- throw new FetchError((err as Error)?.message || 'Network error', status ?? 0);
217
- }
135
+ async request(
136
+ init: RequestInit & {
137
+ path: string;
138
+ method: string;
139
+ query?: Record<string, any>;
218
140
  }
219
- throw lastError as any;
141
+ ) {
142
+ return await super.request(init);
220
143
  }
221
144
 
222
145
  async *requestStream<T = any>(
@@ -228,153 +151,6 @@ export class CoreClient {
228
151
  streamingFormat?: "sse" | "ndjson" | "chunked";
229
152
  }
230
153
  ): AsyncGenerator<T, void, unknown> {
231
- let normalizedPath = init.path || "";
232
- if (normalizedPath.length > 1 && normalizedPath.endsWith('/')) {
233
- normalizedPath = normalizedPath.slice(0, -1);
234
- }
235
- const url = new URL((this.cfg.baseURL || "") + normalizedPath);
236
- if (init.query) {
237
- Object.entries(init.query).forEach(([k, v]) => {
238
- if (v === undefined || v === null) return;
239
- if (Array.isArray(v))
240
- v.forEach((vv) => url.searchParams.append(k, String(vv)));
241
- else url.searchParams.set(k, String(v));
242
- });
243
- }
244
- {{~#each IR.securitySchemes~}}
245
- {{~#if (and (eq this.type "apiKey") (eq this.in "query"))~}}
246
- if (this.cfg.{{camel this.key}}) {
247
- url.searchParams.set("{{this.name}}", String(this.cfg.{{camel this.key}}));
248
- }
249
- {{~/if~}}
250
- {{~/each~}}
251
- const headers = new Headers({
252
- ...(this.cfg.headers || {}),
253
- ...(init.headers as any),
254
- });
255
- // Generic access token support (optional)
256
- if (this.cfg.accessToken) {
257
- const token = typeof this.cfg.accessToken === 'function' ? await this.cfg.accessToken() : this.cfg.accessToken;
258
- // Only set header if token is not nullish
259
- if (token != null) {
260
- const name = this.cfg.headerName || 'Authorization';
261
- if (name.toLowerCase() === 'authorization') headers.set(name, `Bearer ${String(token)}`);
262
- else headers.set(name, String(token));
263
- }
264
- }
265
- {{~#each IR.securitySchemes~}}
266
- {{~#if (eq this.type "http")~}}
267
- {{~#if (eq this.scheme "bearer")~}}
268
- const {{camel this.key}}Key = "{{camel this.key}}";
269
- if (this.cfg[{{camel this.key}}Key])
270
- headers.set("Authorization", `Bearer ${this.cfg[{{camel this.key}}Key]}`);
271
- {{~else if (eq this.scheme "basic")~}}
272
- const {{camel this.key}}Key = "{{camel this.key}}";
273
- if (this.cfg[{{camel this.key}}Key]) {
274
- const u = this.cfg[{{camel this.key}}Key].username;
275
- const p = this.cfg[{{camel this.key}}Key].password;
276
- const encoded = typeof btoa !== 'undefined' ? btoa(`${u}:${p}`) : (typeof Buffer !== 'undefined' ? Buffer.from(`${u}:${p}`).toString('base64') : '' );
277
- if (encoded) headers.set("Authorization", `Basic ${encoded}`);
278
- }
279
- {{~/if~}}
280
- {{~else if (eq this.type "apiKey")~}}
281
- {{~#if (eq this.in "header")~}}
282
- if (this.cfg?.{{camel this.key}})
283
- headers.set("{{this.name}}", String(this.cfg?.{{camel this.key}}));
284
- {{~else if (eq this.in "cookie")~}}
285
- if (this.cfg?.{{camel this.key}})
286
- headers.set("Cookie", `${"{{this.name}}"}=${String(this.cfg?.{{camel this.key}})}`);
287
- {{~/if~}}
288
- {{~/if~}}
289
- {{~/each~}}
290
-
291
- const fetchInit: RequestInit & {
292
- path: string;
293
- method: string;
294
- query?: Record<string, any>;
295
- headers: Headers;
296
- } = {
297
- ...init,
298
- headers,
299
- };
300
- // Set credentials from config if provided
301
- if (this.cfg.credentials !== undefined) {
302
- fetchInit.credentials = this.cfg.credentials;
303
- }
304
-
305
- if (this.cfg.onRequest) await this.cfg.onRequest({ url: url.toString(), init: fetchInit, attempt: 0 });
306
-
307
- let controller: AbortController | undefined;
308
- let timeoutId: any;
309
- const existingSignal = fetchInit.signal;
310
-
311
- if (this.cfg.timeoutMs && typeof AbortController !== 'undefined') {
312
- controller = new AbortController();
313
- if (existingSignal) {
314
- if (existingSignal.aborted) {
315
- controller.abort();
316
- } else {
317
- existingSignal.addEventListener('abort', () => {
318
- controller?.abort();
319
- });
320
- }
321
- }
322
- fetchInit.signal = controller.signal;
323
- timeoutId = setTimeout(() => controller?.abort(), this.cfg.timeoutMs);
324
- }
325
-
326
- try {
327
- const res = await (this.cfg.fetch || fetch)(url.toString(), fetchInit);
328
- if (this.cfg.onResponse) await this.cfg.onResponse({ url: url.toString(), init: fetchInit, attempt: 0, response: res });
329
-
330
- if (!res.ok) {
331
- const ct = res.headers.get("content-type") || "";
332
- let parsed: any;
333
- if (ct.includes("application/json")) {
334
- parsed = await res.json();
335
- } else if (ct.startsWith("text/")) {
336
- parsed = await res.text();
337
- } else {
338
- parsed = await res.arrayBuffer();
339
- }
340
- throw new FetchError(
341
- parsed?.message || `HTTP ${res.status}`,
342
- res.status,
343
- parsed,
344
- res.headers,
345
- );
346
- }
347
-
348
- // Import streaming parsers
349
- const { parseSSEStream, parseNDJSONStream } = await import("./utils");
350
-
351
- // Route to appropriate parser based on streaming format
352
- if (init.streamingFormat === "sse") {
353
- yield* parseSSEStream(res) as AsyncGenerator<T, void, unknown>;
354
- } else if (init.streamingFormat === "ndjson") {
355
- yield* parseNDJSONStream<T>(res);
356
- } else {
357
- // Generic chunked streaming - yield raw chunks as strings
358
- if (!res.body) return;
359
- const reader = res.body.getReader();
360
- const decoder = new TextDecoder();
361
- try {
362
- while (true) {
363
- const { done, value } = await reader.read();
364
- if (done) break;
365
- const chunk = decoder.decode(value, { stream: true });
366
- yield chunk as T;
367
- }
368
- } finally {
369
- reader.releaseLock();
370
- }
371
- }
372
- } catch (err) {
373
- if (this.cfg.onError) await this.cfg.onError(err, { url: url.toString(), init, attempt: 0 });
374
- throw err;
375
- } finally {
376
- if (timeoutId) clearTimeout(timeoutId);
377
- }
154
+ yield* super.requestStream(init);
378
155
  }
379
156
  }
380
- {{~/if~}}
@@ -54,8 +54,10 @@ export class {{Client.name}} {
54
54
 
55
55
  export type { ClientOption };
56
56
 
57
- // Export FetchError for error handling
58
- export { FetchError };
57
+ // Export FetchError and CoreClient for error handling and advanced usage
58
+ export { FetchError, CoreClient };
59
+ // Re-export all error types from @blimu/fetch for instanceof checks
60
+ export * from "@blimu/fetch";
59
61
  export const {{Client.name}}Error = FetchError;
60
62
 
61
63
  // Re-exports for better ergonomics
@@ -3,37 +3,43 @@
3
3
  "version": "0.1.0",
4
4
  "description": "TypeScript SDK for {{Client.name}} API (auto-generated)",
5
5
  "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
6
7
  "types": "dist/index.d.ts",
7
- "files": ["dist/**"],
8
+ "files": ["dist/**", "src/**"],
8
9
  "exports": {
9
10
  ".": {
10
11
  "types": "./dist/index.d.ts",
11
12
  "import": "./dist/index.mjs",
12
- "require": "./dist/index.js"
13
+ "require": "./dist/index.js",
14
+ "default": "./dist/index.js"
13
15
  },
14
16
  "./services/*": {
15
17
  "types": "./dist/services/*.d.ts",
16
18
  "import": "./dist/services/*.mjs",
17
- "require": "./dist/services/*.js"
19
+ "require": "./dist/services/*.js",
20
+ "default": "./dist/services/*.js"
18
21
  },
19
22
  "./schema": {
20
23
  "types": "./dist/schema.d.ts",
21
24
  "import": "./dist/schema.mjs",
22
- "require": "./dist/schema.js"
25
+ "require": "./dist/schema.js",
26
+ "default": "./dist/schema.js"
23
27
  },
24
28
  "./client": {
25
29
  "types": "./dist/client.d.ts",
26
30
  "import": "./dist/client.mjs",
27
- "require": "./dist/client.js"
31
+ "require": "./dist/client.js",
32
+ "default": "./dist/client.js"
28
33
  },
29
34
  "./utils": {
30
35
  "types": "./dist/utils.d.ts",
31
36
  "import": "./dist/utils.mjs",
32
- "require": "./dist/utils.js"
37
+ "require": "./dist/utils.js",
38
+ "default": "./dist/utils.js"
33
39
  }
34
40
  },
35
41
  "scripts": {
36
- "build": "tsup src/index.ts src/services/*.ts src/schema.ts src/schema.zod.ts src/client.ts src/utils.ts --format cjs,esm --dts",
42
+ "build": "tsup src/index.ts src/services/*.ts src/schema.ts src/schema.zod.ts src/client.ts src/utils.ts --format cjs,esm --dts --no-splitting",
37
43
  "typecheck": "tsc -p tsconfig.json --noEmit",
38
44
  "lint": "eslint .",
39
45
  "format": "eslint --fix . && prettier --write .",
@@ -1,14 +1,14 @@
1
- // Generated Zod schemas from OpenAPI components.schemas
1
+ // Generated zod schemas from OpenAPI components.schemas
2
2
  // Use these schemas for runtime validation in forms, API requests, etc.
3
3
 
4
- import { z } from "zod";
5
- import * as Schema from "./schema";
4
+ import { z } from 'zod';
5
+ import * as Schema from './schema';
6
6
 
7
7
  {{! Simple types: generate as regular Zod schema exports (not in namespace) }}
8
8
  {{#each IR.modelDefs}}
9
9
  {{#if (or (eq this.schema.kind "string") (eq this.schema.kind "number") (eq this.schema.kind "integer") (eq this.schema.kind "boolean") (eq this.schema.kind "null"))}}
10
10
  /**
11
- * Zod schema for {{this.name}}
11
+ * Schema for {{this.name}}
12
12
  {{#if this.annotations.description}}
13
13
  * {{decodeHtml (replace this.annotations.description "*/" "*\\/")}}
14
14
  {{/if}}
@@ -89,7 +89,7 @@ export const {{this.name}}Schema = z.union([
89
89
  * {{decodeHtml (replace this.annotations.description "*/" "*\\/")}}
90
90
  {{~/if~}}
91
91
  */
92
- export const {{this.name}}Schema = {{#each this.schema.allOf}}{{#if @first}}{{zodSchema this}}{{else}}.and({{zodSchema this}}){{/if}}{{/each}};
92
+ export const {{this.name}}Schema = {{#each this.schema.allOf}}{{#if @first}}{{zodSchema this}}{{else}}.extend({{zodSchema this}}.shape){{/if}}{{/each}};
93
93
 
94
94
  {{~else if (eq this.schema.kind "array")~}}
95
95
  /**
@@ -116,13 +116,13 @@ export const {{this.name}}Schema = {{zodSchema this.schema}};
116
116
 
117
117
  {{#if IR.services}}
118
118
 
119
- // Operation query parameter Zod schemas
119
+ // Operation query parameter schemas
120
120
 
121
121
  {{#each IR.services}}
122
122
  {{#each this.operations}}
123
123
  {{#if (gt (len this.queryParams) 0)}}
124
124
  /**
125
- * Zod schema for query params of {{../tag}}.{{pascal (methodName this)}}
125
+ * Schema for query params of {{../tag}}.{{pascal (methodName this)}}
126
126
  {{~#if this.description~}}
127
127
  * {{decodeHtml (replace this.description "*/" "*\\/")}}
128
128
  {{~/if~}}