openapi-sync 5.0.6 → 6.0.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.
- package/README.md +206 -2
- package/bin/cli.js +396 -27
- package/bin/mcp.js +36 -0
- package/dist/chunk-3VKPQNDD.mjs +22 -0
- package/dist/chunk-L52BXDAC.mjs +24 -0
- package/dist/chunk-TTLQP4UN.mjs +856 -0
- package/dist/chunk-VLACEFT4.mjs +1 -0
- package/dist/index.d.mts +351 -32
- package/dist/index.d.ts +351 -32
- package/dist/index.js +410 -365
- package/dist/index.mjs +1 -854
- package/dist/interactive-init-XBZJKJCH.mjs +1 -0
- package/dist/mcp/server.d.mts +1 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +913 -0
- package/dist/mcp/server.mjs +4 -0
- package/dist/validate-3G3NZCPG.mjs +11 -0
- package/llms.txt +334 -0
- package/openapi.sync.schema.json +396 -0
- package/package.json +38 -17
- package/dist/chunk-PUWCZVB7.mjs +0 -1
- package/dist/interactive-init-OITE22SZ.mjs +0 -12
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {o,l,m,j,k as k$1}from'../chunk-TTLQP4UN.mjs';import'../chunk-L52BXDAC.mjs';import {c,b}from'../chunk-3VKPQNDD.mjs';import {e,f}from'../chunk-VLACEFT4.mjs';import {McpServer}from'@modelcontextprotocol/sdk/server/mcp.js';import {StdioServerTransport}from'@modelcontextprotocol/sdk/server/stdio.js';import {z}from'zod';import f$1 from'path';import x from'fs';var k=e(c$1=>{o();c();var s=(...t)=>process.stderr.write(t.join(" ")+`
|
|
3
|
+
`),d=process.cwd(),a=new McpServer({name:"openapi-sync",version:"1.0.0"});a.tool("openapi_sync_validate","Validate the openapi-sync config file and all configured API specs without writing any files to disk. Use this as a pre-flight check before syncing. Returns a structured result with per-API validity and endpoint counts.",{},()=>f(null,null,function*(){s("[openapi-sync-mcp] Running validate...");try{let t=yield l({silent:!0});return {content:[{type:"text",text:JSON.stringify(t,null,2)}]}}catch(t){return {content:[{type:"text",text:JSON.stringify({valid:false,configErrors:[t.message],apis:{}})}],isError:true}}}));a.tool("openapi_sync_list_endpoints","Fetch and parse all configured OpenAPI specs, then return a structured list of every endpoint (name, HTTP method, path, tags, summary). No files are written. Use this to understand the API surface before deciding on a client type or tag filters.",{apiName:z.string().optional().describe("Limit results to a specific API name from the config. Omit to list endpoints for all configured APIs."),tags:z.array(z.string()).optional().describe("Filter endpoints to only those with one of these OpenAPI tags.")},n=>f(null,[n],function*({apiName:t,tags:r}){s("[openapi-sync-mcp] Listing endpoints...");try{let o=yield m({apiName:t,tags:r,silent:!0});return {content:[{type:"text",text:JSON.stringify(o,null,2)}]}}catch(o){return {content:[{type:"text",text:`Error: ${o.message}`}],isError:true}}}));a.tool("openapi_sync_sync","Run a full openapi-sync \u2014 fetches all configured OpenAPI specs and writes TypeScript types, endpoint builder functions, and optional validation schemas (Zod/Yup/Joi) to disk. Returns a SyncResult with the list of files written and any errors. Run this after validating your config.",{refetchInterval:z.number().optional().describe("If set, enables continuous auto-sync at this interval (ms). Omit for a single one-time sync.")},r=>f(null,[r],function*({refetchInterval:t}){s("[openapi-sync-mcp] Running sync...");try{let n=yield j({refetchInterval:t,silent:!0});return {content:[{type:"text",text:JSON.stringify(n,null,2)}],isError:!n.success}}catch(n){return {content:[{type:"text",text:JSON.stringify({success:false,apis:[],filesWritten:[],endpointCount:0,warnings:[],errors:[n.message]})}],isError:true}}}));a.tool("openapi_sync_generate_client","Generate a fully-typed API client for one or all configured APIs. Supports: fetch, axios, react-query, swr, rtk-query. Syncs the latest spec first, then writes client files to disk. Returns a SyncResult with the list of files written.",{type:z.enum(["fetch","axios","react-query","swr","rtk-query"]).describe("The type of API client to generate."),apiName:z.string().optional().describe("API name from the config to generate a client for. Omit to generate for all configured APIs."),baseURL:z.string().optional().describe("Base URL to bake into the generated client (e.g. https://api.example.com). Can be overridden at runtime in the generated code."),tags:z.array(z.string()).optional().describe("Only generate client methods for endpoints with these tags."),endpoints:z.array(z.string()).optional().describe("Only generate client methods for these specific endpoint names / operationIds."),outputDir:z.string().optional().describe("Custom output directory for the generated client files. Defaults to the path set in your openapi.sync config.")},I=>f(null,[I],function*({type:t,apiName:r,baseURL:n,tags:o,endpoints:u,outputDir:y}){s(`[openapi-sync-mcp] Generating ${t} client...`);try{let p=yield k$1({type:t,apiName:r,baseURL:n,tags:o,endpoints:u,outputDir:y,silent:!0});return {content:[{type:"text",text:JSON.stringify(p,null,2)}],isError:!p.success}}catch(p){return {content:[{type:"text",text:JSON.stringify({success:false,apis:[],filesWritten:[],endpointCount:0,warnings:[],errors:[p.message]})}],isError:true}}}));a.tool("openapi_sync_init","Create an openapi.sync config file in the current working directory without any interactive prompts. Use this to set up a project from scratch. After calling this tool, run openapi_sync_validate and then openapi_sync_sync.",{apiName:z.string().describe("A short identifier for this API used as a folder name and config key (e.g. 'petstore', 'my-api'). Letters, numbers, hyphens and underscores only."),apiSource:z.string().describe("URL to the OpenAPI spec (https://...) or relative path to a local file (e.g. ./api/openapi.yaml)."),outputFolder:z.string().optional().default("./src/api").describe("Output folder for generated files (default: ./src/api)."),configFormat:z.enum(["typescript","json","javascript"]).optional().default("typescript").describe("Config file format (default: typescript)."),clientType:z.enum(["react-query","swr","fetch","axios","rtk-query"]).optional().describe("Client type to pre-configure in the config. Omit to skip client generation."),validationLibrary:z.enum(["zod","yup","joi"]).optional().describe("Validation library to pre-configure. Omit to skip validation schema generation."),folderSplit:z.boolean().optional().default(false).describe("Organize generated files into folders by OpenAPI tags."),typesPrefix:z.string().optional().default("I").describe("Prefix for generated TypeScript interface names (default: 'I', e.g. IPet)."),excludeTags:z.array(z.string()).optional().describe("Tags to exclude from generation (e.g. ['deprecated', 'internal'])."),runSync:z.boolean().optional().default(false).describe("If true, immediately run a full sync after creating the config file.")},$=>f(null,[$],function*({apiName:t,apiSource:r,outputFolder:n,configFormat:o,clientType:u,validationLibrary:y,folderSplit:I,typesPrefix:p,excludeTags:S,runSync:O}){s("[openapi-sync-mcp] Creating config...");try{let l=yield b({apiName:t,apiSource:r,outputFolder:n,configFormat:o,clientType:u,validationLibrary:y,folderSplit:I,typesPrefix:p,excludeTags:S,runSync:O,silent:!0});return {content:[{type:"text",text:JSON.stringify(l,null,2)}],isError:!l.success}}catch(l){return {content:[{type:"text",text:JSON.stringify({success:false,configFile:"",message:l.message,errors:[l.message]})}],isError:true}}}));a.tool("openapi_sync_read_config","Read the current openapi.sync config file from the working directory and return its contents as a string. Useful to inspect what APIs are configured before running sync or generate-client.",{},()=>f(null,null,function*(){s("[openapi-sync-mcp] Reading config...");let t=[f$1.join(d,"openapi.sync.ts"),f$1.join(d,"openapi.sync.js"),f$1.join(d,"openapi.sync.json")];for(let r of t)if(x.existsSync(r))try{let n=x.readFileSync(r,"utf-8");return {content:[{type:"text",text:JSON.stringify({found:!0,file:f$1.basename(r),path:r,content:n},null,2)}]}}catch(n){return {content:[{type:"text",text:JSON.stringify({found:false,error:`Could not read ${r}: ${n.message}`})}],isError:true}}return {content:[{type:"text",text:JSON.stringify({found:false,searched:t,message:"No openapi.sync config file found. Use the openapi_sync_init tool to create one."})}]}}));function R(){return f(this,null,function*(){let t=new StdioServerTransport;yield a.connect(t),s("[openapi-sync-mcp] Server running on stdio. Ready for tool calls.");})}R().catch(t=>{s("[openapi-sync-mcp] Fatal error:",t),process.exit(1);});});var server = k();
|
|
4
|
+
export{server as default};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {o,d as d$1,f as f$1}from'./chunk-L52BXDAC.mjs';import {d,f,c}from'./chunk-VLACEFT4.mjs';import l from'path';import $ from'fs';import P from'axios';import w from'@apidevtools/swagger-parser';var g,E,b,O,S=d(()=>{o();g=process.cwd(),E=()=>{let i=l.join(g,"openapi.sync.js"),d=l.join(g,"openapi.sync.ts"),r=l.join(g,"openapi.sync.json"),o=[i,d,r];try{c("esbuild-register");}catch(s){}for(let s of o)if($.existsSync(s))try{let n=c(s);return Object.keys(n).length===1&&n.default&&(n=n.default),typeof n=="function"&&(n=n()),{config:n,errors:[]}}catch(n){let c=n instanceof Error?n.message:String(n);return {config:null,errors:[`Failed to parse ${s}: ${c}`]}}return {config:null,errors:[`No config file found. Searched: ${o.join(", ")}. Run \`npx openapi-sync init --no-interactive\` to create one.`]}},b=(i,d)=>f(null,null,function*(){var c;let r;try{if(i.startsWith("http://")||i.startsWith("https://"))r=(yield P.get(i,{timeout:15e3})).data;else {let a=l.isAbsolute(i)?i:l.join(g,i);r=yield $.promises.readFile(a,"utf-8");}}catch(t){return {endpointCount:0,error:`Could not fetch/read spec: ${t instanceof Error?t.message:String(t)}`}}let o;try{let t=d$1(r)?r:f$1(r);o=yield w.parse(t);}catch(t){return {endpointCount:0,error:`Could not parse spec: ${t instanceof Error?t.message:String(t)}`}}let s=0,n=(o==null?void 0:o.paths)||{};for(let t of Object.keys(n)){let a=["get","post","put","patch","delete","head","options"];for(let e of a)(c=n[t])!=null&&c[e]&&s++;}return {endpointCount:s}}),O=i=>f(null,null,function*(){var a;let r=((a=i==null?void 0:i.silent)!=null?a:false)?{log:()=>{},warn:()=>{},error:()=>{}}:{log:console.log,warn:console.warn,error:console.error},o={valid:false,apis:{},configErrors:[]},{config:s,errors:n}=E();if(n.length>0)return o.configErrors=n,r.error(`\u274C Config errors:
|
|
2
|
+
${n.map(e=>` \u2022 ${e}`).join(`
|
|
3
|
+
`)}`),o;if(!s)return o.configErrors=["Config loaded but is empty or null."],o;if((!s.api||Object.keys(s.api).length===0)&&o.configErrors.push('Config must have at least one API defined under the "api" key.'),o.configErrors.length>0)return r.error(`\u274C Config validation errors:
|
|
4
|
+
${o.configErrors.map(e=>` \u2022 ${e}`).join(`
|
|
5
|
+
`)}`),o;let c=Object.keys(s.api);r.log(`
|
|
6
|
+
\u{1F50D} Validating ${c.length} API spec(s)...
|
|
7
|
+
`);let t=true;return yield Promise.all(c.map(e=>f(null,null,function*(){let h=s.api[e];r.log(` \u{1F50E} ${e}: ${h}`);let{endpointCount:m,error:p}=yield b(h,e);p?(o.apis[e]={valid:false,endpointCount:0,error:p},r.error(` \u274C ${e}: ${p}`),t=false):(o.apis[e]={valid:true,endpointCount:m},r.log(` \u2705 ${e}: ${m} endpoint(s) found`));}))),o.valid=t&&o.configErrors.length===0,o.valid?r.log(`
|
|
8
|
+
\u2705 All checks passed \u2014 config and specs are valid.
|
|
9
|
+
`):r.error(`
|
|
10
|
+
\u274C Validation failed \u2014 see errors above.
|
|
11
|
+
`),o});});S();export{O as validateConfig};
|
package/llms.txt
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
# openapi-sync
|
|
2
|
+
|
|
3
|
+
A CLI + Node.js library that generates TypeScript types, fully-typed API clients,
|
|
4
|
+
and runtime validation schemas from OpenAPI (Swagger) specifications.
|
|
5
|
+
|
|
6
|
+
Supports: TypeScript, Python, Fetch, Axios, React Query, SWR, RTK Query, Zod, Yup, Joi.
|
|
7
|
+
npm: https://www.npmjs.com/package/openapi-sync
|
|
8
|
+
Docs: https://openapi-sync.com
|
|
9
|
+
GitHub: https://github.com/akintomiwa-fisayo/openapi-sync
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## AGENT QUICK-START
|
|
13
|
+
|
|
14
|
+
Minimum working setup (no interactive prompts needed):
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# 1. Create config (agent-safe, no prompts)
|
|
18
|
+
npx openapi-sync init --no-interactive \
|
|
19
|
+
--api-name petstore \
|
|
20
|
+
--api-url https://petstore3.swagger.io/api/v3/openapi.json \
|
|
21
|
+
--output-folder ./src/api \
|
|
22
|
+
--config-format typescript
|
|
23
|
+
|
|
24
|
+
# 2. Validate config and spec before writing any files
|
|
25
|
+
npx openapi-sync validate --json
|
|
26
|
+
|
|
27
|
+
# 3. Sync — generates types, endpoints, validation schemas
|
|
28
|
+
npx openapi-sync --json
|
|
29
|
+
|
|
30
|
+
# 4. (Optional) generate a typed API client
|
|
31
|
+
npx openapi-sync generate-client --type react-query --json
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
All commands support `--json` (machine-readable stdout) and exit codes:
|
|
35
|
+
0 = success | 1 = config/validation error | 2 = network error | 3 = generation error
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
## CLI COMMANDS
|
|
39
|
+
|
|
40
|
+
### Agent-safe commands (no stdin required)
|
|
41
|
+
|
|
42
|
+
| Command | Description |
|
|
43
|
+
|---------|-------------|
|
|
44
|
+
| `npx openapi-sync` | Sync specs, generate types + endpoints + schemas |
|
|
45
|
+
| `npx openapi-sync validate` | Validate config + specs; no files written |
|
|
46
|
+
| `npx openapi-sync list-endpoints` | List all endpoints from spec; no files written |
|
|
47
|
+
| `npx openapi-sync generate-client --type <TYPE>` | Generate typed API client |
|
|
48
|
+
| `npx openapi-sync init --no-interactive [FLAGS]` | Create config file without prompts |
|
|
49
|
+
|
|
50
|
+
### Interactive-only (requires human stdin — NOT safe for agents)
|
|
51
|
+
|
|
52
|
+
| Command | Description |
|
|
53
|
+
|---------|-------------|
|
|
54
|
+
| `npx openapi-sync init` | Interactive wizard |
|
|
55
|
+
|
|
56
|
+
### Global flags (all commands)
|
|
57
|
+
|
|
58
|
+
| Flag | Description |
|
|
59
|
+
|------|-------------|
|
|
60
|
+
| `--json` | Emit a single JSON object to stdout; suppress emoji logs |
|
|
61
|
+
| `--silent` | Suppress all console output |
|
|
62
|
+
| `--dry-run` | Show what would be written without writing (sync, generate-client) |
|
|
63
|
+
| `--help, -h` | Help |
|
|
64
|
+
| `--version, -v` | Version |
|
|
65
|
+
|
|
66
|
+
### `init` flags (used with `--no-interactive`)
|
|
67
|
+
|
|
68
|
+
| Flag | Default | Description |
|
|
69
|
+
|------|---------|-------------|
|
|
70
|
+
| `--api-name` | `"myapi"` | API key in config |
|
|
71
|
+
| `--api-url` | — | URL to OpenAPI spec |
|
|
72
|
+
| `--api-file` | — | Path to local spec file |
|
|
73
|
+
| `--output-folder` | `"./src/api"` | Generated files output |
|
|
74
|
+
| `--config-format` | `"typescript"` | `typescript`, `json`, `javascript` |
|
|
75
|
+
| `--client-type` | — | `react-query`, `swr`, `fetch`, `axios`, `rtk-query` |
|
|
76
|
+
| `--validation-library` | — | `zod`, `yup`, `joi` |
|
|
77
|
+
| `--folder-split` | `false` | Organise by OpenAPI tags |
|
|
78
|
+
| `--types-prefix` | `"I"` | TS interface name prefix |
|
|
79
|
+
| `--use-operation-id` | `true` | Use operationId for names |
|
|
80
|
+
| `--exclude-tags` | — | Comma-separated tags to exclude |
|
|
81
|
+
| `--show-curl` | `true` | Include cURL in JSDoc |
|
|
82
|
+
| `--refetch-interval` | `0` | Auto-refetch ms (0=disabled) |
|
|
83
|
+
| `--run-sync` | `false` | Run sync after config creation |
|
|
84
|
+
|
|
85
|
+
### `generate-client` flags
|
|
86
|
+
|
|
87
|
+
| Flag | Alias | Description |
|
|
88
|
+
|------|-------|-------------|
|
|
89
|
+
| `--type` | `-t` | Client type (required) |
|
|
90
|
+
| `--api` | `-a` | Specific API from config |
|
|
91
|
+
| `--tags` | | Filter endpoints by tags |
|
|
92
|
+
| `--endpoints` | `-e` | Filter by endpoint names |
|
|
93
|
+
| `--output` | `-o` | Output directory |
|
|
94
|
+
| `--base-url` | `-b` | Base URL baked into client |
|
|
95
|
+
|
|
96
|
+
### `list-endpoints` flags
|
|
97
|
+
|
|
98
|
+
| Flag | Description |
|
|
99
|
+
|------|-------------|
|
|
100
|
+
| `--api` | Limit to a specific API |
|
|
101
|
+
| `--tags` | Comma-separated tag filter |
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
## PROGRAMMATIC API
|
|
105
|
+
|
|
106
|
+
All functions are exported from the `openapi-sync` package.
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import {
|
|
110
|
+
Init, // Sync specs → types, endpoints, schemas
|
|
111
|
+
GenerateClient, // Generate typed API client
|
|
112
|
+
ValidateConfig, // Pre-flight check (no file writes)
|
|
113
|
+
ListEndpoints, // Inspect API surface (no file writes)
|
|
114
|
+
InteractiveInit, // NOT agent-safe — requires stdin
|
|
115
|
+
} from "openapi-sync";
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Init(options?) → Promise<SyncResult>
|
|
119
|
+
Agent-safe. Returns SyncResult.
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
const result = await Init({ silent: true });
|
|
123
|
+
// result: { success, apis, filesWritten, endpointCount, warnings, errors }
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### GenerateClient(options) → Promise<SyncResult>
|
|
127
|
+
Agent-safe. Syncs then generates a typed client.
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
const result = await GenerateClient({
|
|
131
|
+
type: "react-query", // "fetch"|"axios"|"react-query"|"swr"|"rtk-query"
|
|
132
|
+
apiName: "petstore", // optional; defaults to all APIs
|
|
133
|
+
baseURL: "https://api.example.com",
|
|
134
|
+
tags: ["pets"], // optional tag filter
|
|
135
|
+
silent: true,
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### ValidateConfig(options?) → Promise<ValidationResult>
|
|
140
|
+
Agent-safe. No files written.
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
const validation = await ValidateConfig({ silent: true });
|
|
144
|
+
// validation: { valid, apis: { [name]: { valid, endpointCount, error? } }, configErrors }
|
|
145
|
+
if (!validation.valid) process.exit(1);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### ListEndpoints(options?) → Promise<Record<string, EndpointSummary[]>>
|
|
149
|
+
Agent-safe. No files written.
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
const map = await ListEndpoints({ apiName: "petstore", tags: ["pet"] });
|
|
153
|
+
// map: { petstore: [{ name, method, path, operationId, tags, summary }] }
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### InteractiveInit() → Promise<void>
|
|
157
|
+
NOT agent-safe — blocks on stdin prompts.
|
|
158
|
+
Use CLI `init --no-interactive` instead.
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
## CONFIG FILE FORMAT
|
|
162
|
+
|
|
163
|
+
Config file: `openapi.sync.ts` | `openapi.sync.js` | `openapi.sync.json`
|
|
164
|
+
JSON Schema: https://openapi-sync.com/schema/openapi.sync.schema.json
|
|
165
|
+
|
|
166
|
+
### Minimal config
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"folder": "./src/api",
|
|
171
|
+
"api": {
|
|
172
|
+
"petstore": "https://petstore3.swagger.io/api/v3/openapi.json"
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Full TypeScript config
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
import { IConfig } from "openapi-sync";
|
|
181
|
+
const config: IConfig = {
|
|
182
|
+
folder: "./src/api",
|
|
183
|
+
api: { petstore: "https://petstore3.swagger.io/api/v3/openapi.json" },
|
|
184
|
+
refetchInterval: 5000,
|
|
185
|
+
language: "typescript", // "typescript" | "python"
|
|
186
|
+
folderSplit: { byTags: true },
|
|
187
|
+
types: { name: { prefix: "I", useOperationId: true } },
|
|
188
|
+
endpoints: {
|
|
189
|
+
doc: { showCurl: true },
|
|
190
|
+
exclude: { tags: ["deprecated"] },
|
|
191
|
+
},
|
|
192
|
+
validations: { library: "zod" }, // "zod" | "yup" | "joi"
|
|
193
|
+
clientGeneration: {
|
|
194
|
+
enabled: true,
|
|
195
|
+
type: "react-query", // "fetch"|"axios"|"react-query"|"swr"|"rtk-query"
|
|
196
|
+
baseURL: "https://api.example.com",
|
|
197
|
+
reactQuery: { version: 5, mutations: true },
|
|
198
|
+
},
|
|
199
|
+
customCode: { enabled: true, position: "bottom" },
|
|
200
|
+
};
|
|
201
|
+
export default config;
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Key IConfig fields
|
|
205
|
+
|
|
206
|
+
| Field | Type | Description |
|
|
207
|
+
|-------|------|-------------|
|
|
208
|
+
| `api` | `Record<string, string>` | **Required.** Map of API name → spec URL or file path |
|
|
209
|
+
| `folder` | `string` | Output folder (default: `"api"`) |
|
|
210
|
+
| `language` | `"typescript"\|"python"` | Output language |
|
|
211
|
+
| `refetchInterval` | `number` | Auto-refetch ms |
|
|
212
|
+
| `folderSplit.byTags` | `boolean` | Split output by OpenAPI tags |
|
|
213
|
+
| `validations.library` | `"zod"\|"yup"\|"joi"` | Validation schema library |
|
|
214
|
+
| `clientGeneration.type` | string | Client type to generate |
|
|
215
|
+
| `clientGeneration.baseURL` | `string` | Base URL for generated client |
|
|
216
|
+
| `endpoints.exclude.tags` | `string[]` | Tags to exclude from generation |
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
## STRUCTURED RETURN TYPES
|
|
220
|
+
|
|
221
|
+
### SyncResult (returned by Init, GenerateClient)
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
type SyncResult = {
|
|
225
|
+
success: boolean;
|
|
226
|
+
apis: string[];
|
|
227
|
+
filesWritten: string[];
|
|
228
|
+
endpointCount: number;
|
|
229
|
+
warnings: string[];
|
|
230
|
+
errors: string[];
|
|
231
|
+
};
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### ValidationResult (returned by ValidateConfig)
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
type ValidationResult = {
|
|
238
|
+
valid: boolean;
|
|
239
|
+
apis: Record<string, { valid: boolean; endpointCount: number; error?: string }>;
|
|
240
|
+
configErrors: string[];
|
|
241
|
+
};
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### EndpointSummary (items in ListEndpoints result)
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
type EndpointSummary = {
|
|
248
|
+
name: string;
|
|
249
|
+
method: string;
|
|
250
|
+
path: string;
|
|
251
|
+
operationId?: string;
|
|
252
|
+
tags?: string[];
|
|
253
|
+
summary?: string;
|
|
254
|
+
};
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
## GENERATED FILE STRUCTURE
|
|
259
|
+
|
|
260
|
+
```
|
|
261
|
+
./src/api/
|
|
262
|
+
{apiName}/
|
|
263
|
+
types.ts ← TypeScript interfaces for all schemas
|
|
264
|
+
endpoints.ts ← Typed endpoint URL builder functions
|
|
265
|
+
shared.ts ← Shared component types
|
|
266
|
+
validations.ts ← Zod/Yup/Joi schemas (if enabled)
|
|
267
|
+
client/
|
|
268
|
+
client.ts ← Fetch/Axios client instance
|
|
269
|
+
hooks.ts ← React Query / SWR hooks (if enabled)
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
When `folderSplit.byTags` is true, types/endpoints/validations are split into
|
|
273
|
+
tag-named subdirectories with aggregator index files for easy imports.
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
## ERROR CODES (typed errors)
|
|
277
|
+
|
|
278
|
+
| Code | Class | Trigger |
|
|
279
|
+
|------|-------|---------|
|
|
280
|
+
| `CONFIG_NOT_FOUND` | ConfigNotFoundError | No config file in cwd |
|
|
281
|
+
| `CONFIG_PARSE_FAILED` | ConfigParseError | Config file parse error |
|
|
282
|
+
| `CONFIG_INVALID` | ConfigValidationError | Bad config field value |
|
|
283
|
+
| `SPEC_FETCH_FAILED` | SpecFetchError | Network error fetching spec |
|
|
284
|
+
| `SPEC_READ_FAILED` | SpecReadError | Local file read error |
|
|
285
|
+
| `SPEC_PARSE_FAILED` | SpecParseError | Not a valid OpenAPI spec |
|
|
286
|
+
| `GENERATION_FAILED` | GenerationError | File write error |
|
|
287
|
+
| `UNKNOWN_API` | UnknownApiError | API name not in config |
|
|
288
|
+
|
|
289
|
+
All error classes extend `OpenApiSyncError` and expose `.code`, `.message`, and `.toJSON()`.
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
## COMMON AGENT WORKFLOWS
|
|
293
|
+
|
|
294
|
+
### Workflow 1: First-time setup
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
npx openapi-sync init --no-interactive \
|
|
298
|
+
--api-name myapi \
|
|
299
|
+
--api-url https://api.example.com/openapi.json \
|
|
300
|
+
--output-folder ./src/api \
|
|
301
|
+
--client-type react-query \
|
|
302
|
+
--validation-library zod \
|
|
303
|
+
--config-format typescript \
|
|
304
|
+
--json
|
|
305
|
+
npx openapi-sync validate --json
|
|
306
|
+
npx openapi-sync --json
|
|
307
|
+
npx openapi-sync generate-client --type react-query --json
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Workflow 2: Inspect before generating
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
# See what endpoints exist before committing to a client type
|
|
314
|
+
npx openapi-sync list-endpoints --json | jq '.petstore | map(.method + " " + .path)'
|
|
315
|
+
|
|
316
|
+
# Preview what would be written
|
|
317
|
+
npx openapi-sync --dry-run --json
|
|
318
|
+
npx openapi-sync generate-client --type fetch --dry-run --json
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Workflow 3: Programmatic (TypeScript)
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
import { ValidateConfig, Init, GenerateClient } from "openapi-sync";
|
|
325
|
+
|
|
326
|
+
const validation = await ValidateConfig({ silent: true });
|
|
327
|
+
if (!validation.valid) throw new Error(JSON.stringify(validation));
|
|
328
|
+
|
|
329
|
+
const syncResult = await Init({ silent: true });
|
|
330
|
+
if (!syncResult.success) throw new Error(JSON.stringify(syncResult));
|
|
331
|
+
|
|
332
|
+
const clientResult = await GenerateClient({ type: "axios", silent: true });
|
|
333
|
+
console.log(JSON.stringify(clientResult));
|
|
334
|
+
```
|