sqlite-cloud-backup 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/db-manager.ts","../src/utils/checksum.ts","../src/utils/file-operations.ts","../src/core/sync-engine.ts","../src/providers/google-drive/google-drive-provider.ts","../src/providers/base-provider.ts","../src/providers/google-drive/oauth-flow.ts","../src/providers/google-drive/token-storage.ts","../src/utils/logger.ts","../src/index.ts"],"sourcesContent":["import Database from 'better-sqlite3';\nimport fs from 'fs';\nimport path from 'path';\nimport { ChecksumUtil } from '../utils/checksum';\nimport { FileOperations } from '../utils/file-operations';\nimport { Logger } from '../utils/logger';\nimport { LocalMetadata } from '../types';\n\nexport class DatabaseManager {\n private db: Database.Database | null = null;\n private dbPath: string;\n private metadataPath: string;\n private logger: Logger;\n\n constructor(dbPath: string, logger: Logger) {\n this.dbPath = dbPath;\n this.logger = logger;\n\n const dbDir = path.dirname(dbPath);\n const dbName = path.basename(dbPath, path.extname(dbPath));\n\n this.metadataPath = path.join(dbDir, '.sqlite-cloud-backup', dbName, 'metadata.json');\n\n FileOperations.ensureDir(path.dirname(this.metadataPath));\n }\n\n /**\n * Open database connection\n */\n open(): void {\n if (!fs.existsSync(this.dbPath)) {\n throw new Error(`Database not found: ${this.dbPath}`);\n }\n this.db = new Database(this.dbPath, { readonly: false });\n }\n\n /**\n * Close database connection\n */\n close(): void {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n }\n\n /**\n * Get database file as buffer\n */\n async getBuffer(): Promise<Buffer> {\n this.close(); // Ensure no active connections\n return fs.promises.readFile(this.dbPath);\n }\n\n /**\n * Calculate current database checksum\n */\n async getChecksum(): Promise<string> {\n this.close(); // Ensure no active connections\n return ChecksumUtil.calculateFileChecksum(this.dbPath);\n }\n\n /**\n * Replace database with buffer\n */\n async replaceWithBuffer(buffer: Buffer): Promise<void> {\n this.close();\n\n // Write atomically\n const tempPath = `${this.dbPath}.tmp`;\n await fs.promises.writeFile(tempPath, buffer);\n await fs.promises.rename(tempPath, this.dbPath);\n\n this.logger.info('Database replaced from cloud');\n }\n\n /**\n * Get local metadata\n */\n async getLocalMetadata(): Promise<LocalMetadata> {\n if (!fs.existsSync(this.metadataPath)) {\n return {\n lastSyncTimestamp: 0,\n lastSyncChecksum: ''\n };\n }\n\n const content = await fs.promises.readFile(this.metadataPath, 'utf-8');\n return JSON.parse(content);\n }\n\n /**\n * Update local metadata\n */\n async updateLocalMetadata(metadata: Partial<LocalMetadata>): Promise<void> {\n const current = await this.getLocalMetadata();\n const updated = { ...current, ...metadata };\n\n await fs.promises.writeFile(\n this.metadataPath,\n JSON.stringify(updated, null, 2)\n );\n }\n\n /**\n * Get modification time of database file\n */\n async getModifiedTime(): Promise<number> {\n const stats = await fs.promises.stat(this.dbPath);\n return stats.mtimeMs;\n }\n}\n","import crypto from 'crypto';\nimport fs from 'fs';\n\nexport class ChecksumUtil {\n /**\n * Calculate SHA-256 checksum of a file\n */\n static async calculateFileChecksum(filePath: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const hash = crypto.createHash('sha256');\n const stream = fs.createReadStream(filePath);\n\n stream.on('data', (data) => hash.update(data));\n stream.on('end', () => resolve(hash.digest('hex')));\n stream.on('error', reject);\n });\n }\n\n /**\n * Calculate SHA-256 checksum of a buffer\n */\n static calculateBufferChecksum(buffer: Buffer): string {\n return crypto.createHash('sha256').update(buffer).digest('hex');\n }\n\n /**\n * Verify file integrity\n */\n static async verifyChecksum(filePath: string, expectedChecksum: string): Promise<boolean> {\n const actualChecksum = await this.calculateFileChecksum(filePath);\n return actualChecksum === expectedChecksum;\n }\n}\n","import fs from 'fs';\n\nexport class FileOperations {\n /**\n * Ensure directory exists, create if not\n */\n static ensureDir(dirPath: string): void {\n if (!fs.existsSync(dirPath)) {\n fs.mkdirSync(dirPath, { recursive: true });\n }\n }\n\n /**\n * Copy file atomically\n */\n static async copyFile(source: string, destination: string): Promise<void> {\n const tempDest = `${destination}.tmp`;\n await fs.promises.copyFile(source, tempDest);\n await fs.promises.rename(tempDest, destination);\n }\n}\n","import { DatabaseManager } from './db-manager';\nimport { BaseProvider } from '../providers/base-provider';\nimport { ChecksumUtil } from '../utils/checksum';\nimport { Logger } from '../utils/logger';\nimport { SyncResult, SyncMetadata } from '../types';\n\nexport class SyncEngine {\n private dbManager: DatabaseManager;\n private provider: BaseProvider;\n private logger: Logger;\n\n constructor(\n dbManager: DatabaseManager,\n provider: BaseProvider,\n logger: Logger\n ) {\n this.dbManager = dbManager;\n this.provider = provider;\n this.logger = logger;\n }\n\n /**\n * Push local database to cloud\n */\n async pushToCloud(): Promise<SyncResult> {\n const startTime = Date.now();\n\n try {\n // Get database buffer\n const buffer = await this.dbManager.getBuffer();\n const originalSize = buffer.length;\n\n // Calculate checksum\n const checksum = ChecksumUtil.calculateBufferChecksum(buffer);\n\n // Upload\n await this.provider.uploadFile('current.db', buffer);\n\n // Update metadata\n const metadata: SyncMetadata = {\n dbName: 'current',\n lastSyncTimestamp: Date.now(),\n lastSyncType: 'push',\n checksum,\n version: 1\n };\n await this.provider.updateMetadata(metadata);\n\n // Update local metadata\n await this.dbManager.updateLocalMetadata({\n lastSyncTimestamp: metadata.lastSyncTimestamp,\n lastSyncChecksum: checksum\n });\n\n const result: SyncResult = {\n success: true,\n type: 'push',\n timestamp: Date.now(),\n localChecksum: checksum,\n cloudChecksum: checksum,\n bytesTransferred: buffer.length,\n duration: Date.now() - startTime\n };\n\n this.logger.info(`Push successful: ${originalSize} bytes`);\n return result;\n\n } catch (error) {\n this.logger.error('Push failed', error as Error);\n throw error;\n }\n }\n\n /**\n * Pull database from cloud to local\n */\n async pullFromCloud(): Promise<SyncResult> {\n const startTime = Date.now();\n\n try {\n // Check if cloud version exists\n const exists = await this.provider.fileExists('current.db');\n if (!exists) {\n throw new Error('No cloud version found');\n }\n\n // Download\n const buffer = await this.provider.downloadFile('current.db');\n\n // Verify checksum\n const checksum = ChecksumUtil.calculateBufferChecksum(buffer);\n const cloudMetadata = await this.provider.getMetadata('current.db');\n\n if (cloudMetadata && cloudMetadata.checksum !== checksum) {\n throw new Error('Checksum mismatch - data corruption detected');\n }\n\n // Replace local database\n await this.dbManager.replaceWithBuffer(buffer);\n\n // Update local metadata\n await this.dbManager.updateLocalMetadata({\n lastSyncTimestamp: Date.now(),\n lastSyncChecksum: checksum\n });\n\n const result: SyncResult = {\n success: true,\n type: 'pull',\n timestamp: Date.now(),\n localChecksum: checksum,\n cloudChecksum: checksum,\n bytesTransferred: buffer.length,\n duration: Date.now() - startTime\n };\n\n this.logger.info(`Pull successful: ${buffer.length} bytes`);\n return result;\n\n } catch (error) {\n this.logger.error('Pull failed', error as Error);\n throw error;\n }\n }\n\n /**\n * Bidirectional sync - simple version for v0.1\n */\n async sync(): Promise<SyncResult> {\n const startTime = Date.now();\n\n try {\n const cloudExists = await this.provider.fileExists('current.db');\n\n if (!cloudExists) {\n // No cloud version - push\n this.logger.info('No cloud version found, pushing local database');\n return await this.pushToCloud();\n }\n\n // Compare checksums and timestamps\n const localChecksum = await this.dbManager.getChecksum();\n const cloudMetadata = await this.provider.getMetadata('current.db');\n\n if (!cloudMetadata) {\n this.logger.info('No cloud metadata, pushing local database');\n return await this.pushToCloud();\n }\n\n if (localChecksum === cloudMetadata.checksum) {\n // Already in sync\n const result: SyncResult = {\n success: true,\n type: 'bidirectional',\n timestamp: Date.now(),\n localChecksum,\n cloudChecksum: cloudMetadata.checksum,\n bytesTransferred: 0,\n duration: Date.now() - startTime\n };\n\n this.logger.info('Already in sync');\n return result;\n }\n\n // Determine which is newer\n const localModified = await this.dbManager.getModifiedTime();\n\n // Simple strategy: if local was modified more recently, push; otherwise pull\n if (localModified > cloudMetadata.modifiedAt) {\n this.logger.info('Local is newer, pushing');\n return await this.pushToCloud();\n } else {\n this.logger.info('Cloud is newer, pulling');\n return await this.pullFromCloud();\n }\n\n } catch (error) {\n this.logger.error('Sync failed', error as Error);\n throw error;\n }\n }\n}\n","import { google, drive_v3 } from 'googleapis';\nimport { OAuth2Client } from 'google-auth-library';\nimport { BaseProvider } from '../base-provider';\nimport { GoogleDriveCredentials, ProviderMetadata, SyncMetadata } from '../../types';\nimport { Logger } from '../../utils/logger';\nimport { Readable } from 'stream';\n\nexport class GoogleDriveProvider extends BaseProvider {\n private drive: drive_v3.Drive;\n private oauth2Client: OAuth2Client;\n private rootFolderId: string | null = null;\n private logger: Logger;\n private dbName: string;\n\n constructor(credentials: GoogleDriveCredentials, dbName: string, logger: Logger) {\n super();\n this.logger = logger;\n this.dbName = dbName;\n\n this.oauth2Client = new google.auth.OAuth2(\n credentials.clientId,\n credentials.clientSecret,\n credentials.redirectUri\n );\n\n this.oauth2Client.setCredentials({\n refresh_token: credentials.refreshToken\n });\n\n this.drive = google.drive({ version: 'v3', auth: this.oauth2Client });\n }\n\n /**\n * Initialize folder structure\n */\n private async ensureRootFolder(): Promise<string> {\n if (this.rootFolderId) return this.rootFolderId;\n\n // Check if .sqlite-cloud-backup folder exists\n const response = await this.drive.files.list({\n q: \"name='.sqlite-cloud-backup' and mimeType='application/vnd.google-apps.folder' and trashed=false\",\n fields: 'files(id, name)',\n spaces: 'drive'\n });\n\n if (response.data.files && response.data.files.length > 0) {\n this.rootFolderId = response.data.files[0].id!;\n } else {\n // Create root folder\n const folder = await this.drive.files.create({\n requestBody: {\n name: '.sqlite-cloud-backup',\n mimeType: 'application/vnd.google-apps.folder'\n },\n fields: 'id'\n });\n this.rootFolderId = folder.data.id!;\n }\n\n // Ensure db-specific subfolder\n const dbFolderId = await this.ensureDbFolder();\n\n return dbFolderId;\n }\n\n private async ensureDbFolder(): Promise<string> {\n const response = await this.drive.files.list({\n q: `name='${this.dbName}' and mimeType='application/vnd.google-apps.folder' and '${this.rootFolderId}' in parents and trashed=false`,\n fields: 'files(id, name)'\n });\n\n if (response.data.files && response.data.files.length > 0) {\n return response.data.files[0].id!;\n }\n\n const folder = await this.drive.files.create({\n requestBody: {\n name: this.dbName,\n mimeType: 'application/vnd.google-apps.folder',\n parents: [this.rootFolderId!]\n },\n fields: 'id'\n });\n\n return folder.data.id!;\n }\n\n async uploadFile(fileName: string, buffer: Buffer): Promise<void> {\n const folderId = await this.ensureRootFolder();\n\n // Check if file exists\n const existing = await this.findFile(fileName);\n\n const media = {\n mimeType: 'application/x-sqlite3',\n body: Readable.from(buffer)\n };\n\n if (existing) {\n // Update existing file\n await this.drive.files.update({\n fileId: existing.id!,\n media,\n fields: 'id'\n });\n this.logger.info(`Updated file in Google Drive: ${fileName}`);\n } else {\n // Create new file\n await this.drive.files.create({\n requestBody: {\n name: fileName,\n parents: [folderId]\n },\n media,\n fields: 'id'\n });\n this.logger.info(`Uploaded file to Google Drive: ${fileName}`);\n }\n }\n\n async downloadFile(fileName: string): Promise<Buffer> {\n const file = await this.findFile(fileName);\n if (!file) {\n throw new Error(`File not found: ${fileName}`);\n }\n\n const response = await this.drive.files.get(\n { fileId: file.id!, alt: 'media' },\n { responseType: 'arraybuffer' }\n );\n\n this.logger.info(`Downloaded file from Google Drive: ${fileName}`);\n return Buffer.from(response.data as ArrayBuffer);\n }\n\n async fileExists(fileName: string): Promise<boolean> {\n const file = await this.findFile(fileName);\n return file !== null;\n }\n\n async getMetadata(_fileName: string): Promise<ProviderMetadata | null> {\n const metadataFile = await this.findFile('metadata.json');\n if (!metadataFile) return null;\n\n const buffer = await this.downloadFile('metadata.json');\n const metadata: SyncMetadata = JSON.parse(buffer.toString('utf-8'));\n\n return {\n checksum: metadata.checksum,\n modifiedAt: metadata.lastSyncTimestamp,\n size: 0 // Not tracked in metadata\n };\n }\n\n async updateMetadata(metadata: SyncMetadata): Promise<void> {\n const buffer = Buffer.from(JSON.stringify(metadata, null, 2));\n await this.uploadFile('metadata.json', buffer);\n }\n\n async deleteFile(fileName: string): Promise<void> {\n const file = await this.findFile(fileName);\n if (file) {\n await this.drive.files.delete({ fileId: file.id! });\n this.logger.info(`Deleted file from Google Drive: ${fileName}`);\n }\n }\n\n private async findFile(fileName: string): Promise<drive_v3.Schema$File | null> {\n const folderId = await this.ensureRootFolder();\n\n const response = await this.drive.files.list({\n q: `name='${fileName}' and '${folderId}' in parents and trashed=false`,\n fields: 'files(id, name, modifiedTime)'\n });\n\n return response.data.files?.[0] || null;\n }\n}\n","import { ProviderMetadata } from '../types';\n\nexport abstract class BaseProvider {\n /**\n * Upload database file to cloud\n */\n abstract uploadFile(fileName: string, buffer: Buffer): Promise<void>;\n\n /**\n * Download database file from cloud\n */\n abstract downloadFile(fileName: string): Promise<Buffer>;\n\n /**\n * Check if file exists in cloud\n */\n abstract fileExists(fileName: string): Promise<boolean>;\n\n /**\n * Get file metadata from cloud\n */\n abstract getMetadata(fileName: string): Promise<ProviderMetadata | null>;\n\n /**\n * Update metadata file\n */\n abstract updateMetadata(metadata: unknown): Promise<void>;\n\n /**\n * Delete file from cloud\n */\n abstract deleteFile(fileName: string): Promise<void>;\n}\n","import http from 'http';\nimport { URL } from 'url';\nimport { Logger } from '../../utils/logger';\nimport open from 'open';\n\nexport interface OAuthTokens {\n access_token: string;\n refresh_token: string;\n expiry_date?: number;\n}\n\nexport class OAuthFlow {\n private logger: Logger;\n private server: http.Server | null = null;\n private readonly redirectUri = 'http://localhost:3000/oauth/callback';\n private readonly scopes = ['https://www.googleapis.com/auth/drive.file'];\n\n constructor(logger: Logger) {\n this.logger = logger;\n }\n\n /**\n * Start OAuth flow - opens browser and waits for callback\n */\n async authenticate(clientId: string, clientSecret: string): Promise<OAuthTokens> {\n this.logger.info('Starting OAuth flow...');\n\n // Start local server to receive callback\n const authCode = await this.startLocalServerAndWaitForCode(clientId);\n\n // Exchange code for tokens\n const tokens = await this.exchangeCodeForTokens(authCode, clientId, clientSecret);\n\n this.logger.info('OAuth authentication successful');\n return tokens;\n }\n\n /**\n * Start local HTTP server and wait for OAuth callback\n */\n private async startLocalServerAndWaitForCode(clientId: string): Promise<string> {\n return new Promise((resolve, reject) => {\n this.server = http.createServer((req, res) => {\n const url = new URL(req.url || '', `http://localhost:3000`);\n\n if (url.pathname === '/oauth/callback') {\n const code = url.searchParams.get('code');\n const error = url.searchParams.get('error');\n\n if (error) {\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end('<h1>Authentication Failed</h1><p>You can close this window.</p>');\n this.stopServer();\n reject(new Error(`OAuth error: ${error}`));\n return;\n }\n\n if (code) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('<h1>Authentication Successful!</h1><p>You can close this window and return to the app.</p>');\n this.stopServer();\n resolve(code);\n return;\n }\n\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end('<h1>Invalid Request</h1><p>No authorization code received.</p>');\n this.stopServer();\n reject(new Error('No authorization code received'));\n } else {\n res.writeHead(404);\n res.end();\n }\n });\n\n this.server.listen(3000, () => {\n this.logger.info('Local OAuth server started on http://localhost:3000');\n\n // Build OAuth URL\n const authUrl = this.buildAuthUrl(clientId);\n\n // Open browser\n this.logger.info('Opening browser for authentication...');\n open(authUrl).catch(err => {\n this.logger.error('Failed to open browser', err);\n this.logger.info(`Please open this URL manually: ${authUrl}`);\n });\n });\n\n // Timeout after 5 minutes\n setTimeout(() => {\n this.stopServer();\n reject(new Error('OAuth flow timed out after 5 minutes'));\n }, 5 * 60 * 1000);\n });\n }\n\n /**\n * Build Google OAuth authorization URL\n */\n private buildAuthUrl(clientId: string): string {\n const params = new URLSearchParams({\n client_id: clientId,\n redirect_uri: this.redirectUri,\n response_type: 'code',\n scope: this.scopes.join(' '),\n access_type: 'offline',\n prompt: 'consent' // Force to get refresh token\n });\n\n return `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;\n }\n\n /**\n * Exchange authorization code for tokens\n */\n private async exchangeCodeForTokens(\n code: string,\n clientId: string,\n clientSecret: string\n ): Promise<OAuthTokens> {\n this.logger.info('Exchanging authorization code for tokens...');\n\n const response = await fetch('https://oauth2.googleapis.com/token', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded'\n },\n body: new URLSearchParams({\n code,\n client_id: clientId,\n client_secret: clientSecret,\n redirect_uri: this.redirectUri,\n grant_type: 'authorization_code'\n }).toString()\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to exchange code for tokens: ${error}`);\n }\n\n const data = await response.json() as {\n access_token: string;\n refresh_token: string;\n expires_in?: number;\n };\n\n return {\n access_token: data.access_token,\n refresh_token: data.refresh_token,\n expiry_date: data.expires_in ? Date.now() + data.expires_in * 1000 : undefined\n };\n }\n\n /**\n * Stop the local server\n */\n private stopServer(): void {\n if (this.server) {\n this.server.close();\n this.server = null;\n this.logger.info('Local OAuth server stopped');\n }\n }\n}\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { Logger } from '../../utils/logger.js';\n\nexport interface StoredTokens {\n refreshToken: string;\n accessToken?: string;\n expiryDate?: number;\n}\n\nexport class TokenStorage {\n private logger: Logger;\n private tokenDir: string;\n private tokenFile: string;\n\n constructor(dbPath: string, logLevel: 'debug' | 'info' | 'warn' | 'error' = 'info') {\n this.logger = new Logger(logLevel);\n\n // Store tokens next to the database\n const dbDir = path.dirname(dbPath);\n this.tokenDir = path.join(dbDir, '.sqlite-cloud-backup');\n this.tokenFile = path.join(this.tokenDir, 'tokens.json');\n }\n\n async hasTokens(): Promise<boolean> {\n try {\n await fs.access(this.tokenFile);\n return true;\n } catch {\n return false;\n }\n }\n\n async getTokens(): Promise<StoredTokens | null> {\n try {\n const data = await fs.readFile(this.tokenFile, 'utf-8');\n const tokens = JSON.parse(data) as StoredTokens;\n this.logger.debug('Retrieved stored tokens');\n return tokens;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n this.logger.warn('Failed to read tokens', error);\n }\n return null;\n }\n }\n\n async saveTokens(tokens: StoredTokens): Promise<void> {\n try {\n // Ensure directory exists\n await fs.mkdir(this.tokenDir, { recursive: true });\n\n // Write tokens to file\n await fs.writeFile(\n this.tokenFile,\n JSON.stringify(tokens, null, 2),\n 'utf-8'\n );\n\n this.logger.debug('Saved tokens to storage');\n } catch (error) {\n this.logger.error('Failed to save tokens', error as Error);\n throw new Error('Failed to save authentication tokens');\n }\n }\n\n async clearTokens(): Promise<void> {\n try {\n await fs.unlink(this.tokenFile);\n this.logger.debug('Cleared stored tokens');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n this.logger.warn('Failed to clear tokens', error);\n }\n }\n }\n}\n","export type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport class Logger {\n private level: LogLevel;\n\n constructor(level: LogLevel = 'info') {\n this.level = level;\n }\n\n private shouldLog(level: LogLevel): boolean {\n const levels: LogLevel[] = ['debug', 'info', 'warn', 'error'];\n return levels.indexOf(level) >= levels.indexOf(this.level);\n }\n\n debug(message: string, meta?: unknown): void {\n if (this.shouldLog('debug')) {\n console.debug(`[DEBUG] ${message}`, meta || '');\n }\n }\n\n info(message: string, meta?: unknown): void {\n if (this.shouldLog('info')) {\n console.info(`[INFO] ${message}`, meta || '');\n }\n }\n\n warn(message: string, meta?: unknown): void {\n if (this.shouldLog('warn')) {\n console.warn(`[WARN] ${message}`, meta || '');\n }\n }\n\n error(message: string, error?: Error): void {\n if (this.shouldLog('error')) {\n console.error(`[ERROR] ${message}`, error || '');\n }\n }\n}\n","import { DatabaseManager } from './core/db-manager';\nimport { SyncEngine } from './core/sync-engine';\nimport { GoogleDriveProvider, OAuthFlow, TokenStorage } from './providers/google-drive';\nimport { BaseProvider } from './providers/base-provider';\nimport { Logger } from './utils/logger';\nimport {\n SyncConfig,\n SyncResult,\n GoogleDriveCredentials\n} from './types';\nimport path from 'path';\n\nexport class SqliteCloudBackup {\n private dbManager: DatabaseManager;\n private provider: BaseProvider;\n private syncEngine: SyncEngine;\n private logger: Logger;\n private oauthFlow: OAuthFlow;\n private tokenStorage: TokenStorage;\n private credentials: GoogleDriveCredentials;\n private dbPath: string;\n\n constructor(config: SyncConfig) {\n // Initialize logger\n this.logger = new Logger(config.options?.logLevel ?? 'info');\n\n // Store config for OAuth flow\n this.dbPath = config.dbPath;\n this.credentials = config.credentials as GoogleDriveCredentials;\n\n // Initialize OAuth flow and token storage\n this.oauthFlow = new OAuthFlow(this.logger);\n this.tokenStorage = new TokenStorage(config.dbPath, config.options?.logLevel ?? 'info');\n\n // Initialize components\n this.dbManager = new DatabaseManager(config.dbPath, this.logger);\n\n // Initialize provider based on config\n this.provider = this.createProvider(config);\n\n // Initialize sync engine\n this.syncEngine = new SyncEngine(\n this.dbManager,\n this.provider,\n this.logger\n );\n }\n\n private createProvider(config: SyncConfig): BaseProvider {\n const dbName = path.basename(config.dbPath, path.extname(config.dbPath));\n\n switch (config.provider) {\n case 'google-drive':\n return new GoogleDriveProvider(\n config.credentials as GoogleDriveCredentials,\n dbName,\n this.logger\n );\n default:\n throw new Error(`Unsupported provider: ${config.provider}`);\n }\n }\n\n /**\n * Check if user needs authentication\n */\n async needsAuthentication(): Promise<boolean> {\n // If refreshToken provided in credentials, no need for OAuth\n if (this.credentials.refreshToken) {\n return false;\n }\n\n // Check if we have stored tokens\n return !(await this.tokenStorage.hasTokens());\n }\n\n /**\n * Ensure user is authenticated, trigger OAuth flow if needed\n */\n private async ensureAuthenticated(): Promise<void> {\n // If refreshToken already provided, use it\n if (this.credentials.refreshToken) {\n this.logger.debug('Using provided refresh token');\n return;\n }\n\n // Check if we have stored tokens\n const storedTokens = await this.tokenStorage.getTokens();\n if (storedTokens) {\n this.logger.debug('Using stored refresh token');\n // Update credentials with stored token\n this.credentials.refreshToken = storedTokens.refreshToken;\n\n // Recreate provider with updated credentials\n const dbName = path.basename(this.dbPath, path.extname(this.dbPath));\n this.provider = new GoogleDriveProvider(\n this.credentials,\n dbName,\n this.logger\n );\n\n // Recreate sync engine with new provider\n this.syncEngine = new SyncEngine(\n this.dbManager,\n this.provider,\n this.logger\n );\n return;\n }\n\n // No tokens available, trigger OAuth flow\n this.logger.info('No authentication found, starting OAuth flow...');\n await this.authenticate();\n }\n\n /**\n * Trigger OAuth authentication flow\n */\n async authenticate(): Promise<void> {\n this.logger.info('Starting OAuth authentication flow...');\n\n const tokens = await this.oauthFlow.authenticate(\n this.credentials.clientId,\n this.credentials.clientSecret\n );\n\n // Save tokens to storage\n await this.tokenStorage.saveTokens({\n refreshToken: tokens.refresh_token,\n accessToken: tokens.access_token,\n expiryDate: tokens.expiry_date\n });\n\n // Update credentials\n this.credentials.refreshToken = tokens.refresh_token;\n\n // Recreate provider with updated credentials\n const dbName = path.basename(this.dbPath, path.extname(this.dbPath));\n this.provider = new GoogleDriveProvider(\n this.credentials,\n dbName,\n this.logger\n );\n\n // Recreate sync engine with new provider\n this.syncEngine = new SyncEngine(\n this.dbManager,\n this.provider,\n this.logger\n );\n\n this.logger.info('Authentication successful');\n }\n\n /**\n * Check if user is authenticated\n */\n async isAuthenticated(): Promise<boolean> {\n return !(await this.needsAuthentication());\n }\n\n /**\n * Logout and clear stored tokens\n */\n async logout(): Promise<void> {\n await this.tokenStorage.clearTokens();\n this.credentials.refreshToken = undefined;\n this.logger.info('Logged out successfully');\n }\n\n /**\n * Push local database to cloud\n */\n async pushToCloud(): Promise<SyncResult> {\n await this.ensureAuthenticated();\n return this.syncEngine.pushToCloud();\n }\n\n /**\n * Pull database from cloud to local\n */\n async pullFromCloud(): Promise<SyncResult> {\n await this.ensureAuthenticated();\n return this.syncEngine.pullFromCloud();\n }\n\n /**\n * Bidirectional sync\n */\n async sync(): Promise<SyncResult> {\n await this.ensureAuthenticated();\n return this.syncEngine.sync();\n }\n\n /**\n * Cleanup and shutdown\n */\n async shutdown(): Promise<void> {\n this.dbManager.close();\n this.logger.info('SqliteCloudBackup shutdown complete');\n }\n}\n\n// Re-export types\nexport * from './types';\nexport default SqliteCloudBackup;\n"],"mappings":"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","names":["fs","fs","fs","fs","path","path","fs","path"]}
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "sqlite-cloud-backup",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Lightweight SQLite database synchronization to Google Drive with zero vendor lock-in",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsup",
21
+ "dev": "tsup --watch",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest",
24
+ "test:coverage": "vitest run --coverage",
25
+ "typecheck": "tsc --noEmit",
26
+ "lint": "eslint src --ext .ts",
27
+ "lint:fix": "eslint src --ext .ts --fix",
28
+ "prepare": "npm run build"
29
+ },
30
+ "keywords": [
31
+ "sqlite",
32
+ "backup",
33
+ "sync",
34
+ "cloud",
35
+ "google-drive",
36
+ "database",
37
+ "offline-first",
38
+ "electron",
39
+ "react-native"
40
+ ],
41
+ "author": "1291pravin",
42
+ "license": "MIT",
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "https://github.com/1291pravin/sqlite-cloud-backup.git"
46
+ },
47
+ "bugs": {
48
+ "url": "https://github.com/1291pravin/sqlite-cloud-backup/issues"
49
+ },
50
+ "engines": {
51
+ "node": ">=18.0.0"
52
+ },
53
+ "dependencies": {
54
+ "better-sqlite3": "^11.0.0",
55
+ "googleapis": "^134.0.0",
56
+ "open": "^10.1.0"
57
+ },
58
+ "devDependencies": {
59
+ "@types/better-sqlite3": "^7.6.11",
60
+ "@types/node": "^20.11.0",
61
+ "@typescript-eslint/eslint-plugin": "^6.19.0",
62
+ "@typescript-eslint/parser": "^6.19.0",
63
+ "@vitest/coverage-v8": "^1.2.0",
64
+ "dotenv": "^17.2.3",
65
+ "eslint": "^8.56.0",
66
+ "tsup": "^8.0.0",
67
+ "typescript": "^5.3.0",
68
+ "vitest": "^1.2.0"
69
+ }
70
+ }