Firebase utilities for DoNotDev
npm install @donotdev/firebaseFirebase utilities for DoNotDev applications. This package provides a clean separation between client-safe and server-only Firebase functions.
This package is split into two main parts:
Import from the main package for client-safe functions:
``typescript`
import { initFirebase, getAuth } from '@donotdev/firebase';
import { getFirestore } from '@donotdev/firebase/server';
Available modules:
- auth.ts - Authentication utilitiesinit.ts
- - Firebase initializationtransform.ts
- - Data transformation utilitiesutils.ts
- - Client-safe utility functionsvalidation.ts
- - Client-safe validation functionsuniqueness.ts
- - Uniqueness validation (client-safe functions only)
Import from the server subpath for server-only functions:
`typescript`
import { batchWrite, getActiveSubscription } from '@donotdev/firebase/server';
Available modules:
- batch.ts - Batch operations (create, update, delete)subscription.ts
- - Subscription managementserver/utils.ts
- - Server-only utilitiesvalidation.ts
- - Server-only validation functionsuniqueness.ts
- - Server-only uniqueness functions
- Data Transformation: Convert between Firestore and application formats
- Uniqueness Validation: Enforce field uniqueness constraints
- Schema Validation: Validate documents against schemas
- Batch Operations: Efficiently handle multiple document operations
- Authentication: Type-safe auth utilities with standard error handling
- Initialization: Simple configuration with environment variable support
`bash`
bun add @donotdev/firebase
`typescript
import { initFirebase, getAuth } from '@donotdev/firebase';
// Initialize Firebase
const { app, auth } = initFirebase();
// Use client SDK
const user = auth?.currentUser;
`
`typescript
import { batchWrite, getActiveSubscription } from '@donotdev/firebase/server';
// Batch operations
const result = await batchWrite('users', users, 'create');
// Subscription management
const subscription = await getActiveSubscription(userId);
`
`typescript
import {
transformFirestoreData,
prepareForFirestore,
} from '@donotdev/firebase';
// Convert Firestore Timestamps to ISO strings
const appData = transformFirestoreData(firestoreData);
// Convert ISO strings to Firestore Timestamps
const firestoreData = prepareForFirestore(appData);
`
`typescript
import { enhanceSchema, validateCreate } from '@donotdev/firebase';
import * as v from 'valibot';
// Create a schema with uniqueness constraints
const userSchema = enhanceSchema(
v.object({
email: z.string().email(),
username: z.string().min(3),
createdAt: z.string().datetime(),
}),
{
collection: 'users',
uniqueFields: [
{ field: 'email', errorMessage: 'Email is already in use' },
{ field: 'username', errorMessage: 'Username is taken' },
],
}
);
// Validate a document before saving
try {
await validateCreate(userSchema, userData);
// Document is valid, proceed with saving
} catch (error) {
// Handle validation errors
console.error('Validation failed:', error);
}
`
`typescript
import { batchCreate, batchUpdate, batchDelete } from '@donotdev/firebase';
// Create multiple documents
const createResult = await batchCreate('products', products);
console.log(
Created ${createResult.successes} products with ${createResult.failures} failures
);
// Update multiple documents
const updateResult = await batchUpdate('products', updatedProducts);
// Delete multiple documents
const deleteResult = await batchDelete('products', productIds, {
idField: 'id',
});
`
The Firebase SDK automatically handles authDomain configuration using a dynamic approach:
- Client-Side (CSR): Uses window.location.hostname for same-origin authenticationAPP_URL
- Server-Side (SSR): Uses environment variable hostname${projectId}.firebaseapp.com
- Localhost: Falls back to for Firebase infrastructure
No manual authDomain configuration required - the SDK handles this automatically.
`typescript
import {
signInWithEmail,
signInWithGoogle,
getCurrentUser,
signOut,
getIdToken,
} from '@donotdev/firebase';
// Sign in with email/password
const user = await signInWithEmail('user@example.com', 'password');
// Sign in with Google
const user = await signInWithGoogle();
// Get current user
const currentUser = getCurrentUser();
// Get authentication token
const token = await getIdToken();
// Sign out
await signOut();
`
`typescript
import { initFirebase } from '@donotdev/firebase';
// Initialize Firebase from environment variables
const { app, auth, firestore } = initFirebase();
// Or with custom configuration
const { app, auth, firestore } = initFirebase({
apiKey: 'your-api-key',
authDomain: 'your-project.firebaseapp.com',
projectId: 'your-project-id',
// ...other config
});
// Use emulators for development
const { app, auth, firestore } = initFirebase(undefined, true);
`
1. No Client Bundling Issues: Server-only functions are never bundled in client builds
2. Clear Separation: Easy to understand what's safe for client vs server
3. Type Safety: Full TypeScript support for both client and server functions
4. Framework Agnostic: Works with Next.js, Vite, and other frameworks
If you were previously importing server functions from the main package:
Before:
`typescript`
import { batchWrite } from '@donotdev/firebase';
After:
`typescript`
import { batchWrite } from '@donotdev/firebase/server';
Required for client initialization:
- VITE_FIREBASE_API_KEYVITE_FIREBASE_PROJECT_ID
-
Optional:
- VITE_FIREBASE_STORAGE_BUCKETVITE_FIREBASE_MESSAGING_SENDER_ID
- VITE_FIREBASE_APP_ID
- VITE_FIREBASE_MEASUREMENT_ID
-
The package includes a demo mode that activates when Firebase configuration is missing. This allows development without Firebase setup.
`typescript
import { isFirebaseDemoMode } from '@donotdev/firebase';
if (isFirebaseDemoMode()) {
console.log('Running in demo mode');
}
`
This package integrates seamlessly with other DoNotDev packages:
- Use with @donotdev/schemas for complete entity validation@donotdev/hooks
- Pair with for type-safe data access@donotdev/auth
- Works with for comprehensive authentication
Data transformation utilities for converting between Firestore and application formats.
- transformFirestoreData: Converts Timestamps to ISO stringsprepareForFirestore
- : Converts ISO strings to TimestampstoTimestamp
- : Converts Date or ISO string to Firestore TimestamptoISOString
- : Converts DateValue to ISO stringcreateFirestorePartialUpdate
- : Creates a diff for partial updates
Document validation against schemas with uniqueness constraints.
- validateFirestoreDocument: Validates document against schema and checks uniquenessvalidateCreate
- : Validates document for creationvalidateUpdate
- : Validates document for updateenhanceSchema
- : Adds Firestore metadata to schema
Uniqueness constraint validation to ensure field values are unique.
- validateUniqueness: Validates uniqueness constraints for a documentcreateFirestoreValidator
- : Server-side validator for uniquenesscreateFirestoreClientValidator
- : Client-side validator for uniqueness
Utilities for batch operations with automatic chunking.
- batchWrite: Generic batch write operationbatchCreate
- : Creates multiple documentsbatchUpdate
- : Updates multiple documentsbatchDelete
- : Deletes multiple documentsbulkGet
- : Fetches multiple documents by ID
Authentication utilities for client-side operations.
- signInWithEmail: Signs in with email and passwordsignInWithGoogle
- : Signs in with GoogleresetPassword
- : Sends password reset emailgetCurrentUser
- : Gets current authenticated usergetIdToken
- : Gets authentication tokensignOut
- : Signs out current userisCurrentUserAdmin
- : Checks if current user has admin role
Core utilities for Firebase operations.
- handleFirebaseError: Standardizes Firebase errorsgenerateId
- : Generates unique IDs for documentsexecuteFirebaseOperation
- : Executes operation with retry support
Initialization utilities for Firebase in different environments.
- initFirebase: Initializes Firebase from environment variables or configinitAdminApp
- : Initializes Firebase Admin SDK
1. Always transform data when crossing the Firebase boundary:
`typescript
// Before saving to Firestore
const firestoreData = prepareForFirestore(appData);
// After fetching from Firestore
const appData = transformFirestoreData(firestoreData);
`
2. Use batch operations for multiple documents:
`typescript`
// Instead of multiple individual writes
await batchCreate('products', newProducts);
3. Handle errors consistently:
`typescript`
try {
// Firebase operation
} catch (error) {
throw handleFirebaseError(error, 'Operation name');
}
4. Enforce uniqueness constraints:
`typescript`
const schema = enhanceSchema(productSchema, {
collection: 'products',
uniqueFields: [{ field: 'sku', errorMessage: 'SKU already exists' }],
});
5. For server environments, initialize validator early:
`typescript
import { createFirestoreValidator } from '@donotdev/firebase/server';
async function initializeApp() {
// Set up validator once at app startup
await createFirestoreValidator();
}
``
All rights reserved.
The DoNotDev framework and its premium features are the exclusive property of Ambroise Park Consulting.
- Premium features require an active paid subscription.
- Redistribution, reverse-engineering, or commercial reuse is strictly prohibited without written authorization.
Ā© Ambroise Park Consulting ā 2025