openapi-sync 2.1.6 → 2.1.8

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
@@ -1,138 +1,868 @@
1
- # Openapi-sync
2
-
3
1
  [![NPM Version](https://img.shields.io/npm/v/openapi-sync.svg)](https://www.npmjs.com/package/openapi-sync)
4
2
  [![License](https://img.shields.io/npm/l/openapi-sync.svg)](https://github.com/akintomiwa-fisayo/openapi-sync/blob/main/LICENSE)
5
3
 
6
- **Openapi-sync** is a powerful developer tool that automates the synchronization of your API documentation with your codebase using OpenAPI (formerly Swagger) specifications. It generates TypeScript types and endpoint definitions from your OpenAPI schema, ensuring your API documentation stays up-to-date with your code.
4
+ **OpenAPI Sync** is a powerful developer tool that automates the synchronization of your API documentation with your codebase using OpenAPI (formerly Swagger) specifications. It generates TypeScript types, endpoint definitions, and comprehensive documentation from your OpenAPI schema, ensuring your API documentation stays up-to-date with your code.
5
+
6
+ ## Table of Contents
7
+
8
+ - [Features](#features)
9
+ - [Installation](#installation)
10
+ - [Quick Start](#quick-start)
11
+ - [Configuration](#configuration)
12
+ - [Usage](#usage)
13
+ - [Generated Output](#generated-output)
14
+ - [API Reference](#api-reference)
15
+ - [Advanced Examples](#advanced-examples)
16
+ - [Troubleshooting](#troubleshooting)
7
17
 
8
18
  ## Features
9
19
 
10
- - 🔄 Real-time API Synchronization
11
- - 📝 Automatic Type Generation
12
- - 🔄 Periodic API Refetching
13
- - 📁 Configurable Output Directory
14
- - 🔄 Customizable Naming Conventions
15
- - 🔄 Endpoint URL Transformation
16
- - 🔄 Schema Validation
17
- - 🔄 CLI Integration
18
- - 🔄 TypeScript Support
19
- - 🔄 YAML and JSON Support
20
+ ### 🔄 **Real-time API Synchronization**
21
+
22
+ - Automatically fetches and syncs OpenAPI specifications from remote URLs
23
+ - Supports both JSON and YAML formats
24
+ - Configurable refetch intervals for development environments
25
+ - Smart caching to avoid unnecessary regeneration
26
+
27
+ ### 📝 **Automatic Type Generation**
28
+
29
+ - Generates TypeScript interfaces for all API endpoints
30
+ - Creates type definitions for request/response bodies
31
+ - Supports complex nested objects, arrays, and unions
32
+ - Handles nullable types and optional properties
33
+ - Generates shared component types from OpenAPI components
34
+
35
+ ### 🔧 **Highly Configurable**
36
+
37
+ - Customizable naming conventions for types and endpoints
38
+ - Flexible output directory structure
39
+ - URL transformation and text replacement rules
40
+ - Configurable documentation generation
41
+ - Support for multiple API specifications
42
+
43
+ ### 🛡️ **Enterprise Ready**
44
+
45
+ - Network error handling with exponential backoff retry
46
+ - Schema validation using Redocly OpenAPI Core
47
+ - State persistence to track changes
48
+ - Environment-aware (disables auto-sync in production)
49
+ - TypeScript support with full type safety
50
+
51
+ ### 📚 **Rich Documentation**
52
+
53
+ - Generates comprehensive JSDoc comments
54
+ - Includes cURL examples for each endpoint
55
+ - Security scheme documentation
56
+ - Request/response type documentation
57
+ - Markdown-formatted type references
20
58
 
21
59
  ## Installation
22
60
 
23
- Install the package using npm:
61
+ ### NPM Package
24
62
 
25
63
  ```bash
26
64
  npm install openapi-sync
27
65
  ```
28
66
 
29
- Or use it directly via npx:
67
+ ### Global Installation
68
+
69
+ ```bash
70
+ npm install -g openapi-sync
71
+ ```
72
+
73
+ ### Direct Usage (No Installation)
74
+
75
+ ```bash
76
+ npx openapi-sync
77
+ ```
78
+
79
+ ## Quick Start
80
+
81
+ 1. **Create a configuration file** in your project root:
82
+
83
+ ```json
84
+ // openapi.sync.json
85
+ {
86
+ "refetchInterval": 5000,
87
+ "folder": "./src/api",
88
+ "api": {
89
+ "petstore": "https://petstore3.swagger.io/api/v3/openapi.json"
90
+ }
91
+ }
92
+ ```
93
+
94
+ 2. **Run the sync command**:
30
95
 
31
96
  ```bash
32
97
  npx openapi-sync
33
98
  ```
34
99
 
100
+ 3. **Use the generated types and endpoints**:
101
+
102
+ ```typescript
103
+ import { getPetById } from "./src/api/petstore/endpoints";
104
+ import { IPet, IGetPetByIdResponse } from "./src/api/petstore/types";
105
+
106
+ // Use the endpoint URL
107
+ const petUrl = getPetById("123"); // Returns: "/pet/123"
108
+
109
+ // Use the generated types
110
+ const pet: IPet = {
111
+ id: 1,
112
+ name: "Fluffy",
113
+ status: "available",
114
+ };
115
+ ```
116
+
35
117
  ## Configuration
36
118
 
37
- Create a `openapi.sync.json` file in your project root with the following structure:
119
+ OpenAPI Sync supports multiple configuration file formats:
120
+
121
+ - `openapi.sync.json` (JSON format)
122
+ - `openapi.sync.ts` (TypeScript format)
123
+ - `openapi.sync.js` (JavaScript format)
124
+
125
+ ### Basic Configuration
38
126
 
39
127
  ```json
40
128
  {
41
- "refetchInterval": 5000, // milliseconds between API refetches
42
- "folder": "/path/to/output", // output directory for generated files
129
+ "refetchInterval": 5000,
130
+ "folder": "./src/api",
43
131
  "api": {
44
- "example1": "https://api.example.com/openapi.json",
45
- "example2": "https://api.example.com/openapi.yaml"
132
+ "petstore": "https://petstore3.swagger.io/api/v3/openapi.json",
133
+ "jsonplaceholder": "https://jsonplaceholder.typicode.com/openapi.yaml"
46
134
  },
47
- "naming": {
48
- "replaceWords": [
49
- {
50
- "replace": "Api",
51
- "with": "",
52
- "type": "endpoint"
53
- }
54
- ]
135
+ "server": 0
136
+ }
137
+ ```
138
+
139
+ ### Advanced Configuration
140
+
141
+ ```typescript
142
+ // openapi.sync.ts
143
+ import { IConfig } from "openapi-sync/types";
144
+
145
+ const config: IConfig = {
146
+ refetchInterval: 10000,
147
+ folder: "./src/generated/api",
148
+ api: {
149
+ "main-api": "https://api.example.com/openapi.json",
150
+ "auth-api": "https://auth.example.com/openapi.yaml",
55
151
  },
56
- "endpoints": {
57
- "value": {
58
- "replaceWords": [
59
- {
60
- "replace": "/api/v\\d/",
61
- "with": ""
152
+ server: "https://api.example.com", // Override server URL
153
+
154
+ // Type generation configuration
155
+ types: {
156
+ name: {
157
+ prefix: "I", // Prefix for interface names
158
+ format: (source, data, defaultName) => {
159
+ if (source === "shared") {
160
+ return `${data.name}Type`;
161
+ } else if (source === "endpoint") {
162
+ return `${data.method?.toUpperCase()}${data.path?.replace(
163
+ /\//g,
164
+ "_"
165
+ )}${data.type}`;
62
166
  }
63
- ]
64
- }
65
- }
66
- }
167
+ return defaultName;
168
+ },
169
+ },
170
+ doc: {
171
+ disable: false, // Enable/disable JSDoc generation
172
+ },
173
+ },
174
+
175
+ // Endpoint generation configuration
176
+ endpoints: {
177
+ value: {
178
+ replaceWords: [
179
+ {
180
+ replace: "/api/v\\d+/", // Remove version from URLs
181
+ with: "/",
182
+ },
183
+ {
184
+ replace: "/internal/",
185
+ with: "/",
186
+ type: "endpoint",
187
+ },
188
+ ],
189
+ includeServer: true, // Include server URL in endpoints
190
+ type: "object", // Generate as objects instead of strings
191
+ },
192
+ name: {
193
+ prefix: "API_",
194
+ useOperationId: true, // Use operationId from OpenAPI spec
195
+ format: ({ method, path, summary, operationId }, defaultName) => {
196
+ if (operationId) return operationId;
197
+ return path.replace(/\//g, "_").replace(/{|}/g, "");
198
+ },
199
+ },
200
+ doc: {
201
+ disable: false,
202
+ showCurl: true, // Include cURL examples in documentation
203
+ },
204
+ },
205
+ };
206
+
207
+ export default config;
67
208
  ```
68
209
 
210
+ ### Configuration Options Reference
211
+
212
+ #### Root Configuration
213
+
214
+ | Property | Type | Description | Default |
215
+ | ----------------- | ------------------------ | --------------------------------------------- | -------- |
216
+ | `refetchInterval` | `number` | Milliseconds between API refetches (dev only) | - |
217
+ | `folder` | `string` | Output directory for generated files | `""` |
218
+ | `api` | `Record<string, string>` | Map of API names to OpenAPI spec URLs | Required |
219
+ | `server` | `number \| string` | Server index or custom server URL | `0` |
220
+
221
+ #### Type Configuration (`types`)
222
+
223
+ | Property | Type | Description |
224
+ | ------------- | ---------- | ---------------------------------- |
225
+ | `name.prefix` | `string` | Prefix for generated type names |
226
+ | `name.format` | `function` | Custom naming function for types |
227
+ | `doc.disable` | `boolean` | Disable JSDoc generation for types |
228
+
229
+ #### Endpoint Configuration (`endpoints`)
230
+
231
+ | Property | Type | Description |
232
+ | --------------------- | ---------------------- | -------------------------------------- |
233
+ | `value.replaceWords` | `IConfigReplaceWord[]` | URL transformation rules |
234
+ | `value.includeServer` | `boolean` | Include server URL in endpoints |
235
+ | `value.type` | `"string" \| "object"` | Output format for endpoints |
236
+ | `name.prefix` | `string` | Prefix for endpoint names |
237
+ | `name.useOperationId` | `boolean` | Use OpenAPI operationId for naming |
238
+ | `name.format` | `function` | Custom naming function for endpoints |
239
+ | `doc.disable` | `boolean` | Disable JSDoc generation for endpoints |
240
+ | `doc.showCurl` | `boolean` | Include cURL examples in documentation |
241
+
69
242
  ## Usage
70
243
 
71
- ### CLI Commands
244
+ ### CLI Usage
245
+
246
+ #### Basic Commands
72
247
 
73
248
  ```bash
74
- # Basic usage
249
+ # Run with default configuration
75
250
  npx openapi-sync
76
251
 
77
- # With custom refetch interval
252
+ # Run with custom refetch interval
78
253
  npx openapi-sync --refreshinterval 30000
254
+ npx openapi-sync -ri 30000
255
+
256
+ # Get help
257
+ npx openapi-sync --help
79
258
  ```
80
259
 
260
+ #### CLI Options
261
+
262
+ | Option | Alias | Type | Description |
263
+ | ------------------- | ----- | -------- | ------------------------------------- |
264
+ | `--refreshinterval` | `-ri` | `number` | Override refetch interval from config |
265
+
81
266
  ### Programmatic Usage
82
267
 
268
+ #### Basic Usage
269
+
83
270
  ```typescript
84
271
  import { Init } from "openapi-sync";
85
272
 
273
+ // Initialize with default config
274
+ await Init();
275
+
86
276
  // Initialize with custom options
87
277
  await Init({
88
- refetchInterval: 30000, // optional, defaults to config value
278
+ refetchInterval: 30000,
89
279
  });
90
280
  ```
91
281
 
92
- ## Output Generation
282
+ #### Advanced Integration
283
+
284
+ ```typescript
285
+ import { Init } from "openapi-sync";
286
+
287
+ // In your application startup
288
+ export const initializeAPI = async () => {
289
+ try {
290
+ await Init({
291
+ refetchInterval: process.env.NODE_ENV === "development" ? 5000 : 0,
292
+ });
293
+ console.log("API types synchronized successfully");
294
+ } catch (error) {
295
+ console.error("Failed to sync API types:", error);
296
+ throw error;
297
+ }
298
+ };
299
+
300
+ // Call during app initialization
301
+ initializeAPI();
302
+ ```
303
+
304
+ #### Function-based Configuration
93
305
 
94
- The tool generates:
306
+ ```typescript
307
+ // openapi.sync.ts
308
+ import { IConfig } from "openapi-sync/types";
309
+
310
+ export default (): IConfig => {
311
+ const baseConfig = {
312
+ refetchInterval: 5000,
313
+ folder: "./src/api",
314
+ api: {},
315
+ };
316
+
317
+ // Dynamic configuration based on environment
318
+ if (process.env.NODE_ENV === "development") {
319
+ baseConfig.api = {
320
+ "local-api": "http://localhost:3000/openapi.json",
321
+ };
322
+ } else {
323
+ baseConfig.api = {
324
+ "prod-api": "https://api.production.com/openapi.json",
325
+ };
326
+ }
95
327
 
96
- 1. TypeScript interfaces for API endpoints
97
- 2. Type definitions for request/response bodies
98
- 3. Shared component types
99
- 4. Endpoint URL constants
328
+ return baseConfig;
329
+ };
330
+ ```
100
331
 
101
- ## Type Generation
332
+ ## Generated Output
102
333
 
103
- The tool supports:
334
+ OpenAPI Sync generates a structured output in your specified folder:
104
335
 
105
- - Primitive types (string, number, boolean, etc.)
106
- - Complex types (objects, arrays)
107
- - Enums
108
- - Nullable types
109
- - Any types
110
- - Shared components
111
- - Request/response bodies
336
+ ```
337
+ src/api/
338
+ ├── petstore/
339
+ │ ├── endpoints.ts # Endpoint URLs and metadata
340
+ │ └── types/
341
+ │ ├── index.ts # Endpoint-specific types
342
+ │ └── shared.ts # Shared component types
343
+ └── auth-api/
344
+ ├── endpoints.ts
345
+ └── types/
346
+ ├── index.ts
347
+ └── shared.ts
348
+ ```
112
349
 
113
- ## Error Handling
350
+ ### Generated Endpoints
351
+
352
+ When `endpoints.value.type` is set to `"string"`
353
+
354
+ #### String Format (Default)
355
+
356
+ ````typescript
357
+ // endpoints.ts
358
+ /**
359
+ * **Method**: `GET`
360
+ * **Summary**: Find pet by ID
361
+ * **Tags**: [pet]
362
+ * **OperationId**: getPetById
363
+ * **Response**:
364
+ * - **200**:
365
+ * ```typescript
366
+ * {
367
+ * "id": number;
368
+ * "name": string;
369
+ * "status": ("available"|"pending"|"sold");
370
+ * }
371
+ * ```
372
+ *
373
+ * ```bash
374
+ * curl -X GET "https://petstore3.swagger.io/api/v3/pet/123" \
375
+ * -H "accept: application/json"
376
+ * ```
377
+ */
378
+ export const getPetById = (petId: string) => `/pet/${petId}`;
379
+
380
+ /**
381
+ * **Method**: `POST`
382
+ * **Summary**: Add a new pet to the store
383
+ */
384
+ export const addPet = "/pet";
385
+ ````
386
+
387
+ #### Object Format
388
+
389
+ When `endpoints.value.type` is set to `"object"`, each endpoint is generated as an object containing metadata:
390
+
391
+ ````typescript
392
+ // endpoints.ts (with type: "object")
393
+ /**
394
+ * **Method**: `POST`
395
+ * **Summary**: Add a new pet to the store
396
+ * **Tags**: [pet]
397
+ * **DTO**:
398
+ * ```typescript
399
+ * {
400
+ * "name": string;
401
+ * "photoUrls": string[];
402
+ * "status": ("available"|"pending"|"sold");
403
+ * }
404
+ * ```
405
+ */
406
+ export const addPet = {
407
+ method: "POST",
408
+ operationId: "addPet",
409
+ url: "/pet",
410
+ tags: ["pet"],
411
+ };
412
+
413
+ export const getPetById = {
414
+ method: "GET",
415
+ operationId: "getPetById",
416
+ url: (petId: string) => `/pet/${petId}`,
417
+ tags: ["pet"],
418
+ };
419
+ ````
420
+
421
+ ### Generated Types
422
+
423
+ #### Endpoint Types
114
424
 
115
- The tool includes:
425
+ ```typescript
426
+ // types/index.ts
427
+ import * as Shared from "./shared";
428
+
429
+ // Query parameter types
430
+ export type IFindPetsByStatusQuery = {
431
+ status?: "available" | "pending" | "sold";
432
+ };
433
+
434
+ // Request body types (DTO)
435
+ export type IAddPetDTO = {
436
+ id?: number;
437
+ name: string;
438
+ category?: Shared.ICategory;
439
+ photoUrls: string[];
440
+ tags?: Shared.ITag[];
441
+ status?: "available" | "pending" | "sold";
442
+ };
443
+
444
+ // Response types
445
+ export type IGetPetById200Response = {
446
+ id?: number;
447
+ name: string;
448
+ category?: Shared.ICategory;
449
+ photoUrls: string[];
450
+ tags?: Shared.ITag[];
451
+ status?: "available" | "pending" | "sold";
452
+ };
453
+ ```
116
454
 
117
- - Network error retries
118
- - Schema validation
119
- - Type generation error handling
120
- - State persistence
455
+ #### Shared Component Types
121
456
 
122
- ## API Documentation
457
+ ```typescript
458
+ // types/shared.ts
459
+ /**
460
+ * A category for a pet
461
+ */
462
+ export type ICategory = {
463
+ id?: number;
464
+ name?: string;
465
+ };
466
+
467
+ /**
468
+ * A tag for a pet
469
+ */
470
+ export type ITag = {
471
+ id?: number;
472
+ name?: string;
473
+ };
474
+
475
+ export type IPet = {
476
+ id?: number;
477
+ name: string;
478
+ category?: ICategory;
479
+ photoUrls: string[];
480
+ tags?: ITag[];
481
+ status?: "available" | "pending" | "sold";
482
+ };
483
+ ```
123
484
 
124
- For detailed API documentation, please refer to the [OpenAPI specification](https://spec.openapis.org/oas/v3.0.3).
485
+ ## API Reference
125
486
 
126
- ## License
487
+ ### Exported Functions
127
488
 
128
- This project is licensed under the ISC License - see the [LICENSE](LICENSE) file for details.
489
+ #### `Init(options?: { refetchInterval?: number }): Promise<void>`
129
490
 
130
- ## Support
491
+ Initializes OpenAPI sync with the specified configuration.
492
+
493
+ **Parameters:**
494
+
495
+ - `options.refetchInterval` - Override the refetch interval from config file
496
+
497
+ **Example:**
498
+
499
+ ```typescript
500
+ import { Init } from "openapi-sync";
501
+
502
+ await Init({ refetchInterval: 10000 });
503
+ ```
504
+
505
+ ### Exported Types
506
+
507
+ All types from the `types.ts` file are available for import:
508
+
509
+ ```typescript
510
+ import {
511
+ IConfig,
512
+ IOpenApiSpec,
513
+ IOpenApSchemaSpec,
514
+ IConfigReplaceWord,
515
+ } from "openapi-sync/types";
516
+ ```
517
+
518
+ ## Advanced Examples
519
+
520
+ ### Multi-Environment Configuration
521
+
522
+ ```typescript
523
+ // openapi.sync.ts
524
+ import { IConfig } from "openapi-sync/types";
525
+
526
+ const getConfig = (): IConfig => {
527
+ const env = process.env.NODE_ENV || "development";
528
+
529
+ const baseConfig: IConfig = {
530
+ refetchInterval: env === "development" ? 5000 : 0,
531
+ folder: "./src/api",
532
+ api: {},
533
+ types: {
534
+ name: {
535
+ prefix: "I",
536
+ format: (source, data, defaultName) => {
537
+ if (source === "endpoint" && data.type === "response") {
538
+ return `${defaultName.replace(/Response$/, "")}Data`;
539
+ }
540
+ return defaultName;
541
+ },
542
+ },
543
+ },
544
+ };
545
+
546
+ switch (env) {
547
+ case "development":
548
+ baseConfig.api = {
549
+ "local-api": "http://localhost:3000/api/openapi.json",
550
+ };
551
+ break;
552
+ case "staging":
553
+ baseConfig.api = {
554
+ "staging-api": "https://staging-api.example.com/openapi.json",
555
+ };
556
+ break;
557
+ case "production":
558
+ baseConfig.api = {
559
+ "prod-api": "https://api.example.com/openapi.json",
560
+ };
561
+ break;
562
+ }
563
+
564
+ return baseConfig;
565
+ };
566
+
567
+ export default getConfig;
568
+ ```
569
+
570
+ ### Custom Type Formatting
571
+
572
+ ```typescript
573
+ // Advanced type name formatting
574
+ const config: IConfig = {
575
+ // ... other config
576
+ types: {
577
+ name: {
578
+ prefix: "",
579
+ format: (source, data, defaultName) => {
580
+ if (source === "shared") {
581
+ // Shared types: UserProfile, OrderStatus, etc.
582
+ return `${data.name}`;
583
+ } else if (source === "endpoint") {
584
+ const method = data.method?.toUpperCase();
585
+ const cleanPath = data.path
586
+ ?.replace(/[{}\/]/g, "_")
587
+ .replace(/_+/g, "_");
588
+
589
+ switch (data.type) {
590
+ case "query":
591
+ return `${method}${cleanPath}Query`;
592
+ case "dto":
593
+ return `${method}${cleanPath}Request`;
594
+ case "response":
595
+ return `${method}${cleanPath}${data.code}Response`;
596
+ default:
597
+ return defaultName;
598
+ }
599
+ }
600
+ return defaultName;
601
+ },
602
+ },
603
+ },
604
+ };
605
+ ```
131
606
 
132
- For support, please open an issue in the GitHub repository.
607
+ ### URL Transformation Rules
608
+
609
+ ```typescript
610
+ const config: IConfig = {
611
+ // ... other config
612
+ endpoints: {
613
+ value: {
614
+ replaceWords: [
615
+ // Remove API versioning from URLs
616
+ {
617
+ replace: "/api/v[0-9]+/",
618
+ with: "/",
619
+ },
620
+ // Remove internal prefixes
621
+ {
622
+ replace: "/internal/",
623
+ with: "/",
624
+ },
625
+ // Transform specific paths
626
+ {
627
+ replace: "/users/profile",
628
+ with: "/profile",
629
+ },
630
+ ],
631
+ includeServer: true,
632
+ type: "object",
633
+ },
634
+ name: {
635
+ format: ({ method, path, operationId }, defaultName) => {
636
+ // Use operationId if available, otherwise generate from path
637
+ if (operationId) {
638
+ return operationId.replace(/[^a-zA-Z0-9]/g, "");
639
+ }
640
+
641
+ // Generate meaningful names from path and method
642
+ const cleanPath = path
643
+ .replace(/^\//, "")
644
+ .replace(/\//g, "_")
645
+ .replace(/{([^}]+)}/g, "By$1")
646
+ .replace(/[^a-zA-Z0-9_]/g, "");
647
+
648
+ return `${method.toLowerCase()}${cleanPath}`;
649
+ },
650
+ },
651
+ },
652
+ };
653
+ ```
654
+
655
+ ### Integration with Build Process
656
+
657
+ #### Package.json Scripts
658
+
659
+ ```json
660
+ {
661
+ "scripts": {
662
+ "api:sync": "openapi-sync",
663
+ "api:sync:watch": "openapi-sync --refreshinterval 3000",
664
+ "prebuild": "npm run api:sync",
665
+ "build": "tsc",
666
+ "dev": "concurrently \"npm run api:sync:watch\" \"npm run dev:server\""
667
+ }
668
+ }
669
+ ```
670
+
671
+ #### Pre-commit Hook
672
+
673
+ ```bash
674
+ #!/bin/sh
675
+ # .husky/pre-commit
676
+
677
+ # Sync API types before commit
678
+ npm run api:sync
679
+
680
+ # Add generated files to commit
681
+ git add src/api/
682
+ ```
683
+
684
+ #### CI/CD Integration
685
+
686
+ ```yaml
687
+ # .github/workflows/build.yml
688
+ name: Build
689
+ on: [push, pull_request]
690
+
691
+ jobs:
692
+ build:
693
+ runs-on: ubuntu-latest
694
+ steps:
695
+ - uses: actions/checkout@v2
696
+ - uses: actions/setup-node@v2
697
+ with:
698
+ node-version: "16"
699
+
700
+ - name: Install dependencies
701
+ run: npm ci
702
+
703
+ - name: Sync API types
704
+ run: npm run api:sync
705
+ env:
706
+ NODE_ENV: production
707
+
708
+ - name: Build
709
+ run: npm run build
710
+ ```
711
+
712
+ ### Error Handling and Monitoring
713
+
714
+ ```typescript
715
+ import { Init } from "openapi-sync";
716
+
717
+ const initializeAPIWithRetry = async (maxRetries = 3) => {
718
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
719
+ try {
720
+ await Init({
721
+ refetchInterval: process.env.NODE_ENV === "development" ? 5000 : 0,
722
+ });
723
+
724
+ console.log("✅ API types synchronized successfully");
725
+ return;
726
+ } catch (error) {
727
+ console.error(`❌ Attempt ${attempt} failed:`, error.message);
728
+
729
+ if (attempt === maxRetries) {
730
+ console.error("🚨 Failed to sync API types after all retries");
731
+ throw error;
732
+ }
733
+
734
+ // Wait before retry
735
+ await new Promise((resolve) => setTimeout(resolve, 2000 * attempt));
736
+ }
737
+ }
738
+ };
739
+
740
+ // Usage in your app
741
+ initializeAPIWithRetry().catch((error) => {
742
+ // Handle critical error - maybe use cached types or exit
743
+ console.error("Critical: Could not sync API types", error);
744
+ process.exit(1);
745
+ });
746
+ ```
747
+
748
+ ## Troubleshooting
749
+
750
+ ### Common Issues
751
+
752
+ #### 1. Configuration File Not Found
753
+
754
+ ```
755
+ Error: No config found
756
+ ```
757
+
758
+ **Solution:** Ensure you have one of these files in your project root:
759
+
760
+ - `openapi.sync.json`
761
+ - `openapi.sync.ts`
762
+ - `openapi.sync.js`
763
+
764
+ #### 2. Network Timeout Errors
765
+
766
+ ```
767
+ Error: timeout of 60000ms exceeded
768
+ ```
769
+
770
+ **Solution:** The tool includes automatic retry with exponential backoff. If issues persist:
771
+
772
+ - Check your internet connection
773
+ - Verify the OpenAPI spec URL is accessible
774
+ - Consider increasing timeout in your configuration
775
+
776
+ #### 3. TypeScript Compilation Errors
777
+
778
+ ```
779
+ Error: Cannot find module './src/api/petstore/types'
780
+ ```
781
+
782
+ **Solution:**
783
+
784
+ - Ensure the sync process completed successfully
785
+ - Check that the `folder` path in config is correct
786
+ - Verify TypeScript can resolve the generated paths
787
+
788
+ #### 4. Invalid OpenAPI Specification
789
+
790
+ ```
791
+ Error: Schema validation failed
792
+ ```
793
+
794
+ **Solution:**
795
+
796
+ - Validate your OpenAPI spec using online validators
797
+ - Check for syntax errors in YAML/JSON
798
+ - Ensure the spec follows OpenAPI 3.0+ standards
799
+
800
+ ### Performance Optimization
801
+
802
+ #### 1. Reduce Refetch Frequency
803
+
804
+ ```json
805
+ {
806
+ "refetchInterval": 30000 // Increase to 30 seconds
807
+ }
808
+ ```
809
+
810
+ #### 2. Disable Documentation Generation
811
+
812
+ ```json
813
+ {
814
+ "types": { "doc": { "disable": true } },
815
+ "endpoints": { "doc": { "disable": true } }
816
+ }
817
+ ```
818
+
819
+ #### 3. Use Specific Output Folders
820
+
821
+ ```json
822
+ {
823
+ "folder": "./src/api" // Specific path instead of root
824
+ }
825
+ ```
826
+
827
+ ### Debugging
828
+
829
+ #### Enable Verbose Logging
830
+
831
+ ```typescript
832
+ // Set environment variable for debugging
833
+ process.env.DEBUG = "openapi-sync:*";
834
+
835
+ import { Init } from "openapi-sync";
836
+ await Init();
837
+ ```
838
+
839
+ #### Check Generated State
840
+
841
+ The tool maintains state in `db.json` to track changes:
842
+
843
+ ```json
844
+ // db.json
845
+ {
846
+ "petstore": {
847
+ "openapi": "3.0.0",
848
+ "info": { "title": "Petstore API" }
849
+ // ... full OpenAPI spec
850
+ }
851
+ }
852
+ ```
853
+
854
+ ### Getting Help
855
+
856
+ 1. **Check the Issues**: [GitHub Issues](https://github.com/akintomiwa-fisayo/openapi-sync/issues)
857
+ 2. **Create a Bug Report**: Include your configuration and error logs
858
+ 3. **Feature Requests**: Describe your use case and expected behavior
859
+
860
+ ---
861
+
862
+ ## License
863
+
864
+ This project is licensed under the ISC License - see the [LICENSE](LICENSE) file for details.
133
865
 
134
- ## Acknowledgments
866
+ ## Contributing
135
867
 
136
- - Thanks to the OpenAPI Initiative for the OpenAPI specification
137
- - Thanks to all contributors and users of this package
138
- - Flexible CLI Commands: Sync your API at any point in the development process on app start, pre-commit, or via manual triggers.
868
+ Contributions are welcome! Please read our contributing guidelines and submit pull requests to our GitHub repository.