vyas-auth
v1.0.6
Published
Developer-first SDK that removes friction of wiring Firebase and Cloudinary
Maintainers
Readme
🚀 VysAuth
The developer-first SDK that removes the friction of wiring Firebase and Cloudinary
✨ Features
🚀 Quick Start
Installation
# npm
npm install vys-auth
# yarn
yarn add vys-auth
# pnpm
pnpm add vys-authSetup (30 seconds!)
import { initializeVysAuth } from 'vys-auth';
// Add this to your app entry point (App.tsx, _app.tsx, etc.)
initializeVysAuth({
apiKey: process.env.NEXT_PUBLIC_VYS_API_KEY!, // Get from VysAuth dashboard
baseUrl: 'https://api.vysauth.com' // Optional
});import { AuthButton, useAuth } from 'vys-auth';
function LoginPage() {
const { user, loading, signOut, isAuthenticated } = useAuth();
if (loading) return <div>Loading...</div>;
if (!isAuthenticated) {
return (
<div className="space-y-4">
<AuthButton
auth="google"
onSuccess={(user) => console.log('Welcome!', user)}
onError={(error) => console.error('Oops:', error)}
/>
<AuthButton auth="github" />
<AuthButton auth="facebook" />
</div>
);
}
return (
<div>
<h1>Welcome back, {user?.displayName}! 👋</h1>
<button onClick={signOut}>Sign Out</button>
</div>
);
}import { uploadFile, storeData, storeImageUrl } from 'vys-auth';
function ProfileUpload() {
const { user } = useAuth();
const handleImageUpload = async (file: File) => {
// Upload to Cloudinary with transformations
const upload = await uploadFile(file, {
folder: 'avatars',
transformation: 'w_200,h_200,c_fill,g_face'
});
if (upload.success) {
// Store URL in Firestore
await storeImageUrl(upload.data!.url, {
collection: 'users',
document: user?.uid,
imageField: 'avatar'
});
console.log('Avatar updated! ✨');
}
};
return (
<input
type="file"
onChange={(e) => e.target.files?.[0] && handleImageUpload(e.target.files[0])}
accept="image/*"
/>
);
}That's it! 🎉 You now have authentication, file uploads, and database storage working.
🎯 Why VysAuth?
| Without VysAuth 😩 | With VysAuth 😍 | |-------------------|-----------------| | 🔧 Configure Firebase SDK | ✅ One-line initialization | | 🔧 Setup Cloudinary SDK | ✅ Built-in file uploads | | 🔧 Write auth components | ✅ Ready-to-use components | | 🔧 Handle error states | ✅ Automatic error handling | | 🔧 Manage loading states | ✅ Built-in loading states | | 🔧 TypeScript definitions | ✅ Full type safety included | | ⏰ Days of setup | ⏰ Minutes to production |
📖 API Reference
🎨 Components
<AuthButton>
Beautiful, accessible authentication buttons with built-in providers.
<AuthButton
auth="google" // Provider: 'google' | 'facebook' | 'github' | 'twitter' | 'email'
onSuccess={(user) => {}} // Success callback
onError={(error) => {}} // Error callback
className="custom-styles" // Custom CSS classes
disabled={false} // Disable button
>
Custom Button Text // Optional: custom children
</AuthButton>Providers Available:
- 🟦
google- Google OAuth - 🟦
facebook- Facebook Login - ⚫
github- GitHub OAuth - 🟦
twitter- Twitter OAuth - 📧
email- Email/Password
🎣 Hooks
useAuth()
Complete authentication state management.
const {
user, // Current user object
loading, // Loading state
error, // Error message
isAuthenticated, // Boolean auth status
signIn, // Sign in function
signOut, // Sign out function
refreshUser // Refresh user data
} = useAuth();User Object:
interface User {
uid: string;
email: string | null;
displayName: string | null;
photoURL: string | null;
provider: string;
}🛠️ Utility Functions
File Upload
// Single file upload
const result = await uploadFile(file, {
folder: 'uploads', // Cloudinary folder
transformation: 'w_400,h_400,c_fill', // Image transformations
tags: ['profile', 'user'] // Organization tags
});
// Multiple files
const results = await uploadMultipleFiles(files, options);Data Storage
// Store data
await storeData(userData, {
collection: 'users',
document: 'user123', // Optional: auto-generated if not provided
merge: true // Merge with existing data
});
// Retrieve data
const data = await getData('users', 'user123');
const allUsers = await getData('users'); // Get all documents
// Update data
await updateData(newData, { collection: 'users', document: 'user123' });
// Delete data
await deleteData('users', 'user123');
// Store image URL directly
await storeImageUrl(imageUrl, {
collection: 'posts',
document: 'post123',
imageField: 'thumbnail'
});🔥 Real-World Examples
import { uploadFile, storeData, useAuth } from 'vys-auth';
function PhotoUpload() {
const { user } = useAuth();
const [uploading, setUploading] = useState(false);
const handlePhotoUpload = async (file: File, caption: string) => {
setUploading(true);
// Upload with Instagram-like transformations
const upload = await uploadFile(file, {
folder: 'posts',
transformation: 'w_1080,h_1080,c_fill,q_auto,f_auto'
});
if (upload.success) {
// Store post data
await storeData({
imageUrl: upload.data!.url,
caption,
author: user?.uid,
likes: 0,
createdAt: new Date().toISOString()
}, {
collection: 'posts'
});
console.log('Posted! 📸');
}
setUploading(false);
};
return (
<div>
<input type="file" onChange={/* handle file */} />
<input placeholder="Write a caption..." />
<button disabled={uploading}>
{uploading ? 'Posting...' : 'Share Photo'}
</button>
</div>
);
}import { useAuth, storeData, getData, uploadFile } from 'vys-auth';
function UserProfile() {
const { user } = useAuth();
const [profile, setProfile] = useState(null);
useEffect(() => {
if (user?.uid) {
loadProfile();
}
}, [user]);
const loadProfile = async () => {
const result = await getData('profiles', user?.uid);
if (result.success) {
setProfile(result.data);
}
};
const updateProfile = async (profileData: any) => {
await storeData(profileData, {
collection: 'profiles',
document: user?.uid,
merge: true
});
loadProfile();
};
const updateAvatar = async (file: File) => {
const upload = await uploadFile(file, {
folder: 'avatars',
transformation: 'w_200,h_200,c_fill,g_face,q_auto'
});
if (upload.success) {
await updateProfile({ avatar: upload.data!.url });
}
};
return (
<div>
<img src={profile?.avatar || user?.photoURL} alt="Avatar" />
<input type="file" onChange={(e) =>
e.target.files?.[0] && updateAvatar(e.target.files[0])
} />
<form onSubmit={(e) => {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
updateProfile({
displayName: formData.get('name'),
bio: formData.get('bio'),
website: formData.get('website')
});
}}>
<input name="name" defaultValue={profile?.displayName} />
<textarea name="bio" defaultValue={profile?.bio} />
<input name="website" defaultValue={profile?.website} />
<button type="submit">Save Profile</button>
</form>
</div>
);
}import { uploadMultipleFiles, storeData } from 'vys-auth';
function ProductUpload() {
const [images, setImages] = useState<File[]>([]);
const addProduct = async (productData: any) => {
// Upload all product images
const uploadResults = await uploadMultipleFiles(images, {
folder: 'products',
transformation: 'w_800,h_600,c_fill,q_auto,f_auto'
});
if (uploadResults.success) {
// Store product with image URLs
await storeData({
...productData,
images: uploadResults.data!.map(img => img.url),
thumbnail: uploadResults.data![0].url
}, {
collection: 'products'
});
console.log('Product added! 🛍️');
}
};
return (
<div>
<input
type="file"
multiple
accept="image/*"
onChange={(e) => setImages(Array.from(e.target.files || []))}
/>
<div className="image-preview">
{images.map((file, i) => (
<img key={i} src={URL.createObjectURL(file)} alt={`Preview ${i}`} />
))}
</div>
<form onSubmit={/* handle product submission */}>
<input name="title" placeholder="Product title" />
<input name="price" type="number" placeholder="Price" />
<textarea name="description" placeholder="Description" />
<button type="submit">Add Product</button>
</form>
</div>
);
}🎨 Customization
Custom Auth Button Styles
// Use your own styles
<AuthButton
auth="google"
className="bg-blue-500 hover:bg-blue-600 text-white px-6 py-3 rounded-lg"
>
Sign in with Google
</AuthButton>
// Or customize with CSS modules
<AuthButton
auth="github"
className={styles.customButton}
/>Environment Variables
Create a .env.local file:
# Get your API key from the VysAuth dashboard
NEXT_PUBLIC_VYS_API_KEY=your_api_key_here
# Optional: Custom base URL
NEXT_PUBLIC_VYS_BASE_URL=https://api.vysauth.com🔧 Advanced Configuration
Custom Base URL
initializeVysAuth({
apiKey: process.env.NEXT_PUBLIC_VYS_API_KEY!,
baseUrl: 'https://your-custom-api.com' // Use your own backend
});Error Handling
const { signIn } = useAuth();
try {
await signIn('google');
} catch (error) {
if (error.message.includes('popup_blocked')) {
// Handle popup blocker
} else if (error.message.includes('network')) {
// Handle network errors
}
}File Upload Progress
// For large files, show progress
const uploadWithProgress = async (file: File) => {
const result = await uploadFile(file, {
folder: 'videos',
// Add progress callback when available
});
return result;
};📱 Framework Integration
// pages/_app.tsx or app/layout.tsx
import { initializeVysAuth } from 'vys-auth';
// Initialize once at app startup
initializeVysAuth({
apiKey: process.env.NEXT_PUBLIC_VYS_API_KEY!
});
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
}// src/main.tsx
import { initializeVysAuth } from 'vys-auth';
initializeVysAuth({
apiKey: import.meta.env.VITE_VYS_API_KEY!
});
ReactDOM.render(<App />, document.getElementById('root'));// app/root.tsx
import { initializeVysAuth } from 'vys-auth';
// Initialize in a useEffect or loader
export default function App() {
useEffect(() => {
initializeVysAuth({
apiKey: process.env.VYS_API_KEY!
});
}, []);
return (
<html>
<head />
<body>
<Outlet />
</body>
</html>
);
}🚀 Migration Guide
From Firebase SDK
// Before: Firebase SDK
import { auth } from './firebase';
import { signInWithPopup, GoogleAuthProvider } from 'firebase/auth';
const signInWithGoogle = async () => {
const provider = new GoogleAuthProvider();
const result = await signInWithPopup(auth, provider);
return result.user;
};
// After: VysAuth
import { AuthButton } from 'vys-auth';
<AuthButton
auth="google"
onSuccess={(user) => console.log(user)}
/>From Cloudinary SDK
// Before: Cloudinary SDK
import { Cloudinary } from 'cloudinary-core';
const cloudinary = new Cloudinary({ cloud_name: 'your-cloud' });
// ... complex upload logic
// After: VysAuth
import { uploadFile } from 'vys-auth';
const result = await uploadFile(file, {
folder: 'uploads',
transformation: 'w_400,h_400'
});🤝 Contributing
We love contributions! Here's how to get started:
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes
- Add tests if applicable
- Submit a pull request
Development Setup
git clone https://github.com/vysauth/vys-auth
cd vys-auth
npm install
npm run dev📝 License
MIT License - see LICENSE file for details.
👨💻 Created By
Full-Stack Developer & Creator of VysAuth
⭐ Show Your Support
If VysAuth helped you build something awesome, give us a star! ⭐
