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,268 @@
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
+ * Helper function to apply request modifications from onRequest interceptor
8
+ */
9
+ export function applyRequestModifications(options, modifications) {
10
+ if (modifications.body !== undefined) {
11
+ options.body = modifications.body;
12
+ }
13
+ if (modifications.headers !== undefined) {
14
+ options.headers = {
15
+ ...options.headers,
16
+ ...modifications.headers,
17
+ };
18
+ }
19
+ if (modifications.query !== undefined) {
20
+ options.query = {
21
+ ...options.query,
22
+ ...modifications.query,
23
+ };
24
+ }
25
+ }
26
+ /**
27
+ * Helper function to pick specific keys from an object
28
+ * Supports dot notation for nested paths (e.g., 'person.name')
29
+ */
30
+ export function applyPick(data, paths) {
31
+ const result = {};
32
+ for (const path of paths) {
33
+ const keys = path.split('.');
34
+ // Navigate to the nested value
35
+ let value = data;
36
+ let exists = true;
37
+ for (const key of keys) {
38
+ if (value && typeof value === 'object' && key in value) {
39
+ value = value[key];
40
+ }
41
+ else {
42
+ exists = false;
43
+ break;
44
+ }
45
+ }
46
+ // Set the value in the result, maintaining nested structure
47
+ if (exists) {
48
+ let current = result;
49
+ for (let i = 0; i < keys.length - 1; i++) {
50
+ const key = keys[i];
51
+ if (!(key in current)) {
52
+ current[key] = {};
53
+ }
54
+ current = current[key];
55
+ }
56
+ current[keys[keys.length - 1]] = value;
57
+ }
58
+ }
59
+ return result;
60
+ }
61
+ /**
62
+ * Helper function to get global headers from user configuration
63
+ * Supports two methods:
64
+ * 1. Auto-imported composable: composables/useApiHeaders.ts
65
+ * 2. Nuxt plugin provide: plugins/api-config.ts with $getApiHeaders
66
+ */
67
+ export function getGlobalHeaders() {
68
+ let headers = {};
69
+ // Method 1: Try to use auto-imported composable (useApiHeaders)
70
+ try {
71
+ // @ts-ignore - useApiHeaders may or may not exist (user-defined)
72
+ if (typeof useApiHeaders !== 'undefined') {
73
+ // @ts-ignore
74
+ const getHeaders = useApiHeaders();
75
+ if (getHeaders) {
76
+ const h = typeof getHeaders === 'function' ? getHeaders() : getHeaders;
77
+ if (h && typeof h === 'object') {
78
+ headers = { ...headers, ...h };
79
+ }
80
+ }
81
+ }
82
+ }
83
+ catch (e) {
84
+ // useApiHeaders doesn't exist or failed, that's OK
85
+ }
86
+ // Method 2: Try to use Nuxt App plugin ($getApiHeaders)
87
+ try {
88
+ const nuxtApp = useNuxtApp();
89
+ // @ts-ignore - $getApiHeaders may or may not exist (user-defined)
90
+ if (nuxtApp.$getApiHeaders) {
91
+ // @ts-ignore
92
+ const h = nuxtApp.$getApiHeaders();
93
+ if (h && typeof h === 'object') {
94
+ headers = { ...headers, ...h };
95
+ }
96
+ }
97
+ }
98
+ catch (e) {
99
+ // useNuxtApp not available or plugin not configured, that's OK
100
+ }
101
+ return headers;
102
+ }
103
+ /**
104
+ * Helper function to get global callbacks from user configuration
105
+ * Uses Nuxt plugin provide: plugins/api-callbacks.ts with $getGlobalApiCallbacks
106
+ */
107
+ export function getGlobalCallbacks() {
108
+ try {
109
+ const nuxtApp = useNuxtApp();
110
+ // @ts-ignore - $getGlobalApiCallbacks may or may not exist (user-defined)
111
+ if (nuxtApp.$getGlobalApiCallbacks) {
112
+ // @ts-ignore
113
+ const callbacks = nuxtApp.$getGlobalApiCallbacks();
114
+ if (callbacks && typeof callbacks === 'object') {
115
+ return callbacks;
116
+ }
117
+ }
118
+ }
119
+ catch (e) {
120
+ // useNuxtApp not available or plugin not configured, that's OK
121
+ }
122
+ return {};
123
+ }
124
+ /**
125
+ * Check if a global callback should be applied to a specific request
126
+ * Implements Opción 1 (skipGlobalCallbacks) and Opción 3 (pattern matching)
127
+ */
128
+ export function shouldApplyGlobalCallback(url, callbackName, patterns, skipConfig) {
129
+ // Opción 1: Check if callback is skipped via skipGlobalCallbacks
130
+ if (skipConfig === true) {
131
+ return false; // Skip all global callbacks
132
+ }
133
+ if (Array.isArray(skipConfig) && skipConfig.includes(callbackName)) {
134
+ return false; // Skip this specific callback
135
+ }
136
+ // Opción 3: Check pattern matching
137
+ if (patterns && patterns.length > 0) {
138
+ return patterns.some((pattern) => {
139
+ // Convert glob pattern to regex
140
+ // ** matches any characters including /
141
+ // * matches any characters except /
142
+ const regexPattern = pattern
143
+ .replace(/\*\*/g, '@@DOUBLE_STAR@@')
144
+ .replace(/\*/g, '[^/]*')
145
+ .replace(/@@DOUBLE_STAR@@/g, '.*');
146
+ const regex = new RegExp('^' + regexPattern + '$');
147
+ return regex.test(url);
148
+ });
149
+ }
150
+ // By default, apply global callback
151
+ return true;
152
+ }
153
+ /**
154
+ * Merge local and global callbacks with proper execution order
155
+ * Implements all 3 options:
156
+ * - Opción 1: skipGlobalCallbacks to disable global callbacks
157
+ * - Opción 2: global callbacks can return false to prevent local execution
158
+ * - Opción 3: pattern matching to apply callbacks only to matching URLs
159
+ */
160
+ export function mergeCallbacks(url, localCallbacks, skipConfig) {
161
+ const global = getGlobalCallbacks();
162
+ return {
163
+ /**
164
+ * Merged onRequest callback
165
+ * Executes global first, then local
166
+ * Global can return modifications or false to cancel local
167
+ */
168
+ onRequest: async (ctx) => {
169
+ // Execute global onRequest
170
+ if (shouldApplyGlobalCallback(url, 'onRequest', global.patterns, skipConfig) &&
171
+ global.onRequest) {
172
+ try {
173
+ const result = await global.onRequest(ctx);
174
+ // Opción 2: If global returns false, don't execute local
175
+ if (result === false) {
176
+ return;
177
+ }
178
+ // If global returns modified context, use it
179
+ if (result && typeof result === 'object' && !('then' in result)) {
180
+ return result;
181
+ }
182
+ }
183
+ catch (error) {
184
+ console.error('Error in global onRequest callback:', error);
185
+ }
186
+ }
187
+ // Execute local onRequest
188
+ if (localCallbacks.onRequest) {
189
+ return await localCallbacks.onRequest(ctx);
190
+ }
191
+ },
192
+ /**
193
+ * Merged onSuccess callback
194
+ * Executes global first, then local (if global doesn't return false)
195
+ */
196
+ onSuccess: async (data, context) => {
197
+ let continueLocal = true;
198
+ // Execute global onSuccess
199
+ if (shouldApplyGlobalCallback(url, 'onSuccess', global.patterns, skipConfig) &&
200
+ global.onSuccess) {
201
+ try {
202
+ const result = await global.onSuccess(data, context);
203
+ // Opción 2: If global returns false, don't execute local
204
+ if (result === false) {
205
+ continueLocal = false;
206
+ }
207
+ }
208
+ catch (error) {
209
+ console.error('Error in global onSuccess callback:', error);
210
+ }
211
+ }
212
+ // Execute local onSuccess (if not cancelled)
213
+ if (continueLocal && localCallbacks.onSuccess) {
214
+ await localCallbacks.onSuccess(data, context);
215
+ }
216
+ },
217
+ /**
218
+ * Merged onError callback
219
+ * Executes global first, then local (if global doesn't return false)
220
+ */
221
+ onError: async (error, context) => {
222
+ let continueLocal = true;
223
+ // Execute global onError
224
+ if (shouldApplyGlobalCallback(url, 'onError', global.patterns, skipConfig) &&
225
+ global.onError) {
226
+ try {
227
+ const result = await global.onError(error, context);
228
+ // Opción 2: If global returns false, don't execute local
229
+ if (result === false) {
230
+ continueLocal = false;
231
+ }
232
+ }
233
+ catch (error) {
234
+ console.error('Error in global onError callback:', error);
235
+ }
236
+ }
237
+ // Execute local onError (if not cancelled)
238
+ if (continueLocal && localCallbacks.onError) {
239
+ await localCallbacks.onError(error, context);
240
+ }
241
+ },
242
+ /**
243
+ * Merged onFinish callback
244
+ * Executes global first, then local (if global doesn't return false)
245
+ */
246
+ onFinish: async (context) => {
247
+ let continueLocal = true;
248
+ // Execute global onFinish
249
+ if (shouldApplyGlobalCallback(url, 'onFinish', global.patterns, skipConfig) &&
250
+ global.onFinish) {
251
+ try {
252
+ const result = await global.onFinish(context);
253
+ // Opción 2: If global returns false, don't execute local
254
+ if (result === false) {
255
+ continueLocal = false;
256
+ }
257
+ }
258
+ catch (error) {
259
+ console.error('Error in global onFinish callback:', error);
260
+ }
261
+ }
262
+ // Execute local onFinish (if not cancelled)
263
+ if (continueLocal && localCallbacks.onFinish) {
264
+ await localCallbacks.onFinish(context);
265
+ }
266
+ },
267
+ };
268
+ }
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Global API Callbacks Plugin
3
+ *
4
+ * ⚠️ IMPORTANT: This file is NEVER regenerated - your changes are safe!
5
+ *
6
+ * This plugin allows you to configure global callbacks for all API requests
7
+ * made with useFetch* and useAsyncData* composables.
8
+ *
9
+ * 📚 Three ways to control global callbacks:
10
+ *
11
+ * 1️⃣ OPTION 1: skipGlobalCallbacks (disable from the call)
12
+ * Skip global callbacks for specific requests
13
+ * Example:
14
+ * useFetchGetPets({ skipGlobalCallbacks: true })
15
+ * useFetchGetPets({ skipGlobalCallbacks: ['onSuccess'] })
16
+ *
17
+ * 2️⃣ OPTION 2: return false (disable from the plugin)
18
+ * Global callbacks can return false to prevent local callback execution
19
+ * Example:
20
+ * onError: (error) => {
21
+ * if (error.statusCode === 401) {
22
+ * navigateTo('/login');
23
+ * return false; // Don't execute local onError
24
+ * }
25
+ * }
26
+ *
27
+ * 3️⃣ OPTION 3: patterns (URL matching)
28
+ * Only apply callbacks to URLs matching specific patterns
29
+ * Example:
30
+ * patterns: ['/api/**', '/api/v2/*']
31
+ */
32
+ declare const _default: any;
33
+ export default _default;
34
+ /**
35
+ * Example 1: Use global callbacks (default behavior)
36
+ *
37
+ * const { data, error } = useFetchGetPets();
38
+ * // ✅ All global callbacks execute automatically
39
+ */
40
+ /**
41
+ * Example 2: Skip ALL global callbacks (OPTION 1)
42
+ *
43
+ * const { data, error } = useFetchGetPets({
44
+ * skipGlobalCallbacks: true,
45
+ * });
46
+ * // ❌ No global callbacks execute
47
+ */
48
+ /**
49
+ * Example 3: Skip SPECIFIC global callbacks (OPTION 1)
50
+ *
51
+ * const { data, error } = useFetchUpdatePet(id, pet, {
52
+ * skipGlobalCallbacks: ['onSuccess'], // Skip global onSuccess only
53
+ * onSuccess: (data) => {
54
+ * // Only this local callback executes
55
+ * console.log('Pet updated:', data);
56
+ * }
57
+ * });
58
+ * // ✅ Global onError still executes
59
+ * // ❌ Global onSuccess skipped
60
+ * // ✅ Local onSuccess executes
61
+ */
62
+ /**
63
+ * Example 4: Global callback prevents local execution (OPTION 2)
64
+ *
65
+ * // In plugin:
66
+ * onError: (error) => {
67
+ * if (error.statusCode === 401) {
68
+ * navigateTo('/login');
69
+ * return false; // Don't execute local onError
70
+ * }
71
+ * }
72
+ *
73
+ * // In component:
74
+ * const { data, error } = useFetchGetPets({
75
+ * onError: (error) => {
76
+ * // ❌ This won't execute for 401 errors (global returned false)
77
+ * // ✅ This executes for other errors (404, 500, etc.)
78
+ * console.error('Failed to load pets:', error);
79
+ * }
80
+ * });
81
+ */
82
+ /**
83
+ * Example 5: URL pattern matching (OPTION 3)
84
+ *
85
+ * // In plugin:
86
+ * patterns: ['/api/public/**']
87
+ *
88
+ * // In components:
89
+ * useFetchGetPets(); // URL: /api/public/pets ✅ Global callbacks execute
90
+ * useFetchGetUser(); // URL: /api/users/me ❌ Global callbacks skipped
91
+ * useFetchGetPublicConfig(); // URL: /api/public/config ✅ Global callbacks execute
92
+ */
93
+ /**
94
+ * Example 6: Combine all options
95
+ *
96
+ * // In plugin:
97
+ * patterns: ['/api/**'],
98
+ * onError: (error) => {
99
+ * if (error.statusCode === 401) return false;
100
+ * }
101
+ *
102
+ * // In component:
103
+ * const { data } = useFetchCreatePet(pet, {
104
+ * skipGlobalCallbacks: ['onSuccess'], // Skip global success toast
105
+ * onSuccess: (pet) => {
106
+ * // Show custom success message
107
+ * toast.success(`🐕 ${pet.name} added successfully!`);
108
+ * },
109
+ * onError: (error) => {
110
+ * // This won't execute for 401 (global returns false)
111
+ * // This executes for other errors
112
+ * console.error('Failed to create pet:', error);
113
+ * }
114
+ * });
115
+ */
116
+ /**
117
+ * Pattern 1: Toast notifications for all operations
118
+ *
119
+ * const globalCallbacks = {
120
+ * onSuccess: () => {
121
+ * useNuxtApp().$toast?.success('✅ Success');
122
+ * },
123
+ * onError: (error) => {
124
+ * if (error.statusCode === 401) {
125
+ * navigateTo('/login');
126
+ * return false;
127
+ * }
128
+ * useNuxtApp().$toast?.error(`❌ ${error.message}`);
129
+ * }
130
+ * };
131
+ */
132
+ /**
133
+ * Pattern 2: Authentication + logging
134
+ *
135
+ * const globalCallbacks = {
136
+ * onRequest: (context) => {
137
+ * console.log(`[API] ${context.method} ${context.url}`);
138
+ * const token = useCookie('auth-token').value;
139
+ * if (token) {
140
+ * return { headers: { 'Authorization': `Bearer ${token}` } };
141
+ * }
142
+ * },
143
+ * onError: (error) => {
144
+ * if (error.statusCode === 401) {
145
+ * useCookie('auth-token').value = null;
146
+ * navigateTo('/login');
147
+ * return false;
148
+ * }
149
+ * }
150
+ * };
151
+ */
152
+ /**
153
+ * Pattern 3: Analytics tracking
154
+ *
155
+ * const globalCallbacks = {
156
+ * onSuccess: (data, context) => {
157
+ * trackEvent('api_success', { endpoint: context?.url });
158
+ * },
159
+ * onError: (error, context) => {
160
+ * trackEvent('api_error', {
161
+ * endpoint: context?.url,
162
+ * statusCode: error.statusCode
163
+ * });
164
+ * }
165
+ * };
166
+ */
167
+ /**
168
+ * Pattern 4: Loading states
169
+ *
170
+ * const globalCallbacks = {
171
+ * onRequest: () => {
172
+ * useLoadingStore().increment();
173
+ * },
174
+ * onFinish: () => {
175
+ * useLoadingStore().decrement();
176
+ * }
177
+ * };
178
+ */