Nuxt SDK for Enfyra CMS - A lightweight composable-based API client with full TypeScript integration.
✅ Simple & Flexible - Get base URL and build your own composables
✅ Authentication Integration - Built-in auth composables with automatic header forwarding
✅ Asset Proxy - Automatic /assets/** proxy to backend with no configuration needed
✅ TypeScript Support - Full type safety with auto-generated declarations
✅ SSR Ready - Works seamlessly with Nuxt's useFetch and $fetch
npm install @enfyra/sdk-nuxtAdd the module to your nuxt.config.ts:
export default defineNuxtConfig({
modules: ["@enfyra/sdk-nuxt"],
enfyraSDK: {
apiUrl: "http://localhost:1105", // Only apiUrl is required
},
})The SDK automatically detects your application URL:
- Client-side: Uses
window.location.origin - Server-side: Detects from request headers (supports proxies with
X-Forwarded-*headers) - No configuration needed: Works out of the box with any deployment
// Get the base URL for your API requests
const { baseUrl, apiPrefix } = useEnfyra();
// baseUrl: "http://localhost:3001/enfyra/api"
// apiPrefix: "/enfyra/api"// pages/users.vue
<script setup>
const { baseUrl } = useEnfyra();
// Use with Nuxt's useFetch for SSR support
const { data: users, pending, error, refresh } = await useFetch(`${baseUrl}/users`, {
key: 'users-list' // Optional cache key
});
</script>
<template>
<div>
<div v-if="pending">Loading users...</div>
<div v-else-if="error">Error: {{ error }}</div>
<div v-else>
<h1>Users ({{ users?.meta?.totalCount }})</h1>
<UserCard v-for="user in users?.data" :key="user.id" :user="user" />
<button @click="refresh">Refresh</button>
</div>
</div>
</template>// components/CreateUserForm.vue
<script setup>
const { baseUrl } = useEnfyra();
const pending = ref(false);
const error = ref(null);
const formData = reactive({
name: '',
email: ''
});
async function handleSubmit() {
pending.value = true;
error.value = null;
try {
const response = await $fetch(`${baseUrl}/users`, {
method: 'POST',
body: formData
});
toast.success('User created successfully!');
await navigateTo('/users');
} catch (err) {
error.value = err;
toast.error('Failed to create user');
} finally {
pending.value = false;
}
}
</script><script setup>
const { me, login, logout, fetchUser, isLoggedIn } = useEnfyraAuth();
// Login
await login({
email: 'user@example.com',
password: 'password123'
});
// Check auth status
console.log('Logged in:', isLoggedIn.value);
console.log('Current user:', me.value);
// Fetch user with optional fields
await fetchUser({ fields: ['id', 'email', 'role'] });
// Logout
await logout();
</script>The SDK automatically proxies all asset requests to your backend. Simply use /assets/** paths directly:
<template>
<!-- ✅ Assets are automatically proxied to your backend -->
<img src="/assets/images/logo.svg" alt="Logo" />
<img :src="`/assets/images/users/${user.id}/avatar.jpg`" alt="Avatar" />
<!-- Works with any asset type -->
<video src="/assets/videos/intro.mp4" controls />
<a :href="`/assets/documents/${doc.filename}`" download>Download PDF</a>
</template>How it works:
- All requests to
/assets/**are automatically proxied to{apiUrl}/enfyra/api/assets/** - No configuration needed - works out of the box
- Supports all asset types: images, videos, documents, etc.
- Maintains proper authentication headers
Get the base URL and API prefix for building your own API requests.
const { baseUrl, apiPrefix } = useEnfyra();
// baseUrl: "http://localhost:3001/enfyra/api"
// apiPrefix: "/enfyra/api"Returns:
baseUrl: string- Full base URL including app URL and API prefixapiPrefix: string- API prefix path (e.g., "/enfyra/api")
Authentication composable with reactive state management.
const { me, login, logout, fetchUser, isLoggedIn } = useEnfyraAuth();
// Properties
me.value // Current user data (reactive)
isLoggedIn.value // Auth status (computed)
// Methods
await login({ email, password }) // Login user
await logout() // Logout user
await fetchUser({ fields?: string[] }) // Refresh user data with optional fieldsLogin:
const response = await login({
email: 'user@example.com',
password: 'password123',
remember: true // Optional
});Fetch User:
// Fetch all user fields
await fetchUser();
// Fetch specific fields only
await fetchUser({
fields: ['id', 'email', 'role', 'allowedRoutePermissions']
});Since you have access to baseUrl, you can build your own composables using Nuxt's built-in utilities:
// composables/useUsers.ts
export const useUsers = () => {
const { baseUrl } = useEnfyra();
// SSR mode with useFetch
const getUsers = (options?: { page?: number; limit?: number }) => {
return useFetch(`${baseUrl}/users`, {
key: `users-${options?.page || 1}`,
query: options
});
};
// Client mode with $fetch
const createUser = async (userData: any) => {
return await $fetch(`${baseUrl}/users`, {
method: 'POST',
body: userData
});
};
const updateUser = async (id: string, userData: any) => {
return await $fetch(`${baseUrl}/users/${id}`, {
method: 'PATCH',
body: userData
});
};
const deleteUser = async (id: string) => {
return await $fetch(`${baseUrl}/users/${id}`, {
method: 'DELETE'
});
};
return {
getUsers,
createUser,
updateUser,
deleteUser
};
};// Define your API response types
interface User {
id: string;
name: string;
email: string;
}
interface ApiResponse<T> {
data: T[];
meta: { totalCount: number };
}
// Use with full type safety
const { baseUrl } = useEnfyra();
const { data } = await useFetch<ApiResponse<User>>(`${baseUrl}/users`);
// TypeScript knows data.value is ApiResponse<User> | null
const users = computed(() => data.value?.data || []);const { baseUrl } = useEnfyra();
const searchQuery = ref('');
const page = ref(1);
// SSR mode with reactive query
const { data, refresh } = await useFetch(`${baseUrl}/users`, {
key: () => `users-${page.value}-${searchQuery.value}`,
query: computed(() => ({
search: searchQuery.value,
page: page.value,
limit: 10
}))
});
// Watch for changes and refresh
watch([searchQuery, page], () => refresh());// nuxt.config.ts
export default defineNuxtConfig({
modules: ["@enfyra/sdk-nuxt"],
enfyraSDK: {
// Required: Main API URL
apiUrl: process.env.ENFYRA_API_URL || "http://localhost:1105",
// Optional: API prefix (defaults to "/enfyra/api")
apiPrefix: "/enfyra/api",
},
})# .env
ENFYRA_API_URL=https://api.enfyra.com// ✅ Use useFetch for initial page data (runs immediately, SSR support)
const { baseUrl } = useEnfyra();
const { data } = await useFetch(`${baseUrl}/dashboard`, {
key: 'dashboard'
});// ✅ Use $fetch for user interactions (manual execution)
const { baseUrl } = useEnfyra();
async function saveSettings(settings: any) {
try {
await $fetch(`${baseUrl}/settings`, {
method: 'PATCH',
body: settings
});
toast.success('Saved successfully');
} catch (error) {
toast.error('Failed to save');
}
}// ✅ Create reusable composables for your API endpoints
export const useProducts = () => {
const { baseUrl } = useEnfyra();
return {
list: (query?: any) => useFetch(`${baseUrl}/products`, { query }),
get: (id: string) => useFetch(`${baseUrl}/products/${id}`),
create: (data: any) => $fetch(`${baseUrl}/products`, { method: 'POST', body: data }),
update: (id: string, data: any) => $fetch(`${baseUrl}/products/${id}`, { method: 'PATCH', body: data }),
delete: (id: string) => $fetch(`${baseUrl}/products/${id}`, { method: 'DELETE' }),
};
};- Base URL is empty - Ensure
apiUrlis configured innuxt.config.ts - Assets not loading - Check that
/assets/**routes are accessible - Authentication not working - Verify cookies are being set and forwarded
- Use
useFetchwith cache keys for SSR data (better SEO, faster page loads) - Use
$fetchfor user interactions (better UX) - Build reusable composables to avoid code duplication
- Leverage Nuxt's built-in caching with
useFetchkeys
# Build the module
npm run build
# Development mode
npm run devMIT
Pull requests are welcome! Please read our contributing guidelines and ensure tests pass before submitting.
For issues and questions: