remult-sqlite-github 0.2.0 → 0.2.1
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/dist/index.cjs +37 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +37 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -628,6 +628,8 @@ var GitHubSyncManager = class {
|
|
|
628
628
|
snapshotTimer = null;
|
|
629
629
|
isInitialized = false;
|
|
630
630
|
isClosed = false;
|
|
631
|
+
pendingSync = null;
|
|
632
|
+
syncDebounceTimer = null;
|
|
631
633
|
constructor(options) {
|
|
632
634
|
this.options = options;
|
|
633
635
|
this.github = new GitHubOperations(
|
|
@@ -705,14 +707,37 @@ var GitHubSyncManager = class {
|
|
|
705
707
|
}
|
|
706
708
|
/**
|
|
707
709
|
* Called after database writes to track changes
|
|
708
|
-
* If syncOnWrite is enabled, triggers
|
|
710
|
+
* If syncOnWrite is enabled, triggers a debounced non-blocking snapshot
|
|
709
711
|
*/
|
|
710
712
|
async onWrite() {
|
|
711
713
|
this.hasChanges = true;
|
|
712
714
|
if (this.options.sync.syncOnWrite) {
|
|
713
|
-
|
|
715
|
+
this.scheduleDebouncedSync();
|
|
714
716
|
}
|
|
715
717
|
}
|
|
718
|
+
/**
|
|
719
|
+
* Schedule a debounced sync - waits 100ms for more writes before syncing
|
|
720
|
+
* This prevents multiple rapid writes from each triggering a separate upload
|
|
721
|
+
*/
|
|
722
|
+
scheduleDebouncedSync() {
|
|
723
|
+
if (this.syncDebounceTimer) {
|
|
724
|
+
clearTimeout(this.syncDebounceTimer);
|
|
725
|
+
}
|
|
726
|
+
this.syncDebounceTimer = setTimeout(() => {
|
|
727
|
+
this.syncDebounceTimer = null;
|
|
728
|
+
if (this.pendingSync) {
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
this.pendingSync = this.snapshot().catch((error) => {
|
|
732
|
+
this.log(`Background sync error: ${error}`);
|
|
733
|
+
}).finally(() => {
|
|
734
|
+
this.pendingSync = null;
|
|
735
|
+
if (this.hasChanges) {
|
|
736
|
+
this.scheduleDebouncedSync();
|
|
737
|
+
}
|
|
738
|
+
});
|
|
739
|
+
}, 100);
|
|
740
|
+
}
|
|
716
741
|
/**
|
|
717
742
|
* Create a snapshot and upload to GitHub
|
|
718
743
|
*/
|
|
@@ -838,6 +863,16 @@ var GitHubSyncManager = class {
|
|
|
838
863
|
clearInterval(this.snapshotTimer);
|
|
839
864
|
this.snapshotTimer = null;
|
|
840
865
|
}
|
|
866
|
+
if (this.syncDebounceTimer) {
|
|
867
|
+
clearTimeout(this.syncDebounceTimer);
|
|
868
|
+
this.syncDebounceTimer = null;
|
|
869
|
+
}
|
|
870
|
+
if (this.pendingSync) {
|
|
871
|
+
try {
|
|
872
|
+
await this.pendingSync;
|
|
873
|
+
} catch {
|
|
874
|
+
}
|
|
875
|
+
}
|
|
841
876
|
if (this.hasChanges && this.db) {
|
|
842
877
|
try {
|
|
843
878
|
await this.snapshot();
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sync/github-operations.ts","../src/sync/recovery.ts","../src/sync/sync-manager.ts","../src/provider.ts","../src/index.ts"],"names":["path","crypto","gunzip","promisify","zlib","fs","gzip","zlib2","SNAPSHOT_DB_NAME","SNAPSHOT_DB_GZ_NAME","SNAPSHOT_META_NAME","path2","fs2","Database","crypto2","BetterSqlite3DataProvider","SqlDatabase"],"mappings":"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","file":"index.cjs","sourcesContent":["import * as crypto from \"crypto\";\nimport type {\n GitHubConfig,\n GitHubFileResult,\n GitHubFileEntry,\n RateLimitInfo,\n GitHubSyncEvent,\n} from \"../types.js\";\n\nconst GITHUB_API_BASE = \"https://api.github.com\";\n\n/**\n * GitHub REST API operations wrapper with retry logic and rate limit handling\n */\nexport class GitHubOperations {\n private config: GitHubConfig;\n private maxRetries: number;\n private cachedToken: string | null = null;\n private tokenExpiry: number = 0;\n private onEvent?: (event: GitHubSyncEvent) => void;\n private verbose: boolean;\n\n constructor(\n config: GitHubConfig,\n maxRetries: number = 3,\n onEvent?: (event: GitHubSyncEvent) => void,\n verbose: boolean = false\n ) {\n this.config = config;\n this.maxRetries = maxRetries;\n this.onEvent = onEvent;\n this.verbose = verbose;\n }\n\n /**\n * Get a file from the repository\n */\n async getFile(path: string): Promise<GitHubFileResult | null> {\n const fullPath = this.getFullPath(path);\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/contents/${fullPath}?ref=${this.config.branch}`;\n\n const response = await this.withRetry(() => this.fetch(url));\n\n if (response.status === 404) {\n return null;\n }\n\n if (!response.ok) {\n throw new Error(\n `Failed to get file ${path}: ${response.status} ${response.statusText}`\n );\n }\n\n const data = await response.json();\n\n // GitHub returns base64 encoded content for files under 1MB\n // For larger files, we need to use the blob API\n if (data.content) {\n const content = Buffer.from(data.content, \"base64\");\n return {\n content,\n sha: data.sha,\n size: data.size,\n };\n }\n\n // Large file - use blob API\n if (data.sha && data.size > 0) {\n return this.getBlob(data.sha, data.size);\n }\n\n return null;\n }\n\n /**\n * Get a large file using the blob API\n */\n private async getBlob(sha: string, size: number): Promise<GitHubFileResult> {\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/git/blobs/${sha}`;\n\n const response = await this.withRetry(() => this.fetch(url));\n\n if (!response.ok) {\n throw new Error(\n `Failed to get blob ${sha}: ${response.status} ${response.statusText}`\n );\n }\n\n const data = await response.json();\n const content = Buffer.from(data.content, \"base64\");\n\n return {\n content,\n sha,\n size,\n };\n }\n\n /**\n * Create or update a file in the repository\n * Returns the new commit SHA\n */\n async putFile(\n path: string,\n content: Buffer,\n message: string,\n sha?: string\n ): Promise<string> {\n const fullPath = this.getFullPath(path);\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/contents/${fullPath}`;\n\n const body: Record<string, string> = {\n message,\n content: content.toString(\"base64\"),\n branch: this.config.branch,\n };\n\n if (sha) {\n body.sha = sha;\n }\n\n const response = await this.withRetry(\n () =>\n this.fetch(url, {\n method: \"PUT\",\n body: JSON.stringify(body),\n }),\n true // Allow conflict retry\n );\n\n if (response.status === 409) {\n // Conflict - SHA mismatch, caller should re-fetch and retry\n throw new ConflictError(\n `Conflict updating ${path}: file was modified concurrently`\n );\n }\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to put file ${path}: ${response.status} ${response.statusText} - ${errorText}`\n );\n }\n\n const data = await response.json();\n\n this.emitEvent({\n type: \"commit_created\",\n sha: data.commit.sha,\n message,\n });\n\n return data.content.sha;\n }\n\n /**\n * Delete a file from the repository\n */\n async deleteFile(path: string, sha: string, message: string): Promise<void> {\n const fullPath = this.getFullPath(path);\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/contents/${fullPath}`;\n\n const response = await this.withRetry(() =>\n this.fetch(url, {\n method: \"DELETE\",\n body: JSON.stringify({\n message,\n sha,\n branch: this.config.branch,\n }),\n })\n );\n\n if (!response.ok && response.status !== 404) {\n throw new Error(\n `Failed to delete file ${path}: ${response.status} ${response.statusText}`\n );\n }\n }\n\n /**\n * List files in a directory\n */\n async listFiles(path: string): Promise<GitHubFileEntry[]> {\n const fullPath = this.getFullPath(path);\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/contents/${fullPath}?ref=${this.config.branch}`;\n\n const response = await this.withRetry(() => this.fetch(url));\n\n if (response.status === 404) {\n return [];\n }\n\n if (!response.ok) {\n throw new Error(\n `Failed to list files at ${path}: ${response.status} ${response.statusText}`\n );\n }\n\n const data = await response.json();\n\n // Single file returns object, directory returns array\n if (!Array.isArray(data)) {\n return [\n {\n name: data.name,\n path: data.path,\n sha: data.sha,\n size: data.size,\n type: data.type,\n },\n ];\n }\n\n return data.map(\n (item: {\n name: string;\n path: string;\n sha: string;\n size: number;\n type: \"file\" | \"dir\";\n }) => ({\n name: item.name,\n path: item.path,\n sha: item.sha,\n size: item.size,\n type: item.type,\n })\n );\n }\n\n /**\n * Check current rate limit status\n */\n async checkRateLimit(): Promise<RateLimitInfo> {\n const url = `${GITHUB_API_BASE}/rate_limit`;\n const response = await this.fetch(url);\n\n if (!response.ok) {\n throw new Error(`Failed to check rate limit: ${response.statusText}`);\n }\n\n const data = await response.json();\n return {\n remaining: data.resources.core.remaining,\n resetAt: new Date(data.resources.core.reset * 1000),\n limit: data.resources.core.limit,\n };\n }\n\n /**\n * Ensure the branch exists, create if it doesn't\n * For empty repos, we skip branch creation since files can be pushed directly\n */\n async ensureBranch(): Promise<void> {\n // Check if branch exists\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/branches/${this.config.branch}`;\n const response = await this.fetch(url);\n\n if (response.ok) {\n return; // Branch exists\n }\n\n if (response.status !== 404) {\n // Could be auth error or other issue\n const errorText = await response.text();\n throw new Error(\n `Failed to check branch '${this.config.branch}': ${response.status} ${response.statusText}. ${errorText}`\n );\n }\n\n // Branch doesn't exist, check if repo has any commits\n const repoUrl = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}`;\n const repoResponse = await this.fetch(repoUrl);\n\n if (!repoResponse.ok) {\n const errorText = await repoResponse.text();\n throw new Error(\n `Failed to get repository info for '${this.config.owner}/${this.config.repo}': ${repoResponse.status} ${repoResponse.statusText}. ${errorText}`\n );\n }\n\n const repoData = await repoResponse.json();\n const defaultBranch = repoData.default_branch;\n\n // Check if the repo is empty (no commits yet)\n // Empty repos have size 0 and no refs\n const refUrl = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/git/refs/heads/${defaultBranch}`;\n const refResponse = await this.fetch(refUrl);\n\n if (!refResponse.ok) {\n if (refResponse.status === 409 || refResponse.status === 404) {\n // Empty repository - the branch will be created on first file push\n this.log(\n `Repository appears to be empty. Branch '${this.config.branch}' will be created on first snapshot.`\n );\n return;\n }\n const errorText = await refResponse.text();\n throw new Error(\n `Failed to get default branch ref: ${refResponse.status} ${refResponse.statusText}. ${errorText}`\n );\n }\n\n // If we're using the default branch, we're done\n if (this.config.branch === defaultBranch) {\n return;\n }\n\n const refData = await refResponse.json();\n const sha = refData.object.sha;\n\n // Create new branch from default branch\n const createUrl = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/git/refs`;\n const createResponse = await this.fetch(createUrl, {\n method: \"POST\",\n body: JSON.stringify({\n ref: `refs/heads/${this.config.branch}`,\n sha,\n }),\n });\n\n if (!createResponse.ok && createResponse.status !== 422) {\n const errorText = await createResponse.text();\n throw new Error(\n `Failed to create branch '${this.config.branch}': ${createResponse.status} ${createResponse.statusText}. ${errorText}`\n );\n }\n\n this.log(`Created branch: ${this.config.branch}`);\n }\n\n /**\n * Get the full path including configured prefix\n */\n private getFullPath(path: string): string {\n if (!this.config.path) {\n return path;\n }\n return `${this.config.path}/${path}`.replace(/\\/+/g, \"/\");\n }\n\n /**\n * Make an authenticated fetch request\n */\n private async fetch(\n url: string,\n options: RequestInit = {}\n ): Promise<Response> {\n const token = await this.getAuthToken();\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n Accept: \"application/vnd.github+json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n ...(options.headers as Record<string, string>),\n };\n\n if (options.body) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n return fetch(url, {\n ...options,\n headers,\n });\n }\n\n /**\n * Get authentication token (PAT or GitHub App installation token)\n */\n private async getAuthToken(): Promise<string> {\n // Use PAT if provided\n if (this.config.token) {\n return this.config.token;\n }\n\n // Check if we have a valid cached token\n if (this.cachedToken && Date.now() < this.tokenExpiry) {\n return this.cachedToken;\n }\n\n // Generate GitHub App installation token\n if (\n !this.config.appId ||\n !this.config.privateKey ||\n !this.config.installationId\n ) {\n throw new Error(\n \"Either token or GitHub App credentials (appId, privateKey, installationId) must be provided\"\n );\n }\n\n const jwt = this.generateJWT(this.config.appId, this.config.privateKey);\n\n const response = await fetch(\n `${GITHUB_API_BASE}/app/installations/${this.config.installationId}/access_tokens`,\n {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${jwt}`,\n Accept: \"application/vnd.github+json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n },\n }\n );\n\n if (!response.ok) {\n throw new Error(\n `Failed to get installation token: ${response.statusText}`\n );\n }\n\n const data = await response.json();\n this.cachedToken = data.token;\n // Token expires in 1 hour, refresh 5 minutes early\n this.tokenExpiry = Date.now() + 55 * 60 * 1000;\n\n return this.cachedToken!;\n }\n\n /**\n * Generate a JWT for GitHub App authentication\n */\n private generateJWT(appId: number, privateKey: string): string {\n const now = Math.floor(Date.now() / 1000);\n const payload = {\n iat: now - 60, // Issued 60 seconds ago to account for clock drift\n exp: now + 10 * 60, // Expires in 10 minutes\n iss: appId.toString(),\n };\n\n const header = { alg: \"RS256\", typ: \"JWT\" };\n const encodedHeader = this.base64UrlEncode(JSON.stringify(header));\n const encodedPayload = this.base64UrlEncode(JSON.stringify(payload));\n\n const signatureInput = `${encodedHeader}.${encodedPayload}`;\n const signature = crypto\n .createSign(\"RSA-SHA256\")\n .update(signatureInput)\n .sign(privateKey, \"base64url\");\n\n return `${signatureInput}.${signature}`;\n }\n\n /**\n * Base64 URL encode a string\n */\n private base64UrlEncode(str: string): string {\n return Buffer.from(str)\n .toString(\"base64\")\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=/g, \"\");\n }\n\n /**\n * Execute a function with retry logic and exponential backoff\n */\n private async withRetry<T>(\n fn: () => Promise<T>,\n allowConflict: boolean = false\n ): Promise<T> {\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n try {\n const result = await fn();\n\n // Check for rate limiting in response\n if (result instanceof Response) {\n await this.handleRateLimitHeaders(result);\n }\n\n return result;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Don't retry conflict errors unless specified\n if (error instanceof ConflictError && !allowConflict) {\n throw error;\n }\n\n // Check if this is a rate limit error\n if (\n error instanceof Error &&\n error.message.includes(\"rate limit\")\n ) {\n const rateLimit = await this.checkRateLimit();\n const waitTime = Math.max(\n 0,\n rateLimit.resetAt.getTime() - Date.now()\n );\n\n this.emitEvent({\n type: \"rate_limit_hit\",\n resetAt: rateLimit.resetAt,\n remaining: rateLimit.remaining,\n });\n\n if (waitTime > 0 && waitTime < 60000) {\n // Wait up to 1 minute\n this.log(`Rate limited, waiting ${waitTime}ms`);\n await this.sleep(waitTime);\n continue;\n }\n }\n\n // Emit error event\n this.emitEvent({\n type: \"sync_error\",\n error: lastError,\n context: \"github_operation\",\n willRetry: attempt < this.maxRetries,\n });\n\n if (attempt < this.maxRetries) {\n const delay = Math.min(1000 * Math.pow(2, attempt), 30000);\n this.log(`Retry attempt ${attempt + 1} after ${delay}ms`);\n await this.sleep(delay);\n }\n }\n }\n\n throw lastError || new Error(\"Unknown error\");\n }\n\n /**\n * Handle rate limit headers from response\n */\n private async handleRateLimitHeaders(response: Response): Promise<void> {\n const remaining = parseInt(\n response.headers.get(\"x-ratelimit-remaining\") || \"1000\",\n 10\n );\n const resetTimestamp = parseInt(\n response.headers.get(\"x-ratelimit-reset\") || \"0\",\n 10\n );\n\n if (remaining === 0 && resetTimestamp > 0) {\n const resetAt = new Date(resetTimestamp * 1000);\n const waitTime = Math.max(0, resetAt.getTime() - Date.now());\n\n this.emitEvent({\n type: \"rate_limit_hit\",\n resetAt,\n remaining: 0,\n });\n\n if (waitTime > 0 && waitTime < 60000) {\n this.log(`Rate limit exhausted, waiting ${waitTime}ms`);\n await this.sleep(waitTime);\n }\n }\n }\n\n /**\n * Sleep for the specified duration\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Emit an event if handler is registered\n */\n private emitEvent(event: GitHubSyncEvent): void {\n if (this.onEvent) {\n this.onEvent(event);\n }\n }\n\n /**\n * Log a message if verbose mode is enabled\n */\n private log(message: string): void {\n if (this.verbose) {\n console.log(`[github-operations] ${message}`);\n }\n }\n}\n\n/**\n * Custom error for conflict (SHA mismatch) situations\n */\nexport class ConflictError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ConflictError\";\n }\n}\n","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as zlib from \"zlib\";\nimport { promisify } from \"util\";\nimport type {\n GitHubSyncEvent,\n RecoveryResult,\n SnapshotMetadata,\n} from \"../types.js\";\nimport { GitHubOperations } from \"./github-operations.js\";\n\nconst gunzip = promisify(zlib.gunzip);\n\nconst SNAPSHOT_DB_NAME = \"snapshot.db\";\nconst SNAPSHOT_DB_GZ_NAME = \"snapshot.db.gz\";\nconst SNAPSHOT_META_NAME = \"snapshot.meta.json\";\n\n/**\n * Manages database recovery from GitHub\n */\nexport class RecoveryManager {\n private github: GitHubOperations;\n private dbPath: string;\n private onEvent?: (event: GitHubSyncEvent) => void;\n private verbose: boolean;\n\n constructor(\n github: GitHubOperations,\n dbPath: string,\n onEvent?: (event: GitHubSyncEvent) => void,\n verbose: boolean = false\n ) {\n this.github = github;\n this.dbPath = dbPath;\n this.onEvent = onEvent;\n this.verbose = verbose;\n }\n\n /**\n * Check if local database exists\n */\n localDatabaseExists(): boolean {\n return fs.existsSync(this.dbPath);\n }\n\n /**\n * Find the latest snapshot in the repository\n */\n async findLatestSnapshot(): Promise<{\n path: string;\n sha: string;\n compressed: boolean;\n } | null> {\n try {\n // First check for compressed snapshot\n const compressedFile = await this.github.getFile(SNAPSHOT_DB_GZ_NAME);\n if (compressedFile) {\n return {\n path: SNAPSHOT_DB_GZ_NAME,\n sha: compressedFile.sha,\n compressed: true,\n };\n }\n\n // Then check for uncompressed snapshot\n const uncompressedFile = await this.github.getFile(SNAPSHOT_DB_NAME);\n if (uncompressedFile) {\n return {\n path: SNAPSHOT_DB_NAME,\n sha: uncompressedFile.sha,\n compressed: false,\n };\n }\n\n return null;\n } catch (error) {\n this.log(`Error finding snapshot: ${error}`);\n return null;\n }\n }\n\n /**\n * Recover database from GitHub snapshot\n */\n async recover(): Promise<RecoveryResult> {\n this.emitEvent({\n type: \"recovery_started\",\n branch: \"\", // Branch is handled by GitHubOperations\n });\n\n try {\n // Find the latest snapshot\n const snapshot = await this.findLatestSnapshot();\n\n if (!snapshot) {\n this.log(\"No snapshot found in repository\");\n return { recovered: false };\n }\n\n this.log(`Found snapshot: ${snapshot.path}`);\n\n // Download the snapshot\n const file = await this.github.getFile(snapshot.path);\n if (!file) {\n this.log(\"Failed to download snapshot\");\n return { recovered: false };\n }\n\n // Decompress if necessary\n let dbContent: Buffer;\n if (snapshot.compressed) {\n this.log(\"Decompressing snapshot...\");\n dbContent = await gunzip(file.content);\n } else {\n dbContent = file.content;\n }\n\n // Ensure directory exists\n const dir = path.dirname(this.dbPath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n // Write the database file\n fs.writeFileSync(this.dbPath, dbContent);\n this.log(`Database recovered to ${this.dbPath}`);\n\n // Get metadata if available (for future use)\n await this.getSnapshotMetadata();\n\n this.emitEvent({\n type: \"recovery_completed\",\n sha: file.sha,\n });\n\n return {\n recovered: true,\n sha: file.sha,\n size: dbContent.length,\n compressed: snapshot.compressed,\n };\n } catch (error) {\n this.log(`Recovery error: ${error}`);\n this.emitEvent({\n type: \"sync_error\",\n error: error instanceof Error ? error : new Error(String(error)),\n context: \"recovery\",\n willRetry: false,\n });\n return { recovered: false };\n }\n }\n\n /**\n * Get snapshot metadata from repository\n */\n async getSnapshotMetadata(): Promise<SnapshotMetadata | null> {\n try {\n const file = await this.github.getFile(SNAPSHOT_META_NAME);\n if (!file) {\n return null;\n }\n return JSON.parse(file.content.toString(\"utf-8\"));\n } catch {\n return null;\n }\n }\n\n /**\n * Get the current snapshot SHA from the repository\n */\n async getCurrentSnapshotSha(): Promise<string | null> {\n const snapshot = await this.findLatestSnapshot();\n return snapshot?.sha || null;\n }\n\n /**\n * Emit an event if handler is registered\n */\n private emitEvent(event: GitHubSyncEvent): void {\n if (this.onEvent) {\n this.onEvent(event);\n }\n }\n\n /**\n * Log a message if verbose mode is enabled\n */\n private log(message: string): void {\n if (this.verbose) {\n console.log(`[recovery] ${message}`);\n }\n }\n}\n","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as crypto from \"crypto\";\nimport * as zlib from \"zlib\";\nimport { promisify } from \"util\";\nimport Database from \"better-sqlite3\";\nimport type {\n DatabaseType,\n GitHubSyncEvent,\n GitHubSyncManagerOptions,\n SnapshotMetadata,\n} from \"../types.js\";\nimport { GitHubOperations, ConflictError } from \"./github-operations.js\";\nimport { RecoveryManager } from \"./recovery.js\";\n\nconst gzip = promisify(zlib.gzip);\n\nconst SNAPSHOT_DB_NAME = \"snapshot.db\";\nconst SNAPSHOT_DB_GZ_NAME = \"snapshot.db.gz\";\nconst SNAPSHOT_META_NAME = \"snapshot.meta.json\";\n\n/**\n * Orchestrates database sync operations with GitHub\n */\nexport class GitHubSyncManager {\n private options: GitHubSyncManagerOptions;\n private github: GitHubOperations;\n private recovery: RecoveryManager;\n private db: DatabaseType | null = null;\n private hasChanges: boolean = false;\n private currentSha: string | null = null;\n private snapshotTimer: ReturnType<typeof setInterval> | null = null;\n private isInitialized: boolean = false;\n private isClosed: boolean = false;\n\n constructor(options: GitHubSyncManagerOptions) {\n this.options = options;\n this.github = new GitHubOperations(\n options.github,\n options.sync.maxRetries,\n options.onEvent,\n options.verbose\n );\n this.recovery = new RecoveryManager(\n this.github,\n options.dbPath,\n options.onEvent,\n options.verbose\n );\n }\n\n /**\n * Initialize the sync manager: recover from GitHub if needed, open database\n */\n async initialize(): Promise<DatabaseType> {\n if (this.isInitialized) {\n return this.db!;\n }\n\n this.log(\"Initializing sync manager...\");\n\n // Ensure the branch exists\n await this.github.ensureBranch();\n\n // Check if local database exists\n let recovered = false;\n if (!this.recovery.localDatabaseExists()) {\n this.log(\"Local database not found, attempting recovery from GitHub...\");\n const result = await this.recovery.recover();\n recovered = result.recovered;\n\n if (recovered) {\n this.currentSha = await this.recovery.getCurrentSnapshotSha();\n }\n } else {\n this.log(\"Local database exists, fetching current SHA...\");\n this.currentSha = await this.recovery.getCurrentSnapshotSha();\n }\n\n // Open the database\n this.db = this.openDatabase();\n\n // Start snapshot timer if configured\n if (this.options.sync.snapshotInterval > 0) {\n this.startSnapshotTimer();\n }\n\n this.isInitialized = true;\n\n this.emitEvent({\n type: \"initialized\",\n recovered,\n });\n\n return this.db;\n }\n\n /**\n * Open the SQLite database with configured options\n */\n private openDatabase(): DatabaseType {\n // Ensure the directory exists\n const dir = path.dirname(this.options.dbPath);\n if (dir && !fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n this.log(`Created directory: ${dir}`);\n }\n\n const sqliteOptions = this.options.sqliteOptions || {};\n const db = new Database(this.options.dbPath);\n\n // Set WAL mode if enabled\n if (this.options.sync.enableWal) {\n db.pragma(\"journal_mode = WAL\");\n }\n\n // Set foreign keys\n if (sqliteOptions.foreignKeys !== false) {\n db.pragma(\"foreign_keys = ON\");\n }\n\n // Set busy timeout\n if (sqliteOptions.busyTimeout) {\n db.pragma(`busy_timeout = ${sqliteOptions.busyTimeout}`);\n }\n\n // Apply additional pragmas\n if (sqliteOptions.pragmas) {\n for (const [key, value] of Object.entries(sqliteOptions.pragmas)) {\n db.pragma(`${key} = ${value}`);\n }\n }\n\n this.log(\"Database opened successfully\");\n return db;\n }\n\n /**\n * Called after database writes to track changes\n * If syncOnWrite is enabled, triggers an immediate snapshot\n */\n async onWrite(): Promise<void> {\n this.hasChanges = true;\n\n // If syncOnWrite is enabled, trigger immediate snapshot\n if (this.options.sync.syncOnWrite) {\n await this.snapshot();\n }\n }\n\n /**\n * Create a snapshot and upload to GitHub\n */\n async snapshot(): Promise<void> {\n if (this.isClosed) {\n return;\n }\n\n // Skip if no changes and snapshotOnChange is enabled\n if (this.options.sync.snapshotOnChange && !this.hasChanges) {\n this.log(\"No changes detected, skipping snapshot\");\n return;\n }\n\n if (!this.db) {\n throw new Error(\"Database not initialized\");\n }\n\n this.log(\"Creating snapshot...\");\n\n try {\n // Checkpoint WAL to ensure all changes are in the main file\n if (this.options.sync.enableWal) {\n this.db.pragma(\"wal_checkpoint(TRUNCATE)\");\n }\n\n // Read the database file\n const dbContent = fs.readFileSync(this.options.dbPath);\n\n // Calculate checksum\n const checksum = crypto\n .createHash(\"sha256\")\n .update(dbContent)\n .digest(\"hex\");\n\n // Optionally compress\n let uploadContent: Buffer;\n let filename: string;\n const compressed = this.options.sync.compression;\n\n if (compressed) {\n uploadContent = await gzip(dbContent);\n filename = SNAPSHOT_DB_GZ_NAME;\n this.log(`Compressed ${dbContent.length} -> ${uploadContent.length} bytes`);\n } else {\n uploadContent = dbContent;\n filename = SNAPSHOT_DB_NAME;\n }\n\n // Try to upload with conflict handling\n await this.uploadWithConflictRetry(filename, uploadContent, checksum, compressed);\n\n // Reset change tracking\n this.hasChanges = false;\n\n this.emitEvent({\n type: \"snapshot_uploaded\",\n sha: this.currentSha!,\n size: uploadContent.length,\n compressed,\n });\n\n this.log(`Snapshot uploaded successfully (${uploadContent.length} bytes)`);\n } catch (error) {\n this.emitEvent({\n type: \"sync_error\",\n error: error instanceof Error ? error : new Error(String(error)),\n context: \"snapshot\",\n willRetry: false,\n });\n throw error;\n }\n }\n\n /**\n * Upload file with automatic conflict resolution\n */\n private async uploadWithConflictRetry(\n filename: string,\n content: Buffer,\n checksum: string,\n compressed: boolean,\n retries: number = 3\n ): Promise<void> {\n for (let attempt = 0; attempt < retries; attempt++) {\n try {\n // Upload the database file\n const newSha = await this.github.putFile(\n filename,\n content,\n `Update database snapshot`,\n this.currentSha || undefined\n );\n\n this.currentSha = newSha;\n\n // Upload metadata\n const metadata: SnapshotMetadata = {\n timestamp: new Date().toISOString(),\n size: content.length,\n checksum,\n compressed,\n };\n\n // Get current metadata SHA if it exists\n const existingMeta = await this.github.getFile(SNAPSHOT_META_NAME);\n await this.github.putFile(\n SNAPSHOT_META_NAME,\n Buffer.from(JSON.stringify(metadata, null, 2)),\n `Update snapshot metadata`,\n existingMeta?.sha\n );\n\n // Clean up old format if we switched compression mode\n const oldFilename = compressed ? SNAPSHOT_DB_NAME : SNAPSHOT_DB_GZ_NAME;\n try {\n const oldFile = await this.github.getFile(oldFilename);\n if (oldFile) {\n await this.github.deleteFile(\n oldFilename,\n oldFile.sha,\n `Remove old snapshot format`\n );\n }\n } catch {\n // Ignore errors cleaning up old file\n }\n\n return;\n } catch (error) {\n if (error instanceof ConflictError && attempt < retries - 1) {\n this.log(`Conflict detected, refetching SHA and retrying (attempt ${attempt + 1})`);\n this.currentSha = await this.recovery.getCurrentSnapshotSha();\n continue;\n }\n throw error;\n }\n }\n }\n\n /**\n * Force an immediate sync (alias for snapshot)\n */\n async forceSync(): Promise<void> {\n const originalOnChange = this.options.sync.snapshotOnChange;\n this.options.sync.snapshotOnChange = false;\n try {\n await this.snapshot();\n } finally {\n this.options.sync.snapshotOnChange = originalOnChange;\n }\n }\n\n /**\n * Close the sync manager and perform final sync\n */\n async close(): Promise<void> {\n if (this.isClosed) {\n return;\n }\n\n this.log(\"Closing sync manager...\");\n this.isClosed = true;\n\n // Stop snapshot timer\n if (this.snapshotTimer) {\n clearInterval(this.snapshotTimer);\n this.snapshotTimer = null;\n }\n\n // Final snapshot if there are changes\n if (this.hasChanges && this.db) {\n try {\n await this.snapshot();\n } catch (error) {\n this.log(`Error during final snapshot: ${error}`);\n }\n }\n\n // Close the database\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n\n this.log(\"Sync manager closed\");\n }\n\n /**\n * Start the automatic snapshot timer\n */\n private startSnapshotTimer(): void {\n this.snapshotTimer = setInterval(() => {\n this.snapshot().catch((error) => {\n this.log(`Snapshot error: ${error}`);\n });\n }, this.options.sync.snapshotInterval);\n\n // Ensure timer doesn't prevent process exit\n if (this.snapshotTimer.unref) {\n this.snapshotTimer.unref();\n }\n }\n\n /**\n * Get the raw database instance\n */\n get database(): DatabaseType | null {\n return this.db;\n }\n\n /**\n * Check if there are pending changes\n */\n get hasPendingChanges(): boolean {\n return this.hasChanges;\n }\n\n /**\n * Check if the manager is initialized\n */\n get initialized(): boolean {\n return this.isInitialized;\n }\n\n /**\n * Emit an event if handler is registered\n */\n private emitEvent(event: GitHubSyncEvent): void {\n if (this.options.onEvent) {\n this.options.onEvent(event);\n }\n }\n\n /**\n * Log a message if verbose mode is enabled\n */\n private log(message: string): void {\n if (this.options.verbose) {\n console.log(`[sync-manager] ${message}`);\n }\n }\n}\n","import type {\n EntityMetadata,\n FieldMetadata,\n SqlCommand,\n SqlImplementation,\n} from \"remult\";\nimport { BetterSqlite3DataProvider } from \"remult/remult-better-sqlite3\";\nimport type {\n BetterSqlite3GitHubOptions,\n DatabaseType,\n GitHubConfig,\n GitHubSyncManagerOptions,\n SyncConfig,\n} from \"./types.js\";\nimport { GitHubSyncManager } from \"./sync/index.js\";\n\n/**\n * Default sync configuration values\n */\nconst DEFAULT_SYNC_CONFIG: Required<SyncConfig> = {\n snapshotInterval: 30 * 1000, // 30 seconds\n snapshotOnChange: true,\n syncOnWrite: false,\n enableWal: false,\n walThreshold: 1024 * 1024, // 1MB\n maxRetries: 3,\n compression: false,\n};\n\n/**\n * A Remult data provider that syncs SQLite to GitHub\n */\nexport class BetterSqlite3GitHubDataProvider implements SqlImplementation {\n private syncManager: GitHubSyncManager;\n private _isInitialized: boolean = false;\n private initPromise: Promise<void> | null = null;\n private innerProvider: BetterSqlite3DataProvider | null = null;\n\n constructor(options: BetterSqlite3GitHubOptions) {\n // Build internal config\n const githubConfig: GitHubConfig = {\n owner: options.github.owner,\n repo: options.github.repo,\n branch: options.github.branch || \"main\",\n path: options.github.path || \"\",\n token: options.github.token,\n appId: options.github.appId,\n privateKey: options.github.privateKey,\n installationId: options.github.installationId,\n };\n\n // Apply serverless defaults if enabled\n const serverlessDefaults: Partial<SyncConfig> = options.serverless\n ? {\n syncOnWrite: true,\n snapshotInterval: 0,\n }\n : {};\n\n const syncConfig: Required<SyncConfig> = {\n ...DEFAULT_SYNC_CONFIG,\n ...serverlessDefaults,\n ...options.sync, // User options override serverless defaults\n };\n\n const managerOptions: GitHubSyncManagerOptions = {\n dbPath: options.file,\n github: githubConfig,\n sqliteOptions: options.sqliteOptions,\n sync: syncConfig,\n onEvent: options.onEvent,\n verbose: options.verbose || false,\n };\n\n this.syncManager = new GitHubSyncManager(managerOptions);\n }\n\n /**\n * Initialize the data provider\n * This must be called before using the provider\n */\n async init(): Promise<void> {\n if (this._isInitialized) {\n return;\n }\n\n // Prevent multiple concurrent initializations\n if (this.initPromise) {\n return this.initPromise;\n }\n\n this.initPromise = this.doInit();\n await this.initPromise;\n }\n\n private async doInit(): Promise<void> {\n const db = await this.syncManager.initialize();\n\n // Create the inner BetterSqlite3DataProvider with the initialized database\n this.innerProvider = new BetterSqlite3DataProvider(db);\n\n this._isInitialized = true;\n }\n\n /**\n * Ensure the provider is initialized\n */\n private async ensureInitialized(): Promise<void> {\n if (!this._isInitialized) {\n await this.init();\n }\n }\n\n private getProvider(): BetterSqlite3DataProvider {\n if (!this.innerProvider) {\n throw new Error(\n \"Provider not initialized. Call init() before using the provider.\"\n );\n }\n return this.innerProvider;\n }\n\n // SqlImplementation interface methods\n getLimitSqlSyntax(limit: number, offset: number): string {\n return this.getProvider().getLimitSqlSyntax(limit, offset);\n }\n\n createCommand(): SqlCommand {\n const command = this.getProvider().createCommand();\n // Wrap the command to track writes\n const originalExecute = command.execute.bind(command);\n const syncManager = this.syncManager;\n const isWriteOp = this.isWriteOperation.bind(this);\n command.execute = async (sql: string) => {\n const result = await originalExecute(sql);\n if (isWriteOp(sql)) {\n await syncManager.onWrite();\n }\n return result;\n };\n return command;\n }\n\n async transaction(\n action: (sql: SqlImplementation) => Promise<void>\n ): Promise<void> {\n await this.ensureInitialized();\n return this.getProvider().transaction(action);\n }\n\n async entityIsUsedForTheFirstTime(entity: EntityMetadata): Promise<void> {\n await this.ensureInitialized();\n return this.getProvider().entityIsUsedForTheFirstTime(entity);\n }\n\n async end(): Promise<void> {\n await this.close();\n }\n\n // Passthrough properties from inner provider\n get orderByNullsFirst(): boolean | undefined {\n return this.innerProvider?.orderByNullsFirst;\n }\n\n get afterMutation(): VoidFunction | undefined {\n return this.innerProvider?.afterMutation;\n }\n\n get supportsJsonColumnType(): boolean | undefined {\n return this.innerProvider?.supportsJsonColumnType;\n }\n\n get doesNotSupportReturningSyntax(): boolean {\n return this.innerProvider?.doesNotSupportReturningSyntax ?? true;\n }\n\n // Additional methods from SqliteCoreDataProvider that may be called\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async ensureSchema(entities: EntityMetadata<any>[]): Promise<void> {\n await this.ensureInitialized();\n return this.getProvider().ensureSchema(entities);\n }\n\n wrapIdentifier(name: string): string {\n return this.getProvider().wrapIdentifier(name);\n }\n\n addColumnSqlSyntax(\n x: FieldMetadata,\n dbName: string,\n isAlterTable: boolean\n ): string {\n return this.getProvider().addColumnSqlSyntax(x, dbName, isAlterTable);\n }\n\n /**\n * Check if a SQL statement is a write operation\n */\n private isWriteOperation(sql: string): boolean {\n const upperSql = sql.trim().toUpperCase();\n return (\n upperSql.startsWith(\"INSERT\") ||\n upperSql.startsWith(\"UPDATE\") ||\n upperSql.startsWith(\"DELETE\") ||\n upperSql.startsWith(\"CREATE\") ||\n upperSql.startsWith(\"DROP\") ||\n upperSql.startsWith(\"ALTER\")\n );\n }\n\n /**\n * Force an immediate sync to GitHub\n */\n async forceSync(): Promise<void> {\n await this.ensureInitialized();\n await this.syncManager.forceSync();\n }\n\n /**\n * Create a snapshot and upload to GitHub\n */\n async snapshot(): Promise<void> {\n await this.ensureInitialized();\n await this.syncManager.snapshot();\n }\n\n /**\n * Close the provider and perform final sync\n */\n async close(): Promise<void> {\n await this.syncManager.close();\n this._isInitialized = false;\n this.initPromise = null;\n this.innerProvider = null;\n }\n\n /**\n * Get the raw better-sqlite3 database instance\n */\n get rawDatabase(): DatabaseType | null {\n return this.syncManager.database;\n }\n\n /**\n * Get the sync manager instance\n */\n get sync(): GitHubSyncManager {\n return this.syncManager;\n }\n\n /**\n * Check if the provider is initialized\n */\n get isInitialized(): boolean {\n return this._isInitialized;\n }\n}\n","import { SqlDatabase } from \"remult\";\nimport { BetterSqlite3GitHubDataProvider } from \"./provider.js\";\nimport type { BetterSqlite3GitHubOptions } from \"./types.js\";\n\n/**\n * Create a GitHub-synced SQLite data provider for Remult\n *\n * @param options - Configuration options for the provider\n * @returns A factory function that creates an initialized SqlDatabase\n *\n * @example\n * ```typescript\n * import { createGitHubDataProvider } from \"remult-sqlite-github\";\n *\n * const api = remultApi({\n * dataProvider: createGitHubDataProvider({\n * file: \"./mydb.sqlite\",\n * github: {\n * owner: \"your-username\",\n * repo: \"your-database-repo\",\n * token: process.env.GITHUB_TOKEN,\n * },\n * }),\n * entities: [Task],\n * });\n * ```\n */\nexport function createGitHubDataProvider(\n options: BetterSqlite3GitHubOptions\n): () => Promise<SqlDatabase> {\n let provider: BetterSqlite3GitHubDataProvider | null = null;\n let sqlDatabase: SqlDatabase | null = null;\n\n return async () => {\n if (sqlDatabase) {\n return sqlDatabase;\n }\n\n provider = new BetterSqlite3GitHubDataProvider(options);\n await provider.init();\n\n sqlDatabase = new SqlDatabase(provider);\n return sqlDatabase;\n };\n}\n\n// Export the provider class for advanced usage\nexport { BetterSqlite3GitHubDataProvider } from \"./provider.js\";\n\n// Export sync components for advanced usage\nexport { GitHubSyncManager, GitHubOperations, ConflictError } from \"./sync/index.js\";\n\n// Export types\nexport type {\n BetterSqlite3GitHubOptions,\n GitHubSyncEvent,\n GitHubRepoConfig,\n GitHubAuthConfig,\n SyncConfig,\n SqliteOptions,\n DatabaseType,\n RateLimitInfo,\n RecoveryResult,\n SnapshotMetadata,\n} from \"./types.js\";\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/sync/github-operations.ts","../src/sync/recovery.ts","../src/sync/sync-manager.ts","../src/provider.ts","../src/index.ts"],"names":["path","crypto","gunzip","promisify","zlib","fs","gzip","zlib2","SNAPSHOT_DB_NAME","SNAPSHOT_DB_GZ_NAME","SNAPSHOT_META_NAME","path2","fs2","Database","crypto2","BetterSqlite3DataProvider","SqlDatabase"],"mappings":"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","file":"index.cjs","sourcesContent":["import * as crypto from \"crypto\";\nimport type {\n GitHubConfig,\n GitHubFileResult,\n GitHubFileEntry,\n RateLimitInfo,\n GitHubSyncEvent,\n} from \"../types.js\";\n\nconst GITHUB_API_BASE = \"https://api.github.com\";\n\n/**\n * GitHub REST API operations wrapper with retry logic and rate limit handling\n */\nexport class GitHubOperations {\n private config: GitHubConfig;\n private maxRetries: number;\n private cachedToken: string | null = null;\n private tokenExpiry: number = 0;\n private onEvent?: (event: GitHubSyncEvent) => void;\n private verbose: boolean;\n\n constructor(\n config: GitHubConfig,\n maxRetries: number = 3,\n onEvent?: (event: GitHubSyncEvent) => void,\n verbose: boolean = false\n ) {\n this.config = config;\n this.maxRetries = maxRetries;\n this.onEvent = onEvent;\n this.verbose = verbose;\n }\n\n /**\n * Get a file from the repository\n */\n async getFile(path: string): Promise<GitHubFileResult | null> {\n const fullPath = this.getFullPath(path);\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/contents/${fullPath}?ref=${this.config.branch}`;\n\n const response = await this.withRetry(() => this.fetch(url));\n\n if (response.status === 404) {\n return null;\n }\n\n if (!response.ok) {\n throw new Error(\n `Failed to get file ${path}: ${response.status} ${response.statusText}`\n );\n }\n\n const data = await response.json();\n\n // GitHub returns base64 encoded content for files under 1MB\n // For larger files, we need to use the blob API\n if (data.content) {\n const content = Buffer.from(data.content, \"base64\");\n return {\n content,\n sha: data.sha,\n size: data.size,\n };\n }\n\n // Large file - use blob API\n if (data.sha && data.size > 0) {\n return this.getBlob(data.sha, data.size);\n }\n\n return null;\n }\n\n /**\n * Get a large file using the blob API\n */\n private async getBlob(sha: string, size: number): Promise<GitHubFileResult> {\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/git/blobs/${sha}`;\n\n const response = await this.withRetry(() => this.fetch(url));\n\n if (!response.ok) {\n throw new Error(\n `Failed to get blob ${sha}: ${response.status} ${response.statusText}`\n );\n }\n\n const data = await response.json();\n const content = Buffer.from(data.content, \"base64\");\n\n return {\n content,\n sha,\n size,\n };\n }\n\n /**\n * Create or update a file in the repository\n * Returns the new commit SHA\n */\n async putFile(\n path: string,\n content: Buffer,\n message: string,\n sha?: string\n ): Promise<string> {\n const fullPath = this.getFullPath(path);\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/contents/${fullPath}`;\n\n const body: Record<string, string> = {\n message,\n content: content.toString(\"base64\"),\n branch: this.config.branch,\n };\n\n if (sha) {\n body.sha = sha;\n }\n\n const response = await this.withRetry(\n () =>\n this.fetch(url, {\n method: \"PUT\",\n body: JSON.stringify(body),\n }),\n true // Allow conflict retry\n );\n\n if (response.status === 409) {\n // Conflict - SHA mismatch, caller should re-fetch and retry\n throw new ConflictError(\n `Conflict updating ${path}: file was modified concurrently`\n );\n }\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to put file ${path}: ${response.status} ${response.statusText} - ${errorText}`\n );\n }\n\n const data = await response.json();\n\n this.emitEvent({\n type: \"commit_created\",\n sha: data.commit.sha,\n message,\n });\n\n return data.content.sha;\n }\n\n /**\n * Delete a file from the repository\n */\n async deleteFile(path: string, sha: string, message: string): Promise<void> {\n const fullPath = this.getFullPath(path);\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/contents/${fullPath}`;\n\n const response = await this.withRetry(() =>\n this.fetch(url, {\n method: \"DELETE\",\n body: JSON.stringify({\n message,\n sha,\n branch: this.config.branch,\n }),\n })\n );\n\n if (!response.ok && response.status !== 404) {\n throw new Error(\n `Failed to delete file ${path}: ${response.status} ${response.statusText}`\n );\n }\n }\n\n /**\n * List files in a directory\n */\n async listFiles(path: string): Promise<GitHubFileEntry[]> {\n const fullPath = this.getFullPath(path);\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/contents/${fullPath}?ref=${this.config.branch}`;\n\n const response = await this.withRetry(() => this.fetch(url));\n\n if (response.status === 404) {\n return [];\n }\n\n if (!response.ok) {\n throw new Error(\n `Failed to list files at ${path}: ${response.status} ${response.statusText}`\n );\n }\n\n const data = await response.json();\n\n // Single file returns object, directory returns array\n if (!Array.isArray(data)) {\n return [\n {\n name: data.name,\n path: data.path,\n sha: data.sha,\n size: data.size,\n type: data.type,\n },\n ];\n }\n\n return data.map(\n (item: {\n name: string;\n path: string;\n sha: string;\n size: number;\n type: \"file\" | \"dir\";\n }) => ({\n name: item.name,\n path: item.path,\n sha: item.sha,\n size: item.size,\n type: item.type,\n })\n );\n }\n\n /**\n * Check current rate limit status\n */\n async checkRateLimit(): Promise<RateLimitInfo> {\n const url = `${GITHUB_API_BASE}/rate_limit`;\n const response = await this.fetch(url);\n\n if (!response.ok) {\n throw new Error(`Failed to check rate limit: ${response.statusText}`);\n }\n\n const data = await response.json();\n return {\n remaining: data.resources.core.remaining,\n resetAt: new Date(data.resources.core.reset * 1000),\n limit: data.resources.core.limit,\n };\n }\n\n /**\n * Ensure the branch exists, create if it doesn't\n * For empty repos, we skip branch creation since files can be pushed directly\n */\n async ensureBranch(): Promise<void> {\n // Check if branch exists\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/branches/${this.config.branch}`;\n const response = await this.fetch(url);\n\n if (response.ok) {\n return; // Branch exists\n }\n\n if (response.status !== 404) {\n // Could be auth error or other issue\n const errorText = await response.text();\n throw new Error(\n `Failed to check branch '${this.config.branch}': ${response.status} ${response.statusText}. ${errorText}`\n );\n }\n\n // Branch doesn't exist, check if repo has any commits\n const repoUrl = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}`;\n const repoResponse = await this.fetch(repoUrl);\n\n if (!repoResponse.ok) {\n const errorText = await repoResponse.text();\n throw new Error(\n `Failed to get repository info for '${this.config.owner}/${this.config.repo}': ${repoResponse.status} ${repoResponse.statusText}. ${errorText}`\n );\n }\n\n const repoData = await repoResponse.json();\n const defaultBranch = repoData.default_branch;\n\n // Check if the repo is empty (no commits yet)\n // Empty repos have size 0 and no refs\n const refUrl = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/git/refs/heads/${defaultBranch}`;\n const refResponse = await this.fetch(refUrl);\n\n if (!refResponse.ok) {\n if (refResponse.status === 409 || refResponse.status === 404) {\n // Empty repository - the branch will be created on first file push\n this.log(\n `Repository appears to be empty. Branch '${this.config.branch}' will be created on first snapshot.`\n );\n return;\n }\n const errorText = await refResponse.text();\n throw new Error(\n `Failed to get default branch ref: ${refResponse.status} ${refResponse.statusText}. ${errorText}`\n );\n }\n\n // If we're using the default branch, we're done\n if (this.config.branch === defaultBranch) {\n return;\n }\n\n const refData = await refResponse.json();\n const sha = refData.object.sha;\n\n // Create new branch from default branch\n const createUrl = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/git/refs`;\n const createResponse = await this.fetch(createUrl, {\n method: \"POST\",\n body: JSON.stringify({\n ref: `refs/heads/${this.config.branch}`,\n sha,\n }),\n });\n\n if (!createResponse.ok && createResponse.status !== 422) {\n const errorText = await createResponse.text();\n throw new Error(\n `Failed to create branch '${this.config.branch}': ${createResponse.status} ${createResponse.statusText}. ${errorText}`\n );\n }\n\n this.log(`Created branch: ${this.config.branch}`);\n }\n\n /**\n * Get the full path including configured prefix\n */\n private getFullPath(path: string): string {\n if (!this.config.path) {\n return path;\n }\n return `${this.config.path}/${path}`.replace(/\\/+/g, \"/\");\n }\n\n /**\n * Make an authenticated fetch request\n */\n private async fetch(\n url: string,\n options: RequestInit = {}\n ): Promise<Response> {\n const token = await this.getAuthToken();\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n Accept: \"application/vnd.github+json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n ...(options.headers as Record<string, string>),\n };\n\n if (options.body) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n return fetch(url, {\n ...options,\n headers,\n });\n }\n\n /**\n * Get authentication token (PAT or GitHub App installation token)\n */\n private async getAuthToken(): Promise<string> {\n // Use PAT if provided\n if (this.config.token) {\n return this.config.token;\n }\n\n // Check if we have a valid cached token\n if (this.cachedToken && Date.now() < this.tokenExpiry) {\n return this.cachedToken;\n }\n\n // Generate GitHub App installation token\n if (\n !this.config.appId ||\n !this.config.privateKey ||\n !this.config.installationId\n ) {\n throw new Error(\n \"Either token or GitHub App credentials (appId, privateKey, installationId) must be provided\"\n );\n }\n\n const jwt = this.generateJWT(this.config.appId, this.config.privateKey);\n\n const response = await fetch(\n `${GITHUB_API_BASE}/app/installations/${this.config.installationId}/access_tokens`,\n {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${jwt}`,\n Accept: \"application/vnd.github+json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n },\n }\n );\n\n if (!response.ok) {\n throw new Error(\n `Failed to get installation token: ${response.statusText}`\n );\n }\n\n const data = await response.json();\n this.cachedToken = data.token;\n // Token expires in 1 hour, refresh 5 minutes early\n this.tokenExpiry = Date.now() + 55 * 60 * 1000;\n\n return this.cachedToken!;\n }\n\n /**\n * Generate a JWT for GitHub App authentication\n */\n private generateJWT(appId: number, privateKey: string): string {\n const now = Math.floor(Date.now() / 1000);\n const payload = {\n iat: now - 60, // Issued 60 seconds ago to account for clock drift\n exp: now + 10 * 60, // Expires in 10 minutes\n iss: appId.toString(),\n };\n\n const header = { alg: \"RS256\", typ: \"JWT\" };\n const encodedHeader = this.base64UrlEncode(JSON.stringify(header));\n const encodedPayload = this.base64UrlEncode(JSON.stringify(payload));\n\n const signatureInput = `${encodedHeader}.${encodedPayload}`;\n const signature = crypto\n .createSign(\"RSA-SHA256\")\n .update(signatureInput)\n .sign(privateKey, \"base64url\");\n\n return `${signatureInput}.${signature}`;\n }\n\n /**\n * Base64 URL encode a string\n */\n private base64UrlEncode(str: string): string {\n return Buffer.from(str)\n .toString(\"base64\")\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=/g, \"\");\n }\n\n /**\n * Execute a function with retry logic and exponential backoff\n */\n private async withRetry<T>(\n fn: () => Promise<T>,\n allowConflict: boolean = false\n ): Promise<T> {\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n try {\n const result = await fn();\n\n // Check for rate limiting in response\n if (result instanceof Response) {\n await this.handleRateLimitHeaders(result);\n }\n\n return result;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Don't retry conflict errors unless specified\n if (error instanceof ConflictError && !allowConflict) {\n throw error;\n }\n\n // Check if this is a rate limit error\n if (\n error instanceof Error &&\n error.message.includes(\"rate limit\")\n ) {\n const rateLimit = await this.checkRateLimit();\n const waitTime = Math.max(\n 0,\n rateLimit.resetAt.getTime() - Date.now()\n );\n\n this.emitEvent({\n type: \"rate_limit_hit\",\n resetAt: rateLimit.resetAt,\n remaining: rateLimit.remaining,\n });\n\n if (waitTime > 0 && waitTime < 60000) {\n // Wait up to 1 minute\n this.log(`Rate limited, waiting ${waitTime}ms`);\n await this.sleep(waitTime);\n continue;\n }\n }\n\n // Emit error event\n this.emitEvent({\n type: \"sync_error\",\n error: lastError,\n context: \"github_operation\",\n willRetry: attempt < this.maxRetries,\n });\n\n if (attempt < this.maxRetries) {\n const delay = Math.min(1000 * Math.pow(2, attempt), 30000);\n this.log(`Retry attempt ${attempt + 1} after ${delay}ms`);\n await this.sleep(delay);\n }\n }\n }\n\n throw lastError || new Error(\"Unknown error\");\n }\n\n /**\n * Handle rate limit headers from response\n */\n private async handleRateLimitHeaders(response: Response): Promise<void> {\n const remaining = parseInt(\n response.headers.get(\"x-ratelimit-remaining\") || \"1000\",\n 10\n );\n const resetTimestamp = parseInt(\n response.headers.get(\"x-ratelimit-reset\") || \"0\",\n 10\n );\n\n if (remaining === 0 && resetTimestamp > 0) {\n const resetAt = new Date(resetTimestamp * 1000);\n const waitTime = Math.max(0, resetAt.getTime() - Date.now());\n\n this.emitEvent({\n type: \"rate_limit_hit\",\n resetAt,\n remaining: 0,\n });\n\n if (waitTime > 0 && waitTime < 60000) {\n this.log(`Rate limit exhausted, waiting ${waitTime}ms`);\n await this.sleep(waitTime);\n }\n }\n }\n\n /**\n * Sleep for the specified duration\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Emit an event if handler is registered\n */\n private emitEvent(event: GitHubSyncEvent): void {\n if (this.onEvent) {\n this.onEvent(event);\n }\n }\n\n /**\n * Log a message if verbose mode is enabled\n */\n private log(message: string): void {\n if (this.verbose) {\n console.log(`[github-operations] ${message}`);\n }\n }\n}\n\n/**\n * Custom error for conflict (SHA mismatch) situations\n */\nexport class ConflictError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ConflictError\";\n }\n}\n","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as zlib from \"zlib\";\nimport { promisify } from \"util\";\nimport type {\n GitHubSyncEvent,\n RecoveryResult,\n SnapshotMetadata,\n} from \"../types.js\";\nimport { GitHubOperations } from \"./github-operations.js\";\n\nconst gunzip = promisify(zlib.gunzip);\n\nconst SNAPSHOT_DB_NAME = \"snapshot.db\";\nconst SNAPSHOT_DB_GZ_NAME = \"snapshot.db.gz\";\nconst SNAPSHOT_META_NAME = \"snapshot.meta.json\";\n\n/**\n * Manages database recovery from GitHub\n */\nexport class RecoveryManager {\n private github: GitHubOperations;\n private dbPath: string;\n private onEvent?: (event: GitHubSyncEvent) => void;\n private verbose: boolean;\n\n constructor(\n github: GitHubOperations,\n dbPath: string,\n onEvent?: (event: GitHubSyncEvent) => void,\n verbose: boolean = false\n ) {\n this.github = github;\n this.dbPath = dbPath;\n this.onEvent = onEvent;\n this.verbose = verbose;\n }\n\n /**\n * Check if local database exists\n */\n localDatabaseExists(): boolean {\n return fs.existsSync(this.dbPath);\n }\n\n /**\n * Find the latest snapshot in the repository\n */\n async findLatestSnapshot(): Promise<{\n path: string;\n sha: string;\n compressed: boolean;\n } | null> {\n try {\n // First check for compressed snapshot\n const compressedFile = await this.github.getFile(SNAPSHOT_DB_GZ_NAME);\n if (compressedFile) {\n return {\n path: SNAPSHOT_DB_GZ_NAME,\n sha: compressedFile.sha,\n compressed: true,\n };\n }\n\n // Then check for uncompressed snapshot\n const uncompressedFile = await this.github.getFile(SNAPSHOT_DB_NAME);\n if (uncompressedFile) {\n return {\n path: SNAPSHOT_DB_NAME,\n sha: uncompressedFile.sha,\n compressed: false,\n };\n }\n\n return null;\n } catch (error) {\n this.log(`Error finding snapshot: ${error}`);\n return null;\n }\n }\n\n /**\n * Recover database from GitHub snapshot\n */\n async recover(): Promise<RecoveryResult> {\n this.emitEvent({\n type: \"recovery_started\",\n branch: \"\", // Branch is handled by GitHubOperations\n });\n\n try {\n // Find the latest snapshot\n const snapshot = await this.findLatestSnapshot();\n\n if (!snapshot) {\n this.log(\"No snapshot found in repository\");\n return { recovered: false };\n }\n\n this.log(`Found snapshot: ${snapshot.path}`);\n\n // Download the snapshot\n const file = await this.github.getFile(snapshot.path);\n if (!file) {\n this.log(\"Failed to download snapshot\");\n return { recovered: false };\n }\n\n // Decompress if necessary\n let dbContent: Buffer;\n if (snapshot.compressed) {\n this.log(\"Decompressing snapshot...\");\n dbContent = await gunzip(file.content);\n } else {\n dbContent = file.content;\n }\n\n // Ensure directory exists\n const dir = path.dirname(this.dbPath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n // Write the database file\n fs.writeFileSync(this.dbPath, dbContent);\n this.log(`Database recovered to ${this.dbPath}`);\n\n // Get metadata if available (for future use)\n await this.getSnapshotMetadata();\n\n this.emitEvent({\n type: \"recovery_completed\",\n sha: file.sha,\n });\n\n return {\n recovered: true,\n sha: file.sha,\n size: dbContent.length,\n compressed: snapshot.compressed,\n };\n } catch (error) {\n this.log(`Recovery error: ${error}`);\n this.emitEvent({\n type: \"sync_error\",\n error: error instanceof Error ? error : new Error(String(error)),\n context: \"recovery\",\n willRetry: false,\n });\n return { recovered: false };\n }\n }\n\n /**\n * Get snapshot metadata from repository\n */\n async getSnapshotMetadata(): Promise<SnapshotMetadata | null> {\n try {\n const file = await this.github.getFile(SNAPSHOT_META_NAME);\n if (!file) {\n return null;\n }\n return JSON.parse(file.content.toString(\"utf-8\"));\n } catch {\n return null;\n }\n }\n\n /**\n * Get the current snapshot SHA from the repository\n */\n async getCurrentSnapshotSha(): Promise<string | null> {\n const snapshot = await this.findLatestSnapshot();\n return snapshot?.sha || null;\n }\n\n /**\n * Emit an event if handler is registered\n */\n private emitEvent(event: GitHubSyncEvent): void {\n if (this.onEvent) {\n this.onEvent(event);\n }\n }\n\n /**\n * Log a message if verbose mode is enabled\n */\n private log(message: string): void {\n if (this.verbose) {\n console.log(`[recovery] ${message}`);\n }\n }\n}\n","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as crypto from \"crypto\";\nimport * as zlib from \"zlib\";\nimport { promisify } from \"util\";\nimport Database from \"better-sqlite3\";\nimport type {\n DatabaseType,\n GitHubSyncEvent,\n GitHubSyncManagerOptions,\n SnapshotMetadata,\n} from \"../types.js\";\nimport { GitHubOperations, ConflictError } from \"./github-operations.js\";\nimport { RecoveryManager } from \"./recovery.js\";\n\nconst gzip = promisify(zlib.gzip);\n\nconst SNAPSHOT_DB_NAME = \"snapshot.db\";\nconst SNAPSHOT_DB_GZ_NAME = \"snapshot.db.gz\";\nconst SNAPSHOT_META_NAME = \"snapshot.meta.json\";\n\n/**\n * Orchestrates database sync operations with GitHub\n */\nexport class GitHubSyncManager {\n private options: GitHubSyncManagerOptions;\n private github: GitHubOperations;\n private recovery: RecoveryManager;\n private db: DatabaseType | null = null;\n private hasChanges: boolean = false;\n private currentSha: string | null = null;\n private snapshotTimer: ReturnType<typeof setInterval> | null = null;\n private isInitialized: boolean = false;\n private isClosed: boolean = false;\n private pendingSync: Promise<void> | null = null;\n private syncDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(options: GitHubSyncManagerOptions) {\n this.options = options;\n this.github = new GitHubOperations(\n options.github,\n options.sync.maxRetries,\n options.onEvent,\n options.verbose\n );\n this.recovery = new RecoveryManager(\n this.github,\n options.dbPath,\n options.onEvent,\n options.verbose\n );\n }\n\n /**\n * Initialize the sync manager: recover from GitHub if needed, open database\n */\n async initialize(): Promise<DatabaseType> {\n if (this.isInitialized) {\n return this.db!;\n }\n\n this.log(\"Initializing sync manager...\");\n\n // Ensure the branch exists\n await this.github.ensureBranch();\n\n // Check if local database exists\n let recovered = false;\n if (!this.recovery.localDatabaseExists()) {\n this.log(\"Local database not found, attempting recovery from GitHub...\");\n const result = await this.recovery.recover();\n recovered = result.recovered;\n\n if (recovered) {\n this.currentSha = await this.recovery.getCurrentSnapshotSha();\n }\n } else {\n this.log(\"Local database exists, fetching current SHA...\");\n this.currentSha = await this.recovery.getCurrentSnapshotSha();\n }\n\n // Open the database\n this.db = this.openDatabase();\n\n // Start snapshot timer if configured\n if (this.options.sync.snapshotInterval > 0) {\n this.startSnapshotTimer();\n }\n\n this.isInitialized = true;\n\n this.emitEvent({\n type: \"initialized\",\n recovered,\n });\n\n return this.db;\n }\n\n /**\n * Open the SQLite database with configured options\n */\n private openDatabase(): DatabaseType {\n // Ensure the directory exists\n const dir = path.dirname(this.options.dbPath);\n if (dir && !fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n this.log(`Created directory: ${dir}`);\n }\n\n const sqliteOptions = this.options.sqliteOptions || {};\n const db = new Database(this.options.dbPath);\n\n // Set WAL mode if enabled\n if (this.options.sync.enableWal) {\n db.pragma(\"journal_mode = WAL\");\n }\n\n // Set foreign keys\n if (sqliteOptions.foreignKeys !== false) {\n db.pragma(\"foreign_keys = ON\");\n }\n\n // Set busy timeout\n if (sqliteOptions.busyTimeout) {\n db.pragma(`busy_timeout = ${sqliteOptions.busyTimeout}`);\n }\n\n // Apply additional pragmas\n if (sqliteOptions.pragmas) {\n for (const [key, value] of Object.entries(sqliteOptions.pragmas)) {\n db.pragma(`${key} = ${value}`);\n }\n }\n\n this.log(\"Database opened successfully\");\n return db;\n }\n\n /**\n * Called after database writes to track changes\n * If syncOnWrite is enabled, triggers a debounced non-blocking snapshot\n */\n async onWrite(): Promise<void> {\n this.hasChanges = true;\n\n // If syncOnWrite is enabled, trigger debounced snapshot (non-blocking)\n if (this.options.sync.syncOnWrite) {\n this.scheduleDebouncedSync();\n }\n }\n\n /**\n * Schedule a debounced sync - waits 100ms for more writes before syncing\n * This prevents multiple rapid writes from each triggering a separate upload\n */\n private scheduleDebouncedSync(): void {\n // Clear any existing debounce timer\n if (this.syncDebounceTimer) {\n clearTimeout(this.syncDebounceTimer);\n }\n\n // Schedule sync after 100ms of no writes\n this.syncDebounceTimer = setTimeout(() => {\n this.syncDebounceTimer = null;\n\n // Don't start a new sync if one is already in progress\n if (this.pendingSync) {\n return;\n }\n\n this.pendingSync = this.snapshot()\n .catch((error) => {\n this.log(`Background sync error: ${error}`);\n })\n .finally(() => {\n this.pendingSync = null;\n // If more changes came in during sync, schedule another\n if (this.hasChanges) {\n this.scheduleDebouncedSync();\n }\n });\n }, 100);\n }\n\n /**\n * Create a snapshot and upload to GitHub\n */\n async snapshot(): Promise<void> {\n if (this.isClosed) {\n return;\n }\n\n // Skip if no changes and snapshotOnChange is enabled\n if (this.options.sync.snapshotOnChange && !this.hasChanges) {\n this.log(\"No changes detected, skipping snapshot\");\n return;\n }\n\n if (!this.db) {\n throw new Error(\"Database not initialized\");\n }\n\n this.log(\"Creating snapshot...\");\n\n try {\n // Checkpoint WAL to ensure all changes are in the main file\n if (this.options.sync.enableWal) {\n this.db.pragma(\"wal_checkpoint(TRUNCATE)\");\n }\n\n // Read the database file\n const dbContent = fs.readFileSync(this.options.dbPath);\n\n // Calculate checksum\n const checksum = crypto\n .createHash(\"sha256\")\n .update(dbContent)\n .digest(\"hex\");\n\n // Optionally compress\n let uploadContent: Buffer;\n let filename: string;\n const compressed = this.options.sync.compression;\n\n if (compressed) {\n uploadContent = await gzip(dbContent);\n filename = SNAPSHOT_DB_GZ_NAME;\n this.log(`Compressed ${dbContent.length} -> ${uploadContent.length} bytes`);\n } else {\n uploadContent = dbContent;\n filename = SNAPSHOT_DB_NAME;\n }\n\n // Try to upload with conflict handling\n await this.uploadWithConflictRetry(filename, uploadContent, checksum, compressed);\n\n // Reset change tracking\n this.hasChanges = false;\n\n this.emitEvent({\n type: \"snapshot_uploaded\",\n sha: this.currentSha!,\n size: uploadContent.length,\n compressed,\n });\n\n this.log(`Snapshot uploaded successfully (${uploadContent.length} bytes)`);\n } catch (error) {\n this.emitEvent({\n type: \"sync_error\",\n error: error instanceof Error ? error : new Error(String(error)),\n context: \"snapshot\",\n willRetry: false,\n });\n throw error;\n }\n }\n\n /**\n * Upload file with automatic conflict resolution\n */\n private async uploadWithConflictRetry(\n filename: string,\n content: Buffer,\n checksum: string,\n compressed: boolean,\n retries: number = 3\n ): Promise<void> {\n for (let attempt = 0; attempt < retries; attempt++) {\n try {\n // Upload the database file\n const newSha = await this.github.putFile(\n filename,\n content,\n `Update database snapshot`,\n this.currentSha || undefined\n );\n\n this.currentSha = newSha;\n\n // Upload metadata\n const metadata: SnapshotMetadata = {\n timestamp: new Date().toISOString(),\n size: content.length,\n checksum,\n compressed,\n };\n\n // Get current metadata SHA if it exists\n const existingMeta = await this.github.getFile(SNAPSHOT_META_NAME);\n await this.github.putFile(\n SNAPSHOT_META_NAME,\n Buffer.from(JSON.stringify(metadata, null, 2)),\n `Update snapshot metadata`,\n existingMeta?.sha\n );\n\n // Clean up old format if we switched compression mode\n const oldFilename = compressed ? SNAPSHOT_DB_NAME : SNAPSHOT_DB_GZ_NAME;\n try {\n const oldFile = await this.github.getFile(oldFilename);\n if (oldFile) {\n await this.github.deleteFile(\n oldFilename,\n oldFile.sha,\n `Remove old snapshot format`\n );\n }\n } catch {\n // Ignore errors cleaning up old file\n }\n\n return;\n } catch (error) {\n if (error instanceof ConflictError && attempt < retries - 1) {\n this.log(`Conflict detected, refetching SHA and retrying (attempt ${attempt + 1})`);\n this.currentSha = await this.recovery.getCurrentSnapshotSha();\n continue;\n }\n throw error;\n }\n }\n }\n\n /**\n * Force an immediate sync (alias for snapshot)\n */\n async forceSync(): Promise<void> {\n const originalOnChange = this.options.sync.snapshotOnChange;\n this.options.sync.snapshotOnChange = false;\n try {\n await this.snapshot();\n } finally {\n this.options.sync.snapshotOnChange = originalOnChange;\n }\n }\n\n /**\n * Close the sync manager and perform final sync\n */\n async close(): Promise<void> {\n if (this.isClosed) {\n return;\n }\n\n this.log(\"Closing sync manager...\");\n this.isClosed = true;\n\n // Stop snapshot timer\n if (this.snapshotTimer) {\n clearInterval(this.snapshotTimer);\n this.snapshotTimer = null;\n }\n\n // Clear debounce timer\n if (this.syncDebounceTimer) {\n clearTimeout(this.syncDebounceTimer);\n this.syncDebounceTimer = null;\n }\n\n // Wait for any pending sync to complete\n if (this.pendingSync) {\n try {\n await this.pendingSync;\n } catch {\n // Ignore errors from pending sync\n }\n }\n\n // Final snapshot if there are changes\n if (this.hasChanges && this.db) {\n try {\n await this.snapshot();\n } catch (error) {\n this.log(`Error during final snapshot: ${error}`);\n }\n }\n\n // Close the database\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n\n this.log(\"Sync manager closed\");\n }\n\n /**\n * Start the automatic snapshot timer\n */\n private startSnapshotTimer(): void {\n this.snapshotTimer = setInterval(() => {\n this.snapshot().catch((error) => {\n this.log(`Snapshot error: ${error}`);\n });\n }, this.options.sync.snapshotInterval);\n\n // Ensure timer doesn't prevent process exit\n if (this.snapshotTimer.unref) {\n this.snapshotTimer.unref();\n }\n }\n\n /**\n * Get the raw database instance\n */\n get database(): DatabaseType | null {\n return this.db;\n }\n\n /**\n * Check if there are pending changes\n */\n get hasPendingChanges(): boolean {\n return this.hasChanges;\n }\n\n /**\n * Check if the manager is initialized\n */\n get initialized(): boolean {\n return this.isInitialized;\n }\n\n /**\n * Emit an event if handler is registered\n */\n private emitEvent(event: GitHubSyncEvent): void {\n if (this.options.onEvent) {\n this.options.onEvent(event);\n }\n }\n\n /**\n * Log a message if verbose mode is enabled\n */\n private log(message: string): void {\n if (this.options.verbose) {\n console.log(`[sync-manager] ${message}`);\n }\n }\n}\n","import type {\n EntityMetadata,\n FieldMetadata,\n SqlCommand,\n SqlImplementation,\n} from \"remult\";\nimport { BetterSqlite3DataProvider } from \"remult/remult-better-sqlite3\";\nimport type {\n BetterSqlite3GitHubOptions,\n DatabaseType,\n GitHubConfig,\n GitHubSyncManagerOptions,\n SyncConfig,\n} from \"./types.js\";\nimport { GitHubSyncManager } from \"./sync/index.js\";\n\n/**\n * Default sync configuration values\n */\nconst DEFAULT_SYNC_CONFIG: Required<SyncConfig> = {\n snapshotInterval: 30 * 1000, // 30 seconds\n snapshotOnChange: true,\n syncOnWrite: false,\n enableWal: false,\n walThreshold: 1024 * 1024, // 1MB\n maxRetries: 3,\n compression: false,\n};\n\n/**\n * A Remult data provider that syncs SQLite to GitHub\n */\nexport class BetterSqlite3GitHubDataProvider implements SqlImplementation {\n private syncManager: GitHubSyncManager;\n private _isInitialized: boolean = false;\n private initPromise: Promise<void> | null = null;\n private innerProvider: BetterSqlite3DataProvider | null = null;\n\n constructor(options: BetterSqlite3GitHubOptions) {\n // Build internal config\n const githubConfig: GitHubConfig = {\n owner: options.github.owner,\n repo: options.github.repo,\n branch: options.github.branch || \"main\",\n path: options.github.path || \"\",\n token: options.github.token,\n appId: options.github.appId,\n privateKey: options.github.privateKey,\n installationId: options.github.installationId,\n };\n\n // Apply serverless defaults if enabled\n const serverlessDefaults: Partial<SyncConfig> = options.serverless\n ? {\n syncOnWrite: true,\n snapshotInterval: 0,\n }\n : {};\n\n const syncConfig: Required<SyncConfig> = {\n ...DEFAULT_SYNC_CONFIG,\n ...serverlessDefaults,\n ...options.sync, // User options override serverless defaults\n };\n\n const managerOptions: GitHubSyncManagerOptions = {\n dbPath: options.file,\n github: githubConfig,\n sqliteOptions: options.sqliteOptions,\n sync: syncConfig,\n onEvent: options.onEvent,\n verbose: options.verbose || false,\n };\n\n this.syncManager = new GitHubSyncManager(managerOptions);\n }\n\n /**\n * Initialize the data provider\n * This must be called before using the provider\n */\n async init(): Promise<void> {\n if (this._isInitialized) {\n return;\n }\n\n // Prevent multiple concurrent initializations\n if (this.initPromise) {\n return this.initPromise;\n }\n\n this.initPromise = this.doInit();\n await this.initPromise;\n }\n\n private async doInit(): Promise<void> {\n const db = await this.syncManager.initialize();\n\n // Create the inner BetterSqlite3DataProvider with the initialized database\n this.innerProvider = new BetterSqlite3DataProvider(db);\n\n this._isInitialized = true;\n }\n\n /**\n * Ensure the provider is initialized\n */\n private async ensureInitialized(): Promise<void> {\n if (!this._isInitialized) {\n await this.init();\n }\n }\n\n private getProvider(): BetterSqlite3DataProvider {\n if (!this.innerProvider) {\n throw new Error(\n \"Provider not initialized. Call init() before using the provider.\"\n );\n }\n return this.innerProvider;\n }\n\n // SqlImplementation interface methods\n getLimitSqlSyntax(limit: number, offset: number): string {\n return this.getProvider().getLimitSqlSyntax(limit, offset);\n }\n\n createCommand(): SqlCommand {\n const command = this.getProvider().createCommand();\n // Wrap the command to track writes\n const originalExecute = command.execute.bind(command);\n const syncManager = this.syncManager;\n const isWriteOp = this.isWriteOperation.bind(this);\n command.execute = async (sql: string) => {\n const result = await originalExecute(sql);\n if (isWriteOp(sql)) {\n await syncManager.onWrite();\n }\n return result;\n };\n return command;\n }\n\n async transaction(\n action: (sql: SqlImplementation) => Promise<void>\n ): Promise<void> {\n await this.ensureInitialized();\n return this.getProvider().transaction(action);\n }\n\n async entityIsUsedForTheFirstTime(entity: EntityMetadata): Promise<void> {\n await this.ensureInitialized();\n return this.getProvider().entityIsUsedForTheFirstTime(entity);\n }\n\n async end(): Promise<void> {\n await this.close();\n }\n\n // Passthrough properties from inner provider\n get orderByNullsFirst(): boolean | undefined {\n return this.innerProvider?.orderByNullsFirst;\n }\n\n get afterMutation(): VoidFunction | undefined {\n return this.innerProvider?.afterMutation;\n }\n\n get supportsJsonColumnType(): boolean | undefined {\n return this.innerProvider?.supportsJsonColumnType;\n }\n\n get doesNotSupportReturningSyntax(): boolean {\n return this.innerProvider?.doesNotSupportReturningSyntax ?? true;\n }\n\n // Additional methods from SqliteCoreDataProvider that may be called\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async ensureSchema(entities: EntityMetadata<any>[]): Promise<void> {\n await this.ensureInitialized();\n return this.getProvider().ensureSchema(entities);\n }\n\n wrapIdentifier(name: string): string {\n return this.getProvider().wrapIdentifier(name);\n }\n\n addColumnSqlSyntax(\n x: FieldMetadata,\n dbName: string,\n isAlterTable: boolean\n ): string {\n return this.getProvider().addColumnSqlSyntax(x, dbName, isAlterTable);\n }\n\n /**\n * Check if a SQL statement is a write operation\n */\n private isWriteOperation(sql: string): boolean {\n const upperSql = sql.trim().toUpperCase();\n return (\n upperSql.startsWith(\"INSERT\") ||\n upperSql.startsWith(\"UPDATE\") ||\n upperSql.startsWith(\"DELETE\") ||\n upperSql.startsWith(\"CREATE\") ||\n upperSql.startsWith(\"DROP\") ||\n upperSql.startsWith(\"ALTER\")\n );\n }\n\n /**\n * Force an immediate sync to GitHub\n */\n async forceSync(): Promise<void> {\n await this.ensureInitialized();\n await this.syncManager.forceSync();\n }\n\n /**\n * Create a snapshot and upload to GitHub\n */\n async snapshot(): Promise<void> {\n await this.ensureInitialized();\n await this.syncManager.snapshot();\n }\n\n /**\n * Close the provider and perform final sync\n */\n async close(): Promise<void> {\n await this.syncManager.close();\n this._isInitialized = false;\n this.initPromise = null;\n this.innerProvider = null;\n }\n\n /**\n * Get the raw better-sqlite3 database instance\n */\n get rawDatabase(): DatabaseType | null {\n return this.syncManager.database;\n }\n\n /**\n * Get the sync manager instance\n */\n get sync(): GitHubSyncManager {\n return this.syncManager;\n }\n\n /**\n * Check if the provider is initialized\n */\n get isInitialized(): boolean {\n return this._isInitialized;\n }\n}\n","import { SqlDatabase } from \"remult\";\nimport { BetterSqlite3GitHubDataProvider } from \"./provider.js\";\nimport type { BetterSqlite3GitHubOptions } from \"./types.js\";\n\n/**\n * Create a GitHub-synced SQLite data provider for Remult\n *\n * @param options - Configuration options for the provider\n * @returns A factory function that creates an initialized SqlDatabase\n *\n * @example\n * ```typescript\n * import { createGitHubDataProvider } from \"remult-sqlite-github\";\n *\n * const api = remultApi({\n * dataProvider: createGitHubDataProvider({\n * file: \"./mydb.sqlite\",\n * github: {\n * owner: \"your-username\",\n * repo: \"your-database-repo\",\n * token: process.env.GITHUB_TOKEN,\n * },\n * }),\n * entities: [Task],\n * });\n * ```\n */\nexport function createGitHubDataProvider(\n options: BetterSqlite3GitHubOptions\n): () => Promise<SqlDatabase> {\n let provider: BetterSqlite3GitHubDataProvider | null = null;\n let sqlDatabase: SqlDatabase | null = null;\n\n return async () => {\n if (sqlDatabase) {\n return sqlDatabase;\n }\n\n provider = new BetterSqlite3GitHubDataProvider(options);\n await provider.init();\n\n sqlDatabase = new SqlDatabase(provider);\n return sqlDatabase;\n };\n}\n\n// Export the provider class for advanced usage\nexport { BetterSqlite3GitHubDataProvider } from \"./provider.js\";\n\n// Export sync components for advanced usage\nexport { GitHubSyncManager, GitHubOperations, ConflictError } from \"./sync/index.js\";\n\n// Export types\nexport type {\n BetterSqlite3GitHubOptions,\n GitHubSyncEvent,\n GitHubRepoConfig,\n GitHubAuthConfig,\n SyncConfig,\n SqliteOptions,\n DatabaseType,\n RateLimitInfo,\n RecoveryResult,\n SnapshotMetadata,\n} from \"./types.js\";\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -272,6 +272,8 @@ declare class GitHubSyncManager {
|
|
|
272
272
|
private snapshotTimer;
|
|
273
273
|
private isInitialized;
|
|
274
274
|
private isClosed;
|
|
275
|
+
private pendingSync;
|
|
276
|
+
private syncDebounceTimer;
|
|
275
277
|
constructor(options: GitHubSyncManagerOptions);
|
|
276
278
|
/**
|
|
277
279
|
* Initialize the sync manager: recover from GitHub if needed, open database
|
|
@@ -283,9 +285,14 @@ declare class GitHubSyncManager {
|
|
|
283
285
|
private openDatabase;
|
|
284
286
|
/**
|
|
285
287
|
* Called after database writes to track changes
|
|
286
|
-
* If syncOnWrite is enabled, triggers
|
|
288
|
+
* If syncOnWrite is enabled, triggers a debounced non-blocking snapshot
|
|
287
289
|
*/
|
|
288
290
|
onWrite(): Promise<void>;
|
|
291
|
+
/**
|
|
292
|
+
* Schedule a debounced sync - waits 100ms for more writes before syncing
|
|
293
|
+
* This prevents multiple rapid writes from each triggering a separate upload
|
|
294
|
+
*/
|
|
295
|
+
private scheduleDebouncedSync;
|
|
289
296
|
/**
|
|
290
297
|
* Create a snapshot and upload to GitHub
|
|
291
298
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -272,6 +272,8 @@ declare class GitHubSyncManager {
|
|
|
272
272
|
private snapshotTimer;
|
|
273
273
|
private isInitialized;
|
|
274
274
|
private isClosed;
|
|
275
|
+
private pendingSync;
|
|
276
|
+
private syncDebounceTimer;
|
|
275
277
|
constructor(options: GitHubSyncManagerOptions);
|
|
276
278
|
/**
|
|
277
279
|
* Initialize the sync manager: recover from GitHub if needed, open database
|
|
@@ -283,9 +285,14 @@ declare class GitHubSyncManager {
|
|
|
283
285
|
private openDatabase;
|
|
284
286
|
/**
|
|
285
287
|
* Called after database writes to track changes
|
|
286
|
-
* If syncOnWrite is enabled, triggers
|
|
288
|
+
* If syncOnWrite is enabled, triggers a debounced non-blocking snapshot
|
|
287
289
|
*/
|
|
288
290
|
onWrite(): Promise<void>;
|
|
291
|
+
/**
|
|
292
|
+
* Schedule a debounced sync - waits 100ms for more writes before syncing
|
|
293
|
+
* This prevents multiple rapid writes from each triggering a separate upload
|
|
294
|
+
*/
|
|
295
|
+
private scheduleDebouncedSync;
|
|
289
296
|
/**
|
|
290
297
|
* Create a snapshot and upload to GitHub
|
|
291
298
|
*/
|
package/dist/index.js
CHANGED
|
@@ -600,6 +600,8 @@ var GitHubSyncManager = class {
|
|
|
600
600
|
snapshotTimer = null;
|
|
601
601
|
isInitialized = false;
|
|
602
602
|
isClosed = false;
|
|
603
|
+
pendingSync = null;
|
|
604
|
+
syncDebounceTimer = null;
|
|
603
605
|
constructor(options) {
|
|
604
606
|
this.options = options;
|
|
605
607
|
this.github = new GitHubOperations(
|
|
@@ -677,14 +679,37 @@ var GitHubSyncManager = class {
|
|
|
677
679
|
}
|
|
678
680
|
/**
|
|
679
681
|
* Called after database writes to track changes
|
|
680
|
-
* If syncOnWrite is enabled, triggers
|
|
682
|
+
* If syncOnWrite is enabled, triggers a debounced non-blocking snapshot
|
|
681
683
|
*/
|
|
682
684
|
async onWrite() {
|
|
683
685
|
this.hasChanges = true;
|
|
684
686
|
if (this.options.sync.syncOnWrite) {
|
|
685
|
-
|
|
687
|
+
this.scheduleDebouncedSync();
|
|
686
688
|
}
|
|
687
689
|
}
|
|
690
|
+
/**
|
|
691
|
+
* Schedule a debounced sync - waits 100ms for more writes before syncing
|
|
692
|
+
* This prevents multiple rapid writes from each triggering a separate upload
|
|
693
|
+
*/
|
|
694
|
+
scheduleDebouncedSync() {
|
|
695
|
+
if (this.syncDebounceTimer) {
|
|
696
|
+
clearTimeout(this.syncDebounceTimer);
|
|
697
|
+
}
|
|
698
|
+
this.syncDebounceTimer = setTimeout(() => {
|
|
699
|
+
this.syncDebounceTimer = null;
|
|
700
|
+
if (this.pendingSync) {
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
this.pendingSync = this.snapshot().catch((error) => {
|
|
704
|
+
this.log(`Background sync error: ${error}`);
|
|
705
|
+
}).finally(() => {
|
|
706
|
+
this.pendingSync = null;
|
|
707
|
+
if (this.hasChanges) {
|
|
708
|
+
this.scheduleDebouncedSync();
|
|
709
|
+
}
|
|
710
|
+
});
|
|
711
|
+
}, 100);
|
|
712
|
+
}
|
|
688
713
|
/**
|
|
689
714
|
* Create a snapshot and upload to GitHub
|
|
690
715
|
*/
|
|
@@ -810,6 +835,16 @@ var GitHubSyncManager = class {
|
|
|
810
835
|
clearInterval(this.snapshotTimer);
|
|
811
836
|
this.snapshotTimer = null;
|
|
812
837
|
}
|
|
838
|
+
if (this.syncDebounceTimer) {
|
|
839
|
+
clearTimeout(this.syncDebounceTimer);
|
|
840
|
+
this.syncDebounceTimer = null;
|
|
841
|
+
}
|
|
842
|
+
if (this.pendingSync) {
|
|
843
|
+
try {
|
|
844
|
+
await this.pendingSync;
|
|
845
|
+
} catch {
|
|
846
|
+
}
|
|
847
|
+
}
|
|
813
848
|
if (this.hasChanges && this.db) {
|
|
814
849
|
try {
|
|
815
850
|
await this.snapshot();
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sync/github-operations.ts","../src/sync/recovery.ts","../src/sync/sync-manager.ts","../src/provider.ts","../src/index.ts"],"names":["path","gunzip","gzip","promisify","zlib2","SNAPSHOT_DB_NAME","SNAPSHOT_DB_GZ_NAME","SNAPSHOT_META_NAME","path2","fs2","crypto2"],"mappings":"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","file":"index.js","sourcesContent":["import * as crypto from \"crypto\";\nimport type {\n GitHubConfig,\n GitHubFileResult,\n GitHubFileEntry,\n RateLimitInfo,\n GitHubSyncEvent,\n} from \"../types.js\";\n\nconst GITHUB_API_BASE = \"https://api.github.com\";\n\n/**\n * GitHub REST API operations wrapper with retry logic and rate limit handling\n */\nexport class GitHubOperations {\n private config: GitHubConfig;\n private maxRetries: number;\n private cachedToken: string | null = null;\n private tokenExpiry: number = 0;\n private onEvent?: (event: GitHubSyncEvent) => void;\n private verbose: boolean;\n\n constructor(\n config: GitHubConfig,\n maxRetries: number = 3,\n onEvent?: (event: GitHubSyncEvent) => void,\n verbose: boolean = false\n ) {\n this.config = config;\n this.maxRetries = maxRetries;\n this.onEvent = onEvent;\n this.verbose = verbose;\n }\n\n /**\n * Get a file from the repository\n */\n async getFile(path: string): Promise<GitHubFileResult | null> {\n const fullPath = this.getFullPath(path);\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/contents/${fullPath}?ref=${this.config.branch}`;\n\n const response = await this.withRetry(() => this.fetch(url));\n\n if (response.status === 404) {\n return null;\n }\n\n if (!response.ok) {\n throw new Error(\n `Failed to get file ${path}: ${response.status} ${response.statusText}`\n );\n }\n\n const data = await response.json();\n\n // GitHub returns base64 encoded content for files under 1MB\n // For larger files, we need to use the blob API\n if (data.content) {\n const content = Buffer.from(data.content, \"base64\");\n return {\n content,\n sha: data.sha,\n size: data.size,\n };\n }\n\n // Large file - use blob API\n if (data.sha && data.size > 0) {\n return this.getBlob(data.sha, data.size);\n }\n\n return null;\n }\n\n /**\n * Get a large file using the blob API\n */\n private async getBlob(sha: string, size: number): Promise<GitHubFileResult> {\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/git/blobs/${sha}`;\n\n const response = await this.withRetry(() => this.fetch(url));\n\n if (!response.ok) {\n throw new Error(\n `Failed to get blob ${sha}: ${response.status} ${response.statusText}`\n );\n }\n\n const data = await response.json();\n const content = Buffer.from(data.content, \"base64\");\n\n return {\n content,\n sha,\n size,\n };\n }\n\n /**\n * Create or update a file in the repository\n * Returns the new commit SHA\n */\n async putFile(\n path: string,\n content: Buffer,\n message: string,\n sha?: string\n ): Promise<string> {\n const fullPath = this.getFullPath(path);\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/contents/${fullPath}`;\n\n const body: Record<string, string> = {\n message,\n content: content.toString(\"base64\"),\n branch: this.config.branch,\n };\n\n if (sha) {\n body.sha = sha;\n }\n\n const response = await this.withRetry(\n () =>\n this.fetch(url, {\n method: \"PUT\",\n body: JSON.stringify(body),\n }),\n true // Allow conflict retry\n );\n\n if (response.status === 409) {\n // Conflict - SHA mismatch, caller should re-fetch and retry\n throw new ConflictError(\n `Conflict updating ${path}: file was modified concurrently`\n );\n }\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to put file ${path}: ${response.status} ${response.statusText} - ${errorText}`\n );\n }\n\n const data = await response.json();\n\n this.emitEvent({\n type: \"commit_created\",\n sha: data.commit.sha,\n message,\n });\n\n return data.content.sha;\n }\n\n /**\n * Delete a file from the repository\n */\n async deleteFile(path: string, sha: string, message: string): Promise<void> {\n const fullPath = this.getFullPath(path);\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/contents/${fullPath}`;\n\n const response = await this.withRetry(() =>\n this.fetch(url, {\n method: \"DELETE\",\n body: JSON.stringify({\n message,\n sha,\n branch: this.config.branch,\n }),\n })\n );\n\n if (!response.ok && response.status !== 404) {\n throw new Error(\n `Failed to delete file ${path}: ${response.status} ${response.statusText}`\n );\n }\n }\n\n /**\n * List files in a directory\n */\n async listFiles(path: string): Promise<GitHubFileEntry[]> {\n const fullPath = this.getFullPath(path);\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/contents/${fullPath}?ref=${this.config.branch}`;\n\n const response = await this.withRetry(() => this.fetch(url));\n\n if (response.status === 404) {\n return [];\n }\n\n if (!response.ok) {\n throw new Error(\n `Failed to list files at ${path}: ${response.status} ${response.statusText}`\n );\n }\n\n const data = await response.json();\n\n // Single file returns object, directory returns array\n if (!Array.isArray(data)) {\n return [\n {\n name: data.name,\n path: data.path,\n sha: data.sha,\n size: data.size,\n type: data.type,\n },\n ];\n }\n\n return data.map(\n (item: {\n name: string;\n path: string;\n sha: string;\n size: number;\n type: \"file\" | \"dir\";\n }) => ({\n name: item.name,\n path: item.path,\n sha: item.sha,\n size: item.size,\n type: item.type,\n })\n );\n }\n\n /**\n * Check current rate limit status\n */\n async checkRateLimit(): Promise<RateLimitInfo> {\n const url = `${GITHUB_API_BASE}/rate_limit`;\n const response = await this.fetch(url);\n\n if (!response.ok) {\n throw new Error(`Failed to check rate limit: ${response.statusText}`);\n }\n\n const data = await response.json();\n return {\n remaining: data.resources.core.remaining,\n resetAt: new Date(data.resources.core.reset * 1000),\n limit: data.resources.core.limit,\n };\n }\n\n /**\n * Ensure the branch exists, create if it doesn't\n * For empty repos, we skip branch creation since files can be pushed directly\n */\n async ensureBranch(): Promise<void> {\n // Check if branch exists\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/branches/${this.config.branch}`;\n const response = await this.fetch(url);\n\n if (response.ok) {\n return; // Branch exists\n }\n\n if (response.status !== 404) {\n // Could be auth error or other issue\n const errorText = await response.text();\n throw new Error(\n `Failed to check branch '${this.config.branch}': ${response.status} ${response.statusText}. ${errorText}`\n );\n }\n\n // Branch doesn't exist, check if repo has any commits\n const repoUrl = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}`;\n const repoResponse = await this.fetch(repoUrl);\n\n if (!repoResponse.ok) {\n const errorText = await repoResponse.text();\n throw new Error(\n `Failed to get repository info for '${this.config.owner}/${this.config.repo}': ${repoResponse.status} ${repoResponse.statusText}. ${errorText}`\n );\n }\n\n const repoData = await repoResponse.json();\n const defaultBranch = repoData.default_branch;\n\n // Check if the repo is empty (no commits yet)\n // Empty repos have size 0 and no refs\n const refUrl = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/git/refs/heads/${defaultBranch}`;\n const refResponse = await this.fetch(refUrl);\n\n if (!refResponse.ok) {\n if (refResponse.status === 409 || refResponse.status === 404) {\n // Empty repository - the branch will be created on first file push\n this.log(\n `Repository appears to be empty. Branch '${this.config.branch}' will be created on first snapshot.`\n );\n return;\n }\n const errorText = await refResponse.text();\n throw new Error(\n `Failed to get default branch ref: ${refResponse.status} ${refResponse.statusText}. ${errorText}`\n );\n }\n\n // If we're using the default branch, we're done\n if (this.config.branch === defaultBranch) {\n return;\n }\n\n const refData = await refResponse.json();\n const sha = refData.object.sha;\n\n // Create new branch from default branch\n const createUrl = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/git/refs`;\n const createResponse = await this.fetch(createUrl, {\n method: \"POST\",\n body: JSON.stringify({\n ref: `refs/heads/${this.config.branch}`,\n sha,\n }),\n });\n\n if (!createResponse.ok && createResponse.status !== 422) {\n const errorText = await createResponse.text();\n throw new Error(\n `Failed to create branch '${this.config.branch}': ${createResponse.status} ${createResponse.statusText}. ${errorText}`\n );\n }\n\n this.log(`Created branch: ${this.config.branch}`);\n }\n\n /**\n * Get the full path including configured prefix\n */\n private getFullPath(path: string): string {\n if (!this.config.path) {\n return path;\n }\n return `${this.config.path}/${path}`.replace(/\\/+/g, \"/\");\n }\n\n /**\n * Make an authenticated fetch request\n */\n private async fetch(\n url: string,\n options: RequestInit = {}\n ): Promise<Response> {\n const token = await this.getAuthToken();\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n Accept: \"application/vnd.github+json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n ...(options.headers as Record<string, string>),\n };\n\n if (options.body) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n return fetch(url, {\n ...options,\n headers,\n });\n }\n\n /**\n * Get authentication token (PAT or GitHub App installation token)\n */\n private async getAuthToken(): Promise<string> {\n // Use PAT if provided\n if (this.config.token) {\n return this.config.token;\n }\n\n // Check if we have a valid cached token\n if (this.cachedToken && Date.now() < this.tokenExpiry) {\n return this.cachedToken;\n }\n\n // Generate GitHub App installation token\n if (\n !this.config.appId ||\n !this.config.privateKey ||\n !this.config.installationId\n ) {\n throw new Error(\n \"Either token or GitHub App credentials (appId, privateKey, installationId) must be provided\"\n );\n }\n\n const jwt = this.generateJWT(this.config.appId, this.config.privateKey);\n\n const response = await fetch(\n `${GITHUB_API_BASE}/app/installations/${this.config.installationId}/access_tokens`,\n {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${jwt}`,\n Accept: \"application/vnd.github+json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n },\n }\n );\n\n if (!response.ok) {\n throw new Error(\n `Failed to get installation token: ${response.statusText}`\n );\n }\n\n const data = await response.json();\n this.cachedToken = data.token;\n // Token expires in 1 hour, refresh 5 minutes early\n this.tokenExpiry = Date.now() + 55 * 60 * 1000;\n\n return this.cachedToken!;\n }\n\n /**\n * Generate a JWT for GitHub App authentication\n */\n private generateJWT(appId: number, privateKey: string): string {\n const now = Math.floor(Date.now() / 1000);\n const payload = {\n iat: now - 60, // Issued 60 seconds ago to account for clock drift\n exp: now + 10 * 60, // Expires in 10 minutes\n iss: appId.toString(),\n };\n\n const header = { alg: \"RS256\", typ: \"JWT\" };\n const encodedHeader = this.base64UrlEncode(JSON.stringify(header));\n const encodedPayload = this.base64UrlEncode(JSON.stringify(payload));\n\n const signatureInput = `${encodedHeader}.${encodedPayload}`;\n const signature = crypto\n .createSign(\"RSA-SHA256\")\n .update(signatureInput)\n .sign(privateKey, \"base64url\");\n\n return `${signatureInput}.${signature}`;\n }\n\n /**\n * Base64 URL encode a string\n */\n private base64UrlEncode(str: string): string {\n return Buffer.from(str)\n .toString(\"base64\")\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=/g, \"\");\n }\n\n /**\n * Execute a function with retry logic and exponential backoff\n */\n private async withRetry<T>(\n fn: () => Promise<T>,\n allowConflict: boolean = false\n ): Promise<T> {\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n try {\n const result = await fn();\n\n // Check for rate limiting in response\n if (result instanceof Response) {\n await this.handleRateLimitHeaders(result);\n }\n\n return result;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Don't retry conflict errors unless specified\n if (error instanceof ConflictError && !allowConflict) {\n throw error;\n }\n\n // Check if this is a rate limit error\n if (\n error instanceof Error &&\n error.message.includes(\"rate limit\")\n ) {\n const rateLimit = await this.checkRateLimit();\n const waitTime = Math.max(\n 0,\n rateLimit.resetAt.getTime() - Date.now()\n );\n\n this.emitEvent({\n type: \"rate_limit_hit\",\n resetAt: rateLimit.resetAt,\n remaining: rateLimit.remaining,\n });\n\n if (waitTime > 0 && waitTime < 60000) {\n // Wait up to 1 minute\n this.log(`Rate limited, waiting ${waitTime}ms`);\n await this.sleep(waitTime);\n continue;\n }\n }\n\n // Emit error event\n this.emitEvent({\n type: \"sync_error\",\n error: lastError,\n context: \"github_operation\",\n willRetry: attempt < this.maxRetries,\n });\n\n if (attempt < this.maxRetries) {\n const delay = Math.min(1000 * Math.pow(2, attempt), 30000);\n this.log(`Retry attempt ${attempt + 1} after ${delay}ms`);\n await this.sleep(delay);\n }\n }\n }\n\n throw lastError || new Error(\"Unknown error\");\n }\n\n /**\n * Handle rate limit headers from response\n */\n private async handleRateLimitHeaders(response: Response): Promise<void> {\n const remaining = parseInt(\n response.headers.get(\"x-ratelimit-remaining\") || \"1000\",\n 10\n );\n const resetTimestamp = parseInt(\n response.headers.get(\"x-ratelimit-reset\") || \"0\",\n 10\n );\n\n if (remaining === 0 && resetTimestamp > 0) {\n const resetAt = new Date(resetTimestamp * 1000);\n const waitTime = Math.max(0, resetAt.getTime() - Date.now());\n\n this.emitEvent({\n type: \"rate_limit_hit\",\n resetAt,\n remaining: 0,\n });\n\n if (waitTime > 0 && waitTime < 60000) {\n this.log(`Rate limit exhausted, waiting ${waitTime}ms`);\n await this.sleep(waitTime);\n }\n }\n }\n\n /**\n * Sleep for the specified duration\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Emit an event if handler is registered\n */\n private emitEvent(event: GitHubSyncEvent): void {\n if (this.onEvent) {\n this.onEvent(event);\n }\n }\n\n /**\n * Log a message if verbose mode is enabled\n */\n private log(message: string): void {\n if (this.verbose) {\n console.log(`[github-operations] ${message}`);\n }\n }\n}\n\n/**\n * Custom error for conflict (SHA mismatch) situations\n */\nexport class ConflictError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ConflictError\";\n }\n}\n","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as zlib from \"zlib\";\nimport { promisify } from \"util\";\nimport type {\n GitHubSyncEvent,\n RecoveryResult,\n SnapshotMetadata,\n} from \"../types.js\";\nimport { GitHubOperations } from \"./github-operations.js\";\n\nconst gunzip = promisify(zlib.gunzip);\n\nconst SNAPSHOT_DB_NAME = \"snapshot.db\";\nconst SNAPSHOT_DB_GZ_NAME = \"snapshot.db.gz\";\nconst SNAPSHOT_META_NAME = \"snapshot.meta.json\";\n\n/**\n * Manages database recovery from GitHub\n */\nexport class RecoveryManager {\n private github: GitHubOperations;\n private dbPath: string;\n private onEvent?: (event: GitHubSyncEvent) => void;\n private verbose: boolean;\n\n constructor(\n github: GitHubOperations,\n dbPath: string,\n onEvent?: (event: GitHubSyncEvent) => void,\n verbose: boolean = false\n ) {\n this.github = github;\n this.dbPath = dbPath;\n this.onEvent = onEvent;\n this.verbose = verbose;\n }\n\n /**\n * Check if local database exists\n */\n localDatabaseExists(): boolean {\n return fs.existsSync(this.dbPath);\n }\n\n /**\n * Find the latest snapshot in the repository\n */\n async findLatestSnapshot(): Promise<{\n path: string;\n sha: string;\n compressed: boolean;\n } | null> {\n try {\n // First check for compressed snapshot\n const compressedFile = await this.github.getFile(SNAPSHOT_DB_GZ_NAME);\n if (compressedFile) {\n return {\n path: SNAPSHOT_DB_GZ_NAME,\n sha: compressedFile.sha,\n compressed: true,\n };\n }\n\n // Then check for uncompressed snapshot\n const uncompressedFile = await this.github.getFile(SNAPSHOT_DB_NAME);\n if (uncompressedFile) {\n return {\n path: SNAPSHOT_DB_NAME,\n sha: uncompressedFile.sha,\n compressed: false,\n };\n }\n\n return null;\n } catch (error) {\n this.log(`Error finding snapshot: ${error}`);\n return null;\n }\n }\n\n /**\n * Recover database from GitHub snapshot\n */\n async recover(): Promise<RecoveryResult> {\n this.emitEvent({\n type: \"recovery_started\",\n branch: \"\", // Branch is handled by GitHubOperations\n });\n\n try {\n // Find the latest snapshot\n const snapshot = await this.findLatestSnapshot();\n\n if (!snapshot) {\n this.log(\"No snapshot found in repository\");\n return { recovered: false };\n }\n\n this.log(`Found snapshot: ${snapshot.path}`);\n\n // Download the snapshot\n const file = await this.github.getFile(snapshot.path);\n if (!file) {\n this.log(\"Failed to download snapshot\");\n return { recovered: false };\n }\n\n // Decompress if necessary\n let dbContent: Buffer;\n if (snapshot.compressed) {\n this.log(\"Decompressing snapshot...\");\n dbContent = await gunzip(file.content);\n } else {\n dbContent = file.content;\n }\n\n // Ensure directory exists\n const dir = path.dirname(this.dbPath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n // Write the database file\n fs.writeFileSync(this.dbPath, dbContent);\n this.log(`Database recovered to ${this.dbPath}`);\n\n // Get metadata if available (for future use)\n await this.getSnapshotMetadata();\n\n this.emitEvent({\n type: \"recovery_completed\",\n sha: file.sha,\n });\n\n return {\n recovered: true,\n sha: file.sha,\n size: dbContent.length,\n compressed: snapshot.compressed,\n };\n } catch (error) {\n this.log(`Recovery error: ${error}`);\n this.emitEvent({\n type: \"sync_error\",\n error: error instanceof Error ? error : new Error(String(error)),\n context: \"recovery\",\n willRetry: false,\n });\n return { recovered: false };\n }\n }\n\n /**\n * Get snapshot metadata from repository\n */\n async getSnapshotMetadata(): Promise<SnapshotMetadata | null> {\n try {\n const file = await this.github.getFile(SNAPSHOT_META_NAME);\n if (!file) {\n return null;\n }\n return JSON.parse(file.content.toString(\"utf-8\"));\n } catch {\n return null;\n }\n }\n\n /**\n * Get the current snapshot SHA from the repository\n */\n async getCurrentSnapshotSha(): Promise<string | null> {\n const snapshot = await this.findLatestSnapshot();\n return snapshot?.sha || null;\n }\n\n /**\n * Emit an event if handler is registered\n */\n private emitEvent(event: GitHubSyncEvent): void {\n if (this.onEvent) {\n this.onEvent(event);\n }\n }\n\n /**\n * Log a message if verbose mode is enabled\n */\n private log(message: string): void {\n if (this.verbose) {\n console.log(`[recovery] ${message}`);\n }\n }\n}\n","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as crypto from \"crypto\";\nimport * as zlib from \"zlib\";\nimport { promisify } from \"util\";\nimport Database from \"better-sqlite3\";\nimport type {\n DatabaseType,\n GitHubSyncEvent,\n GitHubSyncManagerOptions,\n SnapshotMetadata,\n} from \"../types.js\";\nimport { GitHubOperations, ConflictError } from \"./github-operations.js\";\nimport { RecoveryManager } from \"./recovery.js\";\n\nconst gzip = promisify(zlib.gzip);\n\nconst SNAPSHOT_DB_NAME = \"snapshot.db\";\nconst SNAPSHOT_DB_GZ_NAME = \"snapshot.db.gz\";\nconst SNAPSHOT_META_NAME = \"snapshot.meta.json\";\n\n/**\n * Orchestrates database sync operations with GitHub\n */\nexport class GitHubSyncManager {\n private options: GitHubSyncManagerOptions;\n private github: GitHubOperations;\n private recovery: RecoveryManager;\n private db: DatabaseType | null = null;\n private hasChanges: boolean = false;\n private currentSha: string | null = null;\n private snapshotTimer: ReturnType<typeof setInterval> | null = null;\n private isInitialized: boolean = false;\n private isClosed: boolean = false;\n\n constructor(options: GitHubSyncManagerOptions) {\n this.options = options;\n this.github = new GitHubOperations(\n options.github,\n options.sync.maxRetries,\n options.onEvent,\n options.verbose\n );\n this.recovery = new RecoveryManager(\n this.github,\n options.dbPath,\n options.onEvent,\n options.verbose\n );\n }\n\n /**\n * Initialize the sync manager: recover from GitHub if needed, open database\n */\n async initialize(): Promise<DatabaseType> {\n if (this.isInitialized) {\n return this.db!;\n }\n\n this.log(\"Initializing sync manager...\");\n\n // Ensure the branch exists\n await this.github.ensureBranch();\n\n // Check if local database exists\n let recovered = false;\n if (!this.recovery.localDatabaseExists()) {\n this.log(\"Local database not found, attempting recovery from GitHub...\");\n const result = await this.recovery.recover();\n recovered = result.recovered;\n\n if (recovered) {\n this.currentSha = await this.recovery.getCurrentSnapshotSha();\n }\n } else {\n this.log(\"Local database exists, fetching current SHA...\");\n this.currentSha = await this.recovery.getCurrentSnapshotSha();\n }\n\n // Open the database\n this.db = this.openDatabase();\n\n // Start snapshot timer if configured\n if (this.options.sync.snapshotInterval > 0) {\n this.startSnapshotTimer();\n }\n\n this.isInitialized = true;\n\n this.emitEvent({\n type: \"initialized\",\n recovered,\n });\n\n return this.db;\n }\n\n /**\n * Open the SQLite database with configured options\n */\n private openDatabase(): DatabaseType {\n // Ensure the directory exists\n const dir = path.dirname(this.options.dbPath);\n if (dir && !fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n this.log(`Created directory: ${dir}`);\n }\n\n const sqliteOptions = this.options.sqliteOptions || {};\n const db = new Database(this.options.dbPath);\n\n // Set WAL mode if enabled\n if (this.options.sync.enableWal) {\n db.pragma(\"journal_mode = WAL\");\n }\n\n // Set foreign keys\n if (sqliteOptions.foreignKeys !== false) {\n db.pragma(\"foreign_keys = ON\");\n }\n\n // Set busy timeout\n if (sqliteOptions.busyTimeout) {\n db.pragma(`busy_timeout = ${sqliteOptions.busyTimeout}`);\n }\n\n // Apply additional pragmas\n if (sqliteOptions.pragmas) {\n for (const [key, value] of Object.entries(sqliteOptions.pragmas)) {\n db.pragma(`${key} = ${value}`);\n }\n }\n\n this.log(\"Database opened successfully\");\n return db;\n }\n\n /**\n * Called after database writes to track changes\n * If syncOnWrite is enabled, triggers an immediate snapshot\n */\n async onWrite(): Promise<void> {\n this.hasChanges = true;\n\n // If syncOnWrite is enabled, trigger immediate snapshot\n if (this.options.sync.syncOnWrite) {\n await this.snapshot();\n }\n }\n\n /**\n * Create a snapshot and upload to GitHub\n */\n async snapshot(): Promise<void> {\n if (this.isClosed) {\n return;\n }\n\n // Skip if no changes and snapshotOnChange is enabled\n if (this.options.sync.snapshotOnChange && !this.hasChanges) {\n this.log(\"No changes detected, skipping snapshot\");\n return;\n }\n\n if (!this.db) {\n throw new Error(\"Database not initialized\");\n }\n\n this.log(\"Creating snapshot...\");\n\n try {\n // Checkpoint WAL to ensure all changes are in the main file\n if (this.options.sync.enableWal) {\n this.db.pragma(\"wal_checkpoint(TRUNCATE)\");\n }\n\n // Read the database file\n const dbContent = fs.readFileSync(this.options.dbPath);\n\n // Calculate checksum\n const checksum = crypto\n .createHash(\"sha256\")\n .update(dbContent)\n .digest(\"hex\");\n\n // Optionally compress\n let uploadContent: Buffer;\n let filename: string;\n const compressed = this.options.sync.compression;\n\n if (compressed) {\n uploadContent = await gzip(dbContent);\n filename = SNAPSHOT_DB_GZ_NAME;\n this.log(`Compressed ${dbContent.length} -> ${uploadContent.length} bytes`);\n } else {\n uploadContent = dbContent;\n filename = SNAPSHOT_DB_NAME;\n }\n\n // Try to upload with conflict handling\n await this.uploadWithConflictRetry(filename, uploadContent, checksum, compressed);\n\n // Reset change tracking\n this.hasChanges = false;\n\n this.emitEvent({\n type: \"snapshot_uploaded\",\n sha: this.currentSha!,\n size: uploadContent.length,\n compressed,\n });\n\n this.log(`Snapshot uploaded successfully (${uploadContent.length} bytes)`);\n } catch (error) {\n this.emitEvent({\n type: \"sync_error\",\n error: error instanceof Error ? error : new Error(String(error)),\n context: \"snapshot\",\n willRetry: false,\n });\n throw error;\n }\n }\n\n /**\n * Upload file with automatic conflict resolution\n */\n private async uploadWithConflictRetry(\n filename: string,\n content: Buffer,\n checksum: string,\n compressed: boolean,\n retries: number = 3\n ): Promise<void> {\n for (let attempt = 0; attempt < retries; attempt++) {\n try {\n // Upload the database file\n const newSha = await this.github.putFile(\n filename,\n content,\n `Update database snapshot`,\n this.currentSha || undefined\n );\n\n this.currentSha = newSha;\n\n // Upload metadata\n const metadata: SnapshotMetadata = {\n timestamp: new Date().toISOString(),\n size: content.length,\n checksum,\n compressed,\n };\n\n // Get current metadata SHA if it exists\n const existingMeta = await this.github.getFile(SNAPSHOT_META_NAME);\n await this.github.putFile(\n SNAPSHOT_META_NAME,\n Buffer.from(JSON.stringify(metadata, null, 2)),\n `Update snapshot metadata`,\n existingMeta?.sha\n );\n\n // Clean up old format if we switched compression mode\n const oldFilename = compressed ? SNAPSHOT_DB_NAME : SNAPSHOT_DB_GZ_NAME;\n try {\n const oldFile = await this.github.getFile(oldFilename);\n if (oldFile) {\n await this.github.deleteFile(\n oldFilename,\n oldFile.sha,\n `Remove old snapshot format`\n );\n }\n } catch {\n // Ignore errors cleaning up old file\n }\n\n return;\n } catch (error) {\n if (error instanceof ConflictError && attempt < retries - 1) {\n this.log(`Conflict detected, refetching SHA and retrying (attempt ${attempt + 1})`);\n this.currentSha = await this.recovery.getCurrentSnapshotSha();\n continue;\n }\n throw error;\n }\n }\n }\n\n /**\n * Force an immediate sync (alias for snapshot)\n */\n async forceSync(): Promise<void> {\n const originalOnChange = this.options.sync.snapshotOnChange;\n this.options.sync.snapshotOnChange = false;\n try {\n await this.snapshot();\n } finally {\n this.options.sync.snapshotOnChange = originalOnChange;\n }\n }\n\n /**\n * Close the sync manager and perform final sync\n */\n async close(): Promise<void> {\n if (this.isClosed) {\n return;\n }\n\n this.log(\"Closing sync manager...\");\n this.isClosed = true;\n\n // Stop snapshot timer\n if (this.snapshotTimer) {\n clearInterval(this.snapshotTimer);\n this.snapshotTimer = null;\n }\n\n // Final snapshot if there are changes\n if (this.hasChanges && this.db) {\n try {\n await this.snapshot();\n } catch (error) {\n this.log(`Error during final snapshot: ${error}`);\n }\n }\n\n // Close the database\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n\n this.log(\"Sync manager closed\");\n }\n\n /**\n * Start the automatic snapshot timer\n */\n private startSnapshotTimer(): void {\n this.snapshotTimer = setInterval(() => {\n this.snapshot().catch((error) => {\n this.log(`Snapshot error: ${error}`);\n });\n }, this.options.sync.snapshotInterval);\n\n // Ensure timer doesn't prevent process exit\n if (this.snapshotTimer.unref) {\n this.snapshotTimer.unref();\n }\n }\n\n /**\n * Get the raw database instance\n */\n get database(): DatabaseType | null {\n return this.db;\n }\n\n /**\n * Check if there are pending changes\n */\n get hasPendingChanges(): boolean {\n return this.hasChanges;\n }\n\n /**\n * Check if the manager is initialized\n */\n get initialized(): boolean {\n return this.isInitialized;\n }\n\n /**\n * Emit an event if handler is registered\n */\n private emitEvent(event: GitHubSyncEvent): void {\n if (this.options.onEvent) {\n this.options.onEvent(event);\n }\n }\n\n /**\n * Log a message if verbose mode is enabled\n */\n private log(message: string): void {\n if (this.options.verbose) {\n console.log(`[sync-manager] ${message}`);\n }\n }\n}\n","import type {\n EntityMetadata,\n FieldMetadata,\n SqlCommand,\n SqlImplementation,\n} from \"remult\";\nimport { BetterSqlite3DataProvider } from \"remult/remult-better-sqlite3\";\nimport type {\n BetterSqlite3GitHubOptions,\n DatabaseType,\n GitHubConfig,\n GitHubSyncManagerOptions,\n SyncConfig,\n} from \"./types.js\";\nimport { GitHubSyncManager } from \"./sync/index.js\";\n\n/**\n * Default sync configuration values\n */\nconst DEFAULT_SYNC_CONFIG: Required<SyncConfig> = {\n snapshotInterval: 30 * 1000, // 30 seconds\n snapshotOnChange: true,\n syncOnWrite: false,\n enableWal: false,\n walThreshold: 1024 * 1024, // 1MB\n maxRetries: 3,\n compression: false,\n};\n\n/**\n * A Remult data provider that syncs SQLite to GitHub\n */\nexport class BetterSqlite3GitHubDataProvider implements SqlImplementation {\n private syncManager: GitHubSyncManager;\n private _isInitialized: boolean = false;\n private initPromise: Promise<void> | null = null;\n private innerProvider: BetterSqlite3DataProvider | null = null;\n\n constructor(options: BetterSqlite3GitHubOptions) {\n // Build internal config\n const githubConfig: GitHubConfig = {\n owner: options.github.owner,\n repo: options.github.repo,\n branch: options.github.branch || \"main\",\n path: options.github.path || \"\",\n token: options.github.token,\n appId: options.github.appId,\n privateKey: options.github.privateKey,\n installationId: options.github.installationId,\n };\n\n // Apply serverless defaults if enabled\n const serverlessDefaults: Partial<SyncConfig> = options.serverless\n ? {\n syncOnWrite: true,\n snapshotInterval: 0,\n }\n : {};\n\n const syncConfig: Required<SyncConfig> = {\n ...DEFAULT_SYNC_CONFIG,\n ...serverlessDefaults,\n ...options.sync, // User options override serverless defaults\n };\n\n const managerOptions: GitHubSyncManagerOptions = {\n dbPath: options.file,\n github: githubConfig,\n sqliteOptions: options.sqliteOptions,\n sync: syncConfig,\n onEvent: options.onEvent,\n verbose: options.verbose || false,\n };\n\n this.syncManager = new GitHubSyncManager(managerOptions);\n }\n\n /**\n * Initialize the data provider\n * This must be called before using the provider\n */\n async init(): Promise<void> {\n if (this._isInitialized) {\n return;\n }\n\n // Prevent multiple concurrent initializations\n if (this.initPromise) {\n return this.initPromise;\n }\n\n this.initPromise = this.doInit();\n await this.initPromise;\n }\n\n private async doInit(): Promise<void> {\n const db = await this.syncManager.initialize();\n\n // Create the inner BetterSqlite3DataProvider with the initialized database\n this.innerProvider = new BetterSqlite3DataProvider(db);\n\n this._isInitialized = true;\n }\n\n /**\n * Ensure the provider is initialized\n */\n private async ensureInitialized(): Promise<void> {\n if (!this._isInitialized) {\n await this.init();\n }\n }\n\n private getProvider(): BetterSqlite3DataProvider {\n if (!this.innerProvider) {\n throw new Error(\n \"Provider not initialized. Call init() before using the provider.\"\n );\n }\n return this.innerProvider;\n }\n\n // SqlImplementation interface methods\n getLimitSqlSyntax(limit: number, offset: number): string {\n return this.getProvider().getLimitSqlSyntax(limit, offset);\n }\n\n createCommand(): SqlCommand {\n const command = this.getProvider().createCommand();\n // Wrap the command to track writes\n const originalExecute = command.execute.bind(command);\n const syncManager = this.syncManager;\n const isWriteOp = this.isWriteOperation.bind(this);\n command.execute = async (sql: string) => {\n const result = await originalExecute(sql);\n if (isWriteOp(sql)) {\n await syncManager.onWrite();\n }\n return result;\n };\n return command;\n }\n\n async transaction(\n action: (sql: SqlImplementation) => Promise<void>\n ): Promise<void> {\n await this.ensureInitialized();\n return this.getProvider().transaction(action);\n }\n\n async entityIsUsedForTheFirstTime(entity: EntityMetadata): Promise<void> {\n await this.ensureInitialized();\n return this.getProvider().entityIsUsedForTheFirstTime(entity);\n }\n\n async end(): Promise<void> {\n await this.close();\n }\n\n // Passthrough properties from inner provider\n get orderByNullsFirst(): boolean | undefined {\n return this.innerProvider?.orderByNullsFirst;\n }\n\n get afterMutation(): VoidFunction | undefined {\n return this.innerProvider?.afterMutation;\n }\n\n get supportsJsonColumnType(): boolean | undefined {\n return this.innerProvider?.supportsJsonColumnType;\n }\n\n get doesNotSupportReturningSyntax(): boolean {\n return this.innerProvider?.doesNotSupportReturningSyntax ?? true;\n }\n\n // Additional methods from SqliteCoreDataProvider that may be called\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async ensureSchema(entities: EntityMetadata<any>[]): Promise<void> {\n await this.ensureInitialized();\n return this.getProvider().ensureSchema(entities);\n }\n\n wrapIdentifier(name: string): string {\n return this.getProvider().wrapIdentifier(name);\n }\n\n addColumnSqlSyntax(\n x: FieldMetadata,\n dbName: string,\n isAlterTable: boolean\n ): string {\n return this.getProvider().addColumnSqlSyntax(x, dbName, isAlterTable);\n }\n\n /**\n * Check if a SQL statement is a write operation\n */\n private isWriteOperation(sql: string): boolean {\n const upperSql = sql.trim().toUpperCase();\n return (\n upperSql.startsWith(\"INSERT\") ||\n upperSql.startsWith(\"UPDATE\") ||\n upperSql.startsWith(\"DELETE\") ||\n upperSql.startsWith(\"CREATE\") ||\n upperSql.startsWith(\"DROP\") ||\n upperSql.startsWith(\"ALTER\")\n );\n }\n\n /**\n * Force an immediate sync to GitHub\n */\n async forceSync(): Promise<void> {\n await this.ensureInitialized();\n await this.syncManager.forceSync();\n }\n\n /**\n * Create a snapshot and upload to GitHub\n */\n async snapshot(): Promise<void> {\n await this.ensureInitialized();\n await this.syncManager.snapshot();\n }\n\n /**\n * Close the provider and perform final sync\n */\n async close(): Promise<void> {\n await this.syncManager.close();\n this._isInitialized = false;\n this.initPromise = null;\n this.innerProvider = null;\n }\n\n /**\n * Get the raw better-sqlite3 database instance\n */\n get rawDatabase(): DatabaseType | null {\n return this.syncManager.database;\n }\n\n /**\n * Get the sync manager instance\n */\n get sync(): GitHubSyncManager {\n return this.syncManager;\n }\n\n /**\n * Check if the provider is initialized\n */\n get isInitialized(): boolean {\n return this._isInitialized;\n }\n}\n","import { SqlDatabase } from \"remult\";\nimport { BetterSqlite3GitHubDataProvider } from \"./provider.js\";\nimport type { BetterSqlite3GitHubOptions } from \"./types.js\";\n\n/**\n * Create a GitHub-synced SQLite data provider for Remult\n *\n * @param options - Configuration options for the provider\n * @returns A factory function that creates an initialized SqlDatabase\n *\n * @example\n * ```typescript\n * import { createGitHubDataProvider } from \"remult-sqlite-github\";\n *\n * const api = remultApi({\n * dataProvider: createGitHubDataProvider({\n * file: \"./mydb.sqlite\",\n * github: {\n * owner: \"your-username\",\n * repo: \"your-database-repo\",\n * token: process.env.GITHUB_TOKEN,\n * },\n * }),\n * entities: [Task],\n * });\n * ```\n */\nexport function createGitHubDataProvider(\n options: BetterSqlite3GitHubOptions\n): () => Promise<SqlDatabase> {\n let provider: BetterSqlite3GitHubDataProvider | null = null;\n let sqlDatabase: SqlDatabase | null = null;\n\n return async () => {\n if (sqlDatabase) {\n return sqlDatabase;\n }\n\n provider = new BetterSqlite3GitHubDataProvider(options);\n await provider.init();\n\n sqlDatabase = new SqlDatabase(provider);\n return sqlDatabase;\n };\n}\n\n// Export the provider class for advanced usage\nexport { BetterSqlite3GitHubDataProvider } from \"./provider.js\";\n\n// Export sync components for advanced usage\nexport { GitHubSyncManager, GitHubOperations, ConflictError } from \"./sync/index.js\";\n\n// Export types\nexport type {\n BetterSqlite3GitHubOptions,\n GitHubSyncEvent,\n GitHubRepoConfig,\n GitHubAuthConfig,\n SyncConfig,\n SqliteOptions,\n DatabaseType,\n RateLimitInfo,\n RecoveryResult,\n SnapshotMetadata,\n} from \"./types.js\";\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/sync/github-operations.ts","../src/sync/recovery.ts","../src/sync/sync-manager.ts","../src/provider.ts","../src/index.ts"],"names":["path","gunzip","gzip","promisify","zlib2","SNAPSHOT_DB_NAME","SNAPSHOT_DB_GZ_NAME","SNAPSHOT_META_NAME","path2","fs2","crypto2"],"mappings":"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","file":"index.js","sourcesContent":["import * as crypto from \"crypto\";\nimport type {\n GitHubConfig,\n GitHubFileResult,\n GitHubFileEntry,\n RateLimitInfo,\n GitHubSyncEvent,\n} from \"../types.js\";\n\nconst GITHUB_API_BASE = \"https://api.github.com\";\n\n/**\n * GitHub REST API operations wrapper with retry logic and rate limit handling\n */\nexport class GitHubOperations {\n private config: GitHubConfig;\n private maxRetries: number;\n private cachedToken: string | null = null;\n private tokenExpiry: number = 0;\n private onEvent?: (event: GitHubSyncEvent) => void;\n private verbose: boolean;\n\n constructor(\n config: GitHubConfig,\n maxRetries: number = 3,\n onEvent?: (event: GitHubSyncEvent) => void,\n verbose: boolean = false\n ) {\n this.config = config;\n this.maxRetries = maxRetries;\n this.onEvent = onEvent;\n this.verbose = verbose;\n }\n\n /**\n * Get a file from the repository\n */\n async getFile(path: string): Promise<GitHubFileResult | null> {\n const fullPath = this.getFullPath(path);\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/contents/${fullPath}?ref=${this.config.branch}`;\n\n const response = await this.withRetry(() => this.fetch(url));\n\n if (response.status === 404) {\n return null;\n }\n\n if (!response.ok) {\n throw new Error(\n `Failed to get file ${path}: ${response.status} ${response.statusText}`\n );\n }\n\n const data = await response.json();\n\n // GitHub returns base64 encoded content for files under 1MB\n // For larger files, we need to use the blob API\n if (data.content) {\n const content = Buffer.from(data.content, \"base64\");\n return {\n content,\n sha: data.sha,\n size: data.size,\n };\n }\n\n // Large file - use blob API\n if (data.sha && data.size > 0) {\n return this.getBlob(data.sha, data.size);\n }\n\n return null;\n }\n\n /**\n * Get a large file using the blob API\n */\n private async getBlob(sha: string, size: number): Promise<GitHubFileResult> {\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/git/blobs/${sha}`;\n\n const response = await this.withRetry(() => this.fetch(url));\n\n if (!response.ok) {\n throw new Error(\n `Failed to get blob ${sha}: ${response.status} ${response.statusText}`\n );\n }\n\n const data = await response.json();\n const content = Buffer.from(data.content, \"base64\");\n\n return {\n content,\n sha,\n size,\n };\n }\n\n /**\n * Create or update a file in the repository\n * Returns the new commit SHA\n */\n async putFile(\n path: string,\n content: Buffer,\n message: string,\n sha?: string\n ): Promise<string> {\n const fullPath = this.getFullPath(path);\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/contents/${fullPath}`;\n\n const body: Record<string, string> = {\n message,\n content: content.toString(\"base64\"),\n branch: this.config.branch,\n };\n\n if (sha) {\n body.sha = sha;\n }\n\n const response = await this.withRetry(\n () =>\n this.fetch(url, {\n method: \"PUT\",\n body: JSON.stringify(body),\n }),\n true // Allow conflict retry\n );\n\n if (response.status === 409) {\n // Conflict - SHA mismatch, caller should re-fetch and retry\n throw new ConflictError(\n `Conflict updating ${path}: file was modified concurrently`\n );\n }\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to put file ${path}: ${response.status} ${response.statusText} - ${errorText}`\n );\n }\n\n const data = await response.json();\n\n this.emitEvent({\n type: \"commit_created\",\n sha: data.commit.sha,\n message,\n });\n\n return data.content.sha;\n }\n\n /**\n * Delete a file from the repository\n */\n async deleteFile(path: string, sha: string, message: string): Promise<void> {\n const fullPath = this.getFullPath(path);\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/contents/${fullPath}`;\n\n const response = await this.withRetry(() =>\n this.fetch(url, {\n method: \"DELETE\",\n body: JSON.stringify({\n message,\n sha,\n branch: this.config.branch,\n }),\n })\n );\n\n if (!response.ok && response.status !== 404) {\n throw new Error(\n `Failed to delete file ${path}: ${response.status} ${response.statusText}`\n );\n }\n }\n\n /**\n * List files in a directory\n */\n async listFiles(path: string): Promise<GitHubFileEntry[]> {\n const fullPath = this.getFullPath(path);\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/contents/${fullPath}?ref=${this.config.branch}`;\n\n const response = await this.withRetry(() => this.fetch(url));\n\n if (response.status === 404) {\n return [];\n }\n\n if (!response.ok) {\n throw new Error(\n `Failed to list files at ${path}: ${response.status} ${response.statusText}`\n );\n }\n\n const data = await response.json();\n\n // Single file returns object, directory returns array\n if (!Array.isArray(data)) {\n return [\n {\n name: data.name,\n path: data.path,\n sha: data.sha,\n size: data.size,\n type: data.type,\n },\n ];\n }\n\n return data.map(\n (item: {\n name: string;\n path: string;\n sha: string;\n size: number;\n type: \"file\" | \"dir\";\n }) => ({\n name: item.name,\n path: item.path,\n sha: item.sha,\n size: item.size,\n type: item.type,\n })\n );\n }\n\n /**\n * Check current rate limit status\n */\n async checkRateLimit(): Promise<RateLimitInfo> {\n const url = `${GITHUB_API_BASE}/rate_limit`;\n const response = await this.fetch(url);\n\n if (!response.ok) {\n throw new Error(`Failed to check rate limit: ${response.statusText}`);\n }\n\n const data = await response.json();\n return {\n remaining: data.resources.core.remaining,\n resetAt: new Date(data.resources.core.reset * 1000),\n limit: data.resources.core.limit,\n };\n }\n\n /**\n * Ensure the branch exists, create if it doesn't\n * For empty repos, we skip branch creation since files can be pushed directly\n */\n async ensureBranch(): Promise<void> {\n // Check if branch exists\n const url = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/branches/${this.config.branch}`;\n const response = await this.fetch(url);\n\n if (response.ok) {\n return; // Branch exists\n }\n\n if (response.status !== 404) {\n // Could be auth error or other issue\n const errorText = await response.text();\n throw new Error(\n `Failed to check branch '${this.config.branch}': ${response.status} ${response.statusText}. ${errorText}`\n );\n }\n\n // Branch doesn't exist, check if repo has any commits\n const repoUrl = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}`;\n const repoResponse = await this.fetch(repoUrl);\n\n if (!repoResponse.ok) {\n const errorText = await repoResponse.text();\n throw new Error(\n `Failed to get repository info for '${this.config.owner}/${this.config.repo}': ${repoResponse.status} ${repoResponse.statusText}. ${errorText}`\n );\n }\n\n const repoData = await repoResponse.json();\n const defaultBranch = repoData.default_branch;\n\n // Check if the repo is empty (no commits yet)\n // Empty repos have size 0 and no refs\n const refUrl = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/git/refs/heads/${defaultBranch}`;\n const refResponse = await this.fetch(refUrl);\n\n if (!refResponse.ok) {\n if (refResponse.status === 409 || refResponse.status === 404) {\n // Empty repository - the branch will be created on first file push\n this.log(\n `Repository appears to be empty. Branch '${this.config.branch}' will be created on first snapshot.`\n );\n return;\n }\n const errorText = await refResponse.text();\n throw new Error(\n `Failed to get default branch ref: ${refResponse.status} ${refResponse.statusText}. ${errorText}`\n );\n }\n\n // If we're using the default branch, we're done\n if (this.config.branch === defaultBranch) {\n return;\n }\n\n const refData = await refResponse.json();\n const sha = refData.object.sha;\n\n // Create new branch from default branch\n const createUrl = `${GITHUB_API_BASE}/repos/${this.config.owner}/${this.config.repo}/git/refs`;\n const createResponse = await this.fetch(createUrl, {\n method: \"POST\",\n body: JSON.stringify({\n ref: `refs/heads/${this.config.branch}`,\n sha,\n }),\n });\n\n if (!createResponse.ok && createResponse.status !== 422) {\n const errorText = await createResponse.text();\n throw new Error(\n `Failed to create branch '${this.config.branch}': ${createResponse.status} ${createResponse.statusText}. ${errorText}`\n );\n }\n\n this.log(`Created branch: ${this.config.branch}`);\n }\n\n /**\n * Get the full path including configured prefix\n */\n private getFullPath(path: string): string {\n if (!this.config.path) {\n return path;\n }\n return `${this.config.path}/${path}`.replace(/\\/+/g, \"/\");\n }\n\n /**\n * Make an authenticated fetch request\n */\n private async fetch(\n url: string,\n options: RequestInit = {}\n ): Promise<Response> {\n const token = await this.getAuthToken();\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n Accept: \"application/vnd.github+json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n ...(options.headers as Record<string, string>),\n };\n\n if (options.body) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n return fetch(url, {\n ...options,\n headers,\n });\n }\n\n /**\n * Get authentication token (PAT or GitHub App installation token)\n */\n private async getAuthToken(): Promise<string> {\n // Use PAT if provided\n if (this.config.token) {\n return this.config.token;\n }\n\n // Check if we have a valid cached token\n if (this.cachedToken && Date.now() < this.tokenExpiry) {\n return this.cachedToken;\n }\n\n // Generate GitHub App installation token\n if (\n !this.config.appId ||\n !this.config.privateKey ||\n !this.config.installationId\n ) {\n throw new Error(\n \"Either token or GitHub App credentials (appId, privateKey, installationId) must be provided\"\n );\n }\n\n const jwt = this.generateJWT(this.config.appId, this.config.privateKey);\n\n const response = await fetch(\n `${GITHUB_API_BASE}/app/installations/${this.config.installationId}/access_tokens`,\n {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${jwt}`,\n Accept: \"application/vnd.github+json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n },\n }\n );\n\n if (!response.ok) {\n throw new Error(\n `Failed to get installation token: ${response.statusText}`\n );\n }\n\n const data = await response.json();\n this.cachedToken = data.token;\n // Token expires in 1 hour, refresh 5 minutes early\n this.tokenExpiry = Date.now() + 55 * 60 * 1000;\n\n return this.cachedToken!;\n }\n\n /**\n * Generate a JWT for GitHub App authentication\n */\n private generateJWT(appId: number, privateKey: string): string {\n const now = Math.floor(Date.now() / 1000);\n const payload = {\n iat: now - 60, // Issued 60 seconds ago to account for clock drift\n exp: now + 10 * 60, // Expires in 10 minutes\n iss: appId.toString(),\n };\n\n const header = { alg: \"RS256\", typ: \"JWT\" };\n const encodedHeader = this.base64UrlEncode(JSON.stringify(header));\n const encodedPayload = this.base64UrlEncode(JSON.stringify(payload));\n\n const signatureInput = `${encodedHeader}.${encodedPayload}`;\n const signature = crypto\n .createSign(\"RSA-SHA256\")\n .update(signatureInput)\n .sign(privateKey, \"base64url\");\n\n return `${signatureInput}.${signature}`;\n }\n\n /**\n * Base64 URL encode a string\n */\n private base64UrlEncode(str: string): string {\n return Buffer.from(str)\n .toString(\"base64\")\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=/g, \"\");\n }\n\n /**\n * Execute a function with retry logic and exponential backoff\n */\n private async withRetry<T>(\n fn: () => Promise<T>,\n allowConflict: boolean = false\n ): Promise<T> {\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n try {\n const result = await fn();\n\n // Check for rate limiting in response\n if (result instanceof Response) {\n await this.handleRateLimitHeaders(result);\n }\n\n return result;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Don't retry conflict errors unless specified\n if (error instanceof ConflictError && !allowConflict) {\n throw error;\n }\n\n // Check if this is a rate limit error\n if (\n error instanceof Error &&\n error.message.includes(\"rate limit\")\n ) {\n const rateLimit = await this.checkRateLimit();\n const waitTime = Math.max(\n 0,\n rateLimit.resetAt.getTime() - Date.now()\n );\n\n this.emitEvent({\n type: \"rate_limit_hit\",\n resetAt: rateLimit.resetAt,\n remaining: rateLimit.remaining,\n });\n\n if (waitTime > 0 && waitTime < 60000) {\n // Wait up to 1 minute\n this.log(`Rate limited, waiting ${waitTime}ms`);\n await this.sleep(waitTime);\n continue;\n }\n }\n\n // Emit error event\n this.emitEvent({\n type: \"sync_error\",\n error: lastError,\n context: \"github_operation\",\n willRetry: attempt < this.maxRetries,\n });\n\n if (attempt < this.maxRetries) {\n const delay = Math.min(1000 * Math.pow(2, attempt), 30000);\n this.log(`Retry attempt ${attempt + 1} after ${delay}ms`);\n await this.sleep(delay);\n }\n }\n }\n\n throw lastError || new Error(\"Unknown error\");\n }\n\n /**\n * Handle rate limit headers from response\n */\n private async handleRateLimitHeaders(response: Response): Promise<void> {\n const remaining = parseInt(\n response.headers.get(\"x-ratelimit-remaining\") || \"1000\",\n 10\n );\n const resetTimestamp = parseInt(\n response.headers.get(\"x-ratelimit-reset\") || \"0\",\n 10\n );\n\n if (remaining === 0 && resetTimestamp > 0) {\n const resetAt = new Date(resetTimestamp * 1000);\n const waitTime = Math.max(0, resetAt.getTime() - Date.now());\n\n this.emitEvent({\n type: \"rate_limit_hit\",\n resetAt,\n remaining: 0,\n });\n\n if (waitTime > 0 && waitTime < 60000) {\n this.log(`Rate limit exhausted, waiting ${waitTime}ms`);\n await this.sleep(waitTime);\n }\n }\n }\n\n /**\n * Sleep for the specified duration\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Emit an event if handler is registered\n */\n private emitEvent(event: GitHubSyncEvent): void {\n if (this.onEvent) {\n this.onEvent(event);\n }\n }\n\n /**\n * Log a message if verbose mode is enabled\n */\n private log(message: string): void {\n if (this.verbose) {\n console.log(`[github-operations] ${message}`);\n }\n }\n}\n\n/**\n * Custom error for conflict (SHA mismatch) situations\n */\nexport class ConflictError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ConflictError\";\n }\n}\n","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as zlib from \"zlib\";\nimport { promisify } from \"util\";\nimport type {\n GitHubSyncEvent,\n RecoveryResult,\n SnapshotMetadata,\n} from \"../types.js\";\nimport { GitHubOperations } from \"./github-operations.js\";\n\nconst gunzip = promisify(zlib.gunzip);\n\nconst SNAPSHOT_DB_NAME = \"snapshot.db\";\nconst SNAPSHOT_DB_GZ_NAME = \"snapshot.db.gz\";\nconst SNAPSHOT_META_NAME = \"snapshot.meta.json\";\n\n/**\n * Manages database recovery from GitHub\n */\nexport class RecoveryManager {\n private github: GitHubOperations;\n private dbPath: string;\n private onEvent?: (event: GitHubSyncEvent) => void;\n private verbose: boolean;\n\n constructor(\n github: GitHubOperations,\n dbPath: string,\n onEvent?: (event: GitHubSyncEvent) => void,\n verbose: boolean = false\n ) {\n this.github = github;\n this.dbPath = dbPath;\n this.onEvent = onEvent;\n this.verbose = verbose;\n }\n\n /**\n * Check if local database exists\n */\n localDatabaseExists(): boolean {\n return fs.existsSync(this.dbPath);\n }\n\n /**\n * Find the latest snapshot in the repository\n */\n async findLatestSnapshot(): Promise<{\n path: string;\n sha: string;\n compressed: boolean;\n } | null> {\n try {\n // First check for compressed snapshot\n const compressedFile = await this.github.getFile(SNAPSHOT_DB_GZ_NAME);\n if (compressedFile) {\n return {\n path: SNAPSHOT_DB_GZ_NAME,\n sha: compressedFile.sha,\n compressed: true,\n };\n }\n\n // Then check for uncompressed snapshot\n const uncompressedFile = await this.github.getFile(SNAPSHOT_DB_NAME);\n if (uncompressedFile) {\n return {\n path: SNAPSHOT_DB_NAME,\n sha: uncompressedFile.sha,\n compressed: false,\n };\n }\n\n return null;\n } catch (error) {\n this.log(`Error finding snapshot: ${error}`);\n return null;\n }\n }\n\n /**\n * Recover database from GitHub snapshot\n */\n async recover(): Promise<RecoveryResult> {\n this.emitEvent({\n type: \"recovery_started\",\n branch: \"\", // Branch is handled by GitHubOperations\n });\n\n try {\n // Find the latest snapshot\n const snapshot = await this.findLatestSnapshot();\n\n if (!snapshot) {\n this.log(\"No snapshot found in repository\");\n return { recovered: false };\n }\n\n this.log(`Found snapshot: ${snapshot.path}`);\n\n // Download the snapshot\n const file = await this.github.getFile(snapshot.path);\n if (!file) {\n this.log(\"Failed to download snapshot\");\n return { recovered: false };\n }\n\n // Decompress if necessary\n let dbContent: Buffer;\n if (snapshot.compressed) {\n this.log(\"Decompressing snapshot...\");\n dbContent = await gunzip(file.content);\n } else {\n dbContent = file.content;\n }\n\n // Ensure directory exists\n const dir = path.dirname(this.dbPath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n // Write the database file\n fs.writeFileSync(this.dbPath, dbContent);\n this.log(`Database recovered to ${this.dbPath}`);\n\n // Get metadata if available (for future use)\n await this.getSnapshotMetadata();\n\n this.emitEvent({\n type: \"recovery_completed\",\n sha: file.sha,\n });\n\n return {\n recovered: true,\n sha: file.sha,\n size: dbContent.length,\n compressed: snapshot.compressed,\n };\n } catch (error) {\n this.log(`Recovery error: ${error}`);\n this.emitEvent({\n type: \"sync_error\",\n error: error instanceof Error ? error : new Error(String(error)),\n context: \"recovery\",\n willRetry: false,\n });\n return { recovered: false };\n }\n }\n\n /**\n * Get snapshot metadata from repository\n */\n async getSnapshotMetadata(): Promise<SnapshotMetadata | null> {\n try {\n const file = await this.github.getFile(SNAPSHOT_META_NAME);\n if (!file) {\n return null;\n }\n return JSON.parse(file.content.toString(\"utf-8\"));\n } catch {\n return null;\n }\n }\n\n /**\n * Get the current snapshot SHA from the repository\n */\n async getCurrentSnapshotSha(): Promise<string | null> {\n const snapshot = await this.findLatestSnapshot();\n return snapshot?.sha || null;\n }\n\n /**\n * Emit an event if handler is registered\n */\n private emitEvent(event: GitHubSyncEvent): void {\n if (this.onEvent) {\n this.onEvent(event);\n }\n }\n\n /**\n * Log a message if verbose mode is enabled\n */\n private log(message: string): void {\n if (this.verbose) {\n console.log(`[recovery] ${message}`);\n }\n }\n}\n","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as crypto from \"crypto\";\nimport * as zlib from \"zlib\";\nimport { promisify } from \"util\";\nimport Database from \"better-sqlite3\";\nimport type {\n DatabaseType,\n GitHubSyncEvent,\n GitHubSyncManagerOptions,\n SnapshotMetadata,\n} from \"../types.js\";\nimport { GitHubOperations, ConflictError } from \"./github-operations.js\";\nimport { RecoveryManager } from \"./recovery.js\";\n\nconst gzip = promisify(zlib.gzip);\n\nconst SNAPSHOT_DB_NAME = \"snapshot.db\";\nconst SNAPSHOT_DB_GZ_NAME = \"snapshot.db.gz\";\nconst SNAPSHOT_META_NAME = \"snapshot.meta.json\";\n\n/**\n * Orchestrates database sync operations with GitHub\n */\nexport class GitHubSyncManager {\n private options: GitHubSyncManagerOptions;\n private github: GitHubOperations;\n private recovery: RecoveryManager;\n private db: DatabaseType | null = null;\n private hasChanges: boolean = false;\n private currentSha: string | null = null;\n private snapshotTimer: ReturnType<typeof setInterval> | null = null;\n private isInitialized: boolean = false;\n private isClosed: boolean = false;\n private pendingSync: Promise<void> | null = null;\n private syncDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(options: GitHubSyncManagerOptions) {\n this.options = options;\n this.github = new GitHubOperations(\n options.github,\n options.sync.maxRetries,\n options.onEvent,\n options.verbose\n );\n this.recovery = new RecoveryManager(\n this.github,\n options.dbPath,\n options.onEvent,\n options.verbose\n );\n }\n\n /**\n * Initialize the sync manager: recover from GitHub if needed, open database\n */\n async initialize(): Promise<DatabaseType> {\n if (this.isInitialized) {\n return this.db!;\n }\n\n this.log(\"Initializing sync manager...\");\n\n // Ensure the branch exists\n await this.github.ensureBranch();\n\n // Check if local database exists\n let recovered = false;\n if (!this.recovery.localDatabaseExists()) {\n this.log(\"Local database not found, attempting recovery from GitHub...\");\n const result = await this.recovery.recover();\n recovered = result.recovered;\n\n if (recovered) {\n this.currentSha = await this.recovery.getCurrentSnapshotSha();\n }\n } else {\n this.log(\"Local database exists, fetching current SHA...\");\n this.currentSha = await this.recovery.getCurrentSnapshotSha();\n }\n\n // Open the database\n this.db = this.openDatabase();\n\n // Start snapshot timer if configured\n if (this.options.sync.snapshotInterval > 0) {\n this.startSnapshotTimer();\n }\n\n this.isInitialized = true;\n\n this.emitEvent({\n type: \"initialized\",\n recovered,\n });\n\n return this.db;\n }\n\n /**\n * Open the SQLite database with configured options\n */\n private openDatabase(): DatabaseType {\n // Ensure the directory exists\n const dir = path.dirname(this.options.dbPath);\n if (dir && !fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n this.log(`Created directory: ${dir}`);\n }\n\n const sqliteOptions = this.options.sqliteOptions || {};\n const db = new Database(this.options.dbPath);\n\n // Set WAL mode if enabled\n if (this.options.sync.enableWal) {\n db.pragma(\"journal_mode = WAL\");\n }\n\n // Set foreign keys\n if (sqliteOptions.foreignKeys !== false) {\n db.pragma(\"foreign_keys = ON\");\n }\n\n // Set busy timeout\n if (sqliteOptions.busyTimeout) {\n db.pragma(`busy_timeout = ${sqliteOptions.busyTimeout}`);\n }\n\n // Apply additional pragmas\n if (sqliteOptions.pragmas) {\n for (const [key, value] of Object.entries(sqliteOptions.pragmas)) {\n db.pragma(`${key} = ${value}`);\n }\n }\n\n this.log(\"Database opened successfully\");\n return db;\n }\n\n /**\n * Called after database writes to track changes\n * If syncOnWrite is enabled, triggers a debounced non-blocking snapshot\n */\n async onWrite(): Promise<void> {\n this.hasChanges = true;\n\n // If syncOnWrite is enabled, trigger debounced snapshot (non-blocking)\n if (this.options.sync.syncOnWrite) {\n this.scheduleDebouncedSync();\n }\n }\n\n /**\n * Schedule a debounced sync - waits 100ms for more writes before syncing\n * This prevents multiple rapid writes from each triggering a separate upload\n */\n private scheduleDebouncedSync(): void {\n // Clear any existing debounce timer\n if (this.syncDebounceTimer) {\n clearTimeout(this.syncDebounceTimer);\n }\n\n // Schedule sync after 100ms of no writes\n this.syncDebounceTimer = setTimeout(() => {\n this.syncDebounceTimer = null;\n\n // Don't start a new sync if one is already in progress\n if (this.pendingSync) {\n return;\n }\n\n this.pendingSync = this.snapshot()\n .catch((error) => {\n this.log(`Background sync error: ${error}`);\n })\n .finally(() => {\n this.pendingSync = null;\n // If more changes came in during sync, schedule another\n if (this.hasChanges) {\n this.scheduleDebouncedSync();\n }\n });\n }, 100);\n }\n\n /**\n * Create a snapshot and upload to GitHub\n */\n async snapshot(): Promise<void> {\n if (this.isClosed) {\n return;\n }\n\n // Skip if no changes and snapshotOnChange is enabled\n if (this.options.sync.snapshotOnChange && !this.hasChanges) {\n this.log(\"No changes detected, skipping snapshot\");\n return;\n }\n\n if (!this.db) {\n throw new Error(\"Database not initialized\");\n }\n\n this.log(\"Creating snapshot...\");\n\n try {\n // Checkpoint WAL to ensure all changes are in the main file\n if (this.options.sync.enableWal) {\n this.db.pragma(\"wal_checkpoint(TRUNCATE)\");\n }\n\n // Read the database file\n const dbContent = fs.readFileSync(this.options.dbPath);\n\n // Calculate checksum\n const checksum = crypto\n .createHash(\"sha256\")\n .update(dbContent)\n .digest(\"hex\");\n\n // Optionally compress\n let uploadContent: Buffer;\n let filename: string;\n const compressed = this.options.sync.compression;\n\n if (compressed) {\n uploadContent = await gzip(dbContent);\n filename = SNAPSHOT_DB_GZ_NAME;\n this.log(`Compressed ${dbContent.length} -> ${uploadContent.length} bytes`);\n } else {\n uploadContent = dbContent;\n filename = SNAPSHOT_DB_NAME;\n }\n\n // Try to upload with conflict handling\n await this.uploadWithConflictRetry(filename, uploadContent, checksum, compressed);\n\n // Reset change tracking\n this.hasChanges = false;\n\n this.emitEvent({\n type: \"snapshot_uploaded\",\n sha: this.currentSha!,\n size: uploadContent.length,\n compressed,\n });\n\n this.log(`Snapshot uploaded successfully (${uploadContent.length} bytes)`);\n } catch (error) {\n this.emitEvent({\n type: \"sync_error\",\n error: error instanceof Error ? error : new Error(String(error)),\n context: \"snapshot\",\n willRetry: false,\n });\n throw error;\n }\n }\n\n /**\n * Upload file with automatic conflict resolution\n */\n private async uploadWithConflictRetry(\n filename: string,\n content: Buffer,\n checksum: string,\n compressed: boolean,\n retries: number = 3\n ): Promise<void> {\n for (let attempt = 0; attempt < retries; attempt++) {\n try {\n // Upload the database file\n const newSha = await this.github.putFile(\n filename,\n content,\n `Update database snapshot`,\n this.currentSha || undefined\n );\n\n this.currentSha = newSha;\n\n // Upload metadata\n const metadata: SnapshotMetadata = {\n timestamp: new Date().toISOString(),\n size: content.length,\n checksum,\n compressed,\n };\n\n // Get current metadata SHA if it exists\n const existingMeta = await this.github.getFile(SNAPSHOT_META_NAME);\n await this.github.putFile(\n SNAPSHOT_META_NAME,\n Buffer.from(JSON.stringify(metadata, null, 2)),\n `Update snapshot metadata`,\n existingMeta?.sha\n );\n\n // Clean up old format if we switched compression mode\n const oldFilename = compressed ? SNAPSHOT_DB_NAME : SNAPSHOT_DB_GZ_NAME;\n try {\n const oldFile = await this.github.getFile(oldFilename);\n if (oldFile) {\n await this.github.deleteFile(\n oldFilename,\n oldFile.sha,\n `Remove old snapshot format`\n );\n }\n } catch {\n // Ignore errors cleaning up old file\n }\n\n return;\n } catch (error) {\n if (error instanceof ConflictError && attempt < retries - 1) {\n this.log(`Conflict detected, refetching SHA and retrying (attempt ${attempt + 1})`);\n this.currentSha = await this.recovery.getCurrentSnapshotSha();\n continue;\n }\n throw error;\n }\n }\n }\n\n /**\n * Force an immediate sync (alias for snapshot)\n */\n async forceSync(): Promise<void> {\n const originalOnChange = this.options.sync.snapshotOnChange;\n this.options.sync.snapshotOnChange = false;\n try {\n await this.snapshot();\n } finally {\n this.options.sync.snapshotOnChange = originalOnChange;\n }\n }\n\n /**\n * Close the sync manager and perform final sync\n */\n async close(): Promise<void> {\n if (this.isClosed) {\n return;\n }\n\n this.log(\"Closing sync manager...\");\n this.isClosed = true;\n\n // Stop snapshot timer\n if (this.snapshotTimer) {\n clearInterval(this.snapshotTimer);\n this.snapshotTimer = null;\n }\n\n // Clear debounce timer\n if (this.syncDebounceTimer) {\n clearTimeout(this.syncDebounceTimer);\n this.syncDebounceTimer = null;\n }\n\n // Wait for any pending sync to complete\n if (this.pendingSync) {\n try {\n await this.pendingSync;\n } catch {\n // Ignore errors from pending sync\n }\n }\n\n // Final snapshot if there are changes\n if (this.hasChanges && this.db) {\n try {\n await this.snapshot();\n } catch (error) {\n this.log(`Error during final snapshot: ${error}`);\n }\n }\n\n // Close the database\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n\n this.log(\"Sync manager closed\");\n }\n\n /**\n * Start the automatic snapshot timer\n */\n private startSnapshotTimer(): void {\n this.snapshotTimer = setInterval(() => {\n this.snapshot().catch((error) => {\n this.log(`Snapshot error: ${error}`);\n });\n }, this.options.sync.snapshotInterval);\n\n // Ensure timer doesn't prevent process exit\n if (this.snapshotTimer.unref) {\n this.snapshotTimer.unref();\n }\n }\n\n /**\n * Get the raw database instance\n */\n get database(): DatabaseType | null {\n return this.db;\n }\n\n /**\n * Check if there are pending changes\n */\n get hasPendingChanges(): boolean {\n return this.hasChanges;\n }\n\n /**\n * Check if the manager is initialized\n */\n get initialized(): boolean {\n return this.isInitialized;\n }\n\n /**\n * Emit an event if handler is registered\n */\n private emitEvent(event: GitHubSyncEvent): void {\n if (this.options.onEvent) {\n this.options.onEvent(event);\n }\n }\n\n /**\n * Log a message if verbose mode is enabled\n */\n private log(message: string): void {\n if (this.options.verbose) {\n console.log(`[sync-manager] ${message}`);\n }\n }\n}\n","import type {\n EntityMetadata,\n FieldMetadata,\n SqlCommand,\n SqlImplementation,\n} from \"remult\";\nimport { BetterSqlite3DataProvider } from \"remult/remult-better-sqlite3\";\nimport type {\n BetterSqlite3GitHubOptions,\n DatabaseType,\n GitHubConfig,\n GitHubSyncManagerOptions,\n SyncConfig,\n} from \"./types.js\";\nimport { GitHubSyncManager } from \"./sync/index.js\";\n\n/**\n * Default sync configuration values\n */\nconst DEFAULT_SYNC_CONFIG: Required<SyncConfig> = {\n snapshotInterval: 30 * 1000, // 30 seconds\n snapshotOnChange: true,\n syncOnWrite: false,\n enableWal: false,\n walThreshold: 1024 * 1024, // 1MB\n maxRetries: 3,\n compression: false,\n};\n\n/**\n * A Remult data provider that syncs SQLite to GitHub\n */\nexport class BetterSqlite3GitHubDataProvider implements SqlImplementation {\n private syncManager: GitHubSyncManager;\n private _isInitialized: boolean = false;\n private initPromise: Promise<void> | null = null;\n private innerProvider: BetterSqlite3DataProvider | null = null;\n\n constructor(options: BetterSqlite3GitHubOptions) {\n // Build internal config\n const githubConfig: GitHubConfig = {\n owner: options.github.owner,\n repo: options.github.repo,\n branch: options.github.branch || \"main\",\n path: options.github.path || \"\",\n token: options.github.token,\n appId: options.github.appId,\n privateKey: options.github.privateKey,\n installationId: options.github.installationId,\n };\n\n // Apply serverless defaults if enabled\n const serverlessDefaults: Partial<SyncConfig> = options.serverless\n ? {\n syncOnWrite: true,\n snapshotInterval: 0,\n }\n : {};\n\n const syncConfig: Required<SyncConfig> = {\n ...DEFAULT_SYNC_CONFIG,\n ...serverlessDefaults,\n ...options.sync, // User options override serverless defaults\n };\n\n const managerOptions: GitHubSyncManagerOptions = {\n dbPath: options.file,\n github: githubConfig,\n sqliteOptions: options.sqliteOptions,\n sync: syncConfig,\n onEvent: options.onEvent,\n verbose: options.verbose || false,\n };\n\n this.syncManager = new GitHubSyncManager(managerOptions);\n }\n\n /**\n * Initialize the data provider\n * This must be called before using the provider\n */\n async init(): Promise<void> {\n if (this._isInitialized) {\n return;\n }\n\n // Prevent multiple concurrent initializations\n if (this.initPromise) {\n return this.initPromise;\n }\n\n this.initPromise = this.doInit();\n await this.initPromise;\n }\n\n private async doInit(): Promise<void> {\n const db = await this.syncManager.initialize();\n\n // Create the inner BetterSqlite3DataProvider with the initialized database\n this.innerProvider = new BetterSqlite3DataProvider(db);\n\n this._isInitialized = true;\n }\n\n /**\n * Ensure the provider is initialized\n */\n private async ensureInitialized(): Promise<void> {\n if (!this._isInitialized) {\n await this.init();\n }\n }\n\n private getProvider(): BetterSqlite3DataProvider {\n if (!this.innerProvider) {\n throw new Error(\n \"Provider not initialized. Call init() before using the provider.\"\n );\n }\n return this.innerProvider;\n }\n\n // SqlImplementation interface methods\n getLimitSqlSyntax(limit: number, offset: number): string {\n return this.getProvider().getLimitSqlSyntax(limit, offset);\n }\n\n createCommand(): SqlCommand {\n const command = this.getProvider().createCommand();\n // Wrap the command to track writes\n const originalExecute = command.execute.bind(command);\n const syncManager = this.syncManager;\n const isWriteOp = this.isWriteOperation.bind(this);\n command.execute = async (sql: string) => {\n const result = await originalExecute(sql);\n if (isWriteOp(sql)) {\n await syncManager.onWrite();\n }\n return result;\n };\n return command;\n }\n\n async transaction(\n action: (sql: SqlImplementation) => Promise<void>\n ): Promise<void> {\n await this.ensureInitialized();\n return this.getProvider().transaction(action);\n }\n\n async entityIsUsedForTheFirstTime(entity: EntityMetadata): Promise<void> {\n await this.ensureInitialized();\n return this.getProvider().entityIsUsedForTheFirstTime(entity);\n }\n\n async end(): Promise<void> {\n await this.close();\n }\n\n // Passthrough properties from inner provider\n get orderByNullsFirst(): boolean | undefined {\n return this.innerProvider?.orderByNullsFirst;\n }\n\n get afterMutation(): VoidFunction | undefined {\n return this.innerProvider?.afterMutation;\n }\n\n get supportsJsonColumnType(): boolean | undefined {\n return this.innerProvider?.supportsJsonColumnType;\n }\n\n get doesNotSupportReturningSyntax(): boolean {\n return this.innerProvider?.doesNotSupportReturningSyntax ?? true;\n }\n\n // Additional methods from SqliteCoreDataProvider that may be called\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async ensureSchema(entities: EntityMetadata<any>[]): Promise<void> {\n await this.ensureInitialized();\n return this.getProvider().ensureSchema(entities);\n }\n\n wrapIdentifier(name: string): string {\n return this.getProvider().wrapIdentifier(name);\n }\n\n addColumnSqlSyntax(\n x: FieldMetadata,\n dbName: string,\n isAlterTable: boolean\n ): string {\n return this.getProvider().addColumnSqlSyntax(x, dbName, isAlterTable);\n }\n\n /**\n * Check if a SQL statement is a write operation\n */\n private isWriteOperation(sql: string): boolean {\n const upperSql = sql.trim().toUpperCase();\n return (\n upperSql.startsWith(\"INSERT\") ||\n upperSql.startsWith(\"UPDATE\") ||\n upperSql.startsWith(\"DELETE\") ||\n upperSql.startsWith(\"CREATE\") ||\n upperSql.startsWith(\"DROP\") ||\n upperSql.startsWith(\"ALTER\")\n );\n }\n\n /**\n * Force an immediate sync to GitHub\n */\n async forceSync(): Promise<void> {\n await this.ensureInitialized();\n await this.syncManager.forceSync();\n }\n\n /**\n * Create a snapshot and upload to GitHub\n */\n async snapshot(): Promise<void> {\n await this.ensureInitialized();\n await this.syncManager.snapshot();\n }\n\n /**\n * Close the provider and perform final sync\n */\n async close(): Promise<void> {\n await this.syncManager.close();\n this._isInitialized = false;\n this.initPromise = null;\n this.innerProvider = null;\n }\n\n /**\n * Get the raw better-sqlite3 database instance\n */\n get rawDatabase(): DatabaseType | null {\n return this.syncManager.database;\n }\n\n /**\n * Get the sync manager instance\n */\n get sync(): GitHubSyncManager {\n return this.syncManager;\n }\n\n /**\n * Check if the provider is initialized\n */\n get isInitialized(): boolean {\n return this._isInitialized;\n }\n}\n","import { SqlDatabase } from \"remult\";\nimport { BetterSqlite3GitHubDataProvider } from \"./provider.js\";\nimport type { BetterSqlite3GitHubOptions } from \"./types.js\";\n\n/**\n * Create a GitHub-synced SQLite data provider for Remult\n *\n * @param options - Configuration options for the provider\n * @returns A factory function that creates an initialized SqlDatabase\n *\n * @example\n * ```typescript\n * import { createGitHubDataProvider } from \"remult-sqlite-github\";\n *\n * const api = remultApi({\n * dataProvider: createGitHubDataProvider({\n * file: \"./mydb.sqlite\",\n * github: {\n * owner: \"your-username\",\n * repo: \"your-database-repo\",\n * token: process.env.GITHUB_TOKEN,\n * },\n * }),\n * entities: [Task],\n * });\n * ```\n */\nexport function createGitHubDataProvider(\n options: BetterSqlite3GitHubOptions\n): () => Promise<SqlDatabase> {\n let provider: BetterSqlite3GitHubDataProvider | null = null;\n let sqlDatabase: SqlDatabase | null = null;\n\n return async () => {\n if (sqlDatabase) {\n return sqlDatabase;\n }\n\n provider = new BetterSqlite3GitHubDataProvider(options);\n await provider.init();\n\n sqlDatabase = new SqlDatabase(provider);\n return sqlDatabase;\n };\n}\n\n// Export the provider class for advanced usage\nexport { BetterSqlite3GitHubDataProvider } from \"./provider.js\";\n\n// Export sync components for advanced usage\nexport { GitHubSyncManager, GitHubOperations, ConflictError } from \"./sync/index.js\";\n\n// Export types\nexport type {\n BetterSqlite3GitHubOptions,\n GitHubSyncEvent,\n GitHubRepoConfig,\n GitHubAuthConfig,\n SyncConfig,\n SqliteOptions,\n DatabaseType,\n RateLimitInfo,\n RecoveryResult,\n SnapshotMetadata,\n} from \"./types.js\";\n"]}
|