nuxt-openapi-hyperfetch 0.1.0-alpha.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.
- package/.editorconfig +26 -0
- package/.prettierignore +17 -0
- package/.prettierrc.json +12 -0
- package/CONTRIBUTING.md +292 -0
- package/INSTRUCTIONS.md +327 -0
- package/LICENSE +202 -0
- package/README.md +202 -0
- package/dist/cli/config.d.ts +57 -0
- package/dist/cli/config.js +85 -0
- package/dist/cli/logger.d.ts +44 -0
- package/dist/cli/logger.js +58 -0
- package/dist/cli/logo.d.ts +6 -0
- package/dist/cli/logo.js +21 -0
- package/dist/cli/messages.d.ts +65 -0
- package/dist/cli/messages.js +86 -0
- package/dist/cli/prompts.d.ts +30 -0
- package/dist/cli/prompts.js +118 -0
- package/dist/cli/types.d.ts +43 -0
- package/dist/cli/types.js +4 -0
- package/dist/cli/utils.d.ts +26 -0
- package/dist/cli/utils.js +45 -0
- package/dist/generate.d.ts +6 -0
- package/dist/generate.js +48 -0
- package/dist/generators/nuxt-server/bff-templates.d.ts +25 -0
- package/dist/generators/nuxt-server/bff-templates.js +737 -0
- package/dist/generators/nuxt-server/generator.d.ts +7 -0
- package/dist/generators/nuxt-server/generator.js +206 -0
- package/dist/generators/nuxt-server/parser.d.ts +5 -0
- package/dist/generators/nuxt-server/parser.js +5 -0
- package/dist/generators/nuxt-server/templates.d.ts +35 -0
- package/dist/generators/nuxt-server/templates.js +412 -0
- package/dist/generators/nuxt-server/types.d.ts +5 -0
- package/dist/generators/nuxt-server/types.js +5 -0
- package/dist/generators/shared/parsers/heyapi-parser.d.ts +11 -0
- package/dist/generators/shared/parsers/heyapi-parser.js +248 -0
- package/dist/generators/shared/parsers/official-parser.d.ts +5 -0
- package/dist/generators/shared/parsers/official-parser.js +5 -0
- package/dist/generators/shared/runtime/apiHelpers.d.ts +183 -0
- package/dist/generators/shared/runtime/apiHelpers.js +268 -0
- package/dist/generators/shared/templates/api-callbacks-plugin.d.ts +178 -0
- package/dist/generators/shared/templates/api-callbacks-plugin.js +338 -0
- package/dist/generators/shared/types.d.ts +25 -0
- package/dist/generators/shared/types.js +4 -0
- package/dist/generators/tanstack-query/generator.d.ts +5 -0
- package/dist/generators/tanstack-query/generator.js +11 -0
- package/dist/generators/use-async-data/generator.d.ts +5 -0
- package/dist/generators/use-async-data/generator.js +156 -0
- package/dist/generators/use-async-data/parser.d.ts +5 -0
- package/dist/generators/use-async-data/parser.js +5 -0
- package/dist/generators/use-async-data/runtime/useApiAsyncData.d.ts +38 -0
- package/dist/generators/use-async-data/runtime/useApiAsyncData.js +122 -0
- package/dist/generators/use-async-data/runtime/useApiAsyncDataRaw.d.ts +54 -0
- package/dist/generators/use-async-data/runtime/useApiAsyncDataRaw.js +126 -0
- package/dist/generators/use-async-data/templates.d.ts +20 -0
- package/dist/generators/use-async-data/templates.js +191 -0
- package/dist/generators/use-async-data/types.d.ts +4 -0
- package/dist/generators/use-async-data/types.js +4 -0
- package/dist/generators/use-fetch/generator.d.ts +5 -0
- package/dist/generators/use-fetch/generator.js +131 -0
- package/dist/generators/use-fetch/parser.d.ts +9 -0
- package/dist/generators/use-fetch/parser.js +282 -0
- package/dist/generators/use-fetch/runtime/useApiRequest.d.ts +46 -0
- package/dist/generators/use-fetch/runtime/useApiRequest.js +158 -0
- package/dist/generators/use-fetch/templates.d.ts +16 -0
- package/dist/generators/use-fetch/templates.js +169 -0
- package/dist/generators/use-fetch/types.d.ts +5 -0
- package/dist/generators/use-fetch/types.js +5 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +213 -0
- package/docs/API-REFERENCE.md +887 -0
- package/docs/ARCHITECTURE.md +649 -0
- package/docs/DEVELOPMENT.md +918 -0
- package/docs/QUICK-START.md +323 -0
- package/docs/README.md +155 -0
- package/docs/TROUBLESHOOTING.md +881 -0
- package/eslint.config.js +72 -0
- package/package.json +65 -0
- package/src/cli/config.ts +140 -0
- package/src/cli/logger.ts +66 -0
- package/src/cli/logo.ts +25 -0
- package/src/cli/messages.ts +97 -0
- package/src/cli/prompts.ts +143 -0
- package/src/cli/types.ts +50 -0
- package/src/cli/utils.ts +49 -0
- package/src/generate.ts +57 -0
- package/src/generators/nuxt-server/bff-templates.ts +754 -0
- package/src/generators/nuxt-server/generator.ts +270 -0
- package/src/generators/nuxt-server/parser.ts +5 -0
- package/src/generators/nuxt-server/templates.ts +483 -0
- package/src/generators/nuxt-server/types.ts +5 -0
- package/src/generators/shared/parsers/heyapi-parser.ts +307 -0
- package/src/generators/shared/parsers/official-parser.ts +5 -0
- package/src/generators/shared/runtime/apiHelpers.ts +466 -0
- package/src/generators/shared/templates/api-callbacks-plugin.ts +352 -0
- package/src/generators/shared/types.ts +27 -0
- package/src/generators/tanstack-query/generator.ts +11 -0
- package/src/generators/use-async-data/generator.ts +204 -0
- package/src/generators/use-async-data/parser.ts +5 -0
- package/src/generators/use-async-data/runtime/useApiAsyncData.ts +220 -0
- package/src/generators/use-async-data/runtime/useApiAsyncDataRaw.ts +236 -0
- package/src/generators/use-async-data/templates.ts +250 -0
- package/src/generators/use-async-data/types.ts +4 -0
- package/src/generators/use-fetch/generator.ts +169 -0
- package/src/generators/use-fetch/parser.ts +341 -0
- package/src/generators/use-fetch/runtime/useApiRequest.ts +223 -0
- package/src/generators/use-fetch/templates.ts +214 -0
- package/src/generators/use-fetch/types.ts +5 -0
- package/src/index.ts +265 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
# 🏗️ Architecture & Design Decisions
|
|
2
|
+
|
|
3
|
+
> **Purpose**: Understand WHY the codebase is structured this way and the trade-offs made.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Architectural Overview](#architectural-overview)
|
|
8
|
+
- [Core Patterns](#core-patterns)
|
|
9
|
+
- [Design Decisions (ADRs)](#design-decisions-adrs)
|
|
10
|
+
- [Component Map](#component-map)
|
|
11
|
+
- [Data Flow](#data-flow)
|
|
12
|
+
- [Extension Points](#extension-points)
|
|
13
|
+
|
|
14
|
+
## Architectural Overview
|
|
15
|
+
|
|
16
|
+
### High-Level Architecture
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
20
|
+
│ CLI Tool │
|
|
21
|
+
│ (Runs on developer's machine during development) │
|
|
22
|
+
└────────────────────────┬─────────────────────────────────────┘
|
|
23
|
+
│
|
|
24
|
+
▼
|
|
25
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
26
|
+
│ OpenAPI Generator (typescript-fetch) │
|
|
27
|
+
│ Generates: PetApi.ts, models/, runtime.ts │
|
|
28
|
+
└────────────────────────┬─────────────────────────────────────┘
|
|
29
|
+
│
|
|
30
|
+
▼
|
|
31
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
32
|
+
│ Parser (ts-morph) │
|
|
33
|
+
│ Extracts: method names, params, paths, HTTP details │
|
|
34
|
+
└────────────────────────┬─────────────────────────────────────┘
|
|
35
|
+
│
|
|
36
|
+
▼
|
|
37
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
38
|
+
│ Template Generator │
|
|
39
|
+
│ Creates: useFetchAddPet, useAsyncDataGetPet │
|
|
40
|
+
└────────────────────────┬─────────────────────────────────────┘
|
|
41
|
+
│
|
|
42
|
+
▼
|
|
43
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
44
|
+
│ User's Nuxt Project │
|
|
45
|
+
│ Runtime: useApiRequest, apiHelpers, global callbacks │
|
|
46
|
+
│ Generated: Individual composables per endpoint │
|
|
47
|
+
└──────────────────────────────────────────────────────────────┘
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Two-Runtime Architecture
|
|
51
|
+
|
|
52
|
+
This project operates in **two separate runtime contexts**:
|
|
53
|
+
|
|
54
|
+
#### 1. **Build-time Runtime** (CLI Tool)
|
|
55
|
+
|
|
56
|
+
- Runs during development
|
|
57
|
+
- Uses Node.js, TypeScript, ts-morph
|
|
58
|
+
- Has access to file system
|
|
59
|
+
- Generates code as strings
|
|
60
|
+
|
|
61
|
+
#### 2. **User Runtime** (Nuxt Project)
|
|
62
|
+
|
|
63
|
+
- Runs in production (browser + server)
|
|
64
|
+
- Uses Vue 3, Nuxt 3 APIs
|
|
65
|
+
- No access to our CLI dependencies
|
|
66
|
+
- Executes generated composables
|
|
67
|
+
|
|
68
|
+
**Critical implication**: Runtime files can't be imported from our npm package - they must be **copied** to user's project.
|
|
69
|
+
|
|
70
|
+
## Core Patterns
|
|
71
|
+
|
|
72
|
+
### 1. Two-Stage Generation Pattern
|
|
73
|
+
|
|
74
|
+
**Problem**: OpenAPI specs are verbose XML/YAML. Nuxt needs composables.
|
|
75
|
+
|
|
76
|
+
**Solution**: Use an existing OpenAPI client generator for Stage 1, then parse and transform its output in Stage 2.
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
OpenAPI Spec → [Stage 1: backend A or B] → TypeScript Client
|
|
80
|
+
TypeScript Client → [Stage 2: Our Parser + Templates] → Nuxt Composables
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Two supported backends for Stage 1:**
|
|
84
|
+
|
|
85
|
+
| Backend | Package | Requires | Parser used in Stage 2 |
|
|
86
|
+
|---|---|---|---|
|
|
87
|
+
| `official` | `@openapitools/openapi-generator-cli` | Java 11+ | `official-parser.ts` (reads `apis/*.ts`) |
|
|
88
|
+
| `heyapi` | `@hey-api/openapi-ts` | Node.js only | `heyapi-parser.ts` (reads `sdk.gen.ts` + `types.gen.ts`) |
|
|
89
|
+
|
|
90
|
+
Both parsers (`src/generators/shared/parsers/`) produce identical `MethodInfo[]` output, so all downstream templates are shared and backend-agnostic.
|
|
91
|
+
|
|
92
|
+
**Benefits**:
|
|
93
|
+
|
|
94
|
+
- ✅ Leverage mature OpenAPI ecosystem
|
|
95
|
+
- ✅ Don't reinvent OpenAPI parsing
|
|
96
|
+
- ✅ No Java required when using heyapi backend
|
|
97
|
+
- ✅ Templates work identically regardless of backend
|
|
98
|
+
|
|
99
|
+
**Trade-offs**:
|
|
100
|
+
|
|
101
|
+
- ⚠️ official backend depends on openapi-generator-cli staying stable
|
|
102
|
+
- ⚠️ Must parse TypeScript (additional complexity)
|
|
103
|
+
- ⚠️ Two-step process (slower than direct)
|
|
104
|
+
|
|
105
|
+
### 2. Wrapper Pattern
|
|
106
|
+
|
|
107
|
+
**Problem**: Want to add features (callbacks, auth) without modifying generated code.
|
|
108
|
+
|
|
109
|
+
**Solution**: Wrap native Nuxt composables with our enhanced version.
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
// Generated composable (auto-regenerated)
|
|
113
|
+
export const useFetchAddPet = (
|
|
114
|
+
params: MaybeRef<AddPetRequest>,
|
|
115
|
+
options?: ApiRequestOptions<Pet>
|
|
116
|
+
) => {
|
|
117
|
+
const p = isRef(params) ? params : shallowRef(params);
|
|
118
|
+
return useApiRequest<Pet>(() => `/pet`, {
|
|
119
|
+
method: 'POST',
|
|
120
|
+
body: computed(() => p.value.pet),
|
|
121
|
+
...options,
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// Our wrapper (user-modifiable)
|
|
126
|
+
export function useApiRequest<T>(url: string | (() => string), options?: ApiRequestOptions<T>) {
|
|
127
|
+
const result = useFetch<T>(url, options);
|
|
128
|
+
// Add: callbacks, auth, transforms, etc.
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Benefits**:
|
|
134
|
+
|
|
135
|
+
- ✅ Generated code stays simple
|
|
136
|
+
- ✅ Features in one place (DRY)
|
|
137
|
+
- ✅ Easy to extend without regeneration
|
|
138
|
+
- ✅ Users can customize wrappers
|
|
139
|
+
|
|
140
|
+
**Trade-offs**:
|
|
141
|
+
|
|
142
|
+
- ⚠️ Extra function call (negligible overhead)
|
|
143
|
+
- ⚠️ Wrapper logic applies to all endpoints
|
|
144
|
+
|
|
145
|
+
### 3. Shared Code Architecture
|
|
146
|
+
|
|
147
|
+
**Problem**: Multiple generators (useFetch, useAsyncData, nuxt-server) duplicate logic.
|
|
148
|
+
|
|
149
|
+
**Solution**: Extract common code to `shared/` folder.
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
generators/
|
|
153
|
+
shared/
|
|
154
|
+
types.ts # MethodInfo interface (all generators use)
|
|
155
|
+
runtime/
|
|
156
|
+
apiHelpers.ts # Callbacks, auth, transforms (all wrappers use)
|
|
157
|
+
use-fetch/
|
|
158
|
+
parser.ts # Re-exported from shared
|
|
159
|
+
templates.ts # Specific to useFetch
|
|
160
|
+
use-async-data/
|
|
161
|
+
parser.ts # Re-exported from shared
|
|
162
|
+
templates.ts # Specific to useAsyncData
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Benefits**:
|
|
166
|
+
|
|
167
|
+
- ✅ Single source of truth
|
|
168
|
+
- ✅ Bug fixes apply everywhere
|
|
169
|
+
- ✅ Easier to add new generators
|
|
170
|
+
|
|
171
|
+
**Trade-offs**:
|
|
172
|
+
|
|
173
|
+
- ⚠️ Changes affect all generators
|
|
174
|
+
- ⚠️ Must maintain backward compatibility
|
|
175
|
+
|
|
176
|
+
### 4. Template-Based Code Generation
|
|
177
|
+
|
|
178
|
+
**Problem**: Generating code programmatically is error-prone with string concatenation.
|
|
179
|
+
|
|
180
|
+
**Solution**: Use template functions that interpolate variables.
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
function generateFunctionBody(method: MethodInfo): string {
|
|
184
|
+
return `export const ${method.composableName} = (
|
|
185
|
+
params: MaybeRef<${method.requestType}>,
|
|
186
|
+
options?: ApiRequestOptions<${method.responseType}>
|
|
187
|
+
) => {
|
|
188
|
+
const p = isRef(params) ? params : shallowRef(params)
|
|
189
|
+
return useApiRequest<${method.responseType}>(
|
|
190
|
+
() => \`${method.path}\`,
|
|
191
|
+
{ method: '${method.method}', body: computed(() => p.value.${method.bodyField}), ...options }
|
|
192
|
+
)
|
|
193
|
+
}`;
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Benefits**:
|
|
198
|
+
|
|
199
|
+
- ✅ Easier to read/maintain
|
|
200
|
+
- ✅ Clear what's generated
|
|
201
|
+
- ✅ Can format with Prettier
|
|
202
|
+
|
|
203
|
+
**Trade-offs**:
|
|
204
|
+
|
|
205
|
+
- ⚠️ Escaping can be tricky
|
|
206
|
+
- ⚠️ Template strings can get long
|
|
207
|
+
|
|
208
|
+
### 5. Copy vs Import Pattern (Runtime Files)
|
|
209
|
+
|
|
210
|
+
**Problem**: How do users get runtime code (wrappers, helpers)?
|
|
211
|
+
|
|
212
|
+
**Option A**: Import from our npm package
|
|
213
|
+
**Option B**: Copy files to user's project
|
|
214
|
+
|
|
215
|
+
**Decision**: **Copy files** (Option B)
|
|
216
|
+
|
|
217
|
+
**Rationale**:
|
|
218
|
+
|
|
219
|
+
- ✅ Zero runtime dependencies
|
|
220
|
+
- ✅ Users can customize wrappers
|
|
221
|
+
- ✅ Works with any Nuxt setup
|
|
222
|
+
- ✅ No version conflicts
|
|
223
|
+
- ✅ Framework agnostic
|
|
224
|
+
|
|
225
|
+
**Trade-offs**:
|
|
226
|
+
|
|
227
|
+
- ⚠️ File duplication
|
|
228
|
+
- ⚠️ Updates require regeneration
|
|
229
|
+
- ⚠️ User modifications can break things
|
|
230
|
+
|
|
231
|
+
**Implementation**: Use `fs.copy()` to copy `runtime/` files to output.
|
|
232
|
+
|
|
233
|
+
### 6. Global Callbacks System
|
|
234
|
+
|
|
235
|
+
**Problem**: Repeating same callbacks (auth, error handling) on every API call.
|
|
236
|
+
|
|
237
|
+
**Solution**: Plugin-based global callbacks with 3 control options.
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
// Define once in plugin
|
|
241
|
+
export default defineNuxtPlugin(() => ({
|
|
242
|
+
provide: {
|
|
243
|
+
getGlobalApiCallbacks: () => ({
|
|
244
|
+
onRequest: (ctx) => {
|
|
245
|
+
/* Add auth header to all requests */
|
|
246
|
+
},
|
|
247
|
+
onError: (error) => {
|
|
248
|
+
/* Handle 401/500 errors globally */
|
|
249
|
+
},
|
|
250
|
+
}),
|
|
251
|
+
},
|
|
252
|
+
}));
|
|
253
|
+
|
|
254
|
+
// Control per-call
|
|
255
|
+
useFetchGetPet({ petId: 123 }, {
|
|
256
|
+
skipGlobalCallbacks: true, // Option 1: Disable
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// Or in global callback
|
|
260
|
+
onError: (error) => {
|
|
261
|
+
if (error.status >= 500) return false; // Option 2: Cancel local
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
// Or with patterns
|
|
265
|
+
{
|
|
266
|
+
patterns: ['/api/auth/**'], // Option 3: URL matching
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
See [Global Callbacks Deep Dive](#global-callbacks-deep-dive) below.
|
|
271
|
+
|
|
272
|
+
## Design Decisions (ADRs)
|
|
273
|
+
|
|
274
|
+
### ADR-001: Use ts-morph Instead of Regex
|
|
275
|
+
|
|
276
|
+
**Context**: Need to parse generated TypeScript to extract API info.
|
|
277
|
+
|
|
278
|
+
**Decision**: Use ts-morph library for TypeScript AST parsing.
|
|
279
|
+
|
|
280
|
+
**Alternatives Considered**:
|
|
281
|
+
|
|
282
|
+
- ❌ Regex: Too fragile, can't handle complex syntax
|
|
283
|
+
- ❌ Babel: Wrong target (designed for JS, not TS)
|
|
284
|
+
- ❌ TypeScript Compiler API: Too low-level
|
|
285
|
+
|
|
286
|
+
**Rationale**:
|
|
287
|
+
|
|
288
|
+
- ✅ Type-aware parsing
|
|
289
|
+
- ✅ Handles complex TypeScript syntax
|
|
290
|
+
- ✅ Provides semantic information
|
|
291
|
+
- ✅ Less brittle than regex
|
|
292
|
+
- ✅ Good documentation
|
|
293
|
+
|
|
294
|
+
**Trade-offs**:
|
|
295
|
+
|
|
296
|
+
- ⚠️ Dependency on ts-morph (large library)
|
|
297
|
+
- ⚠️ AST navigation can be complex
|
|
298
|
+
|
|
299
|
+
**Status**: ✅ Accepted (v1.0)
|
|
300
|
+
|
|
301
|
+
**Date**: Initial design
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
### ADR-002: Copy Runtime Files Instead of NPM Package
|
|
306
|
+
|
|
307
|
+
**Context**: Users need runtime code (wrappers, helpers) in their Nuxt project.
|
|
308
|
+
|
|
309
|
+
**Decision**: Copy runtime files to user's project instead of npm import.
|
|
310
|
+
|
|
311
|
+
**Alternatives Considered**:
|
|
312
|
+
|
|
313
|
+
- ❌ Import from npm: `import { useApiRequest } from 'nuxt-generator/runtime'`
|
|
314
|
+
- ❌ Virtual modules: Nuxt module that provides runtime
|
|
315
|
+
|
|
316
|
+
**Rationale**:
|
|
317
|
+
|
|
318
|
+
- ✅ **Zero dependencies**: User doesn't need to install our package in production
|
|
319
|
+
- ✅ **Customizable**: Users can modify wrappers for their needs
|
|
320
|
+
- ✅ **Framework agnostic**: Works with any Nuxt setup
|
|
321
|
+
- ✅ **No version conflicts**: Each project has its own copy
|
|
322
|
+
- ✅ **Explicit**: Users see exactly what code runs
|
|
323
|
+
|
|
324
|
+
**Trade-offs**:
|
|
325
|
+
|
|
326
|
+
- ⚠️ File duplication across projects
|
|
327
|
+
- ⚠️ Updates require regeneration
|
|
328
|
+
- ⚠️ Users might break things with modifications
|
|
329
|
+
|
|
330
|
+
**Status**: ✅ Accepted (v1.0)
|
|
331
|
+
|
|
332
|
+
**Date**: Initial design
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
### ADR-003: @ts-nocheck in Runtime Files
|
|
337
|
+
|
|
338
|
+
**Context**: Runtime files are copied to user's Nuxt project with different TypeScript config.
|
|
339
|
+
|
|
340
|
+
**Decision**: Add `// @ts-nocheck` to all runtime files.
|
|
341
|
+
|
|
342
|
+
**Rationale**:
|
|
343
|
+
|
|
344
|
+
- ✅ Files run in user's project with different `tsconfig.json`
|
|
345
|
+
- ✅ May use different TS version
|
|
346
|
+
- ✅ Different strict mode settings
|
|
347
|
+
- ✅ CLI doesn't need to compile them
|
|
348
|
+
|
|
349
|
+
**Trade-offs**:
|
|
350
|
+
|
|
351
|
+
- ⚠️ No type checking in our development
|
|
352
|
+
- ⚠️ Potential bugs hidden
|
|
353
|
+
|
|
354
|
+
**Status**: ✅ Accepted (v1.2)
|
|
355
|
+
|
|
356
|
+
**Date**: After user reports of TS errors
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
### ADR-004: Dual Composables for useAsyncData (Normal + Raw)
|
|
361
|
+
|
|
362
|
+
**Context**: Some users need response headers/status, others just need data.
|
|
363
|
+
|
|
364
|
+
**Decision**: Generate both normal and raw versions when possible.
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
// Normal: Simple data access
|
|
368
|
+
const { data } = useAsyncDataGetPet({ petId: 123 });
|
|
369
|
+
// data: Ref<Pet>
|
|
370
|
+
|
|
371
|
+
// Raw: With headers/status
|
|
372
|
+
const { data } = useAsyncDataGetPetRaw({ petId: 123 });
|
|
373
|
+
// data: Ref<{ data: Pet, headers: Headers, status: number }>
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
**Rationale**:
|
|
377
|
+
|
|
378
|
+
- ✅ Covers both use cases
|
|
379
|
+
- ✅ Clean API for simple cases
|
|
380
|
+
- ✅ Power when needed (auth, rate limiting, caching)
|
|
381
|
+
|
|
382
|
+
**Trade-offs**:
|
|
383
|
+
|
|
384
|
+
- ⚠️ 2x composables generated (double the code)
|
|
385
|
+
- ⚠️ Users might be confused which to use
|
|
386
|
+
|
|
387
|
+
**Status**: ✅ Accepted (v1.3)
|
|
388
|
+
|
|
389
|
+
**Date**: When Raw support added
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
### ADR-005: Plugin Template Never Regenerated
|
|
394
|
+
|
|
395
|
+
**Context**: Global callbacks plugin needs user customization.
|
|
396
|
+
|
|
397
|
+
**Decision**: Copy plugin template once, never overwrite.
|
|
398
|
+
|
|
399
|
+
**Implementation**:
|
|
400
|
+
|
|
401
|
+
```typescript
|
|
402
|
+
if (await fs.pathExists(pluginPath)) {
|
|
403
|
+
return; // Already exists, don't overwrite
|
|
404
|
+
}
|
|
405
|
+
await fs.copy(templatePath, pluginPath);
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
**Rationale**:
|
|
409
|
+
|
|
410
|
+
- ✅ Preserves user customizations
|
|
411
|
+
- ✅ Clear ownership (user's file)
|
|
412
|
+
- ✅ Safe regeneration
|
|
413
|
+
|
|
414
|
+
**Trade-offs**:
|
|
415
|
+
|
|
416
|
+
- ⚠️ Updates to template don't apply automatically
|
|
417
|
+
- ⚠️ Users might not know it exists
|
|
418
|
+
|
|
419
|
+
**Status**: ✅ Accepted (v1.4)
|
|
420
|
+
|
|
421
|
+
**Date**: Global callbacks feature
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
### ADR-006: ESLint Flat Config for Modern Standards
|
|
426
|
+
|
|
427
|
+
**Context**: Need linting for maintainability and PR contributions.
|
|
428
|
+
|
|
429
|
+
**Decision**: Use ESLint v9+ flat config format.
|
|
430
|
+
|
|
431
|
+
**Rationale**:
|
|
432
|
+
|
|
433
|
+
- ✅ Future-proof (ESLint's new standard)
|
|
434
|
+
- ✅ Better TypeScript integration
|
|
435
|
+
- ✅ Simpler configuration
|
|
436
|
+
|
|
437
|
+
**Trade-offs**:
|
|
438
|
+
|
|
439
|
+
- ⚠️ Requires ESLint 9+ (breaking for some users)
|
|
440
|
+
|
|
441
|
+
**Status**: ✅ Accepted (v1.5)
|
|
442
|
+
|
|
443
|
+
**Date**: 2026-03-21
|
|
444
|
+
|
|
445
|
+
## Component Map
|
|
446
|
+
|
|
447
|
+
### Dependency Graph
|
|
448
|
+
|
|
449
|
+
```
|
|
450
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
451
|
+
│ CLI Entry (index.ts) │
|
|
452
|
+
│ Commands: generate, ... │
|
|
453
|
+
└────────────────────────┬─────────────────────────────────────┘
|
|
454
|
+
│
|
|
455
|
+
├─► generate.ts (OpenAPI Generator wrapper)
|
|
456
|
+
│
|
|
457
|
+
└─► generators/
|
|
458
|
+
│
|
|
459
|
+
├─► shared/
|
|
460
|
+
│ ├─ types.ts (MethodInfo, ApiClassInfo)
|
|
461
|
+
│ ├─ runtime/apiHelpers.ts (copied to output)
|
|
462
|
+
│ └─ templates/api-callbacks-plugin.ts (copied once)
|
|
463
|
+
│
|
|
464
|
+
├─► use-fetch/
|
|
465
|
+
│ ├─ parser.ts → shared/types.ts
|
|
466
|
+
│ ├─ templates.ts → parser.ts
|
|
467
|
+
│ ├─ generator.ts → parser.ts + templates.ts
|
|
468
|
+
│ └─ runtime/useApiRequest.ts → shared/runtime/
|
|
469
|
+
│
|
|
470
|
+
├─► use-async-data/
|
|
471
|
+
│ ├─ parser.ts (re-exports from use-fetch)
|
|
472
|
+
│ ├─ templates.ts → parser.ts
|
|
473
|
+
│ ├─ generator.ts → parser.ts + templates.ts
|
|
474
|
+
│ └─ runtime/
|
|
475
|
+
│ ├─ useApiAsyncData.ts → shared/runtime/
|
|
476
|
+
│ └─ useApiAsyncDataRaw.ts → shared/runtime/
|
|
477
|
+
│
|
|
478
|
+
└─► nuxt-server/
|
|
479
|
+
├─ parser.ts (re-exports from use-fetch)
|
|
480
|
+
├─ templates.ts
|
|
481
|
+
├─ bff-templates.ts (auth + transformers)
|
|
482
|
+
└─ generator.ts → templates + bff-templates
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### Information Flow
|
|
486
|
+
|
|
487
|
+
```
|
|
488
|
+
swagger.yaml
|
|
489
|
+
│
|
|
490
|
+
▼
|
|
491
|
+
[OpenAPI Generator]
|
|
492
|
+
│
|
|
493
|
+
├─► apis/PetApi.ts
|
|
494
|
+
├─► models/Pet.ts
|
|
495
|
+
└─► runtime.ts
|
|
496
|
+
│
|
|
497
|
+
▼
|
|
498
|
+
[Parser]
|
|
499
|
+
│
|
|
500
|
+
├─► MethodInfo {
|
|
501
|
+
│ name: 'addPet',
|
|
502
|
+
│ path: '/pet',
|
|
503
|
+
│ method: 'POST',
|
|
504
|
+
│ requestType: 'AddPetRequest',
|
|
505
|
+
│ responseType: 'Pet',
|
|
506
|
+
│ ...
|
|
507
|
+
│ }
|
|
508
|
+
│
|
|
509
|
+
▼
|
|
510
|
+
[Template Generator]
|
|
511
|
+
│
|
|
512
|
+
├─► useFetchAddPet.ts
|
|
513
|
+
├─► useFetchUpdatePet.ts
|
|
514
|
+
├─► ...
|
|
515
|
+
│
|
|
516
|
+
▼
|
|
517
|
+
[User's Nuxt Project]
|
|
518
|
+
│
|
|
519
|
+
├─► composables/use-fetch/ (composables)
|
|
520
|
+
├─► composables/shared/runtime/ (helpers)
|
|
521
|
+
└─► plugins/api-callbacks.ts (global config)
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
## Global Callbacks Deep Dive
|
|
525
|
+
|
|
526
|
+
### Architecture
|
|
527
|
+
|
|
528
|
+
```
|
|
529
|
+
┌────────────────────────────────────────────────────────────────┐
|
|
530
|
+
│ User's Nuxt Project │
|
|
531
|
+
├────────────────────────────────────────────────────────────────┤
|
|
532
|
+
│ │
|
|
533
|
+
│ plugins/api-callbacks.ts (NEVER regenerated) │
|
|
534
|
+
│ ┌──────────────────────────────────────────────────┐ │
|
|
535
|
+
│ │ defineNuxtPlugin(() => ({ │ │
|
|
536
|
+
│ │ provide: { │ │
|
|
537
|
+
│ │ getGlobalApiCallbacks: () => ({ │ │
|
|
538
|
+
│ │ patterns: ['/api/auth/**'], │ │
|
|
539
|
+
│ │ onRequest: (ctx) => { ... }, │ │
|
|
540
|
+
│ │ onSuccess: (data) => { ... }, │ │
|
|
541
|
+
│ │ onError: (error) => { ... } │ │
|
|
542
|
+
│ │ }) │ │
|
|
543
|
+
│ │ } │ │
|
|
544
|
+
│ │ })) │ │
|
|
545
|
+
│ └──────────────────────────────────────────────────┘ │
|
|
546
|
+
│ ↓ provide │
|
|
547
|
+
│ ┌──────────────────────────────────────────────────┐ │
|
|
548
|
+
│ │ nuxtApp.$getGlobalApiCallbacks() │ │
|
|
549
|
+
│ └──────────────────────────────────────────────────┘ │
|
|
550
|
+
│ ↓ called by │
|
|
551
|
+
│ ┌──────────────────────────────────────────────────┐ │
|
|
552
|
+
│ │ composables/shared/runtime/apiHelpers.ts │ │
|
|
553
|
+
│ │ - getGlobalCallbacks() │ │
|
|
554
|
+
│ │ - shouldApplyGlobalCallback() │ │
|
|
555
|
+
│ │ - mergeCallbacks() │ │
|
|
556
|
+
│ └──────────────────────────────────────────────────┘ │
|
|
557
|
+
│ ↓ used by │
|
|
558
|
+
│ ┌──────────────────────────────────────────────────┐ │
|
|
559
|
+
│ │ composables/use-fetch/runtime/useApiRequest.ts │ │
|
|
560
|
+
│ │ - Calls mergeCallbacks() │ │
|
|
561
|
+
│ │ - Executes merged callbacks in watch() │ │
|
|
562
|
+
│ └──────────────────────────────────────────────────┘ │
|
|
563
|
+
│ ↓ called by │
|
|
564
|
+
│ ┌──────────────────────────────────────────────────┐ │
|
|
565
|
+
│ │ composables/use-fetch/useFetchAddPet.ts │ │
|
|
566
|
+
│ │ (Generated - CAN be regenerated safely) │ │
|
|
567
|
+
│ └──────────────────────────────────────────────────┘ │
|
|
568
|
+
│ │
|
|
569
|
+
└────────────────────────────────────────────────────────────────┘
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
### Execution Flow
|
|
573
|
+
|
|
574
|
+
```
|
|
575
|
+
User calls: useFetchGetPet({ petId: 123 }, { onSuccess: localCallback })
|
|
576
|
+
│
|
|
577
|
+
▼
|
|
578
|
+
useApiRequest(url, options)
|
|
579
|
+
│
|
|
580
|
+
├─► Extract: skipGlobalCallbacks from options
|
|
581
|
+
│
|
|
582
|
+
├─► Call: mergeCallbacks(url, localCallbacks, skipGlobalCallbacks)
|
|
583
|
+
│ │
|
|
584
|
+
│ ├─► getGlobalCallbacks() → reads nuxtApp.$getGlobalApiCallbacks()
|
|
585
|
+
│ │
|
|
586
|
+
│ ├─► For each callback type (onRequest, onSuccess, onError, onFinish):
|
|
587
|
+
│ │ │
|
|
588
|
+
│ │ ├─► shouldApplyGlobalCallback(name, skipConfig, url, patterns)
|
|
589
|
+
│ │ │ │
|
|
590
|
+
│ │ │ ├─► Check skipConfig: true / array?
|
|
591
|
+
│ │ │ ├─► Match URL against patterns
|
|
592
|
+
│ │ │ └─► Return: boolean
|
|
593
|
+
│ │ │
|
|
594
|
+
│ │ └─► Create merged function:
|
|
595
|
+
│ │ (args) => {
|
|
596
|
+
│ │ if (global && shouldApply) {
|
|
597
|
+
│ │ result = global(args);
|
|
598
|
+
│ │ if (result === false) return; // Cancel local
|
|
599
|
+
│ │ }
|
|
600
|
+
│ │ if (local) local(args);
|
|
601
|
+
│ │ }
|
|
602
|
+
│ │
|
|
603
|
+
│ └─► Return: { onRequest, onSuccess, onError, onFinish }
|
|
604
|
+
│
|
|
605
|
+
├─► useFetch(url, options)
|
|
606
|
+
│
|
|
607
|
+
└─► watch(data/error/pending) → Execute merged callbacks
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
## Extension Points
|
|
611
|
+
|
|
612
|
+
### Want to add a new callback?
|
|
613
|
+
|
|
614
|
+
**Files to modify**:
|
|
615
|
+
|
|
616
|
+
1. `src/generators/shared/runtime/apiHelpers.ts`
|
|
617
|
+
- Add to `GlobalCallbacksConfig` interface
|
|
618
|
+
- Update `mergeCallbacks()` function
|
|
619
|
+
2. `src/generators/use-fetch/runtime/useApiRequest.ts`
|
|
620
|
+
- Add callback execution in `watch()`
|
|
621
|
+
3. `src/generators/use-async-data/runtime/useApiAsyncData.ts`
|
|
622
|
+
- Add callback execution in try/catch/finally
|
|
623
|
+
4. `src/generators/shared/templates/api-callbacks-plugin.ts`
|
|
624
|
+
- Add examples and documentation
|
|
625
|
+
5. `docs/API-REFERENCE.md`
|
|
626
|
+
- Document the new callback
|
|
627
|
+
|
|
628
|
+
### Want to add a new generator?
|
|
629
|
+
|
|
630
|
+
**Steps**:
|
|
631
|
+
|
|
632
|
+
1. Copy `src/generators/use-fetch/` → `src/generators/your-generator/`
|
|
633
|
+
2. Modify `templates.ts` for your output format
|
|
634
|
+
3. Create/modify `runtime/` wrapper for your needs
|
|
635
|
+
4. Update `src/index.ts` to add CLI choice
|
|
636
|
+
5. Test: `npm run build && node dist/index.js generate`
|
|
637
|
+
|
|
638
|
+
### Want to add parser feature?
|
|
639
|
+
|
|
640
|
+
**Steps**:
|
|
641
|
+
|
|
642
|
+
1. Edit `src/generators/shared/types.ts` - Add field to `MethodInfo`
|
|
643
|
+
2. Edit `src/generators/use-fetch/parser.ts` - Extract from AST
|
|
644
|
+
3. Edit `src/generators/*/templates.ts` - Use in generation
|
|
645
|
+
4. Test with complex OpenAPI spec
|
|
646
|
+
|
|
647
|
+
---
|
|
648
|
+
|
|
649
|
+
**Next**: [API Reference](./API-REFERENCE.md) | [Development Guide](./DEVELOPMENT.md)
|