@icib.dev/api-client 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -25,7 +25,7 @@ setAuthToken(process.env.API_TOKEN);
25
25
  const res = await apiClient.allegati.list({ page: 1, size: 10 });
26
26
  ```
27
27
 
28
- 3. Add verify to your build (fails if docs changed or client was modified):
28
+ 3. Add verify to your build (ensures version alignment for production; fails if docs changed or client was modified):
29
29
 
30
30
  ```json
31
31
  {
@@ -90,7 +90,9 @@ api/
90
90
 
91
91
  ### Hash verification
92
92
 
93
- Add `api-client-verify` before your build to ensure the generated client matches the current OpenAPI docs. When you run your build, it:
93
+ Add `api-client-verify` before your build to ensure the generated client matches the current OpenAPI docs. You can insert it in the build step of your utilization library (the app or library that consumes the API client) to verify version alignment before production builds—if the API docs changed or the client was modified, the build fails and you must regenerate.
94
+
95
+ When you run your build, it:
94
96
 
95
97
  1. Reads the manifest (created by `generate`)
96
98
  2. Fetches the current docs and compares their hash
@@ -92,6 +92,46 @@ function getDefinitions(doc) {
92
92
  function getPaths(doc) {
93
93
  return doc.paths ?? {};
94
94
  }
95
+ /**
96
+ * Extract response schema. Compatible with:
97
+ * - OpenAPI 2.0: response.schema
98
+ * - OpenAPI 3.0: response.content['application/json'].schema
99
+ */
100
+ function getResponseSchema(response) {
101
+ if (!response || typeof response !== "object")
102
+ return undefined;
103
+ const r = response;
104
+ // OpenAPI 2.0: schema directly on response
105
+ if (r.schema && typeof r.schema === "object") {
106
+ return r.schema;
107
+ }
108
+ // OpenAPI 3.0: schema under content['application/json'] or content['*/*']
109
+ const content = r.content;
110
+ if (content) {
111
+ const jsonContent = content["application/json"] ??
112
+ content["*/*"] ??
113
+ Object.values(content)[0];
114
+ return jsonContent?.schema;
115
+ }
116
+ return undefined;
117
+ }
118
+ /**
119
+ * Extract request body schema from OpenAPI 3.0 requestBody.content.
120
+ * OpenAPI 2.0 uses parameters with in: "body" (handled separately in extractOperations).
121
+ */
122
+ function getRequestBodySchema(requestBody) {
123
+ if (!requestBody || typeof requestBody !== "object")
124
+ return undefined;
125
+ const rb = requestBody;
126
+ const content = rb.content;
127
+ if (content) {
128
+ const jsonContent = content["application/json"] ??
129
+ content["*/*"] ??
130
+ Object.values(content)[0];
131
+ return jsonContent?.schema;
132
+ }
133
+ return undefined;
134
+ }
95
135
  function schemaToTsType(schema, definitions, refsSeen = new Set()) {
96
136
  if (!schema)
97
137
  return "unknown";
@@ -250,8 +290,31 @@ function extractOperations(paths, definitions) {
250
290
  };
251
291
  }
252
292
  }
293
+ // OpenAPI 3.0: body in requestBody (OAS 2.0 uses parameters in: "body" above)
294
+ if (!bodyParam && op.requestBody) {
295
+ const bodySchema = getRequestBodySchema(op.requestBody);
296
+ if (bodySchema) {
297
+ const propertyDescriptions = {};
298
+ if (bodySchema.properties) {
299
+ for (const [propName, propSchema] of Object.entries(bodySchema.properties)) {
300
+ const desc = propSchema
301
+ .description ??
302
+ propSchema.title;
303
+ if (desc)
304
+ propertyDescriptions[propName] = desc;
305
+ }
306
+ }
307
+ bodyParam = {
308
+ name: "data",
309
+ schema: bodySchema,
310
+ propertyDescriptions: Object.keys(propertyDescriptions).length > 0
311
+ ? propertyDescriptions
312
+ : undefined,
313
+ };
314
+ }
315
+ }
253
316
  const successResponse = op.responses?.["200"] ?? op.responses?.["201"];
254
- const respSchema = successResponse?.schema;
317
+ const respSchema = getResponseSchema(successResponse);
255
318
  const respDesc = successResponse?.description ?? "";
256
319
  const xResponseType = successResponse?.["x-response-type"];
257
320
  let responseType = "unknown";
@@ -536,12 +599,23 @@ function generateContextFile(tag, operations, definitions, tagDescription) {
536
599
  }
537
600
  function generateClient(baseUrl) {
538
601
  return `// Auto-generated Axios client
539
- import axios, { type AxiosInstance } from "axios";
602
+ import axios, { type AxiosInstance, AxiosError } from "axios";
540
603
 
541
604
  let _token: string | null = null;
542
605
 
543
- export function setAuthToken(token: string | null): void {
606
+ export function setAuthToken(token: string | null, callback?: (token: string | null) => void): void {
544
607
  _token = token;
608
+ if (callback) callback(token);
609
+ // insert your own logic here, e.g. save to localStorage, sessionStorage, etc.
610
+ }
611
+
612
+ export function getAuthToken(): string | null {
613
+ return _token;
614
+ }
615
+
616
+ export function clearAuthToken(): void {
617
+ _token = null;
618
+ // insert your own logic here
545
619
  }
546
620
 
547
621
  export const client: AxiosInstance = axios.create({
@@ -558,6 +632,21 @@ client.interceptors.request.use((config) => {
558
632
  return config;
559
633
  });
560
634
 
635
+ client.interceptors.response.use(
636
+ (response) => {
637
+ if (response.status === 401) {
638
+ clearAuthToken();
639
+ }
640
+ return response.data;
641
+ },
642
+ (error) => {
643
+ if (error.response.status === 401) {
644
+ clearAuthToken();
645
+ }
646
+ return AxiosError.from(error);
647
+ },
648
+ );
649
+
561
650
  /** Options for blob/download endpoints */
562
651
  export interface BlobDownloadOptions {
563
652
  /** When true, triggers a file download in the browser */
@@ -631,7 +720,7 @@ function generateIndex(contextTags) {
631
720
  return exports.join("\n");
632
721
  }
633
722
  async function main() {
634
- const { url, out, basePath: basePathOverride, baseUrl: baseUrlOverride } = parseArgs();
723
+ const { url, out, basePath: basePathOverride, baseUrl: baseUrlOverride, } = parseArgs();
635
724
  console.log(`Fetching spec from ${url}...`);
636
725
  const rawSpec = await loadRawSpec(url);
637
726
  const doc = await parseSpec(rawSpec);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@icib.dev/api-client",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Generator for strictly-typed TypeScript API clients from OpenAPI specs",
5
5
  "type": "module",
6
6
  "bin": {