@rgomezp/ganon
v2.7.3
Published
React Native firestore wrapper
Maintainers
Readme
React Native Ganon SDK provides seamless storage management and cloud backup capabilities using Firestore and a local storage manager (MMKV).
Overview
GanonDB is a storage and backup management SDK that simplifies integrating Firestore and a local storage system in React Native projects. It provides a typed instance of a storage managers and a simple API for data locally as well as syncing to Firebase.
Note: Supabase & other DBs are coming soon.
Install
# npm
npm install @potionforge/ganon
# yarn
yarn add @potionforge/ganonConfiguration
GanonDB requires configuration to map local storage data to Firestore backup.
Storage Mapping
Define a storage mapping interface. Include the identifier key you will use to track users.
import { BaseStorageMapping } from '@potionforge/ganon';
// Define a mapping interface
interface MyMapping extends BaseStorageMapping {
email: string; // identifier key
booksRead: number;
books: { [key: string]: { title: string } };
}Cloud Config
Define a configuration object for Firestore backups. Maps documents to document and sub-collection keys.
You can exclude the identifier key as this is handled automatically.
interface CloudBackupConfig {
[key: string]: {
docKeys?: string[];
subcollectionKeys?: string[];
type?: 'string' | 'number' | 'boolean' | 'object' | 'array';
schema?: JSONSchema7; // JSON Schema for validating object/array data
}
}Example with Schema Validation:
import { CloudBackupConfig } from '@potionforge/ganon';
import { JSONSchema7 } from 'json-schema';
// Define a mapping interface
interface MyMapping extends BaseStorageMapping {
email: string; // identifier key
booksRead: number;
books: {
[key: string]: {
title: string;
author: string;
rating: number;
genres: string[];
publishedDate: string;
}
};
userPreferences: {
theme: 'light' | 'dark';
notifications: boolean;
fontSize: number;
};
}
// Define JSON schemas for validation
const bookSchema: JSONSchema7 = {
type: 'object',
required: ['title', 'author', 'rating', 'genres', 'publishedDate'],
properties: {
title: { type: 'string', minLength: 1 },
author: { type: 'string', minLength: 1 },
rating: { type: 'number', minimum: 0, maximum: 5 },
genres: {
type: 'array',
items: { type: 'string' },
minItems: 1
},
publishedDate: {
type: 'string',
format: 'date'
}
}
};
const userPreferencesSchema: JSONSchema7 = {
type: 'object',
required: ['theme', 'notifications', 'fontSize'],
properties: {
theme: {
type: 'string',
enum: ['light', 'dark']
},
notifications: { type: 'boolean' },
fontSize: {
type: 'number',
minimum: 12,
maximum: 24
}
}
};
const cloudConfig: CloudBackupConfig<MyMapping> = {
reading: {
docKeys: ['booksRead'],
subcollectionKeys: ['books'],
type: 'object',
schema: bookSchema
},
preferences: {
docKeys: ['userPreferences'],
type: 'object',
schema: userPreferencesSchema
}
};This configuration:
- Defines strict schemas for both books and user preferences
- Validates data structure and types before syncing to Firestore
- Ensures required fields are present
- Enforces value constraints (e.g., rating between 0-5, font size between 12-24)
- Validates date formats and enum values
When using this configuration, Ganon will automatically validate data against these schemas before syncing to Firestore. If validation fails, the sync operation will be rejected and an error will be thrown.
Ganon Config
| Property | Type | Description |
|-----------------|-------------------------|----------------------------------------------------|
| identifierKey | string | Unique user identifier key for users (e.g. email, uid) |
| cloudConfig | CloudBackupConfig<T> | Configuration object for Firestore backups where T is your custom storage mapping. |
| logLevel | LogLevel | LogLevel enum |
| conflictResolutionConfig | Partial<ConflictResolutionConfig> | Optional configuration for handling data conflicts during sync operations |
| integrityFailureConfig | Partial<IntegrityFailureConfig> | Optional configuration for handling integrity failures during sync operations |
Conflict Resolution & Integrity Failure Handling
Ganon provides robust systems to handle both data conflicts and integrity failures during synchronization.
Conflict Resolution Configuration
import { ConflictResolutionStrategy, ConflictMergeStrategy } from '@potionforge/ganon';
const config = {
// ... other config options
conflictResolutionConfig: {
strategy: ConflictResolutionStrategy.LOCAL_WINS,
mergeStrategy: ConflictMergeStrategy.DEEP_MERGE,
notifyOnConflict: true,
trackConflicts: true,
maxTrackedConflicts: 100
}
};Conflict Resolution Strategies
- Local Wins: Use local data as source of truth
strategy: ConflictResolutionStrategy.LOCAL_WINS- Remote Wins: Use remote data as source of truth
strategy: ConflictResolutionStrategy.REMOTE_WINS- Last Modified Wins: Use data with most recent timestamp
strategy: ConflictResolutionStrategy.LAST_MODIFIED_WINSIntegrity Failure Configuration
import { IntegrityFailureRecoveryStrategy } from '@potionforge/ganon';
const config = {
// ... other config options
integrityFailureConfig: {
maxRetries: 3,
retryDelay: 1000,
recoveryStrategy: IntegrityFailureRecoveryStrategy.FORCE_REFRESH,
notifyOnFailure: true
}
};Integrity Failure Recovery Strategies
- Force Refresh: Refresh metadata and re-fetch data
recoveryStrategy: IntegrityFailureRecoveryStrategy.FORCE_REFRESH- Use Local: Trust local data over remote
recoveryStrategy: IntegrityFailureRecoveryStrategy.USE_LOCAL- Use Remote: Trust remote data over local
recoveryStrategy: IntegrityFailureRecoveryStrategy.USE_REMOTE- Skip: Skip problematic keys and continue
recoveryStrategy: IntegrityFailureRecoveryStrategy.SKIPSetup
Create a new file called ganon.ts. We must use the instance in order for our types to work as expected.
Export the instance for usage across your codebase.
import Ganon, { LogLevel } from "@potionforge/ganon";
import cloudBackupConfig from "./cloudBackupConfig";
import { StorageMapping } from "src/models/StorageMapping";
const logLevel = process.env.NODE_ENV === 'development' ? LogLevel.VERBOSE : LogLevel.NONE;
// Initialize once using your specialized type.
export const ganon: Ganon<StorageMapping> = Ganon.init<StorageMapping>({
identifierKey: 'email',
cloudConfig: cloudBackupConfig,
logLevel,
});Usage
Basic Operations
import { ganon } from "<path_to_file>/ganon";
ganon.set("booksRead", 5);Advanced Sync Operations
Hydration with Conflict Resolution
import { ConflictResolutionStrategy, IntegrityFailureRecoveryStrategy } from '@potionforge/ganon';
// Hydrate specific keys with custom conflict resolution
const result = await ganon.hydrate(
['booksRead', 'books'],
{
strategy: ConflictResolutionStrategy.LOCAL_WINS,
notifyOnConflict: true
},
{
maxRetries: 5,
recoveryStrategy: IntegrityFailureRecoveryStrategy.FORCE_REFRESH
}
);
console.log(`Restored ${result.restoredKeys.length} keys`);
console.log(`Failed ${result.failedKeys.length} keys`);Force Hydration
// Force hydrate specific keys regardless of version comparison
const result = await ganon.forceHydrate(
['userPreferences'],
{
strategy: ConflictResolutionStrategy.REMOTE_WINS
},
{
recoveryStrategy: IntegrityFailureRecoveryStrategy.USE_REMOTE
}
);Restore All Data
// Restore all data from cloud (no per-invocation config needed)
const result = await ganon.restore();Available Enums and Types
Ganon exports several enums and types for configuration and type safety:
import {
// Conflict Resolution
ConflictResolutionStrategy,
ConflictMergeStrategy,
ConflictResolutionConfig,
// Integrity Failure Handling
IntegrityFailureRecoveryStrategy,
IntegrityFailureConfig,
// Sync Status
SyncStatus,
// Results
RestoreResult,
BackupResult,
// Logging
LogLevel
} from '@potionforge/ganon';Conflict Resolution Enums
ConflictResolutionStrategy.LOCAL_WINS- Use local dataConflictResolutionStrategy.REMOTE_WINS- Use remote dataConflictResolutionStrategy.LAST_MODIFIED_WINS- Use most recent data
Integrity Failure Recovery Enums
IntegrityFailureRecoveryStrategy.FORCE_REFRESH- Refresh metadata and re-fetchIntegrityFailureRecoveryStrategy.USE_LOCAL- Trust local dataIntegrityFailureRecoveryStrategy.USE_REMOTE- Trust remote dataIntegrityFailureRecoveryStrategy.SKIP- Skip problematic keys
🤝 Contributing
Contributions, issues, and feature requests are welcome!
Feel free to check the issues page.
Show your support
Give a ⭐️ if this project helped you!
Follow
- Twitter: @ro_gmzp
- Github: @potionforge
- LinkedIn: Rodrigo Gomez-Palacio
📝 License
Copyright © 2025 Honey Wolf LLC This project is Proprietary Licensed.
