@enfyra/sdk-nuxt 0.3.23 → 0.3.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,17 +1,14 @@
1
1
  # @enfyra/sdk-nuxt
2
2
 
3
- Nuxt SDK for Enfyra CMS - A powerful composable-based API client with full SSR support and TypeScript integration.
3
+ Nuxt SDK for Enfyra CMS - A lightweight composable-based API client with full TypeScript integration.
4
4
 
5
5
  ## Features
6
6
 
7
- ✅ **SSR & Client-Side Support** - Automatic server-side rendering with `useFetch` or client-side with `$fetch`
7
+ ✅ **Simple & Flexible** - Get base URL and build your own composables
8
8
  ✅ **Authentication Integration** - Built-in auth composables with automatic header forwarding
9
9
  ✅ **Asset Proxy** - Automatic `/assets/**` proxy to backend with no configuration needed
10
10
  ✅ **TypeScript Support** - Full type safety with auto-generated declarations
11
- ✅ **Batch Operations** - Efficient bulk operations with real-time progress tracking (client-side)
12
- ✅ **Error Handling** - Automatic error management with console logging
13
- ✅ **Reactive State** - Built-in loading, error, and data states
14
- ✅ **Caching Support** - Optional cache keys for SSR mode optimization
11
+ ✅ **SSR Ready** - Works seamlessly with Nuxt's `useFetch` and `$fetch`
15
12
 
16
13
  ## Installation
17
14
 
@@ -42,14 +39,25 @@ The SDK automatically detects your application URL:
42
39
 
43
40
  ## Quick Start
44
41
 
45
- ### SSR Mode - Perfect for Page Data
42
+ ### Get Base URL
43
+
44
+ ```typescript
45
+ // Get the base URL for your API requests
46
+ const { baseUrl, apiPrefix } = useEnfyra();
47
+
48
+ // baseUrl: "http://localhost:3001/enfyra/api"
49
+ // apiPrefix: "/enfyra/api"
50
+ ```
51
+
52
+ ### Using with `useFetch` (SSR)
46
53
 
47
54
  ```typescript
48
55
  // pages/users.vue
49
56
  <script setup>
50
- // Automatic execution on server-side with caching (runs immediately, no execute() needed)
51
- const { data: users, pending, error, refresh } = useEnfyraApi('/users', {
52
- ssr: true,
57
+ const { baseUrl } = useEnfyra();
58
+
59
+ // Use with Nuxt's useFetch for SSR support
60
+ const { data: users, pending, error, refresh } = await useFetch(`${baseUrl}/users`, {
53
61
  key: 'users-list' // Optional cache key
54
62
  });
55
63
  </script>
@@ -67,16 +75,14 @@ const { data: users, pending, error, refresh } = useEnfyraApi('/users', {
67
75
  </template>
68
76
  ```
69
77
 
70
- ### Client Mode - Perfect for User Interactions
78
+ ### Using with `$fetch` (Client)
71
79
 
72
80
  ```typescript
73
81
  // components/CreateUserForm.vue
74
82
  <script setup>
75
- // Manual execution control for form submissions
76
- const { execute: createUser, pending, error } = useEnfyraApi('/users', {
77
- method: 'post',
78
- errorContext: 'Create User'
79
- });
83
+ const { baseUrl } = useEnfyra();
84
+ const pending = ref(false);
85
+ const error = ref(null);
80
86
 
81
87
  const formData = reactive({
82
88
  name: '',
@@ -84,11 +90,22 @@ const formData = reactive({
84
90
  });
85
91
 
86
92
  async function handleSubmit() {
87
- await createUser({ body: formData });
93
+ pending.value = true;
94
+ error.value = null;
88
95
 
89
- if (!error.value) {
96
+ try {
97
+ const response = await $fetch(`${baseUrl}/users`, {
98
+ method: 'POST',
99
+ body: formData
100
+ });
101
+
90
102
  toast.success('User created successfully!');
91
103
  await navigateTo('/users');
104
+ } catch (err) {
105
+ error.value = err;
106
+ toast.error('Failed to create user');
107
+ } finally {
108
+ pending.value = false;
92
109
  }
93
110
  }
94
111
  </script>
@@ -98,7 +115,7 @@ async function handleSubmit() {
98
115
 
99
116
  ```typescript
100
117
  <script setup>
101
- const { me, login, logout, isLoggedIn } = useEnfyraAuth();
118
+ const { me, login, logout, fetchUser, isLoggedIn } = useEnfyraAuth();
102
119
 
103
120
  // Login
104
121
  await login({
@@ -110,6 +127,9 @@ await login({
110
127
  console.log('Logged in:', isLoggedIn.value);
111
128
  console.log('Current user:', me.value);
112
129
 
130
+ // Fetch user with optional fields
131
+ await fetchUser({ fields: ['id', 'email', 'role'] });
132
+
113
133
  // Logout
114
134
  await logout();
115
135
  </script>
@@ -139,69 +159,20 @@ The SDK automatically proxies all asset requests to your backend. Simply use `/a
139
159
 
140
160
  ## Core Composables
141
161
 
142
- ### `useEnfyraApi<T>(path, options)`
162
+ ### `useEnfyra()`
143
163
 
144
- Main composable for API requests with both SSR and client-side support.
164
+ Get the base URL and API prefix for building your own API requests.
145
165
 
146
166
  ```typescript
147
- // SSR Mode - Runs immediately (like useFetch)
148
- const { data, pending, error, refresh } = useEnfyraApi('/endpoint', {
149
- ssr: true,
150
- key: 'cache-key', // Optional
151
- method: 'get',
152
- query: { page: 1 }
153
- });
154
- // ⚠️ Returns useFetch result: { data, pending, error, refresh }
167
+ const { baseUrl, apiPrefix } = useEnfyra();
155
168
 
156
- // Client Mode - Manual execution
157
- const { data, pending, error, execute } = useEnfyraApi('/endpoint', {
158
- method: 'post',
159
- errorContext: 'Create Resource'
160
- });
161
- // ⚠️ Returns custom result: { data, pending, error, execute }
162
-
163
- await execute({
164
- body: { name: 'New Item' },
165
- id: '123' // For /endpoint/123
166
- });
169
+ // baseUrl: "http://localhost:3001/enfyra/api"
170
+ // apiPrefix: "/enfyra/api"
167
171
  ```
168
172
 
169
- **Options:**
170
- - `ssr?: boolean` - Enable server-side rendering mode (executes immediately like useFetch)
171
- - `method?: 'get' | 'post' | 'patch' | 'delete'` - HTTP method
172
- - `body?: any` - Request body (POST/PATCH)
173
- - `query?: Record<string, any>` - URL query parameters
174
- - `headers?: Record<string, string>` - Custom headers
175
- - `errorContext?: string` - Error context for logging
176
- - `onError?: (error: ApiError, context?: string) => void` - Custom error handler
177
- - `key?: string` - Cache key (SSR mode, optional)
178
- - `default?: () => T` - Default value (SSR mode only)
179
-
180
- **Batch Options (only available for PATCH, DELETE, and POST methods):**
181
- - `batchSize?: number` - Batch size for chunking large operations (default: no limit)
182
- - `concurrent?: number` - Maximum concurrent requests (default: no limit)
183
- - `onProgress?: (progress: BatchProgress) => void` - Real-time progress callback for batch operations
184
-
185
- > 🎯 **TypeScript Smart:** Batch options (`batchSize`, `concurrent`, `onProgress`) are only available in TypeScript IntelliSense when using methods that support batch operations (PATCH, DELETE, POST). For GET and PUT methods, these options won't appear in autocomplete.
186
-
187
- **⚠️ Important: Return Types Differ**
188
- - **SSR Mode**: Returns `useFetch` result `{ data, pending, error, refresh }`
189
- - **Client Mode**: Returns custom result `{ data, pending, error, execute }`
190
-
191
- **Execute Options (Client mode only):**
192
-
193
- **Basic Options:**
194
- - `id?: string | number` - Single resource ID
195
- - `body?: any` - Override request body
196
-
197
- **Batch Options (only when using `ids` or `files`):**
198
- - `ids?: (string | number)[]` - Batch operation IDs (PATCH/DELETE)
199
- - `files?: FormData[]` - Array of FormData objects for batch upload (POST)
200
- - `batchSize?: number` - Override batch size for this execution
201
- - `concurrent?: number` - Override concurrent limit for this execution
202
- - `onProgress?: (progress: BatchProgress) => void` - Override progress callback for this execution
203
-
204
- > 🎯 **TypeScript Smart:** Batch execute options (`batchSize`, `concurrent`, `onProgress`) are only available when you provide `ids` or `files` parameters, ensuring type safety.
173
+ **Returns:**
174
+ - `baseUrl: string` - Full base URL including app URL and API prefix
175
+ - `apiPrefix: string` - API prefix path (e.g., "/enfyra/api")
205
176
 
206
177
  ### `useEnfyraAuth()`
207
178
 
@@ -215,174 +186,78 @@ me.value // Current user data (reactive)
215
186
  isLoggedIn.value // Auth status (computed)
216
187
 
217
188
  // Methods
218
- await login({ email, password }) // Login user
219
- await logout() // Logout user
220
- await fetchUser() // Refresh user data
189
+ await login({ email, password }) // Login user
190
+ await logout() // Logout user
191
+ await fetchUser({ fields?: string[] }) // Refresh user data with optional fields
221
192
  ```
222
193
 
223
- ## Advanced Usage
224
-
225
- ### Batch Operations
226
-
194
+ **Login:**
227
195
  ```typescript
228
- // Basic batch delete - unlimited parallel requests
229
- // 🎯 Note: Batch options only appear in IntelliSense for DELETE method
230
- const { execute: deleteItems } = useEnfyraApi('/items', {
231
- method: 'delete',
232
- errorContext: 'Delete Items'
233
- });
234
-
235
- await deleteItems({ ids: ['1', '2', '3'] });
236
-
237
- // Advanced batch operations with concurrency control
238
- // 🎯 TypeScript shows batch options (batchSize, concurrent, onProgress) for DELETE method
239
- const { execute: deleteMany } = useEnfyraApi('/users', {
240
- method: 'delete',
241
- batchSize: 10, // ✅ Available: DELETE method supports batching
242
- concurrent: 3, // ✅ Available: DELETE method supports batching
243
- onProgress: (progress) => { // ✅ Available: DELETE method supports batching
244
- console.log(`Deleting: ${progress.completed}/${progress.total}`);
245
- },
246
- onError: (error, context) => toast.error(`${context}: ${error.message}`)
247
- });
248
-
249
- // GET method example - batch options NOT available
250
- // 🎯 TypeScript won't show batch options for GET method
251
- const { execute: getUsers } = useEnfyraApi('/users', {
252
- method: 'get',
253
- // batchSize: 10, // ❌ Not available: GET doesn't support batching
254
- // concurrent: 3, // ❌ Not available: GET doesn't support batching
255
- // onProgress: () => {} // ❌ Not available: GET doesn't support batching
256
- errorContext: 'Fetch Users'
257
- });
258
-
259
- // Delete 100 users in controlled batches
260
- await deleteMany({ ids: Array.from({length: 100}, (_, i) => `user-${i}`) });
261
-
262
- // Override batch settings per execution
263
- // 🎯 TypeScript shows batch options for PATCH method
264
- const { execute: updateUsers } = useEnfyraApi('/users', {
265
- method: 'patch',
266
- batchSize: 20, // ✅ Available: PATCH method supports batching
267
- concurrent: 5 // ✅ Available: PATCH method supports batching
268
- });
269
-
270
- // This execution uses different settings
271
- // 🎯 Batch options in execute() only available when using `ids` or `files`
272
- await updateUsers({
273
- ids: largeUserList, // ✅ Triggers batch mode
274
- body: { status: 'active' },
275
- batchSize: 50, // ✅ Available: Using `ids` parameter
276
- concurrent: 10, // ✅ Available: Using `ids` parameter
277
- onProgress: (progress) => { // ✅ Available: Using `ids` parameter
278
- console.log(`Updating: ${progress.completed}/${progress.total}`);
279
- }
196
+ const response = await login({
197
+ email: 'user@example.com',
198
+ password: 'password123',
199
+ remember: true // Optional
280
200
  });
201
+ ```
281
202
 
282
- // Single operation - batch options NOT available in execute
283
- await updateUsers({
284
- id: 'single-user-id', // Single operation, no batch options
285
- body: { status: 'active' }
286
- // batchSize: 50, // ❌ Not available: Not using `ids` or `files`
287
- // concurrent: 10, // ❌ Not available: Not using `ids` or `files`
288
- // onProgress: () => {} // ❌ Not available: Not using `ids` or `files`
289
- });
203
+ **Fetch User:**
204
+ ```typescript
205
+ // Fetch all user fields
206
+ await fetchUser();
290
207
 
291
- // Batch file upload with real-time progress tracking
292
- const progressState = ref({
293
- progress: 0,
294
- completed: 0,
295
- total: 0,
296
- failed: 0,
297
- estimatedTimeRemaining: 0,
298
- operationsPerSecond: 0
208
+ // Fetch specific fields only
209
+ await fetchUser({
210
+ fields: ['id', 'email', 'role', 'allowedRoutePermissions']
299
211
  });
212
+ ```
300
213
 
301
- // 🎯 TypeScript shows batch options for POST method (supports file uploads)
302
- const { execute: uploadFiles } = useEnfyraApi('/file_definition', {
303
- method: 'post',
304
- batchSize: 5, // ✅ Available: POST method supports batching for files
305
- concurrent: 2, // ✅ Available: POST method supports batching for files
306
- errorContext: 'Upload Files',
307
- onProgress: (progress) => { // ✅ Available: POST method supports batching
308
- progressState.value = progress;
309
- console.log(`Progress: ${progress.progress}% (${progress.completed}/${progress.total})`);
310
- console.log(`ETA: ${Math.round((progress.estimatedTimeRemaining || 0) / 1000)}s`);
311
- console.log(`Speed: ${progress.operationsPerSecond?.toFixed(1)} ops/sec`);
312
- }
313
- });
214
+ ## Advanced Usage
314
215
 
315
- // Convert files to FormData array (matches enfyra_app pattern)
316
- const formDataArray = selectedFiles.map(file => {
317
- const formData = new FormData();
318
- formData.append('file', file);
319
- formData.append('folder', folderId || 'null');
320
- return formData;
321
- });
216
+ ### Building Custom Composables
322
217
 
323
- await uploadFiles({
324
- files: formDataArray // Array of FormData objects
325
- });
218
+ Since you have access to `baseUrl`, you can build your own composables using Nuxt's built-in utilities:
326
219
 
327
- // Real-time progress tracking with detailed results
328
- const { execute: processData } = useEnfyraApi('/process', {
329
- method: 'post',
330
- batchSize: 10,
331
- concurrent: 3,
332
- onProgress: (progress) => {
333
- // Display progress bar
334
- updateProgressBar(progress.progress);
335
-
336
- // Show detailed metrics
337
- console.log('Batch Progress:', {
338
- percentage: progress.progress,
339
- completed: progress.completed,
340
- total: progress.total,
341
- failed: progress.failed,
342
- currentBatch: progress.currentBatch,
343
- totalBatches: progress.totalBatches,
344
- averageTime: progress.averageTime,
345
- estimatedTimeRemaining: progress.estimatedTimeRemaining,
346
- operationsPerSecond: progress.operationsPerSecond
220
+ ```typescript
221
+ // composables/useUsers.ts
222
+ export const useUsers = () => {
223
+ const { baseUrl } = useEnfyra();
224
+
225
+ // SSR mode with useFetch
226
+ const getUsers = (options?: { page?: number; limit?: number }) => {
227
+ return useFetch(`${baseUrl}/users`, {
228
+ key: `users-${options?.page || 1}`,
229
+ query: options
347
230
  });
348
-
349
- // Handle individual results
350
- progress.results.forEach(result => {
351
- if (result.status === 'failed') {
352
- console.error(`Item ${result.index} failed:`, result.error);
353
- }
231
+ };
232
+
233
+ // Client mode with $fetch
234
+ const createUser = async (userData: any) => {
235
+ return await $fetch(`${baseUrl}/users`, {
236
+ method: 'POST',
237
+ body: userData
354
238
  });
355
- }
356
- });
357
-
358
- await processData({
359
- ids: largeDataSet,
360
- body: processingOptions
361
- });
362
- ```
363
-
364
- ### Real-time Progress Interface
365
-
366
- ```typescript
367
- interface BatchProgress {
368
- progress: number; // 0-100 percentage
369
- completed: number; // Number of completed operations
370
- total: number; // Total number of operations
371
- failed: number; // Number of failed operations
372
- inProgress: number; // Operations currently running
373
- estimatedTimeRemaining?: number; // Milliseconds remaining
374
- averageTime?: number; // Average time per operation (ms)
375
- currentBatch: number; // Current batch being processed
376
- totalBatches: number; // Total number of batches
377
- operationsPerSecond?: number; // Processing speed
378
- results: Array<{ // Detailed results
379
- index: number;
380
- status: 'completed' | 'failed';
381
- result?: any;
382
- error?: ApiError;
383
- duration?: number;
384
- }>;
385
- }
239
+ };
240
+
241
+ const updateUser = async (id: string, userData: any) => {
242
+ return await $fetch(`${baseUrl}/users/${id}`, {
243
+ method: 'PATCH',
244
+ body: userData
245
+ });
246
+ };
247
+
248
+ const deleteUser = async (id: string) => {
249
+ return await $fetch(`${baseUrl}/users/${id}`, {
250
+ method: 'DELETE'
251
+ });
252
+ };
253
+
254
+ return {
255
+ getUsers,
256
+ createUser,
257
+ updateUser,
258
+ deleteUser
259
+ };
260
+ };
386
261
  ```
387
262
 
388
263
  ### TypeScript Integration
@@ -401,24 +276,23 @@ interface ApiResponse<T> {
401
276
  }
402
277
 
403
278
  // Use with full type safety
404
- const { data } = useEnfyraApi<ApiResponse<User>>('/users', {
405
- ssr: true
406
- });
279
+ const { baseUrl } = useEnfyra();
280
+ const { data } = await useFetch<ApiResponse<User>>(`${baseUrl}/users`);
407
281
 
408
282
  // TypeScript knows data.value is ApiResponse<User> | null
409
283
  const users = computed(() => data.value?.data || []);
410
284
  ```
411
285
 
412
- ### Reactive Parameters
286
+ ### Reactive Parameters with `useFetch`
413
287
 
414
288
  ```typescript
289
+ const { baseUrl } = useEnfyra();
415
290
  const searchQuery = ref('');
416
291
  const page = ref(1);
417
292
 
418
- // SSR mode with reactive query (executes immediately)
419
- const { data, refresh } = useEnfyraApi('/users', {
420
- ssr: true,
421
- key: () => `users-${page.value}-${searchQuery.value}`, // Optional
293
+ // SSR mode with reactive query
294
+ const { data, refresh } = await useFetch(`${baseUrl}/users`, {
295
+ key: () => `users-${page.value}-${searchQuery.value}`,
422
296
  query: computed(() => ({
423
297
  search: searchQuery.value,
424
298
  page: page.value,
@@ -430,24 +304,6 @@ const { data, refresh } = useEnfyraApi('/users', {
430
304
  watch([searchQuery, page], () => refresh());
431
305
  ```
432
306
 
433
- ## Documentation
434
-
435
- For comprehensive guides and examples:
436
-
437
- 📚 **[useEnfyraApi Complete Guide](https://github.com/dothinh115/enfyra-sdk-nuxt/blob/main/docs/useEnfyraApi.md)** - API client composable with SSR support, batch operations, and error handling
438
-
439
- 🔐 **[useEnfyraAuth Complete Guide](https://github.com/dothinh115/enfyra-sdk-nuxt/blob/main/docs/useEnfyraAuth.md)** - Authentication composable with user management and login/logout functionality
440
-
441
- Key topics covered:
442
- - SSR vs Client Mode comparison
443
- - Authentication and headers forwarding
444
- - Batch operations and CRUD patterns
445
- - User management and authentication flows
446
- - Error handling best practices
447
- - TypeScript integration
448
- - Performance optimization
449
- - Migration guides
450
-
451
307
  ## Configuration
452
308
 
453
309
  ### Module Options
@@ -460,8 +316,8 @@ export default defineNuxtConfig({
460
316
  // Required: Main API URL
461
317
  apiUrl: process.env.ENFYRA_API_URL || "http://localhost:1105",
462
318
 
463
- // Required: App URL for SSR requests
464
- appUrl: process.env.ENFYRA_APP_URL || "http://localhost:3001",
319
+ // Optional: API prefix (defaults to "/enfyra/api")
320
+ apiPrefix: "/enfyra/api",
465
321
  },
466
322
  })
467
323
  ```
@@ -471,97 +327,73 @@ export default defineNuxtConfig({
471
327
  ```bash
472
328
  # .env
473
329
  ENFYRA_API_URL=https://api.enfyra.com
474
- ENFYRA_APP_URL=https://app.enfyra.com
475
330
  ```
476
331
 
477
332
  ## Best Practices
478
333
 
479
- ### 1. Choose the Right Mode
334
+ ### 1. Use `useFetch` for SSR Data
480
335
 
481
336
  ```typescript
482
- // ✅ Use SSR for initial page data (runs immediately)
483
- const { data } = useEnfyraApi('/dashboard', {
484
- ssr: true,
485
- key: 'dashboard' // Optional
486
- });
487
-
488
- // ✅ Use Client mode for user interactions (manual execution)
489
- const { execute: saveData } = useEnfyraApi('/settings', {
490
- method: 'patch',
491
- errorContext: 'Save Settings'
337
+ // ✅ Use useFetch for initial page data (runs immediately, SSR support)
338
+ const { baseUrl } = useEnfyra();
339
+ const { data } = await useFetch(`${baseUrl}/dashboard`, {
340
+ key: 'dashboard'
492
341
  });
493
342
  ```
494
343
 
495
- ### 2. Proper Error Handling
344
+ ### 2. Use `$fetch` for Client Actions
496
345
 
497
346
  ```typescript
498
- // ✅ Check error state (don't use try-catch)
499
- async function handleSubmit() {
500
- await execute({ body: formData });
501
-
502
- if (error.value) {
503
- return; // Error already logged
347
+ // ✅ Use $fetch for user interactions (manual execution)
348
+ const { baseUrl } = useEnfyra();
349
+
350
+ async function saveSettings(settings: any) {
351
+ try {
352
+ await $fetch(`${baseUrl}/settings`, {
353
+ method: 'PATCH',
354
+ body: settings
355
+ });
356
+ toast.success('Saved successfully');
357
+ } catch (error) {
358
+ toast.error('Failed to save');
504
359
  }
505
-
506
- // Success handling
507
- toast.success('Saved successfully');
508
360
  }
509
361
  ```
510
362
 
511
- ### 3. Type Safety
363
+ ### 3. Build Reusable Composables
512
364
 
513
365
  ```typescript
514
- // ✅ Define interfaces for API responses
515
- interface CreateUserResponse {
516
- data: User;
517
- message: string;
518
- }
519
-
520
- const { execute } = useEnfyraApi<CreateUserResponse>('/users', {
521
- method: 'post'
522
- });
366
+ // ✅ Create reusable composables for your API endpoints
367
+ export const useProducts = () => {
368
+ const { baseUrl } = useEnfyra();
369
+
370
+ return {
371
+ list: (query?: any) => useFetch(`${baseUrl}/products`, { query }),
372
+ get: (id: string) => useFetch(`${baseUrl}/products/${id}`),
373
+ create: (data: any) => $fetch(`${baseUrl}/products`, { method: 'POST', body: data }),
374
+ update: (id: string, data: any) => $fetch(`${baseUrl}/products/${id}`, { method: 'PATCH', body: data }),
375
+ delete: (id: string) => $fetch(`${baseUrl}/products/${id}`, { method: 'DELETE' }),
376
+ };
377
+ };
523
378
  ```
524
379
 
525
380
  ## Troubleshooting
526
381
 
527
382
  ### Common Issues
528
383
 
529
- 1. **Headers not forwarded in SSR** - Ensure `ssr: true` is set
530
- 2. **Batch operations not working** - Only available in Client mode
531
- 3. **Data not reactive** - Use computed refs for reactive parameters
532
- 4. **TypeScript errors** - Check return type differences between modes
384
+ 1. **Base URL is empty** - Ensure `apiUrl` is configured in `nuxt.config.ts`
385
+ 2. **Assets not loading** - Check that `/assets/**` routes are accessible
386
+ 3. **Authentication not working** - Verify cookies are being set and forwarded
533
387
 
534
388
  ### Performance Tips
535
389
 
536
- - Use SSR for initial data loading (better SEO, faster page loads)
537
- - Use Client mode for user interactions (better UX)
538
- - Implement proper cache keys to avoid over-caching
539
- - Group related operations with batch APIs
390
+ - Use `useFetch` with cache keys for SSR data (better SEO, faster page loads)
391
+ - Use `$fetch` for user interactions (better UX)
392
+ - Build reusable composables to avoid code duplication
393
+ - Leverage Nuxt's built-in caching with `useFetch` keys
540
394
 
541
395
  ## Development
542
396
 
543
- ### Testing
544
-
545
- The SDK includes a comprehensive test suite using Vitest:
546
-
547
- ```bash
548
- # Run tests once
549
- npm run test:run
550
-
551
- # Run tests in watch mode
552
- npm test
553
-
554
- # Run tests with UI
555
- npm run test:ui
556
- ```
557
-
558
- **Test Coverage:**
559
- - ✅ **Extension naming utilities** - UUID generation and validation
560
- - ✅ **Vue SFC validation** - Syntax and structure validation
561
- - ✅ **JS bundle validation** - Syntax and export validation
562
- - ✅ **Extension processing** - Complete workflow testing
563
- - ✅ **35 test cases** covering all edge cases and error handling
564
-
565
397
  ### Building
566
398
 
567
399
  ```bash
@@ -580,13 +412,8 @@ MIT
580
412
 
581
413
  Pull requests are welcome! Please read our contributing guidelines and ensure tests pass before submitting.
582
414
 
583
- ## Changelog
584
-
585
- See [CHANGELOG.md](https://github.com/dothinh115/enfyra-sdk-nuxt/blob/main/CHANGELOG.md) for a detailed history of changes and migration guides.
586
-
587
415
  ## Support
588
416
 
589
417
  For issues and questions:
590
- - 📖 Check the [detailed documentation](https://github.com/dothinh115/enfyra-sdk-nuxt/blob/main/docs/useEnfyraApi.md)
591
- - 🐛 [Report bugs](https://github.com/dothinh115/enfyra-sdk-nuxt/issues)
592
- - 💬 [GitHub Discussions](https://github.com/dothinh115/enfyra-sdk-nuxt/discussions)
418
+ - 🐛 [Report bugs](https://github.com/enfyra/sdk-nuxt/issues)
419
+ - 💬 [GitHub Discussions](https://github.com/enfyra/sdk-nuxt/discussions)