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.
Files changed (109) hide show
  1. package/.editorconfig +26 -0
  2. package/.prettierignore +17 -0
  3. package/.prettierrc.json +12 -0
  4. package/CONTRIBUTING.md +292 -0
  5. package/INSTRUCTIONS.md +327 -0
  6. package/LICENSE +202 -0
  7. package/README.md +202 -0
  8. package/dist/cli/config.d.ts +57 -0
  9. package/dist/cli/config.js +85 -0
  10. package/dist/cli/logger.d.ts +44 -0
  11. package/dist/cli/logger.js +58 -0
  12. package/dist/cli/logo.d.ts +6 -0
  13. package/dist/cli/logo.js +21 -0
  14. package/dist/cli/messages.d.ts +65 -0
  15. package/dist/cli/messages.js +86 -0
  16. package/dist/cli/prompts.d.ts +30 -0
  17. package/dist/cli/prompts.js +118 -0
  18. package/dist/cli/types.d.ts +43 -0
  19. package/dist/cli/types.js +4 -0
  20. package/dist/cli/utils.d.ts +26 -0
  21. package/dist/cli/utils.js +45 -0
  22. package/dist/generate.d.ts +6 -0
  23. package/dist/generate.js +48 -0
  24. package/dist/generators/nuxt-server/bff-templates.d.ts +25 -0
  25. package/dist/generators/nuxt-server/bff-templates.js +737 -0
  26. package/dist/generators/nuxt-server/generator.d.ts +7 -0
  27. package/dist/generators/nuxt-server/generator.js +206 -0
  28. package/dist/generators/nuxt-server/parser.d.ts +5 -0
  29. package/dist/generators/nuxt-server/parser.js +5 -0
  30. package/dist/generators/nuxt-server/templates.d.ts +35 -0
  31. package/dist/generators/nuxt-server/templates.js +412 -0
  32. package/dist/generators/nuxt-server/types.d.ts +5 -0
  33. package/dist/generators/nuxt-server/types.js +5 -0
  34. package/dist/generators/shared/parsers/heyapi-parser.d.ts +11 -0
  35. package/dist/generators/shared/parsers/heyapi-parser.js +248 -0
  36. package/dist/generators/shared/parsers/official-parser.d.ts +5 -0
  37. package/dist/generators/shared/parsers/official-parser.js +5 -0
  38. package/dist/generators/shared/runtime/apiHelpers.d.ts +183 -0
  39. package/dist/generators/shared/runtime/apiHelpers.js +268 -0
  40. package/dist/generators/shared/templates/api-callbacks-plugin.d.ts +178 -0
  41. package/dist/generators/shared/templates/api-callbacks-plugin.js +338 -0
  42. package/dist/generators/shared/types.d.ts +25 -0
  43. package/dist/generators/shared/types.js +4 -0
  44. package/dist/generators/tanstack-query/generator.d.ts +5 -0
  45. package/dist/generators/tanstack-query/generator.js +11 -0
  46. package/dist/generators/use-async-data/generator.d.ts +5 -0
  47. package/dist/generators/use-async-data/generator.js +156 -0
  48. package/dist/generators/use-async-data/parser.d.ts +5 -0
  49. package/dist/generators/use-async-data/parser.js +5 -0
  50. package/dist/generators/use-async-data/runtime/useApiAsyncData.d.ts +38 -0
  51. package/dist/generators/use-async-data/runtime/useApiAsyncData.js +122 -0
  52. package/dist/generators/use-async-data/runtime/useApiAsyncDataRaw.d.ts +54 -0
  53. package/dist/generators/use-async-data/runtime/useApiAsyncDataRaw.js +126 -0
  54. package/dist/generators/use-async-data/templates.d.ts +20 -0
  55. package/dist/generators/use-async-data/templates.js +191 -0
  56. package/dist/generators/use-async-data/types.d.ts +4 -0
  57. package/dist/generators/use-async-data/types.js +4 -0
  58. package/dist/generators/use-fetch/generator.d.ts +5 -0
  59. package/dist/generators/use-fetch/generator.js +131 -0
  60. package/dist/generators/use-fetch/parser.d.ts +9 -0
  61. package/dist/generators/use-fetch/parser.js +282 -0
  62. package/dist/generators/use-fetch/runtime/useApiRequest.d.ts +46 -0
  63. package/dist/generators/use-fetch/runtime/useApiRequest.js +158 -0
  64. package/dist/generators/use-fetch/templates.d.ts +16 -0
  65. package/dist/generators/use-fetch/templates.js +169 -0
  66. package/dist/generators/use-fetch/types.d.ts +5 -0
  67. package/dist/generators/use-fetch/types.js +5 -0
  68. package/dist/index.d.ts +2 -0
  69. package/dist/index.js +213 -0
  70. package/docs/API-REFERENCE.md +887 -0
  71. package/docs/ARCHITECTURE.md +649 -0
  72. package/docs/DEVELOPMENT.md +918 -0
  73. package/docs/QUICK-START.md +323 -0
  74. package/docs/README.md +155 -0
  75. package/docs/TROUBLESHOOTING.md +881 -0
  76. package/eslint.config.js +72 -0
  77. package/package.json +65 -0
  78. package/src/cli/config.ts +140 -0
  79. package/src/cli/logger.ts +66 -0
  80. package/src/cli/logo.ts +25 -0
  81. package/src/cli/messages.ts +97 -0
  82. package/src/cli/prompts.ts +143 -0
  83. package/src/cli/types.ts +50 -0
  84. package/src/cli/utils.ts +49 -0
  85. package/src/generate.ts +57 -0
  86. package/src/generators/nuxt-server/bff-templates.ts +754 -0
  87. package/src/generators/nuxt-server/generator.ts +270 -0
  88. package/src/generators/nuxt-server/parser.ts +5 -0
  89. package/src/generators/nuxt-server/templates.ts +483 -0
  90. package/src/generators/nuxt-server/types.ts +5 -0
  91. package/src/generators/shared/parsers/heyapi-parser.ts +307 -0
  92. package/src/generators/shared/parsers/official-parser.ts +5 -0
  93. package/src/generators/shared/runtime/apiHelpers.ts +466 -0
  94. package/src/generators/shared/templates/api-callbacks-plugin.ts +352 -0
  95. package/src/generators/shared/types.ts +27 -0
  96. package/src/generators/tanstack-query/generator.ts +11 -0
  97. package/src/generators/use-async-data/generator.ts +204 -0
  98. package/src/generators/use-async-data/parser.ts +5 -0
  99. package/src/generators/use-async-data/runtime/useApiAsyncData.ts +220 -0
  100. package/src/generators/use-async-data/runtime/useApiAsyncDataRaw.ts +236 -0
  101. package/src/generators/use-async-data/templates.ts +250 -0
  102. package/src/generators/use-async-data/types.ts +4 -0
  103. package/src/generators/use-fetch/generator.ts +169 -0
  104. package/src/generators/use-fetch/parser.ts +341 -0
  105. package/src/generators/use-fetch/runtime/useApiRequest.ts +223 -0
  106. package/src/generators/use-fetch/templates.ts +214 -0
  107. package/src/generators/use-fetch/types.ts +5 -0
  108. package/src/index.ts +265 -0
  109. package/tsconfig.json +15 -0
@@ -0,0 +1,466 @@
1
+ // @ts-nocheck - This file runs in user's Nuxt project with different TypeScript config
2
+ /**
3
+ * Shared API Helpers - Used by both useFetch and useAsyncData wrappers
4
+ * This file contains common logic for callbacks, transforms, and global configuration
5
+ */
6
+
7
+ /**
8
+ * Context provided to onRequest interceptor
9
+ */
10
+ export interface RequestContext {
11
+ /** Request URL */
12
+ url: string;
13
+ /** HTTP method */
14
+ method: string;
15
+ /** Request body (if any) */
16
+ body?: any;
17
+ /** Request headers */
18
+ headers?: Record<string, string>;
19
+ /** Query parameters */
20
+ query?: Record<string, any>;
21
+ }
22
+
23
+ /**
24
+ * Modified context that can be returned from onRequest
25
+ */
26
+ export interface ModifiedRequestContext {
27
+ /** Modified request body */
28
+ body?: any;
29
+ /** Modified request headers */
30
+ headers?: Record<string, string>;
31
+ /** Modified query parameters */
32
+ query?: Record<string, any>;
33
+ }
34
+
35
+ /**
36
+ * Result context provided to onFinish callback
37
+ */
38
+ export interface FinishContext<T> {
39
+ /** Response data (if successful) */
40
+ data?: T;
41
+ /** Error (if failed) */
42
+ error?: any;
43
+ /** Whether the request was successful */
44
+ success: boolean;
45
+ }
46
+
47
+ /**
48
+ * Global callbacks configuration
49
+ * Can be provided via Nuxt plugin: $getGlobalApiCallbacks
50
+ */
51
+ export interface GlobalCallbacksConfig {
52
+ /**
53
+ * Optional URL patterns to match (Opción 3)
54
+ * Only apply global callbacks to URLs matching these patterns
55
+ * Supports wildcards: '/api/**', '/api/public/*', etc.
56
+ * If omitted, callbacks apply to all requests
57
+ */
58
+ patterns?: string[];
59
+
60
+ /**
61
+ * Called before every request matching patterns
62
+ * Return false to prevent local callback execution (Opción 2)
63
+ * Return modified context to change request
64
+ */
65
+ onRequest?: (
66
+ context: RequestContext
67
+ ) =>
68
+ | void
69
+ | Promise<void>
70
+ | ModifiedRequestContext
71
+ | Promise<ModifiedRequestContext>
72
+ | boolean
73
+ | Promise<boolean>;
74
+
75
+ /**
76
+ * Called when request succeeds
77
+ * Return false to prevent local callback execution (Opción 2)
78
+ */
79
+ onSuccess?: (data: any, context?: any) => void | Promise<void> | boolean | Promise<boolean>;
80
+
81
+ /**
82
+ * Called when request fails
83
+ * Return false to prevent local callback execution (Opción 2)
84
+ */
85
+ onError?: (error: any, context?: any) => void | Promise<void> | boolean | Promise<boolean>;
86
+
87
+ /**
88
+ * Called when request finishes (success or error)
89
+ * Return false to prevent local callback execution (Opción 2)
90
+ */
91
+ onFinish?: (context: FinishContext<any>) => void | Promise<void> | boolean | Promise<boolean>;
92
+ }
93
+
94
+ /**
95
+ * Type for skipGlobalCallbacks option (Opción 1)
96
+ * - true: skip all global callbacks
97
+ * - array: skip specific callbacks by name
98
+ */
99
+ export type SkipGlobalCallbacks =
100
+ | boolean
101
+ | Array<'onRequest' | 'onSuccess' | 'onError' | 'onFinish'>;
102
+
103
+ /**
104
+ * Base options for API requests with lifecycle callbacks
105
+ * This is extended by specific wrapper options (useFetch, useAsyncData)
106
+ */
107
+ export interface ApiRequestOptions<T = any> {
108
+ /**
109
+ * Called before the request is sent - can be used as an interceptor
110
+ * Return modified body/headers to transform the request
111
+ */
112
+ onRequest?: (
113
+ context: RequestContext
114
+ ) => void | Promise<void> | ModifiedRequestContext | Promise<ModifiedRequestContext>;
115
+
116
+ /** Called when the request succeeds with data (after transform/pick if provided) */
117
+ onSuccess?: (data: any) => void | Promise<void>;
118
+
119
+ /** Called when the request fails with an error */
120
+ onError?: (error: any) => void | Promise<void>;
121
+
122
+ /** Called when the request finishes (success or error) with result context */
123
+ onFinish?: (context: FinishContext<any>) => void | Promise<void>;
124
+
125
+ /**
126
+ * Skip global callbacks for this specific request (Opción 1)
127
+ * - true: skip all global callbacks
128
+ * - ['onSuccess', 'onError']: skip specific callbacks
129
+ * - false/undefined: use global callbacks (default)
130
+ * @example
131
+ * skipGlobalCallbacks: true // Skip all global callbacks
132
+ * skipGlobalCallbacks: ['onSuccess'] // Skip only global onSuccess
133
+ */
134
+ skipGlobalCallbacks?: SkipGlobalCallbacks;
135
+
136
+ /**
137
+ * Transform the response data
138
+ * @example
139
+ * transform: (pet) => ({ displayName: pet.name, isAvailable: pet.status === 'available' })
140
+ */
141
+ transform?: (data: T) => any;
142
+
143
+ /**
144
+ * Pick specific keys from the response (applied before transform)
145
+ * Supports dot notation for nested paths
146
+ * @example
147
+ * pick: ['id', 'name'] as const
148
+ * pick: ['person.name', 'person.email', 'status']
149
+ */
150
+ pick?: ReadonlyArray<string>;
151
+ }
152
+
153
+ /**
154
+ * Helper function to apply request modifications from onRequest interceptor
155
+ */
156
+ export function applyRequestModifications(
157
+ options: Record<string, any>,
158
+ modifications: ModifiedRequestContext
159
+ ): void {
160
+ if (modifications.body !== undefined) {
161
+ options.body = modifications.body;
162
+ }
163
+ if (modifications.headers !== undefined) {
164
+ options.headers = {
165
+ ...options.headers,
166
+ ...modifications.headers,
167
+ };
168
+ }
169
+ if (modifications.query !== undefined) {
170
+ options.query = {
171
+ ...options.query,
172
+ ...modifications.query,
173
+ };
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Helper function to pick specific keys from an object
179
+ * Supports dot notation for nested paths (e.g., 'person.name')
180
+ */
181
+ export function applyPick<T>(data: T, paths: ReadonlyArray<string>): any {
182
+ const result: any = {};
183
+
184
+ for (const path of paths) {
185
+ const keys = path.split('.');
186
+
187
+ // Navigate to the nested value
188
+ let value: any = data;
189
+ let exists = true;
190
+
191
+ for (const key of keys) {
192
+ if (value && typeof value === 'object' && key in value) {
193
+ value = value[key];
194
+ } else {
195
+ exists = false;
196
+ break;
197
+ }
198
+ }
199
+
200
+ // Set the value in the result, maintaining nested structure
201
+ if (exists) {
202
+ let current = result;
203
+ for (let i = 0; i < keys.length - 1; i++) {
204
+ const key = keys[i];
205
+ if (!(key in current)) {
206
+ current[key] = {};
207
+ }
208
+ current = current[key];
209
+ }
210
+ current[keys[keys.length - 1]] = value;
211
+ }
212
+ }
213
+
214
+ return result;
215
+ }
216
+
217
+ /**
218
+ * Helper function to get global headers from user configuration
219
+ * Supports two methods:
220
+ * 1. Auto-imported composable: composables/useApiHeaders.ts
221
+ * 2. Nuxt plugin provide: plugins/api-config.ts with $getApiHeaders
222
+ */
223
+ export function getGlobalHeaders(): Record<string, string> {
224
+ let headers: Record<string, string> = {};
225
+
226
+ // Method 1: Try to use auto-imported composable (useApiHeaders)
227
+ try {
228
+ // @ts-ignore - useApiHeaders may or may not exist (user-defined)
229
+ if (typeof useApiHeaders !== 'undefined') {
230
+ // @ts-ignore
231
+ const getHeaders = useApiHeaders();
232
+ if (getHeaders) {
233
+ const h = typeof getHeaders === 'function' ? getHeaders() : getHeaders;
234
+ if (h && typeof h === 'object') {
235
+ headers = { ...headers, ...h };
236
+ }
237
+ }
238
+ }
239
+ } catch (e) {
240
+ // useApiHeaders doesn't exist or failed, that's OK
241
+ }
242
+
243
+ // Method 2: Try to use Nuxt App plugin ($getApiHeaders)
244
+ try {
245
+ const nuxtApp = useNuxtApp();
246
+ // @ts-ignore - $getApiHeaders may or may not exist (user-defined)
247
+ if (nuxtApp.$getApiHeaders) {
248
+ // @ts-ignore
249
+ const h = nuxtApp.$getApiHeaders();
250
+ if (h && typeof h === 'object') {
251
+ headers = { ...headers, ...h };
252
+ }
253
+ }
254
+ } catch (e) {
255
+ // useNuxtApp not available or plugin not configured, that's OK
256
+ }
257
+
258
+ return headers;
259
+ }
260
+
261
+ /**
262
+ * Helper function to get global callbacks from user configuration
263
+ * Uses Nuxt plugin provide: plugins/api-callbacks.ts with $getGlobalApiCallbacks
264
+ */
265
+ export function getGlobalCallbacks(): GlobalCallbacksConfig {
266
+ try {
267
+ const nuxtApp = useNuxtApp();
268
+ // @ts-ignore - $getGlobalApiCallbacks may or may not exist (user-defined)
269
+ if (nuxtApp.$getGlobalApiCallbacks) {
270
+ // @ts-ignore
271
+ const callbacks = nuxtApp.$getGlobalApiCallbacks();
272
+ if (callbacks && typeof callbacks === 'object') {
273
+ return callbacks;
274
+ }
275
+ }
276
+ } catch (e) {
277
+ // useNuxtApp not available or plugin not configured, that's OK
278
+ }
279
+
280
+ return {};
281
+ }
282
+
283
+ /**
284
+ * Check if a global callback should be applied to a specific request
285
+ * Implements Opción 1 (skipGlobalCallbacks) and Opción 3 (pattern matching)
286
+ */
287
+ export function shouldApplyGlobalCallback(
288
+ url: string,
289
+ callbackName: 'onRequest' | 'onSuccess' | 'onError' | 'onFinish',
290
+ patterns?: string[],
291
+ skipConfig?: SkipGlobalCallbacks
292
+ ): boolean {
293
+ // Opción 1: Check if callback is skipped via skipGlobalCallbacks
294
+ if (skipConfig === true) {
295
+ return false; // Skip all global callbacks
296
+ }
297
+
298
+ if (Array.isArray(skipConfig) && skipConfig.includes(callbackName)) {
299
+ return false; // Skip this specific callback
300
+ }
301
+
302
+ // Opción 3: Check pattern matching
303
+ if (patterns && patterns.length > 0) {
304
+ return patterns.some((pattern) => {
305
+ // Convert glob pattern to regex
306
+ // ** matches any characters including /
307
+ // * matches any characters except /
308
+ const regexPattern = pattern
309
+ .replace(/\*\*/g, '@@DOUBLE_STAR@@')
310
+ .replace(/\*/g, '[^/]*')
311
+ .replace(/@@DOUBLE_STAR@@/g, '.*');
312
+
313
+ const regex = new RegExp('^' + regexPattern + '$');
314
+ return regex.test(url);
315
+ });
316
+ }
317
+
318
+ // By default, apply global callback
319
+ return true;
320
+ }
321
+
322
+ /**
323
+ * Merge local and global callbacks with proper execution order
324
+ * Implements all 3 options:
325
+ * - Opción 1: skipGlobalCallbacks to disable global callbacks
326
+ * - Opción 2: global callbacks can return false to prevent local execution
327
+ * - Opción 3: pattern matching to apply callbacks only to matching URLs
328
+ */
329
+ export function mergeCallbacks(
330
+ url: string,
331
+ localCallbacks: {
332
+ onRequest?: Function;
333
+ onSuccess?: Function;
334
+ onError?: Function;
335
+ onFinish?: Function;
336
+ },
337
+ skipConfig?: SkipGlobalCallbacks
338
+ ) {
339
+ const global = getGlobalCallbacks();
340
+
341
+ return {
342
+ /**
343
+ * Merged onRequest callback
344
+ * Executes global first, then local
345
+ * Global can return modifications or false to cancel local
346
+ */
347
+ onRequest: async (ctx: RequestContext) => {
348
+ // Execute global onRequest
349
+ if (
350
+ shouldApplyGlobalCallback(url, 'onRequest', global.patterns, skipConfig) &&
351
+ global.onRequest
352
+ ) {
353
+ try {
354
+ const result = await global.onRequest(ctx);
355
+
356
+ // Opción 2: If global returns false, don't execute local
357
+ if (result === false) {
358
+ return;
359
+ }
360
+
361
+ // If global returns modified context, use it
362
+ if (result && typeof result === 'object' && !('then' in result)) {
363
+ return result;
364
+ }
365
+ } catch (error) {
366
+ console.error('Error in global onRequest callback:', error);
367
+ }
368
+ }
369
+
370
+ // Execute local onRequest
371
+ if (localCallbacks.onRequest) {
372
+ return await localCallbacks.onRequest(ctx);
373
+ }
374
+ },
375
+
376
+ /**
377
+ * Merged onSuccess callback
378
+ * Executes global first, then local (if global doesn't return false)
379
+ */
380
+ onSuccess: async (data: any, context?: any) => {
381
+ let continueLocal = true;
382
+
383
+ // Execute global onSuccess
384
+ if (
385
+ shouldApplyGlobalCallback(url, 'onSuccess', global.patterns, skipConfig) &&
386
+ global.onSuccess
387
+ ) {
388
+ try {
389
+ const result = await global.onSuccess(data, context);
390
+
391
+ // Opción 2: If global returns false, don't execute local
392
+ if (result === false) {
393
+ continueLocal = false;
394
+ }
395
+ } catch (error) {
396
+ console.error('Error in global onSuccess callback:', error);
397
+ }
398
+ }
399
+
400
+ // Execute local onSuccess (if not cancelled)
401
+ if (continueLocal && localCallbacks.onSuccess) {
402
+ await localCallbacks.onSuccess(data, context);
403
+ }
404
+ },
405
+
406
+ /**
407
+ * Merged onError callback
408
+ * Executes global first, then local (if global doesn't return false)
409
+ */
410
+ onError: async (error: any, context?: any) => {
411
+ let continueLocal = true;
412
+
413
+ // Execute global onError
414
+ if (
415
+ shouldApplyGlobalCallback(url, 'onError', global.patterns, skipConfig) &&
416
+ global.onError
417
+ ) {
418
+ try {
419
+ const result = await global.onError(error, context);
420
+
421
+ // Opción 2: If global returns false, don't execute local
422
+ if (result === false) {
423
+ continueLocal = false;
424
+ }
425
+ } catch (error) {
426
+ console.error('Error in global onError callback:', error);
427
+ }
428
+ }
429
+
430
+ // Execute local onError (if not cancelled)
431
+ if (continueLocal && localCallbacks.onError) {
432
+ await localCallbacks.onError(error, context);
433
+ }
434
+ },
435
+
436
+ /**
437
+ * Merged onFinish callback
438
+ * Executes global first, then local (if global doesn't return false)
439
+ */
440
+ onFinish: async (context: any) => {
441
+ let continueLocal = true;
442
+
443
+ // Execute global onFinish
444
+ if (
445
+ shouldApplyGlobalCallback(url, 'onFinish', global.patterns, skipConfig) &&
446
+ global.onFinish
447
+ ) {
448
+ try {
449
+ const result = await global.onFinish(context);
450
+
451
+ // Opción 2: If global returns false, don't execute local
452
+ if (result === false) {
453
+ continueLocal = false;
454
+ }
455
+ } catch (error) {
456
+ console.error('Error in global onFinish callback:', error);
457
+ }
458
+ }
459
+
460
+ // Execute local onFinish (if not cancelled)
461
+ if (continueLocal && localCallbacks.onFinish) {
462
+ await localCallbacks.onFinish(context);
463
+ }
464
+ },
465
+ };
466
+ }