remult-sqlite-s3 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.
- package/LICENSE +21 -0
- package/README.md +145 -0
- package/dist/index.cjs +1117 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +285 -0
- package/dist/index.d.ts +285 -0
- package/dist/index.js +1109 -0
- package/dist/index.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sync/s3-operations.ts","../src/sync/lock.ts","../src/sync/wal-manager.ts","../src/sync/recovery.ts","../src/sync/sync-manager.ts","../src/provider.ts","../src/index.ts"],"names":["S3Client","GetObjectCommand","PutObjectCommand","DeleteObjectCommand","HeadObjectCommand","ListObjectsV2Command","randomUUID","hostname","existsSync","statSync","readFileSync","createHash","dirname","mkdirSync","writeFileSync","appendFileSync","unlinkSync","Database","SqliteCoreDataProvider","SqlDatabase"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\r\n * S3 operations with retry logic\r\n */\r\n\r\nimport {\r\n S3Client,\r\n GetObjectCommand,\r\n PutObjectCommand,\r\n DeleteObjectCommand,\r\n ListObjectsV2Command,\r\n HeadObjectCommand,\r\n type S3ClientConfig,\r\n} from '@aws-sdk/client-s3';\r\nimport type { S3Config } from '../types';\r\n\r\nexport class S3Operations {\r\n private client: S3Client;\r\n private bucket: string;\r\n private keyPrefix: string;\r\n private maxRetries: number;\r\n\r\n constructor(config: S3Config, maxRetries: number = 3) {\r\n const clientConfig: S3ClientConfig = {\r\n region: config.region,\r\n };\r\n\r\n if (config.endpoint) {\r\n clientConfig.endpoint = config.endpoint;\r\n }\r\n\r\n if (config.credentials) {\r\n clientConfig.credentials = {\r\n accessKeyId: config.credentials.accessKeyId,\r\n secretAccessKey: config.credentials.secretAccessKey,\r\n };\r\n }\r\n\r\n if (config.forcePathStyle) {\r\n clientConfig.forcePathStyle = true;\r\n }\r\n\r\n this.client = new S3Client(clientConfig);\r\n this.bucket = config.bucket;\r\n this.keyPrefix = config.keyPrefix.replace(/\\/$/, ''); // Remove trailing slash\r\n this.maxRetries = maxRetries;\r\n }\r\n\r\n private getFullKey(key: string): string {\r\n return `${this.keyPrefix}/${key}`;\r\n }\r\n\r\n /**\r\n * Get an object from S3\r\n */\r\n async get(key: string): Promise<Buffer | null> {\r\n return this.withRetry(async () => {\r\n try {\r\n const response = await this.client.send(\r\n new GetObjectCommand({\r\n Bucket: this.bucket,\r\n Key: this.getFullKey(key),\r\n })\r\n );\r\n\r\n if (!response.Body) {\r\n return null;\r\n }\r\n\r\n const chunks: Uint8Array[] = [];\r\n for await (const chunk of response.Body as AsyncIterable<Uint8Array>) {\r\n chunks.push(chunk);\r\n }\r\n return Buffer.concat(chunks);\r\n } catch (error: any) {\r\n if (error.name === 'NoSuchKey' || error.$metadata?.httpStatusCode === 404) {\r\n return null;\r\n }\r\n throw error;\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Get object as JSON\r\n */\r\n async getJson<T>(key: string): Promise<T | null> {\r\n const data = await this.get(key);\r\n if (!data) return null;\r\n return JSON.parse(data.toString('utf-8'));\r\n }\r\n\r\n /**\r\n * Put an object to S3\r\n */\r\n async put(key: string, data: Buffer | string): Promise<void> {\r\n return this.withRetry(async () => {\r\n await this.client.send(\r\n new PutObjectCommand({\r\n Bucket: this.bucket,\r\n Key: this.getFullKey(key),\r\n Body: typeof data === 'string' ? Buffer.from(data, 'utf-8') : data,\r\n })\r\n );\r\n });\r\n }\r\n\r\n /**\r\n * Put JSON object to S3\r\n */\r\n async putJson(key: string, data: unknown): Promise<void> {\r\n await this.put(key, JSON.stringify(data, null, 2));\r\n }\r\n\r\n /**\r\n * Delete an object from S3\r\n */\r\n async delete(key: string): Promise<void> {\r\n return this.withRetry(async () => {\r\n await this.client.send(\r\n new DeleteObjectCommand({\r\n Bucket: this.bucket,\r\n Key: this.getFullKey(key),\r\n })\r\n );\r\n });\r\n }\r\n\r\n /**\r\n * Check if an object exists\r\n */\r\n async exists(key: string): Promise<boolean> {\r\n try {\r\n await this.client.send(\r\n new HeadObjectCommand({\r\n Bucket: this.bucket,\r\n Key: this.getFullKey(key),\r\n })\r\n );\r\n return true;\r\n } catch (error: any) {\r\n if (error.name === 'NotFound' || error.$metadata?.httpStatusCode === 404) {\r\n return false;\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * List objects with a prefix\r\n */\r\n async list(prefix: string): Promise<string[]> {\r\n return this.withRetry(async () => {\r\n const keys: string[] = [];\r\n let continuationToken: string | undefined;\r\n\r\n do {\r\n const response = await this.client.send(\r\n new ListObjectsV2Command({\r\n Bucket: this.bucket,\r\n Prefix: this.getFullKey(prefix),\r\n ContinuationToken: continuationToken,\r\n })\r\n );\r\n\r\n if (response.Contents) {\r\n for (const obj of response.Contents) {\r\n if (obj.Key) {\r\n // Remove the keyPrefix from the returned key\r\n const relativeKey = obj.Key.substring(this.keyPrefix.length + 1);\r\n keys.push(relativeKey);\r\n }\r\n }\r\n }\r\n\r\n continuationToken = response.NextContinuationToken;\r\n } while (continuationToken);\r\n\r\n return keys;\r\n });\r\n }\r\n\r\n /**\r\n * Conditional put - only succeeds if key doesn't exist\r\n * Used for lock acquisition\r\n */\r\n async putIfNotExists(key: string, data: string): Promise<boolean> {\r\n try {\r\n // Check if exists first\r\n const exists = await this.exists(key);\r\n if (exists) {\r\n return false;\r\n }\r\n\r\n // Try to put\r\n await this.put(key, data);\r\n return true;\r\n } catch (error) {\r\n // Race condition - another process might have created it\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Conditional update - only succeeds if current content matches expected\r\n * Used for lock refresh\r\n */\r\n async updateIfMatch(key: string, expectedContent: string, newContent: string): Promise<boolean> {\r\n try {\r\n const current = await this.get(key);\r\n if (!current || current.toString('utf-8') !== expectedContent) {\r\n return false;\r\n }\r\n\r\n await this.put(key, newContent);\r\n return true;\r\n } catch (error) {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Execute with retry logic\r\n */\r\n private async withRetry<T>(fn: () => Promise<T>): Promise<T> {\r\n let lastError: Error | null = null;\r\n\r\n for (let attempt = 0; attempt < this.maxRetries; attempt++) {\r\n try {\r\n return await fn();\r\n } catch (error: any) {\r\n lastError = error;\r\n\r\n // Don't retry on client errors (4xx except 429)\r\n if (error.$metadata?.httpStatusCode >= 400 &&\r\n error.$metadata?.httpStatusCode < 500 &&\r\n error.$metadata?.httpStatusCode !== 429) {\r\n throw error;\r\n }\r\n\r\n // Exponential backoff with jitter\r\n const delay = Math.min(1000 * Math.pow(2, attempt) + Math.random() * 1000, 30000);\r\n await new Promise(resolve => setTimeout(resolve, delay));\r\n }\r\n }\r\n\r\n throw lastError;\r\n }\r\n\r\n /**\r\n * Close the S3 client\r\n */\r\n destroy(): void {\r\n this.client.destroy();\r\n }\r\n}\r\n","/**\r\n * Distributed lock using S3\r\n * Ensures only one writer can access the database at a time\r\n */\r\n\r\nimport { randomUUID } from 'crypto';\r\nimport { hostname } from 'os';\r\nimport type { S3Operations } from './s3-operations';\r\nimport type { LockInfo, S3SyncEvent, SyncConfig } from '../types';\r\n\r\nconst LOCK_KEY = 'lock.json';\r\n\r\nexport class S3Lock {\r\n private s3: S3Operations;\r\n private lockId: string;\r\n private holder: string;\r\n private generation: string = '';\r\n private ttl: number;\r\n private refreshInterval: number;\r\n private refreshTimer: ReturnType<typeof setInterval> | null = null;\r\n private acquired = false;\r\n private forceLock: boolean;\r\n private onEvent: (event: S3SyncEvent) => void;\r\n private verbose: boolean;\r\n\r\n constructor(\r\n s3: S3Operations,\r\n config: SyncConfig,\r\n onEvent: (event: S3SyncEvent) => void,\r\n verbose: boolean = false\r\n ) {\r\n this.s3 = s3;\r\n this.lockId = randomUUID();\r\n this.holder = `${hostname()}-${process.pid}-${this.lockId.substring(0, 8)}`;\r\n this.ttl = config.lockTtl;\r\n this.refreshInterval = config.lockRefresh;\r\n this.forceLock = config.forceLock;\r\n this.onEvent = onEvent;\r\n this.verbose = verbose;\r\n }\r\n\r\n /**\r\n * Acquire the lock\r\n * Returns the current generation ID if successful\r\n */\r\n async acquire(): Promise<string> {\r\n this.log('Attempting to acquire lock...');\r\n\r\n // Check if there's an existing lock\r\n const existingLock = await this.s3.getJson<LockInfo>(LOCK_KEY);\r\n\r\n if (existingLock) {\r\n const expiresAt = new Date(existingLock.expiresAt).getTime();\r\n const now = Date.now();\r\n\r\n if (expiresAt > now && !this.forceLock) {\r\n throw new Error(\r\n `Database is locked by another process: ${existingLock.holder} ` +\r\n `(expires in ${Math.round((expiresAt - now) / 1000)}s)`\r\n );\r\n }\r\n\r\n if (this.forceLock && expiresAt > now) {\r\n // Force taking over the lock\r\n this.log(`Force taking over lock from ${existingLock.holder}`);\r\n } else {\r\n // Lock has expired, we can take over\r\n this.log(`Taking over expired lock from ${existingLock.holder}`);\r\n }\r\n this.generation = existingLock.generation;\r\n }\r\n\r\n // If no generation exists, create a new one\r\n if (!this.generation) {\r\n this.generation = randomUUID();\r\n this.log(`Creating new generation: ${this.generation}`);\r\n }\r\n\r\n // Create lock info\r\n const lockInfo: LockInfo = {\r\n lockId: this.lockId,\r\n holder: this.holder,\r\n acquiredAt: new Date().toISOString(),\r\n expiresAt: new Date(Date.now() + this.ttl).toISOString(),\r\n generation: this.generation,\r\n };\r\n\r\n // Write the lock\r\n await this.s3.putJson(LOCK_KEY, lockInfo);\r\n\r\n // Verify we got the lock (check for race conditions)\r\n const verifyLock = await this.s3.getJson<LockInfo>(LOCK_KEY);\r\n if (!verifyLock || verifyLock.lockId !== this.lockId) {\r\n throw new Error('Failed to acquire lock - race condition detected');\r\n }\r\n\r\n this.acquired = true;\r\n this.startRefresh();\r\n\r\n this.onEvent({ type: 'lock_acquired', lockId: this.lockId });\r\n this.log(`Lock acquired: ${this.holder}`);\r\n\r\n return this.generation;\r\n }\r\n\r\n /**\r\n * Release the lock\r\n */\r\n async release(): Promise<void> {\r\n if (!this.acquired) return;\r\n\r\n this.stopRefresh();\r\n\r\n try {\r\n // Only delete if we still own it\r\n const currentLock = await this.s3.getJson<LockInfo>(LOCK_KEY);\r\n if (currentLock && currentLock.lockId === this.lockId) {\r\n await this.s3.delete(LOCK_KEY);\r\n this.log('Lock released');\r\n }\r\n } catch (error) {\r\n this.log(`Error releasing lock: ${error}`);\r\n }\r\n\r\n this.acquired = false;\r\n }\r\n\r\n /**\r\n * Check if we still hold the lock\r\n */\r\n async isValid(): Promise<boolean> {\r\n if (!this.acquired) return false;\r\n\r\n try {\r\n const currentLock = await this.s3.getJson<LockInfo>(LOCK_KEY);\r\n return currentLock?.lockId === this.lockId;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Get current generation\r\n */\r\n getGeneration(): string {\r\n return this.generation;\r\n }\r\n\r\n /**\r\n * Set generation (used during recovery)\r\n */\r\n setGeneration(generation: string): void {\r\n this.generation = generation;\r\n }\r\n\r\n /**\r\n * Create a new generation (used when starting fresh)\r\n */\r\n async newGeneration(): Promise<string> {\r\n this.generation = randomUUID();\r\n\r\n // Update lock with new generation\r\n if (this.acquired) {\r\n const lockInfo: LockInfo = {\r\n lockId: this.lockId,\r\n holder: this.holder,\r\n acquiredAt: new Date().toISOString(),\r\n expiresAt: new Date(Date.now() + this.ttl).toISOString(),\r\n generation: this.generation,\r\n };\r\n await this.s3.putJson(LOCK_KEY, lockInfo);\r\n }\r\n\r\n return this.generation;\r\n }\r\n\r\n private startRefresh(): void {\r\n this.refreshTimer = setInterval(async () => {\r\n try {\r\n await this.refresh();\r\n } catch (error) {\r\n this.log(`Lock refresh failed: ${error}`);\r\n this.onEvent({ type: 'lock_lost', reason: String(error) });\r\n this.stopRefresh();\r\n this.acquired = false;\r\n }\r\n }, this.refreshInterval);\r\n }\r\n\r\n private stopRefresh(): void {\r\n if (this.refreshTimer) {\r\n clearInterval(this.refreshTimer);\r\n this.refreshTimer = null;\r\n }\r\n }\r\n\r\n private async refresh(): Promise<void> {\r\n if (!this.acquired) return;\r\n\r\n const currentLock = await this.s3.getJson<LockInfo>(LOCK_KEY);\r\n\r\n if (!currentLock || currentLock.lockId !== this.lockId) {\r\n throw new Error('Lock was taken by another process');\r\n }\r\n\r\n // Update expiration\r\n const lockInfo: LockInfo = {\r\n ...currentLock,\r\n expiresAt: new Date(Date.now() + this.ttl).toISOString(),\r\n };\r\n\r\n await this.s3.putJson(LOCK_KEY, lockInfo);\r\n this.log('Lock refreshed');\r\n }\r\n\r\n private log(message: string): void {\r\n if (this.verbose) {\r\n console.log(`[S3Lock] ${message}`);\r\n }\r\n }\r\n}\r\n","/**\r\n * WAL (Write-Ahead Log) Manager\r\n * Handles segmentation and upload of SQLite WAL to S3\r\n */\r\n\r\nimport { createHash } from 'crypto';\r\nimport { readFileSync, statSync, existsSync } from 'fs';\r\nimport type { S3Operations } from './s3-operations';\r\nimport type { S3SyncEvent, SyncConfig, WalSegmentMeta } from '../types';\r\n\r\nexport class WALManager {\r\n private s3: S3Operations;\r\n private dbPath: string;\r\n private walPath: string;\r\n private generation: string;\r\n private walThreshold: number;\r\n private onEvent: (event: S3SyncEvent) => void;\r\n private verbose: boolean;\r\n\r\n private walIndex = 0;\r\n private lastUploadedOffset = 0;\r\n private pendingUpload: Promise<void> | null = null;\r\n\r\n constructor(\r\n s3: S3Operations,\r\n dbPath: string,\r\n generation: string,\r\n config: SyncConfig,\r\n onEvent: (event: S3SyncEvent) => void,\r\n verbose: boolean = false\r\n ) {\r\n this.s3 = s3;\r\n this.dbPath = dbPath;\r\n this.walPath = `${dbPath}-wal`;\r\n this.generation = generation;\r\n this.walThreshold = config.walThreshold;\r\n this.onEvent = onEvent;\r\n this.verbose = verbose;\r\n }\r\n\r\n /**\r\n * Set the generation ID\r\n */\r\n setGeneration(generation: string): void {\r\n this.generation = generation;\r\n this.walIndex = 0;\r\n this.lastUploadedOffset = 0;\r\n }\r\n\r\n /**\r\n * Set the starting WAL index (used during recovery)\r\n */\r\n setWalIndex(index: number): void {\r\n this.walIndex = index;\r\n }\r\n\r\n /**\r\n * Check if WAL needs to be synced based on threshold\r\n */\r\n needsSync(): boolean {\r\n if (!existsSync(this.walPath)) {\r\n return false;\r\n }\r\n\r\n try {\r\n const stat = statSync(this.walPath);\r\n const pendingBytes = stat.size - this.lastUploadedOffset;\r\n return pendingBytes >= this.walThreshold;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Get the current WAL size\r\n */\r\n getWalSize(): number {\r\n if (!existsSync(this.walPath)) {\r\n return 0;\r\n }\r\n\r\n try {\r\n return statSync(this.walPath).size;\r\n } catch {\r\n return 0;\r\n }\r\n }\r\n\r\n /**\r\n * Sync WAL to S3 (non-blocking in async mode)\r\n */\r\n async syncAsync(): Promise<void> {\r\n if (this.pendingUpload) {\r\n // Wait for any pending upload to complete\r\n await this.pendingUpload;\r\n }\r\n\r\n if (!this.needsSync()) {\r\n return;\r\n }\r\n\r\n this.pendingUpload = this.uploadWalSegment();\r\n\r\n // Fire and forget - don't await\r\n this.pendingUpload.catch(error => {\r\n this.log(`Async WAL upload failed: ${error}`);\r\n this.onEvent({\r\n type: 'sync_error',\r\n error: error as Error,\r\n context: 'wal_upload',\r\n willRetry: true,\r\n });\r\n }).finally(() => {\r\n this.pendingUpload = null;\r\n });\r\n }\r\n\r\n /**\r\n * Sync WAL to S3 (blocking)\r\n */\r\n async sync(): Promise<void> {\r\n if (this.pendingUpload) {\r\n await this.pendingUpload;\r\n }\r\n\r\n if (!existsSync(this.walPath)) {\r\n return;\r\n }\r\n\r\n await this.uploadWalSegment();\r\n }\r\n\r\n /**\r\n * Force sync all pending WAL data\r\n */\r\n async flush(): Promise<void> {\r\n if (this.pendingUpload) {\r\n await this.pendingUpload;\r\n }\r\n\r\n if (!existsSync(this.walPath)) {\r\n return;\r\n }\r\n\r\n const stat = statSync(this.walPath);\r\n if (stat.size > this.lastUploadedOffset) {\r\n await this.uploadWalSegment();\r\n }\r\n }\r\n\r\n /**\r\n * Wait for any pending uploads to complete\r\n */\r\n async waitForPending(): Promise<void> {\r\n if (this.pendingUpload) {\r\n await this.pendingUpload;\r\n }\r\n }\r\n\r\n private async uploadWalSegment(): Promise<void> {\r\n if (!existsSync(this.walPath)) {\r\n return;\r\n }\r\n\r\n const walData = readFileSync(this.walPath);\r\n const currentSize = walData.length;\r\n\r\n if (currentSize <= this.lastUploadedOffset) {\r\n return;\r\n }\r\n\r\n // Extract the new segment\r\n const segment = walData.subarray(this.lastUploadedOffset);\r\n const checksum = createHash('sha256').update(segment).digest('hex');\r\n\r\n // Increment index\r\n this.walIndex++;\r\n const indexStr = this.walIndex.toString().padStart(10, '0');\r\n\r\n // Upload segment\r\n const segmentKey = `generations/${this.generation}/wal/${indexStr}.wal`;\r\n await this.s3.put(segmentKey, segment);\r\n\r\n // Upload metadata\r\n const meta: WalSegmentMeta = {\r\n generation: this.generation,\r\n index: this.walIndex,\r\n createdAt: new Date().toISOString(),\r\n size: segment.length,\r\n checksum,\r\n startOffset: this.lastUploadedOffset,\r\n endOffset: currentSize,\r\n };\r\n await this.s3.putJson(`generations/${this.generation}/wal/${indexStr}.meta.json`, meta);\r\n\r\n this.lastUploadedOffset = currentSize;\r\n\r\n this.log(`Uploaded WAL segment ${this.walIndex} (${segment.length} bytes)`);\r\n this.onEvent({\r\n type: 'wal_uploaded',\r\n generation: this.generation,\r\n index: this.walIndex,\r\n size: segment.length,\r\n });\r\n }\r\n\r\n private log(message: string): void {\r\n if (this.verbose) {\r\n console.log(`[WALManager] ${message}`);\r\n }\r\n }\r\n}\r\n","/**\r\n * Recovery Manager\r\n * Handles recovery of SQLite database from S3\r\n */\r\n\r\nimport { createHash } from 'crypto';\r\nimport { writeFileSync, existsSync, mkdirSync, unlinkSync, appendFileSync } from 'fs';\r\nimport { dirname } from 'path';\r\nimport type { S3Operations } from './s3-operations';\r\nimport type { S3SyncEvent, GenerationInfo, SnapshotMeta, WalSegmentMeta } from '../types';\r\n\r\nexport interface RecoveryResult {\r\n generation: string;\r\n walIndex: number;\r\n recovered: boolean;\r\n}\r\n\r\nexport class RecoveryManager {\r\n private s3: S3Operations;\r\n private dbPath: string;\r\n private onEvent: (event: S3SyncEvent) => void;\r\n private verbose: boolean;\r\n\r\n constructor(\r\n s3: S3Operations,\r\n dbPath: string,\r\n onEvent: (event: S3SyncEvent) => void,\r\n verbose: boolean = false\r\n ) {\r\n this.s3 = s3;\r\n this.dbPath = dbPath;\r\n this.onEvent = onEvent;\r\n this.verbose = verbose;\r\n }\r\n\r\n /**\r\n * Find the latest generation in S3 that has a valid snapshot\r\n */\r\n async findLatestGeneration(): Promise<string | null> {\r\n const generations = await this.s3.list('generations/');\r\n\r\n // Extract unique generation IDs\r\n const genSet = new Set<string>();\r\n for (const key of generations) {\r\n const match = key.match(/^generations\\/([^/]+)\\//);\r\n if (match) {\r\n genSet.add(match[1]);\r\n }\r\n }\r\n\r\n if (genSet.size === 0) {\r\n return null;\r\n }\r\n\r\n // Find the latest by checking generation.json timestamps\r\n // Only consider generations that have a valid snapshot\r\n let latestGen: string | null = null;\r\n let latestTime = 0;\r\n\r\n for (const gen of genSet) {\r\n // Check if this generation has a snapshot\r\n const hasSnapshot = await this.s3.exists(`generations/${gen}/snapshot.db`);\r\n if (!hasSnapshot) {\r\n this.log(`Skipping generation ${gen} - no snapshot`);\r\n continue;\r\n }\r\n\r\n const genInfo = await this.s3.getJson<GenerationInfo>(`generations/${gen}/generation.json`);\r\n if (genInfo) {\r\n const createdAt = new Date(genInfo.createdAt).getTime();\r\n if (createdAt > latestTime) {\r\n latestTime = createdAt;\r\n latestGen = gen;\r\n }\r\n }\r\n }\r\n\r\n return latestGen;\r\n }\r\n\r\n /**\r\n * Recover database from S3\r\n * Returns the generation ID and highest WAL index\r\n */\r\n async recover(generation: string): Promise<RecoveryResult> {\r\n this.log(`Starting recovery for generation: ${generation}`);\r\n this.onEvent({ type: 'recovery_started', generation });\r\n\r\n // Ensure directory exists\r\n const dir = dirname(this.dbPath);\r\n if (!existsSync(dir)) {\r\n mkdirSync(dir, { recursive: true });\r\n }\r\n\r\n // Clean up any existing files\r\n this.cleanupLocalFiles();\r\n\r\n // Download and verify snapshot\r\n const snapshotMeta = await this.s3.getJson<SnapshotMeta>(\r\n `generations/${generation}/snapshot.meta.json`\r\n );\r\n\r\n if (!snapshotMeta) {\r\n throw new Error(`No snapshot metadata found for generation ${generation}`);\r\n }\r\n\r\n const snapshotData = await this.s3.get(`generations/${generation}/snapshot.db`);\r\n if (!snapshotData) {\r\n throw new Error(`No snapshot found for generation ${generation}`);\r\n }\r\n\r\n // Verify checksum\r\n const checksum = createHash('sha256').update(snapshotData).digest('hex');\r\n if (checksum !== snapshotMeta.checksum) {\r\n throw new Error(\r\n `Snapshot checksum mismatch: expected ${snapshotMeta.checksum}, got ${checksum}`\r\n );\r\n }\r\n\r\n // Write snapshot to disk\r\n writeFileSync(this.dbPath, snapshotData);\r\n this.log(`Restored snapshot (${snapshotData.length} bytes)`);\r\n\r\n // Find and apply WAL segments\r\n const walFiles = await this.s3.list(`generations/${generation}/wal/`);\r\n const walMetas: WalSegmentMeta[] = [];\r\n\r\n for (const key of walFiles) {\r\n if (key.endsWith('.meta.json')) {\r\n const meta = await this.s3.getJson<WalSegmentMeta>(key);\r\n if (meta) {\r\n walMetas.push(meta);\r\n }\r\n }\r\n }\r\n\r\n // Sort by index\r\n walMetas.sort((a, b) => a.index - b.index);\r\n\r\n // Apply WAL segments\r\n let highestWalIndex = 0;\r\n const walPath = `${this.dbPath}-wal`;\r\n\r\n for (const meta of walMetas) {\r\n const indexStr = meta.index.toString().padStart(10, '0');\r\n const walData = await this.s3.get(`generations/${generation}/wal/${indexStr}.wal`);\r\n\r\n if (!walData) {\r\n this.log(`Warning: WAL segment ${meta.index} not found, stopping recovery`);\r\n break;\r\n }\r\n\r\n // Verify checksum\r\n const walChecksum = createHash('sha256').update(walData).digest('hex');\r\n if (walChecksum !== meta.checksum) {\r\n this.log(`Warning: WAL segment ${meta.index} checksum mismatch, stopping recovery`);\r\n break;\r\n }\r\n\r\n // Append to WAL file\r\n appendFileSync(walPath, walData);\r\n highestWalIndex = meta.index;\r\n this.log(`Applied WAL segment ${meta.index} (${walData.length} bytes)`);\r\n }\r\n\r\n this.log(`Recovery completed: ${walMetas.length} WAL segments applied`);\r\n this.onEvent({\r\n type: 'recovery_completed',\r\n generation,\r\n segments: walMetas.length,\r\n });\r\n\r\n return {\r\n generation,\r\n walIndex: highestWalIndex,\r\n recovered: true,\r\n };\r\n }\r\n\r\n /**\r\n * Check if local database exists and is valid\r\n */\r\n localDatabaseExists(): boolean {\r\n return existsSync(this.dbPath);\r\n }\r\n\r\n /**\r\n * Clean up local database files\r\n */\r\n cleanupLocalFiles(): void {\r\n const files = [\r\n this.dbPath,\r\n `${this.dbPath}-wal`,\r\n `${this.dbPath}-shm`,\r\n ];\r\n\r\n for (const file of files) {\r\n if (existsSync(file)) {\r\n try {\r\n unlinkSync(file);\r\n } catch (error) {\r\n this.log(`Warning: Could not delete ${file}: ${error}`);\r\n }\r\n }\r\n }\r\n }\r\n\r\n private log(message: string): void {\r\n if (this.verbose) {\r\n console.log(`[Recovery] ${message}`);\r\n }\r\n }\r\n}\r\n","/**\r\n * S3 Sync Manager\r\n * Coordinates lock, WAL, and snapshot operations\r\n */\r\n\r\nimport Database, { type Database as DatabaseType, type Options as SqliteOptions } from 'better-sqlite3';\r\nimport { createHash } from 'crypto';\r\nimport { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';\r\nimport { dirname } from 'path';\r\nimport { S3Operations } from './s3-operations';\r\nimport { S3Lock } from './lock';\r\nimport { WALManager } from './wal-manager';\r\nimport { RecoveryManager } from './recovery';\r\nimport type {\r\n S3SyncEvent,\r\n S3Config,\r\n SyncConfig,\r\n GenerationInfo,\r\n SnapshotMeta,\r\n} from '../types';\r\n\r\nexport interface S3SyncManagerOptions {\r\n dbPath: string;\r\n sqliteOptions?: SqliteOptions;\r\n s3: S3Config;\r\n sync: SyncConfig;\r\n onEvent: (event: S3SyncEvent) => void;\r\n verbose: boolean;\r\n}\r\n\r\nexport class S3SyncManager {\r\n private s3: S3Operations;\r\n private lock: S3Lock;\r\n private walManager!: WALManager;\r\n private recoveryManager: RecoveryManager;\r\n\r\n private db!: DatabaseType;\r\n private dbPath: string;\r\n private sqliteOptions?: SqliteOptions;\r\n private syncConfig: SyncConfig;\r\n private onEvent: (event: S3SyncEvent) => void;\r\n private verbose: boolean;\r\n\r\n private generation: string = '';\r\n private snapshotTimer: ReturnType<typeof setInterval> | null = null;\r\n private closed = false;\r\n\r\n constructor(options: S3SyncManagerOptions) {\r\n this.dbPath = options.dbPath;\r\n this.sqliteOptions = options.sqliteOptions;\r\n this.syncConfig = options.sync;\r\n this.onEvent = options.onEvent;\r\n this.verbose = options.verbose;\r\n\r\n this.s3 = new S3Operations(options.s3, options.sync.maxRetries);\r\n this.lock = new S3Lock(this.s3, options.sync, options.onEvent, options.verbose);\r\n this.recoveryManager = new RecoveryManager(this.s3, this.dbPath, options.onEvent, options.verbose);\r\n }\r\n\r\n /**\r\n * Initialize the sync manager\r\n * - Acquire lock\r\n * - Recover from S3 if needed\r\n * - Open database\r\n * - Start sync timers\r\n */\r\n async initialize(): Promise<DatabaseType> {\r\n this.log('Initializing S3SyncManager...');\r\n\r\n // Acquire lock\r\n const lockGeneration = await this.lock.acquire();\r\n\r\n // Check if we need to recover\r\n const latestGeneration = await this.recoveryManager.findLatestGeneration();\r\n let recovered = false;\r\n\r\n if (latestGeneration) {\r\n // We have data in S3 - decide if we should recover\r\n if (!this.recoveryManager.localDatabaseExists()) {\r\n // No local database - must recover\r\n this.log('No local database found, recovering from S3...');\r\n const result = await this.recoveryManager.recover(latestGeneration);\r\n this.generation = result.generation;\r\n recovered = true;\r\n\r\n // Update lock with recovered generation\r\n this.lock.setGeneration(this.generation);\r\n } else {\r\n // Local database exists - use the lock's generation\r\n // (We assume local is authoritative if it exists and we acquired the lock)\r\n this.generation = lockGeneration;\r\n this.log('Local database exists, using existing generation');\r\n }\r\n } else {\r\n // No data in S3 - start fresh\r\n this.generation = await this.lock.newGeneration();\r\n this.log('No S3 data found, starting new generation');\r\n }\r\n\r\n // Initialize WAL manager\r\n this.walManager = new WALManager(\r\n this.s3,\r\n this.dbPath,\r\n this.generation,\r\n this.syncConfig,\r\n this.onEvent,\r\n this.verbose\r\n );\r\n\r\n // Ensure directory exists\r\n const dir = dirname(this.dbPath);\r\n if (!existsSync(dir)) {\r\n mkdirSync(dir, { recursive: true });\r\n }\r\n\r\n // Open database\r\n this.db = new Database(this.dbPath, this.sqliteOptions);\r\n\r\n // Enable WAL mode\r\n this.db.pragma('journal_mode = WAL');\r\n\r\n // Create generation info in S3\r\n await this.createGenerationInfo();\r\n\r\n // Take initial snapshot if this is a new generation or recovery\r\n if (!latestGeneration || recovered) {\r\n await this.snapshot();\r\n }\r\n\r\n // Start snapshot timer\r\n this.startSnapshotTimer();\r\n\r\n this.log(`Initialized with generation: ${this.generation}`);\r\n this.onEvent({ type: 'initialized', generation: this.generation, recovered });\r\n\r\n return this.db;\r\n }\r\n\r\n /**\r\n * Called after write operations\r\n */\r\n async onWrite(): Promise<void> {\r\n if (this.closed) return;\r\n\r\n if (this.syncConfig.mode === 'sync') {\r\n // In sync mode, take a full snapshot after each write\r\n await this.snapshot();\r\n }\r\n // In async mode, snapshots happen on interval\r\n }\r\n\r\n /**\r\n * Force sync WAL to S3\r\n */\r\n async syncWal(): Promise<void> {\r\n if (this.closed) return;\r\n // Take a full snapshot instead of trying to sync WAL\r\n await this.snapshot();\r\n }\r\n\r\n /**\r\n * Force full sync (WAL + check for snapshot)\r\n */\r\n async sync(): Promise<void> {\r\n if (this.closed) return;\r\n\r\n await this.walManager.flush();\r\n\r\n // Check if we should take a snapshot\r\n if (this.walManager.getWalSize() > this.syncConfig.walThreshold * 10) {\r\n await this.snapshot();\r\n }\r\n }\r\n\r\n /**\r\n * Create a full snapshot\r\n */\r\n async snapshot(): Promise<void> {\r\n if (this.closed) return;\r\n\r\n this.log('Creating snapshot...');\r\n\r\n // Flush WAL first\r\n await this.walManager.flush();\r\n\r\n // Checkpoint the database to merge WAL\r\n this.db.pragma('wal_checkpoint(TRUNCATE)');\r\n\r\n // Read the database file\r\n const dbData = readFileSync(this.dbPath);\r\n const checksum = createHash('sha256').update(dbData).digest('hex');\r\n\r\n // Upload snapshot\r\n await this.s3.put(`generations/${this.generation}/snapshot.db`, dbData);\r\n\r\n // Upload metadata\r\n const meta: SnapshotMeta = {\r\n generation: this.generation,\r\n createdAt: new Date().toISOString(),\r\n size: dbData.length,\r\n checksum,\r\n };\r\n await this.s3.putJson(`generations/${this.generation}/snapshot.meta.json`, meta);\r\n\r\n // Update generation info\r\n await this.updateGenerationInfo();\r\n\r\n this.log(`Snapshot created (${dbData.length} bytes)`);\r\n this.onEvent({\r\n type: 'snapshot_uploaded',\r\n generation: this.generation,\r\n size: dbData.length,\r\n });\r\n }\r\n\r\n /**\r\n * Close the sync manager\r\n */\r\n async close(): Promise<void> {\r\n if (this.closed) return;\r\n\r\n this.log('Closing S3SyncManager...');\r\n\r\n // Stop timers first\r\n this.stopSnapshotTimer();\r\n\r\n // Wait for pending uploads\r\n await this.walManager.waitForPending();\r\n\r\n // Final sync (before marking closed so snapshot() doesn't skip)\r\n try {\r\n await this.snapshot();\r\n this.log('Final snapshot completed');\r\n } catch (error) {\r\n this.log(`Error during final snapshot: ${error}`);\r\n }\r\n\r\n // Now mark as closed\r\n this.closed = true;\r\n\r\n // Close database\r\n if (this.db) {\r\n this.db.close();\r\n this.log('Database closed');\r\n }\r\n\r\n // Release lock\r\n await this.lock.release();\r\n this.log('Lock released');\r\n\r\n // Cleanup S3 client\r\n this.s3.destroy();\r\n\r\n this.log('S3SyncManager closed');\r\n }\r\n\r\n /**\r\n * Get the current generation\r\n */\r\n getGeneration(): string {\r\n return this.generation;\r\n }\r\n\r\n private async createGenerationInfo(): Promise<void> {\r\n const info: GenerationInfo = {\r\n id: this.generation,\r\n createdAt: new Date().toISOString(),\r\n snapshotIndex: 0,\r\n walIndex: 0,\r\n };\r\n await this.s3.putJson(`generations/${this.generation}/generation.json`, info);\r\n }\r\n\r\n private async updateGenerationInfo(): Promise<void> {\r\n const existing = await this.s3.getJson<GenerationInfo>(\r\n `generations/${this.generation}/generation.json`\r\n );\r\n\r\n const info: GenerationInfo = {\r\n id: this.generation,\r\n createdAt: existing?.createdAt ?? new Date().toISOString(),\r\n snapshotIndex: (existing?.snapshotIndex ?? 0) + 1,\r\n walIndex: existing?.walIndex ?? 0,\r\n };\r\n await this.s3.putJson(`generations/${this.generation}/generation.json`, info);\r\n }\r\n\r\n private startSnapshotTimer(): void {\r\n this.snapshotTimer = setInterval(async () => {\r\n try {\r\n await this.snapshot();\r\n } catch (error) {\r\n this.log(`Scheduled snapshot failed: ${error}`);\r\n this.onEvent({\r\n type: 'sync_error',\r\n error: error as Error,\r\n context: 'scheduled_snapshot',\r\n willRetry: true,\r\n });\r\n }\r\n }, this.syncConfig.snapshotInterval);\r\n }\r\n\r\n private stopSnapshotTimer(): void {\r\n if (this.snapshotTimer) {\r\n clearInterval(this.snapshotTimer);\r\n this.snapshotTimer = null;\r\n }\r\n }\r\n\r\n private log(message: string): void {\r\n if (this.verbose) {\r\n console.log(`[S3SyncManager] ${message}`);\r\n }\r\n }\r\n}\r\n","/**\r\n * BetterSqlite3S3DataProvider\r\n * A Remult data provider that wraps better-sqlite3 with automatic S3 synchronization\r\n */\r\n\r\nimport type { Database as DatabaseType } from 'better-sqlite3';\r\nimport type { SqlCommand, SqlResult } from 'remult';\r\nimport { SqliteCoreDataProvider } from 'remult/remult-sqlite-core-js';\r\nimport { S3SyncManager } from './sync';\r\nimport type { BetterSqlite3S3Options, S3SyncEvent, ResolvedOptions } from './types';\r\n\r\n/**\r\n * SQL Result implementation for better-sqlite3\r\n */\r\nclass BetterSqlite3S3SqlResult implements SqlResult {\r\n rows: unknown[];\r\n\r\n constructor(private result: unknown[]) {\r\n this.rows = result;\r\n }\r\n\r\n getColumnKeyInResultForIndexInSelect(index: number): string {\r\n if (this.result.length === 0) return '';\r\n return Object.keys(this.result[0] as object)[index];\r\n }\r\n}\r\n\r\n/**\r\n * SQL Command implementation for S3-synced better-sqlite3\r\n */\r\nclass BetterSqlite3S3Command implements SqlCommand {\r\n private values: Record<string, unknown> = {};\r\n private i = 0;\r\n\r\n constructor(\r\n private db: DatabaseType,\r\n private syncManager: S3SyncManager | null,\r\n private syncMode: 'async' | 'sync' = 'async'\r\n ) {}\r\n\r\n /** @deprecated use `param` instead */\r\n addParameterAndReturnSqlToken(val: unknown): string {\r\n return this.param(val);\r\n }\r\n\r\n param(val: unknown): string {\r\n // Convert Date to number (timestamp)\r\n if (val instanceof Date) {\r\n val = val.valueOf();\r\n }\r\n // Convert boolean to 0/1\r\n if (typeof val === 'boolean') {\r\n val = val ? 1 : 0;\r\n }\r\n\r\n const key = ':' + this.i++;\r\n this.values[key.substring(1)] = val;\r\n return key;\r\n }\r\n\r\n async execute(sql: string): Promise<SqlResult> {\r\n const stmt = this.db.prepare(sql);\r\n\r\n if (stmt.reader) {\r\n // Read operations - no sync needed\r\n const rows = stmt.all(this.values);\r\n return new BetterSqlite3S3SqlResult(rows);\r\n } else {\r\n // Write operations - sync based on mode\r\n stmt.run(this.values);\r\n\r\n if (this.syncManager) {\r\n if (this.syncMode === 'sync') {\r\n await this.syncManager.syncWal();\r\n } else {\r\n // Fire and forget\r\n this.syncManager.onWrite().catch(console.error);\r\n }\r\n }\r\n\r\n return new BetterSqlite3S3SqlResult([]);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * BetterSqlite3S3DataProvider\r\n *\r\n * A drop-in replacement for BetterSqlite3DataProvider with automatic S3 synchronization.\r\n *\r\n * Usage:\r\n * ```typescript\r\n * const provider = new BetterSqlite3S3DataProvider({\r\n * file: './mydb.sqlite',\r\n * s3: {\r\n * bucket: 'my-bucket',\r\n * databaseName: 'myapp-main', // Required: unique name for this database\r\n * keyPrefix: 'databases/', // Optional: prefix for all keys\r\n * },\r\n * });\r\n * await provider.init();\r\n * const dataProvider = new SqlDatabase(provider);\r\n * ```\r\n */\r\nexport class BetterSqlite3S3DataProvider extends SqliteCoreDataProvider {\r\n private db!: DatabaseType;\r\n private syncManager!: S3SyncManager;\r\n private options: ResolvedOptions;\r\n private initialized = false;\r\n private initPromise: Promise<void> | null = null;\r\n\r\n constructor(options: BetterSqlite3S3Options) {\r\n // Initialize with a placeholder command factory - will be replaced after init\r\n super(\r\n () => {\r\n this.ensureInitialized();\r\n return new BetterSqlite3S3Command(this.db, this.syncManager, this.options.sync.mode);\r\n },\r\n async () => {\r\n await this.close();\r\n }\r\n );\r\n\r\n this.options = this.applyDefaults(options);\r\n }\r\n\r\n /**\r\n * Async initialization - must be called before use\r\n */\r\n async init(): Promise<void> {\r\n if (this.initialized) return;\r\n if (this.initPromise) return this.initPromise;\r\n\r\n this.initPromise = this.doInit();\r\n return this.initPromise;\r\n }\r\n\r\n private async doInit(): Promise<void> {\r\n // Initialize S3 sync manager (handles lock acquisition and recovery)\r\n this.syncManager = new S3SyncManager({\r\n dbPath: this.options.file,\r\n sqliteOptions: this.options.sqliteOptions,\r\n s3: this.options.s3,\r\n sync: this.options.sync,\r\n onEvent: this.options.onEvent,\r\n verbose: this.options.verbose,\r\n });\r\n\r\n // This will:\r\n // 1. Acquire S3 lock\r\n // 2. Recover from S3 if needed\r\n // 3. Open the database\r\n this.db = await this.syncManager.initialize();\r\n\r\n this.initialized = true;\r\n }\r\n\r\n /**\r\n * Get the underlying database (for advanced use cases)\r\n */\r\n get rawDatabase(): DatabaseType {\r\n this.ensureInitialized();\r\n return this.db;\r\n }\r\n\r\n /**\r\n * Get the sync manager (for manual sync control)\r\n */\r\n get sync(): S3SyncManager {\r\n this.ensureInitialized();\r\n return this.syncManager;\r\n }\r\n\r\n /**\r\n * Force sync to S3\r\n */\r\n async forceSync(): Promise<void> {\r\n this.ensureInitialized();\r\n await this.syncManager.sync();\r\n }\r\n\r\n /**\r\n * Force a full snapshot\r\n */\r\n async snapshot(): Promise<void> {\r\n this.ensureInitialized();\r\n await this.syncManager.snapshot();\r\n }\r\n\r\n /**\r\n * Close the database and release resources\r\n */\r\n async close(): Promise<void> {\r\n if (!this.initialized) return;\r\n await this.syncManager.close();\r\n this.initialized = false;\r\n }\r\n\r\n /**\r\n * Check if the provider is initialized\r\n */\r\n get isInitialized(): boolean {\r\n return this.initialized;\r\n }\r\n\r\n /**\r\n * Get the current generation ID\r\n */\r\n get generation(): string {\r\n this.ensureInitialized();\r\n return this.syncManager.getGeneration();\r\n }\r\n\r\n private ensureInitialized(): void {\r\n if (!this.initialized) {\r\n throw new Error(\r\n 'BetterSqlite3S3DataProvider not initialized. Call init() before using.'\r\n );\r\n }\r\n }\r\n\r\n private applyDefaults(options: BetterSqlite3S3Options): ResolvedOptions {\r\n // Build the full key prefix: [keyPrefix/]databaseName\r\n const prefix = options.s3.keyPrefix\r\n ? `${options.s3.keyPrefix.replace(/\\/$/, '')}/${options.s3.databaseName}`\r\n : options.s3.databaseName;\r\n\r\n return {\r\n file: options.file,\r\n sqliteOptions: options.sqliteOptions ?? {},\r\n s3: {\r\n bucket: options.s3.bucket,\r\n databaseName: options.s3.databaseName,\r\n keyPrefix: prefix,\r\n region: options.s3.region ?? 'us-east-1',\r\n endpoint: options.s3.endpoint,\r\n credentials: options.s3.credentials,\r\n forcePathStyle: options.s3.forcePathStyle,\r\n },\r\n sync: {\r\n mode: options.sync?.mode ?? 'async',\r\n walThreshold: options.sync?.walThreshold ?? 1024 * 1024, // 1MB\r\n snapshotInterval: options.sync?.snapshotInterval ?? 5 * 60 * 1000, // 5 min\r\n maxRetries: options.sync?.maxRetries ?? 3,\r\n lockTtl: options.sync?.lockTtl ?? 60 * 1000, // 60s\r\n lockRefresh: options.sync?.lockRefresh ?? 30 * 1000, // 30s\r\n forceLock: options.sync?.forceLock ?? false,\r\n },\r\n onEvent: options.onEvent ?? (() => {}),\r\n verbose: options.verbose ?? false,\r\n };\r\n }\r\n}\r\n","/**\r\n * remult-sqlite-s3\r\n * A Remult data provider that syncs SQLite to S3 for serverless deployments\r\n */\r\n\r\nimport { SqlDatabase } from 'remult';\r\nimport { BetterSqlite3S3DataProvider } from './provider';\r\nimport type { BetterSqlite3S3Options } from './types';\r\n\r\nexport { BetterSqlite3S3DataProvider } from './provider';\r\nexport type {\r\n BetterSqlite3S3Options,\r\n S3SyncEvent,\r\n S3Config,\r\n SyncConfig,\r\n} from './types';\r\n\r\n// Re-export sync components for advanced usage\r\nexport { S3SyncManager } from './sync';\r\n\r\n/**\r\n * Creates an S3-synced SQLite data provider for Remult.\r\n * Handles initialization and graceful shutdown automatically.\r\n *\r\n * @example\r\n * ```typescript\r\n * import { remultApi } from 'remult/remult-express'\r\n * import { createS3DataProvider } from 'remult-sqlite-s3'\r\n *\r\n * export const api = remultApi({\r\n * dataProvider: createS3DataProvider({\r\n * file: './mydb.sqlite',\r\n * s3: {\r\n * bucket: 'my-bucket',\r\n * databaseName: 'my-database',\r\n * },\r\n * }),\r\n * entities: [Task],\r\n * })\r\n * ```\r\n */\r\nexport function createS3DataProvider(\r\n options: BetterSqlite3S3Options\r\n): () => Promise<SqlDatabase> {\r\n let provider: BetterSqlite3S3DataProvider | undefined;\r\n let dataProvider: SqlDatabase | undefined;\r\n let initPromise: Promise<SqlDatabase> | undefined;\r\n\r\n return async () => {\r\n if (dataProvider) return dataProvider;\r\n if (initPromise) return initPromise;\r\n\r\n initPromise = (async () => {\r\n provider = new BetterSqlite3S3DataProvider(options);\r\n await provider.init();\r\n dataProvider = new SqlDatabase(provider);\r\n\r\n // Graceful shutdown\r\n let shuttingDown = false;\r\n const shutdown = async (signal: string) => {\r\n if (shuttingDown) return;\r\n shuttingDown = true;\r\n if (options.verbose) {\r\n console.log(`[remult-sqlite-s3] ${signal} received, closing...`);\r\n }\r\n try {\r\n await provider?.close();\r\n if (options.verbose) {\r\n console.log('[remult-sqlite-s3] Shutdown complete');\r\n }\r\n } catch (error) {\r\n console.error('[remult-sqlite-s3] Shutdown error:', error);\r\n }\r\n process.exit(0);\r\n };\r\n\r\n process.on('SIGTERM', () => shutdown('SIGTERM'));\r\n process.on('SIGINT', () => shutdown('SIGINT'));\r\n\r\n return dataProvider;\r\n })();\r\n\r\n return initPromise;\r\n };\r\n}\r\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { SqlDatabase } from 'remult';
|
|
2
|
+
import { Options, Database } from 'better-sqlite3';
|
|
3
|
+
import { SqliteCoreDataProvider } from 'remult/remult-sqlite-core-js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Public types for BetterSqlite3S3DataProvider
|
|
7
|
+
*/
|
|
8
|
+
interface BetterSqlite3S3Options {
|
|
9
|
+
/** Path to SQLite database file */
|
|
10
|
+
file: string;
|
|
11
|
+
/** better-sqlite3 options (optional) */
|
|
12
|
+
sqliteOptions?: {
|
|
13
|
+
readonly?: boolean;
|
|
14
|
+
fileMustExist?: boolean;
|
|
15
|
+
timeout?: number;
|
|
16
|
+
verbose?: (message?: unknown, ...additionalArgs: unknown[]) => void;
|
|
17
|
+
nativeBinding?: string;
|
|
18
|
+
};
|
|
19
|
+
s3: {
|
|
20
|
+
/** S3 bucket name */
|
|
21
|
+
bucket: string;
|
|
22
|
+
/**
|
|
23
|
+
* Unique database name (required)
|
|
24
|
+
* Used to namespace all S3 keys for this database.
|
|
25
|
+
* Must be unique per database to prevent data conflicts.
|
|
26
|
+
* Example: "myapp-users", "myapp-orders", "prod-main"
|
|
27
|
+
*/
|
|
28
|
+
databaseName: string;
|
|
29
|
+
/** Optional key prefix prepended to all S3 keys (e.g., "databases/") */
|
|
30
|
+
keyPrefix?: string;
|
|
31
|
+
/** AWS region (default: "us-east-1") */
|
|
32
|
+
region?: string;
|
|
33
|
+
/** Custom endpoint for S3-compatible storage (MinIO, R2, Backblaze, etc.) */
|
|
34
|
+
endpoint?: string;
|
|
35
|
+
/** Explicit credentials (optional - uses AWS SDK default chain if not provided) */
|
|
36
|
+
credentials?: {
|
|
37
|
+
accessKeyId: string;
|
|
38
|
+
secretAccessKey: string;
|
|
39
|
+
};
|
|
40
|
+
/** Force path style for S3-compatible storage like MinIO */
|
|
41
|
+
forcePathStyle?: boolean;
|
|
42
|
+
};
|
|
43
|
+
sync?: {
|
|
44
|
+
/**
|
|
45
|
+
* Sync mode:
|
|
46
|
+
* - 'async': Fast writes, eventual durability (default)
|
|
47
|
+
* - 'sync': Wait for S3 confirmation on every write
|
|
48
|
+
*/
|
|
49
|
+
mode?: 'async' | 'sync';
|
|
50
|
+
/** Sync WAL to S3 when it reaches this size in bytes (default: 1MB) */
|
|
51
|
+
walThreshold?: number;
|
|
52
|
+
/** Create full snapshot every N milliseconds (default: 5 minutes) */
|
|
53
|
+
snapshotInterval?: number;
|
|
54
|
+
/** S3 operation retry count (default: 3) */
|
|
55
|
+
maxRetries?: number;
|
|
56
|
+
/** Lock TTL in milliseconds (default: 60000) */
|
|
57
|
+
lockTtl?: number;
|
|
58
|
+
/** Lock refresh interval in milliseconds (default: 30000) */
|
|
59
|
+
lockRefresh?: number;
|
|
60
|
+
/** Force acquire lock even if another process holds it (use only in development) */
|
|
61
|
+
forceLock?: boolean;
|
|
62
|
+
};
|
|
63
|
+
/** Called on sync events (uploads, recoveries, errors) */
|
|
64
|
+
onEvent?: (event: S3SyncEvent) => void;
|
|
65
|
+
/** Enable verbose logging */
|
|
66
|
+
verbose?: boolean;
|
|
67
|
+
}
|
|
68
|
+
type S3SyncEvent = {
|
|
69
|
+
type: 'wal_uploaded';
|
|
70
|
+
generation: string;
|
|
71
|
+
index: number;
|
|
72
|
+
size: number;
|
|
73
|
+
} | {
|
|
74
|
+
type: 'snapshot_uploaded';
|
|
75
|
+
generation: string;
|
|
76
|
+
size: number;
|
|
77
|
+
} | {
|
|
78
|
+
type: 'recovery_started';
|
|
79
|
+
generation: string;
|
|
80
|
+
} | {
|
|
81
|
+
type: 'recovery_completed';
|
|
82
|
+
generation: string;
|
|
83
|
+
segments: number;
|
|
84
|
+
} | {
|
|
85
|
+
type: 'lock_acquired';
|
|
86
|
+
lockId: string;
|
|
87
|
+
} | {
|
|
88
|
+
type: 'lock_lost';
|
|
89
|
+
reason: string;
|
|
90
|
+
} | {
|
|
91
|
+
type: 'sync_error';
|
|
92
|
+
error: Error;
|
|
93
|
+
context: string;
|
|
94
|
+
willRetry: boolean;
|
|
95
|
+
} | {
|
|
96
|
+
type: 'initialized';
|
|
97
|
+
generation: string;
|
|
98
|
+
recovered: boolean;
|
|
99
|
+
};
|
|
100
|
+
interface S3Config {
|
|
101
|
+
bucket: string;
|
|
102
|
+
databaseName: string;
|
|
103
|
+
keyPrefix: string;
|
|
104
|
+
region: string;
|
|
105
|
+
endpoint?: string;
|
|
106
|
+
credentials?: {
|
|
107
|
+
accessKeyId: string;
|
|
108
|
+
secretAccessKey: string;
|
|
109
|
+
};
|
|
110
|
+
forcePathStyle?: boolean;
|
|
111
|
+
}
|
|
112
|
+
interface SyncConfig {
|
|
113
|
+
mode: 'async' | 'sync';
|
|
114
|
+
walThreshold: number;
|
|
115
|
+
snapshotInterval: number;
|
|
116
|
+
maxRetries: number;
|
|
117
|
+
lockTtl: number;
|
|
118
|
+
lockRefresh: number;
|
|
119
|
+
forceLock: boolean;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* S3 Sync Manager
|
|
124
|
+
* Coordinates lock, WAL, and snapshot operations
|
|
125
|
+
*/
|
|
126
|
+
|
|
127
|
+
interface S3SyncManagerOptions {
|
|
128
|
+
dbPath: string;
|
|
129
|
+
sqliteOptions?: Options;
|
|
130
|
+
s3: S3Config;
|
|
131
|
+
sync: SyncConfig;
|
|
132
|
+
onEvent: (event: S3SyncEvent) => void;
|
|
133
|
+
verbose: boolean;
|
|
134
|
+
}
|
|
135
|
+
declare class S3SyncManager {
|
|
136
|
+
private s3;
|
|
137
|
+
private lock;
|
|
138
|
+
private walManager;
|
|
139
|
+
private recoveryManager;
|
|
140
|
+
private db;
|
|
141
|
+
private dbPath;
|
|
142
|
+
private sqliteOptions?;
|
|
143
|
+
private syncConfig;
|
|
144
|
+
private onEvent;
|
|
145
|
+
private verbose;
|
|
146
|
+
private generation;
|
|
147
|
+
private snapshotTimer;
|
|
148
|
+
private closed;
|
|
149
|
+
constructor(options: S3SyncManagerOptions);
|
|
150
|
+
/**
|
|
151
|
+
* Initialize the sync manager
|
|
152
|
+
* - Acquire lock
|
|
153
|
+
* - Recover from S3 if needed
|
|
154
|
+
* - Open database
|
|
155
|
+
* - Start sync timers
|
|
156
|
+
*/
|
|
157
|
+
initialize(): Promise<Database>;
|
|
158
|
+
/**
|
|
159
|
+
* Called after write operations
|
|
160
|
+
*/
|
|
161
|
+
onWrite(): Promise<void>;
|
|
162
|
+
/**
|
|
163
|
+
* Force sync WAL to S3
|
|
164
|
+
*/
|
|
165
|
+
syncWal(): Promise<void>;
|
|
166
|
+
/**
|
|
167
|
+
* Force full sync (WAL + check for snapshot)
|
|
168
|
+
*/
|
|
169
|
+
sync(): Promise<void>;
|
|
170
|
+
/**
|
|
171
|
+
* Create a full snapshot
|
|
172
|
+
*/
|
|
173
|
+
snapshot(): Promise<void>;
|
|
174
|
+
/**
|
|
175
|
+
* Close the sync manager
|
|
176
|
+
*/
|
|
177
|
+
close(): Promise<void>;
|
|
178
|
+
/**
|
|
179
|
+
* Get the current generation
|
|
180
|
+
*/
|
|
181
|
+
getGeneration(): string;
|
|
182
|
+
private createGenerationInfo;
|
|
183
|
+
private updateGenerationInfo;
|
|
184
|
+
private startSnapshotTimer;
|
|
185
|
+
private stopSnapshotTimer;
|
|
186
|
+
private log;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* BetterSqlite3S3DataProvider
|
|
191
|
+
* A Remult data provider that wraps better-sqlite3 with automatic S3 synchronization
|
|
192
|
+
*/
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* BetterSqlite3S3DataProvider
|
|
196
|
+
*
|
|
197
|
+
* A drop-in replacement for BetterSqlite3DataProvider with automatic S3 synchronization.
|
|
198
|
+
*
|
|
199
|
+
* Usage:
|
|
200
|
+
* ```typescript
|
|
201
|
+
* const provider = new BetterSqlite3S3DataProvider({
|
|
202
|
+
* file: './mydb.sqlite',
|
|
203
|
+
* s3: {
|
|
204
|
+
* bucket: 'my-bucket',
|
|
205
|
+
* databaseName: 'myapp-main', // Required: unique name for this database
|
|
206
|
+
* keyPrefix: 'databases/', // Optional: prefix for all keys
|
|
207
|
+
* },
|
|
208
|
+
* });
|
|
209
|
+
* await provider.init();
|
|
210
|
+
* const dataProvider = new SqlDatabase(provider);
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
declare class BetterSqlite3S3DataProvider extends SqliteCoreDataProvider {
|
|
214
|
+
private db;
|
|
215
|
+
private syncManager;
|
|
216
|
+
private options;
|
|
217
|
+
private initialized;
|
|
218
|
+
private initPromise;
|
|
219
|
+
constructor(options: BetterSqlite3S3Options);
|
|
220
|
+
/**
|
|
221
|
+
* Async initialization - must be called before use
|
|
222
|
+
*/
|
|
223
|
+
init(): Promise<void>;
|
|
224
|
+
private doInit;
|
|
225
|
+
/**
|
|
226
|
+
* Get the underlying database (for advanced use cases)
|
|
227
|
+
*/
|
|
228
|
+
get rawDatabase(): Database;
|
|
229
|
+
/**
|
|
230
|
+
* Get the sync manager (for manual sync control)
|
|
231
|
+
*/
|
|
232
|
+
get sync(): S3SyncManager;
|
|
233
|
+
/**
|
|
234
|
+
* Force sync to S3
|
|
235
|
+
*/
|
|
236
|
+
forceSync(): Promise<void>;
|
|
237
|
+
/**
|
|
238
|
+
* Force a full snapshot
|
|
239
|
+
*/
|
|
240
|
+
snapshot(): Promise<void>;
|
|
241
|
+
/**
|
|
242
|
+
* Close the database and release resources
|
|
243
|
+
*/
|
|
244
|
+
close(): Promise<void>;
|
|
245
|
+
/**
|
|
246
|
+
* Check if the provider is initialized
|
|
247
|
+
*/
|
|
248
|
+
get isInitialized(): boolean;
|
|
249
|
+
/**
|
|
250
|
+
* Get the current generation ID
|
|
251
|
+
*/
|
|
252
|
+
get generation(): string;
|
|
253
|
+
private ensureInitialized;
|
|
254
|
+
private applyDefaults;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* remult-sqlite-s3
|
|
259
|
+
* A Remult data provider that syncs SQLite to S3 for serverless deployments
|
|
260
|
+
*/
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Creates an S3-synced SQLite data provider for Remult.
|
|
264
|
+
* Handles initialization and graceful shutdown automatically.
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```typescript
|
|
268
|
+
* import { remultApi } from 'remult/remult-express'
|
|
269
|
+
* import { createS3DataProvider } from 'remult-sqlite-s3'
|
|
270
|
+
*
|
|
271
|
+
* export const api = remultApi({
|
|
272
|
+
* dataProvider: createS3DataProvider({
|
|
273
|
+
* file: './mydb.sqlite',
|
|
274
|
+
* s3: {
|
|
275
|
+
* bucket: 'my-bucket',
|
|
276
|
+
* databaseName: 'my-database',
|
|
277
|
+
* },
|
|
278
|
+
* }),
|
|
279
|
+
* entities: [Task],
|
|
280
|
+
* })
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
declare function createS3DataProvider(options: BetterSqlite3S3Options): () => Promise<SqlDatabase>;
|
|
284
|
+
|
|
285
|
+
export { BetterSqlite3S3DataProvider, type BetterSqlite3S3Options, type S3Config, type S3SyncEvent, S3SyncManager, type SyncConfig, createS3DataProvider };
|