@enfyra/sdk-nuxt 0.1.13 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,16 @@
1
1
  # @enfyra/sdk-nuxt
2
2
 
3
- Nuxt SDK for Enfyra CMS
3
+ Nuxt SDK for Enfyra CMS - A powerful composable-based API client with full SSR support and TypeScript integration.
4
+
5
+ ## Features
6
+
7
+ ✅ **SSR & Client-Side Support** - Automatic server-side rendering with `useFetch` or client-side with `$fetch`
8
+ ✅ **Authentication Integration** - Built-in auth composables with automatic header forwarding
9
+ ✅ **TypeScript Support** - Full type safety with auto-generated declarations
10
+ ✅ **Batch Operations** - Efficient bulk operations for CRUD actions (client-side)
11
+ ✅ **Error Handling** - Automatic error management with console logging
12
+ ✅ **Reactive State** - Built-in loading, error, and data states
13
+ ✅ **Caching Support** - Optional cache keys for SSR mode optimization
4
14
 
5
15
  ## Installation
6
16
 
@@ -8,9 +18,9 @@ Nuxt SDK for Enfyra CMS
8
18
  npm install @enfyra/sdk-nuxt
9
19
  ```
10
20
 
11
- ## Usage
21
+ ## Setup
12
22
 
13
- Add to your `nuxt.config.ts`:
23
+ Add the module to your `nuxt.config.ts`:
14
24
 
15
25
  ```typescript
16
26
  export default defineNuxtConfig({
@@ -20,25 +30,351 @@ export default defineNuxtConfig({
20
30
  runtimeConfig: {
21
31
  public: {
22
32
  enfyraSDK: {
23
- appUrl: 'http://localhost:3000',
24
- apiUrl: process.env.API_URL,
25
- apiPrefix: '/api',
33
+ apiUrl: process.env.ENFYRA_API_URL || 'https://api.enfyra.com',
34
+ apiPrefix: '/api/v1', // Optional: API prefix
35
+ appUrl: process.env.ENFYRA_APP_URL || 'https://app.enfyra.com'
36
+ },
37
+ },
38
+ },
39
+ })
40
+ ```
41
+
42
+ ## Quick Start
43
+
44
+ ### SSR Mode - Perfect for Page Data
45
+
46
+ ```typescript
47
+ // pages/users.vue
48
+ <script setup>
49
+ // ✅ Automatic server-side rendering with caching
50
+ const { data: users, pending, error, refresh } = useEnfyraApi('/users', {
51
+ ssr: true,
52
+ key: 'users-list'
53
+ });
54
+ </script>
55
+
56
+ <template>
57
+ <div>
58
+ <div v-if="pending">Loading users...</div>
59
+ <div v-else-if="error">Error: {{ error }}</div>
60
+ <div v-else>
61
+ <h1>Users ({{ users?.meta?.totalCount }})</h1>
62
+ <UserCard v-for="user in users?.data" :key="user.id" :user="user" />
63
+ <button @click="refresh">Refresh</button>
64
+ </div>
65
+ </div>
66
+ </template>
67
+ ```
68
+
69
+ ### Client Mode - Perfect for User Interactions
70
+
71
+ ```typescript
72
+ // components/CreateUserForm.vue
73
+ <script setup>
74
+ // ✅ Manual execution control for form submissions
75
+ const { execute: createUser, pending, error } = useEnfyraApi('/users', {
76
+ method: 'post',
77
+ errorContext: 'Create User'
78
+ });
79
+
80
+ const formData = reactive({
81
+ name: '',
82
+ email: ''
83
+ });
84
+
85
+ async function handleSubmit() {
86
+ await createUser({ body: formData });
87
+
88
+ if (!error.value) {
89
+ toast.success('User created successfully!');
90
+ await navigateTo('/users');
91
+ }
92
+ }
93
+ </script>
94
+ ```
95
+
96
+ ### Authentication
97
+
98
+ ```typescript
99
+ <script setup>
100
+ const { me, login, logout, isLoggedIn } = useEnfyraAuth();
101
+
102
+ // Login
103
+ await login({
104
+ email: 'user@example.com',
105
+ password: 'password123'
106
+ });
107
+
108
+ // Check auth status
109
+ console.log('Logged in:', isLoggedIn.value);
110
+ console.log('Current user:', me.value);
111
+
112
+ // Logout
113
+ await logout();
114
+ </script>
115
+ ```
116
+
117
+ ## Core Composables
118
+
119
+ ### `useEnfyraApi<T>(path, options)`
120
+
121
+ Main composable for API requests with both SSR and client-side support.
122
+
123
+ ```typescript
124
+ // SSR Mode - Automatic execution
125
+ const { data, pending, error, refresh } = useEnfyraApi('/endpoint', {
126
+ ssr: true,
127
+ key: 'cache-key',
128
+ method: 'get',
129
+ query: { page: 1 }
130
+ });
131
+
132
+ // Client Mode - Manual execution
133
+ const { data, pending, error, execute } = useEnfyraApi('/endpoint', {
134
+ method: 'post',
135
+ errorContext: 'Create Resource'
136
+ });
137
+
138
+ await execute({
139
+ body: { name: 'New Item' },
140
+ id: '123' // For /endpoint/123
141
+ });
142
+ ```
143
+
144
+ **Options:**
145
+ - `ssr?: boolean` - Enable server-side rendering mode
146
+ - `method?: 'get' | 'post' | 'patch' | 'delete'` - HTTP method
147
+ - `body?: any` - Request body (POST/PATCH)
148
+ - `query?: Record<string, any>` - URL query parameters
149
+ - `headers?: Record<string, string>` - Custom headers
150
+ - `errorContext?: string` - Error context for logging
151
+ - `key?: string` - Cache key (SSR mode only)
152
+ - `default?: () => T` - Default value (SSR mode only)
153
+
154
+ **Execute Options (Client mode only):**
155
+ - `id?: string | number` - Single resource ID
156
+ - `ids?: (string | number)[]` - Batch operation IDs (PATCH/DELETE)
157
+ - `files?: FormData[]` - Batch file upload (POST)
158
+ - `body?: any` - Override request body
159
+
160
+ ### `useEnfyraAuth()`
161
+
162
+ Authentication composable with reactive state management.
163
+
164
+ ```typescript
165
+ const { me, login, logout, fetchUser, isLoggedIn } = useEnfyraAuth();
166
+
167
+ // Properties
168
+ me.value // Current user data (reactive)
169
+ isLoggedIn.value // Auth status (computed)
170
+
171
+ // Methods
172
+ await login({ email, password }) // Login user
173
+ await logout() // Logout user
174
+ await fetchUser() // Refresh user data
175
+ ```
176
+
177
+ ## Advanced Usage
178
+
179
+ ### Batch Operations
180
+
181
+ ```typescript
182
+ // Batch delete multiple items
183
+ const { execute: deleteItems } = useEnfyraApi('/items', {
184
+ method: 'delete',
185
+ errorContext: 'Delete Items'
186
+ });
187
+
188
+ await deleteItems({ ids: ['1', '2', '3'] });
189
+
190
+ // Batch file upload
191
+ const { execute: uploadFiles } = useEnfyraApi('/files', {
192
+ method: 'post',
193
+ errorContext: 'Upload Files'
194
+ });
195
+
196
+ await uploadFiles({
197
+ files: [formData1, formData2, formData3]
198
+ });
199
+ ```
200
+
201
+ ### TypeScript Integration
202
+
203
+ ```typescript
204
+ // Define your API response types
205
+ interface User {
206
+ id: string;
207
+ name: string;
208
+ email: string;
209
+ }
210
+
211
+ interface ApiResponse<T> {
212
+ data: T[];
213
+ meta: { totalCount: number };
214
+ }
215
+
216
+ // Use with full type safety
217
+ const { data } = useEnfyraApi<ApiResponse<User>>('/users', {
218
+ ssr: true
219
+ });
220
+
221
+ // TypeScript knows data.value is ApiResponse<User> | null
222
+ const users = computed(() => data.value?.data || []);
223
+ ```
224
+
225
+ ### Reactive Parameters
226
+
227
+ ```typescript
228
+ const searchQuery = ref('');
229
+ const page = ref(1);
230
+
231
+ // SSR mode with reactive query
232
+ const { data, refresh } = useEnfyraApi('/users', {
233
+ ssr: true,
234
+ key: () => `users-${page.value}-${searchQuery.value}`,
235
+ query: computed(() => ({
236
+ search: searchQuery.value,
237
+ page: page.value,
238
+ limit: 10
239
+ }))
240
+ });
241
+
242
+ // Watch for changes and refresh
243
+ watch([searchQuery, page], () => refresh());
244
+ ```
245
+
246
+ ## Documentation
247
+
248
+ For comprehensive guides and examples:
249
+
250
+ 📚 **[useEnfyraApi Complete Guide](./docs/useEnfyraApi.md)** - Detailed documentation with examples, best practices, and troubleshooting
251
+
252
+ Key topics covered:
253
+ - SSR vs Client Mode comparison
254
+ - Authentication and headers forwarding
255
+ - Batch operations and CRUD patterns
256
+ - Error handling best practices
257
+ - TypeScript integration
258
+ - Performance optimization
259
+ - Migration guides
260
+
261
+ ## Configuration
262
+
263
+ ### Runtime Config Options
264
+
265
+ ```typescript
266
+ // nuxt.config.ts
267
+ export default defineNuxtConfig({
268
+ runtimeConfig: {
269
+ public: {
270
+ enfyraSDK: {
271
+ // Required: Main API URL
272
+ apiUrl: process.env.ENFYRA_API_URL,
273
+
274
+ // Optional: API path prefix (default: '')
275
+ apiPrefix: '/api/v1',
276
+
277
+ // Required: App URL for SSR requests
278
+ appUrl: process.env.ENFYRA_APP_URL,
279
+
280
+ // Optional: Default headers for all requests
281
+ defaultHeaders: {
282
+ 'Accept': 'application/json',
283
+ 'Content-Type': 'application/json'
284
+ }
26
285
  },
27
286
  },
28
287
  },
29
288
  })
30
289
  ```
31
290
 
32
- ## Composables
291
+ ### Environment Variables
292
+
293
+ ```bash
294
+ # .env
295
+ ENFYRA_API_URL=https://api.enfyra.com
296
+ ENFYRA_APP_URL=https://app.enfyra.com
297
+ ```
33
298
 
34
- ### useEnfyraApi
299
+ ## Best Practices
300
+
301
+ ### 1. Choose the Right Mode
35
302
 
36
303
  ```typescript
37
- const { data, error, pending, execute } = useEnfyraApi('/users')
304
+ // Use SSR for initial page data
305
+ const { data } = useEnfyraApi('/dashboard', {
306
+ ssr: true,
307
+ key: 'dashboard'
308
+ });
309
+
310
+ // ✅ Use Client mode for user interactions
311
+ const { execute: saveData } = useEnfyraApi('/settings', {
312
+ method: 'patch',
313
+ errorContext: 'Save Settings'
314
+ });
38
315
  ```
39
316
 
40
- ### useEnfyraAuth
317
+ ### 2. Proper Error Handling
41
318
 
42
319
  ```typescript
43
- const { me, login, logout, fetchUser } = useEnfyraAuth()
44
- ```
320
+ // Check error state (don't use try-catch)
321
+ async function handleSubmit() {
322
+ await execute({ body: formData });
323
+
324
+ if (error.value) {
325
+ return; // Error already logged
326
+ }
327
+
328
+ // Success handling
329
+ toast.success('Saved successfully');
330
+ }
331
+ ```
332
+
333
+ ### 3. Type Safety
334
+
335
+ ```typescript
336
+ // ✅ Define interfaces for API responses
337
+ interface CreateUserResponse {
338
+ data: User;
339
+ message: string;
340
+ }
341
+
342
+ const { execute } = useEnfyraApi<CreateUserResponse>('/users', {
343
+ method: 'post'
344
+ });
345
+ ```
346
+
347
+ ## Troubleshooting
348
+
349
+ ### Common Issues
350
+
351
+ 1. **Headers not forwarded in SSR** - Ensure `ssr: true` is set
352
+ 2. **Batch operations not working** - Only available in Client mode
353
+ 3. **Data not reactive** - Use computed refs for reactive parameters
354
+ 4. **TypeScript errors** - Check return type differences between modes
355
+
356
+ ### Performance Tips
357
+
358
+ - Use SSR for initial data loading (better SEO, faster page loads)
359
+ - Use Client mode for user interactions (better UX)
360
+ - Implement proper cache keys to avoid over-caching
361
+ - Group related operations with batch APIs
362
+
363
+ ## License
364
+
365
+ MIT
366
+
367
+ ## Contributing
368
+
369
+ Pull requests are welcome! Please read our contributing guidelines and ensure tests pass.
370
+
371
+ ## Changelog
372
+
373
+ See [CHANGELOG.md](./CHANGELOG.md) for a detailed history of changes and migration guides.
374
+
375
+ ## Support
376
+
377
+ For issues and questions:
378
+ - 📖 Check the [detailed documentation](./docs/useEnfyraApi.md)
379
+ - 🐛 [Report bugs](https://github.com/enfyra/sdk-nuxt/issues)
380
+ - 💬 [Join our community](https://discord.gg/enfyra)
@@ -1,6 +1,6 @@
1
1
  import { ref, unref, toRaw } from "vue";
2
2
  import { $fetch } from "../utils/http";
3
- import { useRuntimeConfig } from "#imports";
3
+ import { useRuntimeConfig, useFetch, useRequestHeaders } from "#imports";
4
4
  function handleApiError(error, context) {
5
5
  let message = "Request failed";
6
6
  let errorCode = "UNKNOWN_ERROR";
@@ -33,7 +33,42 @@ function handleApiError(error, context) {
33
33
  });
34
34
  }
35
35
  export function useEnfyraApi(path, opts = {}) {
36
- const { method = "get", body, query, errorContext } = opts;
36
+ const { method = "get", body, query, errorContext, ssr, key } = opts;
37
+ if (ssr) {
38
+ const config = useRuntimeConfig().public.enfyraSDK;
39
+ const basePath = (typeof path === "function" ? path() : path).replace(/^\/?api\/?/, "").replace(/^\/+/, "");
40
+ const finalUrl = (config?.appUrl || "") + (config?.apiPrefix || "") + "/" + basePath;
41
+ const clientHeaders = process.client ? {} : useRequestHeaders([
42
+ "authorization",
43
+ "cookie",
44
+ "user-agent",
45
+ "accept",
46
+ "accept-language",
47
+ "referer"
48
+ ]);
49
+ const serverHeaders = { ...clientHeaders };
50
+ delete serverHeaders.connection;
51
+ delete serverHeaders["keep-alive"];
52
+ delete serverHeaders.host;
53
+ delete serverHeaders["content-length"];
54
+ const fetchOptions = {
55
+ method,
56
+ body,
57
+ query,
58
+ headers: {
59
+ ...serverHeaders,
60
+ ...opts.headers
61
+ // Custom headers override client headers
62
+ }
63
+ };
64
+ if (key) {
65
+ fetchOptions.key = key;
66
+ }
67
+ if (opts.default) {
68
+ fetchOptions.default = opts.default;
69
+ }
70
+ return useFetch(finalUrl, fetchOptions);
71
+ }
37
72
  const data = ref(null);
38
73
  const error = ref(null);
39
74
  const pending = ref(false);
package/dist/index.d.ts CHANGED
@@ -11,6 +11,10 @@ export interface ApiOptions<T> {
11
11
  errorContext?: string;
12
12
  disableBatch?: boolean;
13
13
  default?: () => T;
14
+ /** Enable SSR with useFetch instead of $fetch */
15
+ ssr?: boolean;
16
+ /** Unique key for useFetch caching */
17
+ key?: string;
14
18
  }
15
19
  export interface BackendError {
16
20
  success: false;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IACnG,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,KAAK,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAqB,SAAQ,YAAY;IACxD,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,GAAG,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE/B,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACnC,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACpB,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACtB,OAAO,EAAE,CAAC,WAAW,CAAC,EAAE;QACtB,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QACrB,GAAG,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;QAC1B,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;KACf,KAAK,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;CAC/B;AAGD,cAAc,QAAQ,CAAC;AAGvB,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IACnG,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;IAClB,iDAAiD;IACjD,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,KAAK,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAqB,SAAQ,YAAY;IACxD,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,GAAG,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE/B,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACnC,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACpB,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACtB,OAAO,EAAE,CAAC,WAAW,CAAC,EAAE;QACtB,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QACrB,GAAG,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;QAC1B,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;KACf,KAAK,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;CAC/B;AAGD,cAAc,QAAQ,CAAC;AAGvB,cAAc,eAAe,CAAC"}
package/dist/module.cjs CHANGED
@@ -15,6 +15,10 @@ const module$1 = kit.defineNuxtModule({
15
15
  },
16
16
  setup(options, nuxt) {
17
17
  const { resolve } = kit.createResolver((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('module.cjs', document.baseURI).href)));
18
+ nuxt.options.runtimeConfig.public.enfyraSDK = {
19
+ ...nuxt.options.runtimeConfig.public.enfyraSDK,
20
+ ...options
21
+ };
18
22
  kit.addImportsDir(resolve("./composables"));
19
23
  kit.addServerHandler({
20
24
  handler: resolve("./runtime/server/middleware/auth"),
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@enfyra/sdk-nuxt",
3
3
  "configKey": "enfyraSDK",
4
- "version": "0.1.13",
4
+ "version": "0.2.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "0.8.4",
7
7
  "unbuild": "2.0.0"
package/dist/module.mjs CHANGED
@@ -12,6 +12,10 @@ const module = defineNuxtModule({
12
12
  },
13
13
  setup(options, nuxt) {
14
14
  const { resolve } = createResolver(import.meta.url);
15
+ nuxt.options.runtimeConfig.public.enfyraSDK = {
16
+ ...nuxt.options.runtimeConfig.public.enfyraSDK,
17
+ ...options
18
+ };
15
19
  addImportsDir(resolve("./composables"));
16
20
  addServerHandler({
17
21
  handler: resolve("./runtime/server/middleware/auth"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enfyra/sdk-nuxt",
3
- "version": "0.1.13",
3
+ "version": "0.2.0",
4
4
  "description": "Nuxt SDK for Enfyra CMS",
5
5
  "main": "./dist/module.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -5,7 +5,7 @@ import type {
5
5
  UseEnfyraApiReturn,
6
6
  } from "../types";
7
7
  import { $fetch } from "../utils/http";
8
- import { useRuntimeConfig } from "#imports";
8
+ import { useRuntimeConfig, useFetch, useRequestHeaders } from "#imports";
9
9
 
10
10
  function handleApiError(error: any, context?: string) {
11
11
  let message = "Request failed";
@@ -50,7 +50,57 @@ export function useEnfyraApi<T = any>(
50
50
  path: (() => string) | string,
51
51
  opts: ApiOptions<T> = {}
52
52
  ): UseEnfyraApiReturn<T> {
53
- const { method = "get", body, query, errorContext } = opts;
53
+ const { method = "get", body, query, errorContext, ssr, key } = opts;
54
+
55
+ // SSR mode - use useFetch
56
+ if (ssr) {
57
+ const config = useRuntimeConfig().public.enfyraSDK;
58
+ const basePath = (typeof path === "function" ? path() : path)
59
+ .replace(/^\/?api\/?/, "")
60
+ .replace(/^\/+/, ""); // Remove leading slashes
61
+
62
+ const finalUrl =
63
+ (config?.appUrl || "") + (config?.apiPrefix || "") + "/" + basePath;
64
+
65
+ // Get headers from client request and filter out connection-specific headers
66
+ const clientHeaders = process.client
67
+ ? {}
68
+ : useRequestHeaders([
69
+ "authorization",
70
+ "cookie",
71
+ "user-agent",
72
+ "accept",
73
+ "accept-language",
74
+ "referer",
75
+ ]);
76
+
77
+ // Remove connection-specific headers that shouldn't be forwarded
78
+ const serverHeaders = { ...clientHeaders };
79
+ delete serverHeaders.connection;
80
+ delete serverHeaders["keep-alive"];
81
+ delete serverHeaders.host;
82
+ delete serverHeaders["content-length"];
83
+
84
+ const fetchOptions: any = {
85
+ method: method as any,
86
+ body: body,
87
+ query: query,
88
+ headers: {
89
+ ...serverHeaders,
90
+ ...opts.headers, // Custom headers override client headers
91
+ },
92
+ };
93
+
94
+ // Only add useFetch-specific options if provided
95
+ if (key) {
96
+ fetchOptions.key = key;
97
+ }
98
+ if (opts.default) {
99
+ fetchOptions.default = opts.default;
100
+ }
101
+
102
+ return useFetch<T>(finalUrl, fetchOptions) as any;
103
+ }
54
104
  const data = ref<T | null>(null);
55
105
  const error = ref<any>(null);
56
106
  const pending = ref(false);
@@ -69,7 +119,6 @@ export function useEnfyraApi<T = any>(
69
119
  const config: any = useRuntimeConfig().public.enfyraSDK;
70
120
  const apiUrl = config?.appUrl;
71
121
  const apiPrefix = config?.apiPrefix;
72
-
73
122
  const basePath = (typeof path === "function" ? path() : path)
74
123
  .replace(/^\/?api\/?/, "")
75
124
  .replace(/^\/+/, ""); // Remove leading slashes
package/src/module.ts CHANGED
@@ -18,6 +18,12 @@ export default defineNuxtModule({
18
18
  setup(options, nuxt) {
19
19
  const { resolve } = createResolver(import.meta.url);
20
20
 
21
+ // Make module options available at runtime
22
+ nuxt.options.runtimeConfig.public.enfyraSDK = {
23
+ ...nuxt.options.runtimeConfig.public.enfyraSDK,
24
+ ...options,
25
+ };
26
+
21
27
  // Auto-import composables
22
28
  addImportsDir(resolve("./composables"));
23
29
 
@@ -12,6 +12,10 @@ export interface ApiOptions<T> {
12
12
  errorContext?: string;
13
13
  disableBatch?: boolean;
14
14
  default?: () => T;
15
+ /** Enable SSR with useFetch instead of $fetch */
16
+ ssr?: boolean;
17
+ /** Unique key for useFetch caching */
18
+ key?: string;
15
19
  }
16
20
 
17
21
  export interface BackendError {