@loro-dev/unisqlite
Advanced tools
| {"version":3,"file":"node2.cjs","names":["BaseAdapter","Database"],"sources":["../src/adapters/logger.ts","../src/adapters/node.ts"],"sourcesContent":["/**\n * Debug Logger for UniSQLite\n *\n * Uses the `debug` package for conditional logging.\n * Enable logs by setting DEBUG env var:\n *\n * - `unisqlite:*` - Enable all unisqlite logs\n * - `unisqlite:node` - Node.js adapter logs only\n *\n * In Node.js:\n * DEBUG=unisqlite:* node app.js\n */\n\nimport debug from \"debug\";\n\nconst NAMESPACE = \"unisqlite\";\n\n// Package version - will be output on initialization\nexport const VERSION = \"0.4.0\";\n\n/**\n * Logger interface with log, warn, and error methods\n */\nexport interface Logger {\n log: (...args: unknown[]) => void;\n warn: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n}\n\n/**\n * Create a namespaced debug logger with log/warn/error methods\n */\nfunction createModuleLogger(name: string): Logger {\n const logDebug = debug(`${NAMESPACE}:${name}`);\n const warnDebug = debug(`${NAMESPACE}:${name}:warn`);\n const errorDebug = debug(`${NAMESPACE}:${name}:error`);\n\n // Enable error logs by default (they go to stderr)\n errorDebug.enabled = true;\n\n return {\n log: logDebug as (...args: unknown[]) => void,\n warn: warnDebug as (...args: unknown[]) => void,\n error: errorDebug as (...args: unknown[]) => void,\n };\n}\n\n// Pre-created logger for node adapter\nexport const nodeLogger = createModuleLogger(\"node\");\n\n/**\n * Create a custom debug logger\n */\nexport function createDebugLogger(name: string): Logger {\n return createModuleLogger(name);\n}\n\n/**\n * Enable debug logging programmatically\n * This is useful for enabling logs without setting localStorage/env\n *\n * @param namespaces - Debug namespaces to enable (default: \"unisqlite:*\")\n *\n * @example\n * // Enable all unisqlite logs\n * enableDebug(\"unisqlite:*\");\n *\n * // Enable only node adapter logs\n * enableDebug(\"unisqlite:node\");\n */\nexport function enableDebug(namespaces: string = \"unisqlite:*\"): void {\n debug.enable(namespaces);\n}\n\n/**\n * Disable all debug logging\n */\nexport function disableDebug(): void {\n debug.disable();\n}\n","import { BaseAdapter } from \"./base.js\";\nimport type {\n QueryResult,\n RunResult,\n SQLiteParams,\n SQLiteValue,\n UniStoreConnection,\n UniStoreOptions,\n ConnectionType,\n} from \"../types.js\";\nimport Database from \"better-sqlite3\";\nimport { nodeLogger as logger, VERSION } from \"./logger.js\";\n\nexport class NodeAdapter extends BaseAdapter {\n private db: Database.Database;\n private _closed: boolean = false;\n\n constructor(options: UniStoreOptions) {\n super(options);\n logger.log(`UniSQLite v${VERSION} - Opening database: ${options.path}`);\n // Open database with WAL mode for better concurrency\n this.db = new Database(options.path, { fileMustExist: false });\n this.db.pragma(\"journal_mode = WAL\");\n this.db.pragma(\"busy_timeout = 5000\"); // 5 second timeout for locks\n logger.log(\"Database opened with WAL mode\");\n }\n\n private normalizeParams(params?: SQLiteParams): unknown[] {\n if (!params) return [];\n if (Array.isArray(params)) return params;\n // Convert object params to array format for better-sqlite3\n // This is a simplified conversion - in practice you'd need to handle named parameters\n return Object.values(params);\n }\n\n private convertBuffersToUint8Array<T>(value: T): T {\n if (value === null || value === undefined) {\n return value;\n }\n\n if (Buffer.isBuffer(value)) {\n return new Uint8Array(value) as T;\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => this.convertBuffersToUint8Array(item)) as T;\n }\n\n if (typeof value === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value)) {\n result[key] = this.convertBuffersToUint8Array(val);\n }\n return result as T;\n }\n\n return value;\n }\n\n private checkConnection(): void {\n if (this._closed || !this.db.open) {\n throw new Error(\"Database connection is closed\");\n }\n }\n\n async query<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): Promise<T[]> {\n this.checkConnection();\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n return this.convertBuffersToUint8Array(rows);\n }\n\n async queryRaw<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): Promise<QueryResult<T>> {\n this.checkConnection();\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n const columns = stmt.columns().map((col) => col.name);\n\n return {\n rows: this.convertBuffersToUint8Array(rows),\n columns,\n rowsAffected: 0,\n lastInsertRowId: 0,\n };\n }\n\n async run(sql: string, params?: SQLiteParams): Promise<RunResult> {\n this.checkConnection();\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const info = stmt.run(paramsArray);\n\n return {\n rowsAffected: info.changes,\n lastInsertRowId: info.lastInsertRowid as number,\n };\n }\n\n async exec(sql: string): Promise<void> {\n this.checkConnection();\n this.db.exec(sql);\n }\n\n transaction<T>(fn: (tx: UniStoreConnection) => Promise<T> | T): Promise<T> {\n this.checkConnection();\n // better-sqlite3 supports synchronous transactions\n this.db.exec(\"BEGIN\");\n const transactionAdapter = new SyncTransactionAdapter(this.db);\n return (async () => {\n try {\n const result = await fn(transactionAdapter);\n this.db.exec(\"COMMIT\");\n return result;\n } catch (error) {\n this.db.exec(\"ROLLBACK\");\n throw error;\n }\n })();\n }\n\n /**\n * Execute an async transaction with manual transaction management.\n * This allows async operations within the transaction but comes with timeout support\n * to prevent long-running transactions from blocking the database.\n *\n * @param fn Transaction function that can contain async operations\n * @param options Transaction options including timeout (default: 30000ms)\n */\n async asyncTransaction<T>(fn: (tx: UniStoreConnection) => Promise<T>, options?: { timeoutMs?: number }): Promise<T> {\n this.checkConnection();\n\n const timeoutMs = options?.timeoutMs ?? 30000; // Default 30 seconds\n let alreadyInTransaction = false;\n\n // Manual transaction management using BEGIN/COMMIT/ROLLBACK\n try {\n this.db.exec(\"BEGIN IMMEDIATE\");\n } catch (e) {\n if ((e as Error).message.includes(\"cannot start a transaction within a transaction\")) {\n alreadyInTransaction = true;\n } else {\n throw e;\n }\n }\n\n let timeoutHandle: NodeJS.Timeout | undefined;\n let transactionCompleted = false;\n\n try {\n // Set up timeout\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutHandle = setTimeout(() => {\n if (!transactionCompleted) {\n reject(new Error(`Async transaction timeout after ${timeoutMs}ms`));\n }\n }, timeoutMs);\n });\n\n const transactionAdapter = new AsyncTransactionAdapter(this.db);\n\n // Race between transaction execution and timeout\n const result = await Promise.race([fn(transactionAdapter), timeoutPromise]);\n\n transactionCompleted = true;\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n\n // If we get here, the transaction completed successfully\n if (!alreadyInTransaction) {\n this.db.exec(\"COMMIT\");\n }\n return result;\n } catch (error) {\n transactionCompleted = true;\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n\n try {\n this.db.exec(\"ROLLBACK\");\n } catch (rollbackError) {\n logger.error(\"Rollback failed:\", rollbackError);\n }\n\n throw error;\n }\n }\n\n getConnectionType(): ConnectionType {\n return \"direct\";\n }\n\n async close(): Promise<void> {\n if (!this._closed && this.db.open) {\n this.db.close();\n this._closed = true;\n }\n }\n\n get isOpen(): boolean {\n return !this._closed && this.db.open;\n }\n}\n\nabstract class BaseTransactionAdapter implements UniStoreConnection {\n public readonly inTransaction = true;\n\n constructor(protected db: Database.Database) {}\n\n private normalizeParams(params?: SQLiteParams): unknown[] {\n if (!params) return [];\n if (Array.isArray(params)) return params;\n return Object.values(params);\n }\n\n private convertBuffersToUint8Array<T>(value: T): T {\n if (value === null || value === undefined) {\n return value;\n }\n\n if (Buffer.isBuffer(value)) {\n return new Uint8Array(value) as T;\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => this.convertBuffersToUint8Array(item)) as T;\n }\n\n if (typeof value === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value)) {\n result[key] = this.convertBuffersToUint8Array(val);\n }\n return result as T;\n }\n\n return value;\n }\n\n // Synchronous database methods for use in transactions\n query<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): Promise<T[]> {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n const result = this.convertBuffersToUint8Array(rows);\n return Promise.resolve(result);\n }\n\n queryRaw<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): Promise<QueryResult<T>> {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n const columns = stmt.columns().map((col) => col.name);\n\n const result = {\n rows: this.convertBuffersToUint8Array(rows),\n columns,\n rowsAffected: 0,\n lastInsertRowId: 0,\n };\n return Promise.resolve(result);\n }\n\n run(sql: string, params?: SQLiteParams): Promise<RunResult> {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const info = stmt.run(paramsArray);\n\n const result = {\n rowsAffected: info.changes,\n lastInsertRowId: info.lastInsertRowid as number,\n };\n return Promise.resolve(result);\n }\n\n exec(sql: string): Promise<void> {\n this.db.exec(sql);\n return Promise.resolve();\n }\n\n // Synchronous versions for use in sync transactions\n querySync<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): T[] {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n return this.convertBuffersToUint8Array(rows);\n }\n\n runSync(sql: string, params?: SQLiteParams): RunResult {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const info = stmt.run(paramsArray);\n\n return {\n rowsAffected: info.changes,\n lastInsertRowId: info.lastInsertRowid as number,\n };\n }\n\n execSync(sql: string): void {\n this.db.exec(sql);\n }\n\n abstract getConnectionType(): ConnectionType;\n abstract transaction<T>(fn: (tx: UniStoreConnection) => Promise<T> | T): Promise<T>;\n abstract asyncTransaction<T>(\n fn: (tx: UniStoreConnection) => Promise<T>,\n options?: { timeoutMs?: number }\n ): Promise<T>;\n\n async close(): Promise<void> {\n // No-op for transaction\n }\n}\n\nclass SyncTransactionAdapter extends BaseTransactionAdapter {\n getConnectionType(): ConnectionType {\n return \"syncTxn\";\n }\n\n async transaction<T>(fn: (tx: UniStoreConnection) => Promise<T> | T): Promise<T> {\n // For syncTxn, we can execute the transaction using itself as the connection\n // This allows nested operations within the same transaction\n return await fn(this);\n }\n\n async asyncTransaction<T>(\n _fn: (tx: UniStoreConnection) => Promise<T>,\n _options?: { timeoutMs?: number }\n ): Promise<T> {\n // syncTxn connections cannot run asyncTransaction\n throw new Error(\n \"asyncTransaction is not supported in syncTxn connections. Use transaction() instead or create a direct connection.\"\n );\n }\n}\n\nclass AsyncTransactionAdapter extends BaseTransactionAdapter {\n getConnectionType(): ConnectionType {\n return \"asyncTxn\";\n }\n\n async transaction<T>(fn: (tx: UniStoreConnection) => Promise<T> | T): Promise<T> {\n // For asyncTxn, we can execute the transaction using itself as the connection\n // This allows nested operations within the same transaction\n return await fn(this);\n }\n\n async asyncTransaction<T>(fn: (tx: UniStoreConnection) => Promise<T>, _options?: { timeoutMs?: number }): Promise<T> {\n // For asyncTxn, we can execute asyncTransaction using itself as the connection\n // This allows nested async operations within the same transaction\n return await fn(this);\n }\n}\n"],"mappings":"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"} |
| {"version":3,"file":"node2.mjs","names":[],"sources":["../src/adapters/logger.ts","../src/adapters/node.ts"],"sourcesContent":["/**\n * Debug Logger for UniSQLite\n *\n * Uses the `debug` package for conditional logging.\n * Enable logs by setting DEBUG env var:\n *\n * - `unisqlite:*` - Enable all unisqlite logs\n * - `unisqlite:node` - Node.js adapter logs only\n *\n * In Node.js:\n * DEBUG=unisqlite:* node app.js\n */\n\nimport debug from \"debug\";\n\nconst NAMESPACE = \"unisqlite\";\n\n// Package version - will be output on initialization\nexport const VERSION = \"0.4.0\";\n\n/**\n * Logger interface with log, warn, and error methods\n */\nexport interface Logger {\n log: (...args: unknown[]) => void;\n warn: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n}\n\n/**\n * Create a namespaced debug logger with log/warn/error methods\n */\nfunction createModuleLogger(name: string): Logger {\n const logDebug = debug(`${NAMESPACE}:${name}`);\n const warnDebug = debug(`${NAMESPACE}:${name}:warn`);\n const errorDebug = debug(`${NAMESPACE}:${name}:error`);\n\n // Enable error logs by default (they go to stderr)\n errorDebug.enabled = true;\n\n return {\n log: logDebug as (...args: unknown[]) => void,\n warn: warnDebug as (...args: unknown[]) => void,\n error: errorDebug as (...args: unknown[]) => void,\n };\n}\n\n// Pre-created logger for node adapter\nexport const nodeLogger = createModuleLogger(\"node\");\n\n/**\n * Create a custom debug logger\n */\nexport function createDebugLogger(name: string): Logger {\n return createModuleLogger(name);\n}\n\n/**\n * Enable debug logging programmatically\n * This is useful for enabling logs without setting localStorage/env\n *\n * @param namespaces - Debug namespaces to enable (default: \"unisqlite:*\")\n *\n * @example\n * // Enable all unisqlite logs\n * enableDebug(\"unisqlite:*\");\n *\n * // Enable only node adapter logs\n * enableDebug(\"unisqlite:node\");\n */\nexport function enableDebug(namespaces: string = \"unisqlite:*\"): void {\n debug.enable(namespaces);\n}\n\n/**\n * Disable all debug logging\n */\nexport function disableDebug(): void {\n debug.disable();\n}\n","import { BaseAdapter } from \"./base.js\";\nimport type {\n QueryResult,\n RunResult,\n SQLiteParams,\n SQLiteValue,\n UniStoreConnection,\n UniStoreOptions,\n ConnectionType,\n} from \"../types.js\";\nimport Database from \"better-sqlite3\";\nimport { nodeLogger as logger, VERSION } from \"./logger.js\";\n\nexport class NodeAdapter extends BaseAdapter {\n private db: Database.Database;\n private _closed: boolean = false;\n\n constructor(options: UniStoreOptions) {\n super(options);\n logger.log(`UniSQLite v${VERSION} - Opening database: ${options.path}`);\n // Open database with WAL mode for better concurrency\n this.db = new Database(options.path, { fileMustExist: false });\n this.db.pragma(\"journal_mode = WAL\");\n this.db.pragma(\"busy_timeout = 5000\"); // 5 second timeout for locks\n logger.log(\"Database opened with WAL mode\");\n }\n\n private normalizeParams(params?: SQLiteParams): unknown[] {\n if (!params) return [];\n if (Array.isArray(params)) return params;\n // Convert object params to array format for better-sqlite3\n // This is a simplified conversion - in practice you'd need to handle named parameters\n return Object.values(params);\n }\n\n private convertBuffersToUint8Array<T>(value: T): T {\n if (value === null || value === undefined) {\n return value;\n }\n\n if (Buffer.isBuffer(value)) {\n return new Uint8Array(value) as T;\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => this.convertBuffersToUint8Array(item)) as T;\n }\n\n if (typeof value === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value)) {\n result[key] = this.convertBuffersToUint8Array(val);\n }\n return result as T;\n }\n\n return value;\n }\n\n private checkConnection(): void {\n if (this._closed || !this.db.open) {\n throw new Error(\"Database connection is closed\");\n }\n }\n\n async query<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): Promise<T[]> {\n this.checkConnection();\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n return this.convertBuffersToUint8Array(rows);\n }\n\n async queryRaw<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): Promise<QueryResult<T>> {\n this.checkConnection();\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n const columns = stmt.columns().map((col) => col.name);\n\n return {\n rows: this.convertBuffersToUint8Array(rows),\n columns,\n rowsAffected: 0,\n lastInsertRowId: 0,\n };\n }\n\n async run(sql: string, params?: SQLiteParams): Promise<RunResult> {\n this.checkConnection();\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const info = stmt.run(paramsArray);\n\n return {\n rowsAffected: info.changes,\n lastInsertRowId: info.lastInsertRowid as number,\n };\n }\n\n async exec(sql: string): Promise<void> {\n this.checkConnection();\n this.db.exec(sql);\n }\n\n transaction<T>(fn: (tx: UniStoreConnection) => Promise<T> | T): Promise<T> {\n this.checkConnection();\n // better-sqlite3 supports synchronous transactions\n this.db.exec(\"BEGIN\");\n const transactionAdapter = new SyncTransactionAdapter(this.db);\n return (async () => {\n try {\n const result = await fn(transactionAdapter);\n this.db.exec(\"COMMIT\");\n return result;\n } catch (error) {\n this.db.exec(\"ROLLBACK\");\n throw error;\n }\n })();\n }\n\n /**\n * Execute an async transaction with manual transaction management.\n * This allows async operations within the transaction but comes with timeout support\n * to prevent long-running transactions from blocking the database.\n *\n * @param fn Transaction function that can contain async operations\n * @param options Transaction options including timeout (default: 30000ms)\n */\n async asyncTransaction<T>(fn: (tx: UniStoreConnection) => Promise<T>, options?: { timeoutMs?: number }): Promise<T> {\n this.checkConnection();\n\n const timeoutMs = options?.timeoutMs ?? 30000; // Default 30 seconds\n let alreadyInTransaction = false;\n\n // Manual transaction management using BEGIN/COMMIT/ROLLBACK\n try {\n this.db.exec(\"BEGIN IMMEDIATE\");\n } catch (e) {\n if ((e as Error).message.includes(\"cannot start a transaction within a transaction\")) {\n alreadyInTransaction = true;\n } else {\n throw e;\n }\n }\n\n let timeoutHandle: NodeJS.Timeout | undefined;\n let transactionCompleted = false;\n\n try {\n // Set up timeout\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutHandle = setTimeout(() => {\n if (!transactionCompleted) {\n reject(new Error(`Async transaction timeout after ${timeoutMs}ms`));\n }\n }, timeoutMs);\n });\n\n const transactionAdapter = new AsyncTransactionAdapter(this.db);\n\n // Race between transaction execution and timeout\n const result = await Promise.race([fn(transactionAdapter), timeoutPromise]);\n\n transactionCompleted = true;\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n\n // If we get here, the transaction completed successfully\n if (!alreadyInTransaction) {\n this.db.exec(\"COMMIT\");\n }\n return result;\n } catch (error) {\n transactionCompleted = true;\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n\n try {\n this.db.exec(\"ROLLBACK\");\n } catch (rollbackError) {\n logger.error(\"Rollback failed:\", rollbackError);\n }\n\n throw error;\n }\n }\n\n getConnectionType(): ConnectionType {\n return \"direct\";\n }\n\n async close(): Promise<void> {\n if (!this._closed && this.db.open) {\n this.db.close();\n this._closed = true;\n }\n }\n\n get isOpen(): boolean {\n return !this._closed && this.db.open;\n }\n}\n\nabstract class BaseTransactionAdapter implements UniStoreConnection {\n public readonly inTransaction = true;\n\n constructor(protected db: Database.Database) {}\n\n private normalizeParams(params?: SQLiteParams): unknown[] {\n if (!params) return [];\n if (Array.isArray(params)) return params;\n return Object.values(params);\n }\n\n private convertBuffersToUint8Array<T>(value: T): T {\n if (value === null || value === undefined) {\n return value;\n }\n\n if (Buffer.isBuffer(value)) {\n return new Uint8Array(value) as T;\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => this.convertBuffersToUint8Array(item)) as T;\n }\n\n if (typeof value === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value)) {\n result[key] = this.convertBuffersToUint8Array(val);\n }\n return result as T;\n }\n\n return value;\n }\n\n // Synchronous database methods for use in transactions\n query<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): Promise<T[]> {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n const result = this.convertBuffersToUint8Array(rows);\n return Promise.resolve(result);\n }\n\n queryRaw<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): Promise<QueryResult<T>> {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n const columns = stmt.columns().map((col) => col.name);\n\n const result = {\n rows: this.convertBuffersToUint8Array(rows),\n columns,\n rowsAffected: 0,\n lastInsertRowId: 0,\n };\n return Promise.resolve(result);\n }\n\n run(sql: string, params?: SQLiteParams): Promise<RunResult> {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const info = stmt.run(paramsArray);\n\n const result = {\n rowsAffected: info.changes,\n lastInsertRowId: info.lastInsertRowid as number,\n };\n return Promise.resolve(result);\n }\n\n exec(sql: string): Promise<void> {\n this.db.exec(sql);\n return Promise.resolve();\n }\n\n // Synchronous versions for use in sync transactions\n querySync<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): T[] {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n return this.convertBuffersToUint8Array(rows);\n }\n\n runSync(sql: string, params?: SQLiteParams): RunResult {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const info = stmt.run(paramsArray);\n\n return {\n rowsAffected: info.changes,\n lastInsertRowId: info.lastInsertRowid as number,\n };\n }\n\n execSync(sql: string): void {\n this.db.exec(sql);\n }\n\n abstract getConnectionType(): ConnectionType;\n abstract transaction<T>(fn: (tx: UniStoreConnection) => Promise<T> | T): Promise<T>;\n abstract asyncTransaction<T>(\n fn: (tx: UniStoreConnection) => Promise<T>,\n options?: { timeoutMs?: number }\n ): Promise<T>;\n\n async close(): Promise<void> {\n // No-op for transaction\n }\n}\n\nclass SyncTransactionAdapter extends BaseTransactionAdapter {\n getConnectionType(): ConnectionType {\n return \"syncTxn\";\n }\n\n async transaction<T>(fn: (tx: UniStoreConnection) => Promise<T> | T): Promise<T> {\n // For syncTxn, we can execute the transaction using itself as the connection\n // This allows nested operations within the same transaction\n return await fn(this);\n }\n\n async asyncTransaction<T>(\n _fn: (tx: UniStoreConnection) => Promise<T>,\n _options?: { timeoutMs?: number }\n ): Promise<T> {\n // syncTxn connections cannot run asyncTransaction\n throw new Error(\n \"asyncTransaction is not supported in syncTxn connections. Use transaction() instead or create a direct connection.\"\n );\n }\n}\n\nclass AsyncTransactionAdapter extends BaseTransactionAdapter {\n getConnectionType(): ConnectionType {\n return \"asyncTxn\";\n }\n\n async transaction<T>(fn: (tx: UniStoreConnection) => Promise<T> | T): Promise<T> {\n // For asyncTxn, we can execute the transaction using itself as the connection\n // This allows nested operations within the same transaction\n return await fn(this);\n }\n\n async asyncTransaction<T>(fn: (tx: UniStoreConnection) => Promise<T>, _options?: { timeoutMs?: number }): Promise<T> {\n // For asyncTxn, we can execute asyncTransaction using itself as the connection\n // This allows nested async operations within the same transaction\n return await fn(this);\n }\n}\n"],"mappings":"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"} |
| /** | ||
| * Debug Logger for UniSQLite | ||
| * | ||
| * Uses the `debug` package for conditional logging. | ||
| * Enable logs by setting DEBUG env var: | ||
| * | ||
| * - `unisqlite:*` - Enable all unisqlite logs | ||
| * - `unisqlite:node` - Node.js adapter logs only | ||
| * | ||
| * In Node.js: | ||
| * DEBUG=unisqlite:* node app.js | ||
| */ | ||
| import debug from "debug"; | ||
| const NAMESPACE = "unisqlite"; | ||
| // Package version - will be output on initialization | ||
| export const VERSION = "0.4.0"; | ||
| /** | ||
| * Logger interface with log, warn, and error methods | ||
| */ | ||
| export interface Logger { | ||
| log: (...args: unknown[]) => void; | ||
| warn: (...args: unknown[]) => void; | ||
| error: (...args: unknown[]) => void; | ||
| } | ||
| /** | ||
| * Create a namespaced debug logger with log/warn/error methods | ||
| */ | ||
| function createModuleLogger(name: string): Logger { | ||
| const logDebug = debug(`${NAMESPACE}:${name}`); | ||
| const warnDebug = debug(`${NAMESPACE}:${name}:warn`); | ||
| const errorDebug = debug(`${NAMESPACE}:${name}:error`); | ||
| // Enable error logs by default (they go to stderr) | ||
| errorDebug.enabled = true; | ||
| return { | ||
| log: logDebug as (...args: unknown[]) => void, | ||
| warn: warnDebug as (...args: unknown[]) => void, | ||
| error: errorDebug as (...args: unknown[]) => void, | ||
| }; | ||
| } | ||
| // Pre-created logger for node adapter | ||
| export const nodeLogger = createModuleLogger("node"); | ||
| /** | ||
| * Create a custom debug logger | ||
| */ | ||
| export function createDebugLogger(name: string): Logger { | ||
| return createModuleLogger(name); | ||
| } | ||
| /** | ||
| * Enable debug logging programmatically | ||
| * This is useful for enabling logs without setting localStorage/env | ||
| * | ||
| * @param namespaces - Debug namespaces to enable (default: "unisqlite:*") | ||
| * | ||
| * @example | ||
| * // Enable all unisqlite logs | ||
| * enableDebug("unisqlite:*"); | ||
| * | ||
| * // Enable only node adapter logs | ||
| * enableDebug("unisqlite:node"); | ||
| */ | ||
| export function enableDebug(namespaces: string = "unisqlite:*"): void { | ||
| debug.enable(namespaces); | ||
| } | ||
| /** | ||
| * Disable all debug logging | ||
| */ | ||
| export function disableDebug(): void { | ||
| debug.disable(); | ||
| } |
@@ -1,8 +0,8 @@ | ||
| const e=require(`./chunk.cjs`),t=require(`./base.cjs`);let n=require(`debug`);n=e.t(n);const r=`unisqlite`;function i(e){let t=(0,n.default)(`${r}:${e}`),i=(0,n.default)(`${r}:${e}:warn`),a=(0,n.default)(`${r}:${e}:error`);return a.enabled=!0,{log:t,warn:i,error:a}}const a=i(`host`),o=i(`txn`),s=i(`adapter`);var c=class e{constructor(e){this.options=e,this.abortController=null,this._isHost=!1,this._isStarted=!1,this.releaseResolver=null,this.hostReadyResolver=null,this.hostReadyPromise=null,this.lockName=`sqlite:host:${e.dbName}`,this.txnLockName=`sqlite:txn:${e.dbName}`}static isSupported(){return typeof navigator<`u`&&navigator.locks!==void 0}get isHost(){return this._isHost}async start(){if(!this._isStarted){if(!e.isSupported()){a.warn(`Web Locks API not supported. Running in local-only mode.`),this._isStarted=!0,this._isHost=!0,this.options.onBecomeHost().catch(e=>{a.error(`Error in onBecomeHost callback:`,e),this._isHost=!1});return}this.options.checkVisibility&&!this.options.checkVisibility()||(this._isStarted=!0,this.hostReadyPromise=new Promise(e=>{this.hostReadyResolver=e}),this.tryAcquireHost().catch(e=>{a.error(`Error in host election:`,e)}))}}async waitForHost(){if(!this._isHost&&(this.hostReadyPromise||(await this.start(),this.hostReadyPromise)))return this.hostReadyPromise}async tryAcquireHost(){this.abortController=new AbortController;try{await navigator.locks.request(this.lockName,{mode:`exclusive`,signal:this.abortController.signal},async e=>{if(e){this._isHost=!0,a.log(`Tab ${this.options.tabId} became Host for ${this.options.dbName}`);try{await this.options.onBecomeHost()}catch(e){throw a.error(`Error in onBecomeHost callback:`,e),this._isHost=!1,e}this.hostReadyResolver&&(this.hostReadyResolver(),this.hostReadyResolver=null,this.hostReadyPromise=null),await new Promise(e=>{this.releaseResolver=e,this.abortController.signal.addEventListener(`abort`,()=>{e()})}),this._isHost=!1,this.releaseResolver=null,a.log(`Tab ${this.options.tabId} lost Host role for ${this.options.dbName}`);try{this.options.onLoseHost()}catch(e){a.error(`Error in onLoseHost callback:`,e)}}})}catch(e){if(e.name===`AbortError`)return;throw a.error(`Error acquiring Host lock:`,e),e}finally{this._isStarted=!1,this.abortController=null}}releaseHost(){this.releaseResolver&&=(this.releaseResolver(),null),this.abortController&&=(this.abortController.abort(),null)}async acquireTransactionLock(){if(!e.isSupported())return()=>{};let t=new AbortController,n=null,r=null,i=new Promise(e=>{r=e});return navigator.locks.request(this.txnLockName,{mode:`exclusive`,signal:t.signal},async e=>{e&&(r?.(),await new Promise(e=>{n=e}))}).catch(e=>{e.name!==`AbortError`&&a.error(`Error acquiring transaction lock:`,e),r?.()}),await i,()=>{n?n():t.abort()}}async hasTransactionLock(){if(!e.isSupported())return!1;try{return(await navigator.locks.query()).held?.some(e=>e.name===this.txnLockName)??!1}catch{return!1}}async close(){this.releaseHost()}},l=class{constructor(){this.listeners=new Set,this.boundHandler=this.handleVisibilityChange.bind(this),typeof document<`u`&&document.addEventListener(`visibilitychange`,this.boundHandler)}handleVisibilityChange(){let e=this.isVisible();this.listeners.forEach(t=>{try{t(e)}catch(e){console.error(`Error in visibility change listener:`,e)}})}isVisible(){return typeof document>`u`?!0:document.visibilityState===`visible`}onVisibilityChange(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}destroy(){typeof document<`u`&&document.removeEventListener(`visibilitychange`,this.boundHandler),this.listeners.clear()}};function u(e){return e instanceof Error?{name:e.name,message:e.message,stack:e.stack}:{name:`Error`,message:String(e)}}function d(e){let t=Error(e.message);return t.name=e.name,e.stack&&(t.stack=e.stack),t}function f(e){return e.t===`req`||e.t===`txn_begin`||e.t===`txn_exec`||e.t===`txn_commit`||e.t===`txn_rollback`||e.t===`txn_heartbeat`}function p(e){return e.t===`res`||e.t===`txn_ack`||e.t===`txn_result`||e.t===`txn_done`||e.t===`txn_error`}function m(){return crypto.randomUUID()}function h(){return crypto.randomUUID()}function g(){return crypto.randomUUID()}var _=class{constructor(e,t,n=3e4){this.dbName=e,this.tabId=t,this.defaultTimeoutMs=n,this.pending=new Map,this.closed=!1,this.channel=new BroadcastChannel(`sqlite:rpc:${e}`),this.channel.onmessage=this.handleMessage.bind(this)}handleMessage(e){if(this.closed)return;let t=e.data;!t||typeof t.t!=`string`||(p(t)?this.handleResponse(t):f(t)&&this.requestHandler&&`from`in t&&t.from!==this.tabId&&this.handleRequest(t))}handleResponse(e){if(`to`in e&&e.to!==this.tabId||!(`id`in e))return;let t=this.pending.get(e.id);if(t)switch(clearTimeout(t.timer),this.pending.delete(e.id),e.t){case`res`:e.ok?t.resolve(e.result):t.reject(d(e.error));break;case`txn_ack`:case`txn_done`:t.resolve(void 0);break;case`txn_result`:e.ok?t.resolve(e.result):t.reject(d(e.error));break;case`txn_error`:t.reject(d(e.error));break}}async handleRequest(e){if(this.requestHandler)try{let t=await this.requestHandler(e);this.sendResponse(e,t)}catch(t){this.sendErrorResponse(e,t)}}sendResponse(e,t){if(this.closed)return;let n=`from`in e?e.from:void 0,r=`id`in e?e.id:void 0;if(!(!n||!r))switch(e.t){case`req`:this.channel.postMessage({t:`res`,to:n,id:r,ok:!0,result:t});break;case`txn_begin`:this.channel.postMessage({t:`txn_ack`,to:n,id:r,txnId:e.txnId});break;case`txn_exec`:this.channel.postMessage({t:`txn_result`,to:n,id:r,txnId:e.txnId,ok:!0,result:t});break;case`txn_commit`:case`txn_rollback`:this.channel.postMessage({t:`txn_done`,to:n,id:r,txnId:e.txnId});break;case`txn_heartbeat`:break}}sendErrorResponse(e,t){if(this.closed)return;let n=`from`in e?e.from:void 0,r=`id`in e?e.id:void 0;if(!n||!r)return;let i=u(t);switch(e.t){case`req`:this.channel.postMessage({t:`res`,to:n,id:r,ok:!1,error:i});break;case`txn_begin`:case`txn_exec`:case`txn_commit`:case`txn_rollback`:this.channel.postMessage({t:`txn_error`,to:n,id:r,txnId:e.txnId,error:i});break}}setRequestHandler(e){this.requestHandler=e}async request(e,t,n){let r=m(),i=n??this.defaultTimeoutMs;return new Promise((n,a)=>{let o=setTimeout(()=>{this.pending.delete(r),a(Error(`RPC timeout after ${i}ms for ${e}`))},i);this.pending.set(r,{resolve:n,reject:a,timer:o}),this.channel.postMessage({t:`req`,from:this.tabId,id:r,op:e,payload:t})})}async txnBegin(e,t=`immediate`,n){let r=m(),i=n??this.defaultTimeoutMs;return new Promise((n,a)=>{let o=setTimeout(()=>{this.pending.delete(r),a(Error(`Transaction begin timeout after ${i}ms`))},i);this.pending.set(r,{resolve:n,reject:a,timer:o}),this.channel.postMessage({t:`txn_begin`,from:this.tabId,id:r,txnId:e,mode:t})})}async txnExec(e,t,n,r){let i=m(),a=r??1e4;return new Promise((r,o)=>{let s=setTimeout(()=>{this.pending.delete(i),o(Error(`Transaction SQL timeout after ${a}ms`))},a);this.pending.set(i,{resolve:r,reject:o,timer:s}),this.channel.postMessage({t:`txn_exec`,from:this.tabId,id:i,txnId:e,op:t,payload:n})})}async txnCommit(e,t){let n=m(),r=t??1e4;return new Promise((t,i)=>{let a=setTimeout(()=>{this.pending.delete(n),i(Error(`Transaction commit timeout after ${r}ms`))},r);this.pending.set(n,{resolve:t,reject:i,timer:a}),this.channel.postMessage({t:`txn_commit`,from:this.tabId,id:n,txnId:e})})}async txnRollback(e,t){let n=m(),r=t??1e4;return new Promise((t,i)=>{let a=setTimeout(()=>{this.pending.delete(n),i(Error(`Transaction rollback timeout after ${r}ms`))},r);this.pending.set(n,{resolve:t,reject:i,timer:a}),this.channel.postMessage({t:`txn_rollback`,from:this.tabId,id:n,txnId:e})})}txnHeartbeat(e){this.closed||this.channel.postMessage({t:`txn_heartbeat`,from:this.tabId,txnId:e})}close(){this.closed=!0,this.channel.close();for(let e of this.pending.values())clearTimeout(e.timer),e.reject(Error(`RPC channel closed`));this.pending.clear()}};const v=new Map,y=new Map;var b=class e{constructor(e,t){this.dbName=e,this.config=t,this.workerQueue=Promise.resolve(),this.activeStorageBackend=`memory`,this.closed=!1}static async create(t){let n=new e(t.dbName,t.config);return await n.initialize(),n}async initialize(){console.log(`Loading SQLite WASM using strategy: ${this.config.loadStrategy}`);let e=await this.loadSQLiteWasm(),t={print:console.log,printErr:console.error};if(this.config.locateFile)t.locateFile=this.config.locateFile;else if(typeof window<`u`){let e=window;e.sqlite3InitModuleState?.locateFile&&(t.locateFile=e.sqlite3InitModuleState.locateFile)}if(console.log(`Initializing SQLite WASM module...`),this.sqlite3=await e(t),!this.sqlite3)throw Error(`Failed to initialize SQLite WASM module`);let n=this.sqlite3;console.log(`SQLite WASM module initialized successfully`);let r=this.config.storageBackend??`auto`,i=this.dbName===`:memory:`?`:memory:`:`/unisqlite/${this.dbName}`;r===`memory`||this.dbName===`:memory:`?(console.log(`Using in-memory database`),this.db=new n.oo1.DB(`:memory:`),this.activeStorageBackend=`memory`):await this.tryCreatePersistentDatabase(n,i,r)||(console.log(`All persistent storage backends failed, using in-memory database`),this.db=new n.oo1.DB(`:memory:`),this.activeStorageBackend=`memory`);try{await this.execInternal(`PRAGMA journal_mode=WAL`),console.log(`Enabled WAL mode`)}catch(e){console.warn(`Could not enable WAL mode:`,e)}}async query(e,t){return(await this.executeSql(e,t)).rows}async queryRaw(e,t){return await this.executeSql(e,t)}async run(e,t){let n=await this.executeSql(e,t);return{rowsAffected:n.rowsAffected??0,lastInsertRowId:n.lastInsertRowId??0}}async exec(e){await this.execInternal(e)}async execRaw(e){await this.execInternal(e,{bypassQueue:!0})}async executeSqlRaw(e,t){return await this.executeSql(e,t,{bypassQueue:!0})}getActiveStorageBackend(){return this.activeStorageBackend}getActiveOpfsVfs(){return this.activeOpfsVfs}isWorkerDbActive(){return!!this.workerPromiser&&this.workerDbId!==void 0}async close(){if(!this.closed){if(this.closed=!0,this.workerPromiser){let e=this.workerPromiser,t=this.workerDbId;try{t!==void 0&&await this.enqueueWorker(async()=>{await e(`close`,{dbId:t})})}catch(e){console.warn(`Failed to close SQLite worker database:`,e)}finally{this.workerDbId=void 0;let t=e.worker;t?.terminate&&t.terminate(),this.workerPromiser=void 0}}this.db&&=(this.db.close(),void 0)}}enqueueWorker(e){let t=async()=>e(),n=this.workerQueue.then(t,t);return this.workerQueue=n.then(()=>void 0,()=>void 0),n}normalizeParams(e){if(!e)return;if(Array.isArray(e))return e;let t=Object.keys(e),n=e;return t.map(e=>n[e])}async execInternal(e,t){if(this.isWorkerDbActive()){let n=async()=>{if(!this.workerPromiser||this.workerDbId===void 0)throw Error(`Database not initialized`);await this.workerPromiser(`exec`,{dbId:this.workerDbId,sql:e})};t?.bypassQueue?await n():await this.enqueueWorker(n);return}if(!this.db)throw Error(`Database not initialized`);this.db.exec(e)}async executeSql(e,t,n){try{if(this.isWorkerDbActive()){let r=async()=>{if(!this.workerPromiser||this.workerDbId===void 0)throw Error(`Database not initialized`);let n=this.normalizeParams(t),r={dbId:this.workerDbId,sql:e,rowMode:`object`,resultRows:[],columnNames:[],countChanges:!0};n&&(r.bind=n);let i=await this.workerPromiser(`exec`,r),a=i.result??i,o=Array.isArray(a.resultRows)?a.resultRows:[],s=Array.isArray(a.columnNames)?a.columnNames:[],c=typeof a.changeCount==`number`?a.changeCount:0,l={dbId:this.workerDbId,sql:`SELECT last_insert_rowid() AS lastInsertRowId`,rowMode:`object`,resultRows:[],columnNames:[]},u=await this.workerPromiser(`exec`,l),d=u.result??u,f=Array.isArray(d.resultRows)?d.resultRows:[];return{rows:o,columns:s,rowsAffected:c,lastInsertRowId:Number(f[0]?.lastInsertRowId??0)}};return n?.bypassQueue?await r():await this.enqueueWorker(r)}if(!this.db||!this.sqlite3)throw Error(`Database not initialized`);let r=this.normalizeParams(t),i=[],a=[],o=this.db.prepare(e);try{let e=o;r&&o.bind(r);let t=typeof e.getColumnCount==`function`?e.getColumnCount():typeof e.columnCount==`number`?e.columnCount:0;if(t>0)if(typeof e.getColumnNames==`function`)a=e.getColumnNames();else for(let e=0;e<t;e++)a.push(o.getColumnName(e));for(;o.step();){let e={};for(let n=0;n<t;n++)e[a[n]]=o.get(n);i.push(e)}return{rows:i,columns:a,rowsAffected:this.db.changes(),lastInsertRowId:Number(this.sqlite3.capi.sqlite3_last_insert_rowid(this.db.pointer)||0)}}finally{o.finalize()}}catch(e){let t=e instanceof Error?e.message:String(e),n=Error(`SQLite error: ${t}`);throw e instanceof Error&&(n.cause=e),n}}async loadSQLiteWasm(){let e=`${this.config.loadStrategy}-${this.config.wasmUrl||this.config.cdnBaseUrl}-${this.config.version}`;if(v.has(e))return v.get(e);let t=this.loadSQLiteWasmInternal();return v.set(e,t),t}async loadSQLiteWasmInternal(){let{loadStrategy:e,wasmUrl:t,cdnBaseUrl:n,version:r,bundlerFriendly:i}=this.config;switch(e){case`npm`:return await this.loadFromNpm();case`cdn`:return await this.loadFromCdn(n,r,i);case`url`:if(!t)throw Error(`wasmUrl must be provided when using 'url' loading strategy`);return await this.loadFromUrl(t);case`module`:return await this.loadAsModule();case`global`:default:return this.loadFromGlobal()}}async loadFromNpm(){try{let e=await import(`@sqlite.org/sqlite-wasm`);return e.default||e}catch(e){return console.warn(`Failed to load SQLite WASM from npm, falling back to CDN:`,e),this.loadFromCdn(this.config.cdnBaseUrl,this.config.version,this.config.bundlerFriendly)}}async loadFromCdn(e,t,n){let r=n?`sqlite3-bundler-friendly.mjs`:`index.mjs`,i=[`https://cdn.jsdelivr.net/npm/@sqlite.org/sqlite-wasm@${t}/${r}`,`https://cdn.jsdelivr.net/npm/@sqlite.org/sqlite-wasm@${t}/dist/${r}`],a;for(let e of i)try{console.log(`Trying to load SQLite WASM from: ${e}`);let t=await import(e);return console.log(`Successfully loaded SQLite WASM from: ${e}`),t.default||t}catch(t){a=t,console.warn(`Failed to load SQLite WASM from ${e}:`,t)}let o=a instanceof Error?a.message:String(a);throw Error(`Failed to load SQLite WASM from any CDN source. Last error: ${o}`)}async loadFromUrl(e){let t=await import(e);return t.default||t.sqlite3InitModule}async loadAsModule(){if(globalThis.importScripts!==void 0)throw Error(`ES6 module loading not supported in Web Worker context`);for(let e of[`./sqlite3.mjs`,`./sqlite3-bundler-friendly.mjs`,`/sqlite3.mjs`])try{let t=await import(e);return t.default||t.sqlite3InitModule}catch(t){console.warn(`Failed to load SQLite WASM from ${e}:`,t)}throw Error(`Could not load SQLite WASM as ES6 module from any known path`)}loadFromGlobal(){if(typeof window<`u`){let e=window;if(e.sqlite3InitModule)return e.sqlite3InitModule}throw Error(`SQLite WASM module not found globally. Please: | ||
| const e=require(`./chunk.cjs`),t=require(`./base.cjs`);let n=require(`debug`);n=e.t(n);const r=`unisqlite`,i=`0.4.0`;function a(e){let t=(0,n.default)(`${r}:${e}`),i=(0,n.default)(`${r}:${e}:warn`),a=(0,n.default)(`${r}:${e}:error`);return a.enabled=!0,{log:t,warn:i,error:a}}const o=a(`host`),s=a(`txn`),c=a(`adapter`),l=a(`wasm`),u=a(`visibility`);var d=class e{constructor(e){this.options=e,this.abortController=null,this._isHost=!1,this._isStarted=!1,this.releaseResolver=null,this.hostReadyResolver=null,this.hostReadyPromise=null,this.lockName=`sqlite:host:${e.dbName}`,this.txnLockName=`sqlite:txn:${e.dbName}`}static isSupported(){return typeof navigator<`u`&&navigator.locks!==void 0}get isHost(){return this._isHost}async start(){if(!this._isStarted){if(!e.isSupported()){o.warn(`Web Locks API not supported. Running in local-only mode.`),this._isStarted=!0,this._isHost=!0,this.options.onBecomeHost().catch(e=>{o.error(`Error in onBecomeHost callback:`,e),this._isHost=!1});return}this.options.checkVisibility&&!this.options.checkVisibility()||(this._isStarted=!0,this.hostReadyPromise=new Promise(e=>{this.hostReadyResolver=e}),this.tryAcquireHost().catch(e=>{o.error(`Error in host election:`,e)}))}}async waitForHost(){if(!this._isHost&&(this.hostReadyPromise||(await this.start(),this.hostReadyPromise)))return this.hostReadyPromise}async tryAcquireHost(){this.abortController=new AbortController;try{await navigator.locks.request(this.lockName,{mode:`exclusive`,signal:this.abortController.signal},async e=>{if(e){this._isHost=!0,o.log(`Tab ${this.options.tabId} became Host for ${this.options.dbName}`);try{await this.options.onBecomeHost()}catch(e){throw o.error(`Error in onBecomeHost callback:`,e),this._isHost=!1,e}this.hostReadyResolver&&(this.hostReadyResolver(),this.hostReadyResolver=null,this.hostReadyPromise=null),await new Promise(e=>{this.releaseResolver=e,this.abortController.signal.addEventListener(`abort`,()=>{e()})}),this._isHost=!1,this.releaseResolver=null,o.log(`Tab ${this.options.tabId} lost Host role for ${this.options.dbName}`);try{this.options.onLoseHost()}catch(e){o.error(`Error in onLoseHost callback:`,e)}}})}catch(e){if(e.name===`AbortError`)return;throw o.error(`Error acquiring Host lock:`,e),e}finally{this._isStarted=!1,this.abortController=null}}releaseHost(){this.releaseResolver&&=(this.releaseResolver(),null),this.abortController&&=(this.abortController.abort(),null)}async acquireTransactionLock(){if(!e.isSupported())return()=>{};let t=new AbortController,n=null,r=null,i=new Promise(e=>{r=e});return navigator.locks.request(this.txnLockName,{mode:`exclusive`,signal:t.signal},async e=>{e&&(r?.(),await new Promise(e=>{n=e}))}).catch(e=>{e.name!==`AbortError`&&o.error(`Error acquiring transaction lock:`,e),r?.()}),await i,()=>{n?n():t.abort()}}async hasTransactionLock(){if(!e.isSupported())return!1;try{return(await navigator.locks.query()).held?.some(e=>e.name===this.txnLockName)??!1}catch{return!1}}async close(){this.releaseHost()}},f=class{constructor(){this.listeners=new Set,this.boundHandler=this.handleVisibilityChange.bind(this),typeof document<`u`&&document.addEventListener(`visibilitychange`,this.boundHandler)}handleVisibilityChange(){let e=this.isVisible();this.listeners.forEach(t=>{try{t(e)}catch(e){u.error(`Error in visibility change listener:`,e)}})}isVisible(){return typeof document>`u`?!0:document.visibilityState===`visible`}onVisibilityChange(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}destroy(){typeof document<`u`&&document.removeEventListener(`visibilitychange`,this.boundHandler),this.listeners.clear()}};function p(e){return e instanceof Error?{name:e.name,message:e.message,stack:e.stack}:{name:`Error`,message:String(e)}}function m(e){let t=Error(e.message);return t.name=e.name,e.stack&&(t.stack=e.stack),t}function h(e){return e.t===`req`||e.t===`txn_begin`||e.t===`txn_exec`||e.t===`txn_commit`||e.t===`txn_rollback`||e.t===`txn_heartbeat`}function g(e){return e.t===`res`||e.t===`txn_ack`||e.t===`txn_result`||e.t===`txn_done`||e.t===`txn_error`}function _(){return crypto.randomUUID()}function v(){return crypto.randomUUID()}function y(){return crypto.randomUUID()}var b=class{constructor(e,t,n=3e4){this.dbName=e,this.tabId=t,this.defaultTimeoutMs=n,this.pending=new Map,this.closed=!1,this.channel=new BroadcastChannel(`sqlite:rpc:${e}`),this.channel.onmessage=this.handleMessage.bind(this)}handleMessage(e){if(this.closed)return;let t=e.data;!t||typeof t.t!=`string`||(g(t)?this.handleResponse(t):h(t)&&this.requestHandler&&`from`in t&&t.from!==this.tabId&&this.handleRequest(t))}handleResponse(e){if(`to`in e&&e.to!==this.tabId||!(`id`in e))return;let t=this.pending.get(e.id);if(t)switch(clearTimeout(t.timer),this.pending.delete(e.id),e.t){case`res`:e.ok?t.resolve(e.result):t.reject(m(e.error));break;case`txn_ack`:case`txn_done`:t.resolve(void 0);break;case`txn_result`:e.ok?t.resolve(e.result):t.reject(m(e.error));break;case`txn_error`:t.reject(m(e.error));break}}async handleRequest(e){if(this.requestHandler)try{let t=await this.requestHandler(e);this.sendResponse(e,t)}catch(t){this.sendErrorResponse(e,t)}}sendResponse(e,t){if(this.closed)return;let n=`from`in e?e.from:void 0,r=`id`in e?e.id:void 0;if(!(!n||!r))switch(e.t){case`req`:this.channel.postMessage({t:`res`,to:n,id:r,ok:!0,result:t});break;case`txn_begin`:this.channel.postMessage({t:`txn_ack`,to:n,id:r,txnId:e.txnId});break;case`txn_exec`:this.channel.postMessage({t:`txn_result`,to:n,id:r,txnId:e.txnId,ok:!0,result:t});break;case`txn_commit`:case`txn_rollback`:this.channel.postMessage({t:`txn_done`,to:n,id:r,txnId:e.txnId});break;case`txn_heartbeat`:break}}sendErrorResponse(e,t){if(this.closed)return;let n=`from`in e?e.from:void 0,r=`id`in e?e.id:void 0;if(!n||!r)return;let i=p(t);switch(e.t){case`req`:this.channel.postMessage({t:`res`,to:n,id:r,ok:!1,error:i});break;case`txn_begin`:case`txn_exec`:case`txn_commit`:case`txn_rollback`:this.channel.postMessage({t:`txn_error`,to:n,id:r,txnId:e.txnId,error:i});break}}setRequestHandler(e){this.requestHandler=e}async request(e,t,n){let r=_(),i=n??this.defaultTimeoutMs;return new Promise((n,a)=>{let o=setTimeout(()=>{this.pending.delete(r),a(Error(`RPC timeout after ${i}ms for ${e}`))},i);this.pending.set(r,{resolve:n,reject:a,timer:o}),this.channel.postMessage({t:`req`,from:this.tabId,id:r,op:e,payload:t})})}async txnBegin(e,t=`immediate`,n){let r=_(),i=n??this.defaultTimeoutMs;return new Promise((n,a)=>{let o=setTimeout(()=>{this.pending.delete(r),a(Error(`Transaction begin timeout after ${i}ms`))},i);this.pending.set(r,{resolve:n,reject:a,timer:o}),this.channel.postMessage({t:`txn_begin`,from:this.tabId,id:r,txnId:e,mode:t})})}async txnExec(e,t,n,r){let i=_(),a=r??1e4;return new Promise((r,o)=>{let s=setTimeout(()=>{this.pending.delete(i),o(Error(`Transaction SQL timeout after ${a}ms`))},a);this.pending.set(i,{resolve:r,reject:o,timer:s}),this.channel.postMessage({t:`txn_exec`,from:this.tabId,id:i,txnId:e,op:t,payload:n})})}async txnCommit(e,t){let n=_(),r=t??1e4;return new Promise((t,i)=>{let a=setTimeout(()=>{this.pending.delete(n),i(Error(`Transaction commit timeout after ${r}ms`))},r);this.pending.set(n,{resolve:t,reject:i,timer:a}),this.channel.postMessage({t:`txn_commit`,from:this.tabId,id:n,txnId:e})})}async txnRollback(e,t){let n=_(),r=t??1e4;return new Promise((t,i)=>{let a=setTimeout(()=>{this.pending.delete(n),i(Error(`Transaction rollback timeout after ${r}ms`))},r);this.pending.set(n,{resolve:t,reject:i,timer:a}),this.channel.postMessage({t:`txn_rollback`,from:this.tabId,id:n,txnId:e})})}txnHeartbeat(e){this.closed||this.channel.postMessage({t:`txn_heartbeat`,from:this.tabId,txnId:e})}close(){this.closed=!0,this.channel.close();for(let e of this.pending.values())clearTimeout(e.timer),e.reject(Error(`RPC channel closed`));this.pending.clear()}};const x=new Map,S=new Map;var C=class e{constructor(e,t){this.dbName=e,this.config=t,this.workerQueue=Promise.resolve(),this.activeStorageBackend=`memory`,this.closed=!1}static async create(t){let n=new e(t.dbName,t.config);return await n.initialize(),n}async initialize(){l.log(`UniSQLite v0.4.0 - Loading SQLite WASM using strategy: ${this.config.loadStrategy}`);let e=await this.loadSQLiteWasm(),t={print:(...e)=>l.log(...e),printErr:(...e)=>l.error(...e)};if(this.config.locateFile)t.locateFile=this.config.locateFile;else if(typeof window<`u`){let e=window;e.sqlite3InitModuleState?.locateFile&&(t.locateFile=e.sqlite3InitModuleState.locateFile)}if(l.log(`Initializing SQLite WASM module...`),this.sqlite3=await e(t),!this.sqlite3)throw Error(`Failed to initialize SQLite WASM module`);let n=this.sqlite3;l.log(`SQLite WASM module initialized successfully`);let r=this.config.storageBackend??`auto`,i=this.dbName===`:memory:`?`:memory:`:`/unisqlite/${this.dbName}`;r===`memory`||this.dbName===`:memory:`?(l.log(`Using in-memory database`),this.db=new n.oo1.DB(`:memory:`),this.activeStorageBackend=`memory`):await this.tryCreatePersistentDatabase(n,i,r)||(l.log(`All persistent storage backends failed, using in-memory database`),this.db=new n.oo1.DB(`:memory:`),this.activeStorageBackend=`memory`);try{await this.execInternal(`PRAGMA journal_mode=WAL`),l.log(`Enabled WAL mode`)}catch(e){l.warn(`Could not enable WAL mode:`,e)}}async query(e,t){return(await this.executeSql(e,t)).rows}async queryRaw(e,t){return await this.executeSql(e,t)}async run(e,t){let n=await this.executeSql(e,t);return{rowsAffected:n.rowsAffected??0,lastInsertRowId:n.lastInsertRowId??0}}async exec(e){await this.execInternal(e)}async execRaw(e){await this.execInternal(e,{bypassQueue:!0})}async executeSqlRaw(e,t){return await this.executeSql(e,t,{bypassQueue:!0})}getActiveStorageBackend(){return this.activeStorageBackend}getActiveOpfsVfs(){return this.activeOpfsVfs}isWorkerDbActive(){return!!this.workerPromiser&&this.workerDbId!==void 0}async close(){if(!this.closed){if(this.closed=!0,this.workerPromiser){let e=this.workerPromiser,t=this.workerDbId;try{t!==void 0&&await this.enqueueWorker(async()=>{await e(`close`,{dbId:t})})}catch(e){l.warn(`Failed to close SQLite worker database:`,e)}finally{this.workerDbId=void 0;let t=e.worker;t?.terminate&&t.terminate(),this.workerPromiser=void 0}}this.db&&=(this.db.close(),void 0)}}enqueueWorker(e){let t=async()=>e(),n=this.workerQueue.then(t,t);return this.workerQueue=n.then(()=>void 0,()=>void 0),n}normalizeParams(e){if(!e)return;if(Array.isArray(e))return e;let t=Object.keys(e),n=e;return t.map(e=>n[e])}async execInternal(e,t){if(this.isWorkerDbActive()){let n=async()=>{if(!this.workerPromiser||this.workerDbId===void 0)throw Error(`Database not initialized`);await this.workerPromiser(`exec`,{dbId:this.workerDbId,sql:e})};t?.bypassQueue?await n():await this.enqueueWorker(n);return}if(!this.db)throw Error(`Database not initialized`);this.db.exec(e)}async executeSql(e,t,n){try{if(this.isWorkerDbActive()){let r=async()=>{if(!this.workerPromiser||this.workerDbId===void 0)throw Error(`Database not initialized`);let n=this.normalizeParams(t),r={dbId:this.workerDbId,sql:e,rowMode:`object`,resultRows:[],columnNames:[],countChanges:!0};n&&(r.bind=n);let i=await this.workerPromiser(`exec`,r),a=i.result??i,o=Array.isArray(a.resultRows)?a.resultRows:[],s=Array.isArray(a.columnNames)?a.columnNames:[],c=typeof a.changeCount==`number`?a.changeCount:0,l={dbId:this.workerDbId,sql:`SELECT last_insert_rowid() AS lastInsertRowId`,rowMode:`object`,resultRows:[],columnNames:[]},u=await this.workerPromiser(`exec`,l),d=u.result??u,f=Array.isArray(d.resultRows)?d.resultRows:[];return{rows:o,columns:s,rowsAffected:c,lastInsertRowId:Number(f[0]?.lastInsertRowId??0)}};return n?.bypassQueue?await r():await this.enqueueWorker(r)}if(!this.db||!this.sqlite3)throw Error(`Database not initialized`);let r=this.normalizeParams(t),i=[],a=[],o=this.db.prepare(e);try{let e=o;r&&o.bind(r);let t=typeof e.getColumnCount==`function`?e.getColumnCount():typeof e.columnCount==`number`?e.columnCount:0;if(t>0)if(typeof e.getColumnNames==`function`)a=e.getColumnNames();else for(let e=0;e<t;e++)a.push(o.getColumnName(e));for(;o.step();){let e={};for(let n=0;n<t;n++)e[a[n]]=o.get(n);i.push(e)}return{rows:i,columns:a,rowsAffected:this.db.changes(),lastInsertRowId:Number(this.sqlite3.capi.sqlite3_last_insert_rowid(this.db.pointer)||0)}}finally{o.finalize()}}catch(e){let t=e instanceof Error?e.message:String(e),n=Error(`SQLite error: ${t}`);throw e instanceof Error&&(n.cause=e),n}}async loadSQLiteWasm(){let e=`${this.config.loadStrategy}-${this.config.wasmUrl||this.config.cdnBaseUrl}-${this.config.version}`;if(x.has(e))return x.get(e);let t=this.loadSQLiteWasmInternal();return x.set(e,t),t}async loadSQLiteWasmInternal(){let{loadStrategy:e,wasmUrl:t,cdnBaseUrl:n,version:r,bundlerFriendly:i}=this.config;switch(e){case`npm`:return await this.loadFromNpm();case`cdn`:return await this.loadFromCdn(n,r,i);case`url`:if(!t)throw Error(`wasmUrl must be provided when using 'url' loading strategy`);return await this.loadFromUrl(t);case`module`:return await this.loadAsModule();case`global`:default:return this.loadFromGlobal()}}async loadFromNpm(){try{let e=await import(`@sqlite.org/sqlite-wasm`);return e.default||e}catch(e){return l.warn(`Failed to load SQLite WASM from npm, falling back to CDN:`,e),this.loadFromCdn(this.config.cdnBaseUrl,this.config.version,this.config.bundlerFriendly)}}async loadFromCdn(e,t,n){let r=n?`sqlite3-bundler-friendly.mjs`:`index.mjs`,i=[`https://cdn.jsdelivr.net/npm/@sqlite.org/sqlite-wasm@${t}/${r}`,`https://cdn.jsdelivr.net/npm/@sqlite.org/sqlite-wasm@${t}/dist/${r}`],a;for(let e of i)try{l.log(`Trying to load SQLite WASM from: ${e}`);let t=await import(e);return l.log(`Successfully loaded SQLite WASM from: ${e}`),t.default||t}catch(t){a=t,l.warn(`Failed to load SQLite WASM from ${e}:`,t)}let o=a instanceof Error?a.message:String(a);throw Error(`Failed to load SQLite WASM from any CDN source. Last error: ${o}`)}async loadFromUrl(e){let t=await import(e);return t.default||t.sqlite3InitModule}async loadAsModule(){if(globalThis.importScripts!==void 0)throw Error(`ES6 module loading not supported in Web Worker context`);for(let e of[`./sqlite3.mjs`,`./sqlite3-bundler-friendly.mjs`,`/sqlite3.mjs`])try{let t=await import(e);return t.default||t.sqlite3InitModule}catch(t){l.warn(`Failed to load SQLite WASM from ${e}:`,t)}throw Error(`Could not load SQLite WASM as ES6 module from any known path`)}loadFromGlobal(){if(typeof window<`u`){let e=window;if(e.sqlite3InitModule)return e.sqlite3InitModule}throw Error(`SQLite WASM module not found globally. Please: | ||
| 1. Install via npm: npm install @sqlite.org/sqlite-wasm | ||
| 2. Or set loadStrategy to 'cdn' for automatic CDN loading | ||
| 3. Or include SQLite WASM script in your HTML before using UniSqlite`)}async loadSQLiteWorkerPromiserFactory(){let e=`worker-${this.config.loadStrategy}-${this.config.wasmUrl||this.config.cdnBaseUrl}-${this.config.version}`;if(y.has(e))return y.get(e);let t=this.loadSQLiteWorkerPromiserFactoryInternal();return y.set(e,t),t}async loadSQLiteWorkerPromiserFactoryInternal(){let{loadStrategy:e,wasmUrl:t,cdnBaseUrl:n,version:r,bundlerFriendly:i}=this.config;switch(e){case`npm`:return await this.loadWorkerPromiserFromNpm();case`cdn`:return await this.loadWorkerPromiserFromCdn(n,r,i);case`url`:if(!t)throw Error(`wasmUrl must be provided when using 'url' loading strategy`);return await this.loadWorkerPromiserFromUrl(t);case`module`:return await this.loadWorkerPromiserAsModule();case`global`:default:return this.loadWorkerPromiserFromGlobal()}}async loadWorkerPromiserFromNpm(){try{let e=(await import(`@sqlite.org/sqlite-wasm`)).sqlite3Worker1Promiser;if(typeof e==`function`)return e;throw Error(`sqlite3Worker1Promiser export not found`)}catch(e){return console.warn(`Failed to load SQLite WASM worker promiser from npm, falling back to CDN:`,e),this.loadWorkerPromiserFromCdn(this.config.cdnBaseUrl,this.config.version,this.config.bundlerFriendly)}}async loadWorkerPromiserFromCdn(e,t,n){let r=n?`sqlite3-bundler-friendly.mjs`:`index.mjs`,i=[`${e}@${t}/${r}`,`${e}@${t}/dist/${r}`],a;for(let e of i)try{console.log(`Trying to load SQLite WASM worker promiser from: ${e}`);let t=(await import(e)).sqlite3Worker1Promiser;if(typeof t==`function`)return console.log(`Successfully loaded SQLite WASM worker promiser from: ${e}`),t;throw Error(`sqlite3Worker1Promiser export not found`)}catch(t){a=t,console.warn(`Failed to load SQLite WASM worker promiser from ${e}:`,t)}let o=a instanceof Error?a.message:String(a);throw Error(`Failed to load sqlite3Worker1Promiser from any CDN source. Last error: ${o}`)}async loadWorkerPromiserFromUrl(e){let t=(await import(e)).sqlite3Worker1Promiser;if(typeof t!=`function`)throw Error(`sqlite3Worker1Promiser export not found in module loaded from ${e}`);return t}async loadWorkerPromiserAsModule(){if(globalThis.importScripts!==void 0)throw Error(`ES6 module loading not supported in Web Worker context`);for(let e of[`./sqlite3.mjs`,`./sqlite3-bundler-friendly.mjs`,`/sqlite3.mjs`])try{let t=(await import(e)).sqlite3Worker1Promiser;if(typeof t==`function`)return t}catch(t){console.warn(`Failed to load SQLite WASM worker promiser from ${e}:`,t)}throw Error(`Could not load sqlite3Worker1Promiser as ES6 module from any known path`)}loadWorkerPromiserFromGlobal(){let e=globalThis;if(typeof e.sqlite3Worker1Promiser==`function`)return e.sqlite3Worker1Promiser;throw Error(`SQLite WASM worker promiser not found globally. Please: | ||
| 3. Or include SQLite WASM script in your HTML before using UniSqlite`)}async loadSQLiteWorkerPromiserFactory(){let e=`worker-${this.config.loadStrategy}-${this.config.wasmUrl||this.config.cdnBaseUrl}-${this.config.version}`;if(S.has(e))return S.get(e);let t=this.loadSQLiteWorkerPromiserFactoryInternal();return S.set(e,t),t}async loadSQLiteWorkerPromiserFactoryInternal(){let{loadStrategy:e,wasmUrl:t,cdnBaseUrl:n,version:r,bundlerFriendly:i}=this.config;switch(e){case`npm`:return await this.loadWorkerPromiserFromNpm();case`cdn`:return await this.loadWorkerPromiserFromCdn(n,r,i);case`url`:if(!t)throw Error(`wasmUrl must be provided when using 'url' loading strategy`);return await this.loadWorkerPromiserFromUrl(t);case`module`:return await this.loadWorkerPromiserAsModule();case`global`:default:return this.loadWorkerPromiserFromGlobal()}}async loadWorkerPromiserFromNpm(){try{let e=(await import(`@sqlite.org/sqlite-wasm`)).sqlite3Worker1Promiser;if(typeof e==`function`)return e;throw Error(`sqlite3Worker1Promiser export not found`)}catch(e){return l.warn(`Failed to load SQLite WASM worker promiser from npm, falling back to CDN:`,e),this.loadWorkerPromiserFromCdn(this.config.cdnBaseUrl,this.config.version,this.config.bundlerFriendly)}}async loadWorkerPromiserFromCdn(e,t,n){let r=n?`sqlite3-bundler-friendly.mjs`:`index.mjs`,i=[`${e}@${t}/${r}`,`${e}@${t}/dist/${r}`],a;for(let e of i)try{l.log(`Trying to load SQLite WASM worker promiser from: ${e}`);let t=(await import(e)).sqlite3Worker1Promiser;if(typeof t==`function`)return l.log(`Successfully loaded SQLite WASM worker promiser from: ${e}`),t;throw Error(`sqlite3Worker1Promiser export not found`)}catch(t){a=t,l.warn(`Failed to load SQLite WASM worker promiser from ${e}:`,t)}let o=a instanceof Error?a.message:String(a);throw Error(`Failed to load sqlite3Worker1Promiser from any CDN source. Last error: ${o}`)}async loadWorkerPromiserFromUrl(e){let t=(await import(e)).sqlite3Worker1Promiser;if(typeof t!=`function`)throw Error(`sqlite3Worker1Promiser export not found in module loaded from ${e}`);return t}async loadWorkerPromiserAsModule(){if(globalThis.importScripts!==void 0)throw Error(`ES6 module loading not supported in Web Worker context`);for(let e of[`./sqlite3.mjs`,`./sqlite3-bundler-friendly.mjs`,`/sqlite3.mjs`])try{let t=(await import(e)).sqlite3Worker1Promiser;if(typeof t==`function`)return t}catch(t){l.warn(`Failed to load SQLite WASM worker promiser from ${e}:`,t)}throw Error(`Could not load sqlite3Worker1Promiser as ES6 module from any known path`)}loadWorkerPromiserFromGlobal(){let e=globalThis;if(typeof e.sqlite3Worker1Promiser==`function`)return e.sqlite3Worker1Promiser;throw Error(`SQLite WASM worker promiser not found globally. Please: | ||
| 1. Install via npm: npm install @sqlite.org/sqlite-wasm and set loadStrategy to 'npm' | ||
| 2. Or set loadStrategy to 'cdn' for automatic CDN loading | ||
| 3. Or include SQLite WASM worker promiser script in your HTML before using UniSqlite`)}async tryCreatePersistentDatabase(e,t,n){if(n===`opfs`||n===`auto`){let r=this.config.opfsVfsType??`auto`,i=r===`auto`?e.oo1.OpfsDb?[`opfs`]:[`opfs-sahpool`,`opfs`]:r===`sahpool`?[`opfs-sahpool`]:[`opfs`];for(let n of i)if(await this.tryCreateOpfsDatabase(e,t,n))return!0;if(n===`opfs`)throw Error(this.getOpfsUnavailableError())}if(n===`localStorage`||n===`auto`){if(e.oo1.JsStorageDb)if(this.dbName===`local`||this.dbName===`session`)try{return console.log(`Creating localStorage-backed database:`,this.dbName),this.db=new e.oo1.JsStorageDb(this.dbName),this.activeStorageBackend=`localStorage`,console.log(`Successfully created localStorage-backed database`),!0}catch(e){if(console.warn(`localStorage database creation failed:`,e),n===`localStorage`)throw Error(`localStorage database creation failed: ${e instanceof Error?e.message:String(e)}`)}else if(n===`localStorage`)throw Error(`localStorage storage backend requires path to be 'local' or 'session', got '${this.dbName}'. Use storageBackend: 'opfs' for custom database names with persistence.`);else console.log(`Skipping localStorage: path '${this.dbName}' is not 'local' or 'session'`);else if(n===`localStorage`)throw Error(`JsStorageDb is not available in this environment.`)}return!1}getOpfsUnavailableError(){return`OPFS is not available. | ||
| 3. Or include SQLite WASM worker promiser script in your HTML before using UniSqlite`)}async tryCreatePersistentDatabase(e,t,n){if(n===`opfs`||n===`auto`){let r=this.config.opfsVfsType??`auto`,i=r===`auto`?e.oo1.OpfsDb?[`opfs`]:[`opfs-sahpool`,`opfs`]:r===`sahpool`?[`opfs-sahpool`]:[`opfs`];for(let n of i)if(await this.tryCreateOpfsDatabase(e,t,n))return!0;if(n===`opfs`)throw Error(this.getOpfsUnavailableError())}if(n===`localStorage`||n===`auto`){if(e.oo1.JsStorageDb)if(this.dbName===`local`||this.dbName===`session`)try{return l.log(`Creating localStorage-backed database:`,this.dbName),this.db=new e.oo1.JsStorageDb(this.dbName),this.activeStorageBackend=`localStorage`,l.log(`Successfully created localStorage-backed database`),!0}catch(e){if(l.warn(`localStorage database creation failed:`,e),n===`localStorage`)throw Error(`localStorage database creation failed: ${e instanceof Error?e.message:String(e)}`)}else if(n===`localStorage`)throw Error(`localStorage storage backend requires path to be 'local' or 'session', got '${this.dbName}'. Use storageBackend: 'opfs' for custom database names with persistence.`);else l.log(`Skipping localStorage: path '${this.dbName}' is not 'local' or 'session'`);else if(n===`localStorage`)throw Error(`JsStorageDb is not available in this environment.`)}return!1}getOpfsUnavailableError(){return`OPFS is not available. | ||
@@ -14,5 +14,5 @@ SQLite WASM OPFS backends only work in Worker contexts. When running on the main thread, UniSQLite will try to use SQLite WASM's wrapped-worker API (sqlite3Worker1Promiser) under the hood. | ||
| - For VFS 'opfs': COOP/COEP headers are set and SharedArrayBuffer is available | ||
| - Your sqlite load strategy can load sqlite3Worker1Promiser (use sqlite.loadStrategy = 'npm' or 'cdn', or provide it globally)`}async tryCreateOpfsDatabase(e,t,n){if(n===`opfs`){if(e.oo1.OpfsDb)try{return console.log(`Creating OPFS-backed database (OpfsDb):`,t),this.db=new e.oo1.OpfsDb(t),this.workerDbId=void 0,this.activeStorageBackend=`opfs`,this.activeOpfsVfs=`opfs`,console.log(`Successfully created OPFS-backed database (OpfsDb)`),!0}catch(e){console.warn(`OPFS database creation via OpfsDb failed:`,e)}return await this.tryCreateWrappedWorkerOpfsDatabase(t,n)}if(await this.ensureSahpoolVfs(e))try{return console.log(`Creating SAHPool OPFS-backed database:`,t),this.db=new e.oo1.DB(t,`c`,`opfs-sahpool`),this.workerDbId=void 0,this.activeStorageBackend=`opfs`,this.activeOpfsVfs=`opfs-sahpool`,console.log(`Successfully created SAHPool OPFS-backed database`),!0}catch(e){console.warn(`SAHPool OPFS database creation failed:`,e)}return await this.tryCreateWrappedWorkerOpfsDatabase(t,n)}async ensureSahpoolVfs(e){if(globalThis.importScripts===void 0)return!1;let t=`opfs-sahpool`;try{if(e.capi.sqlite3_vfs_find?.(t))return!0}catch(e){console.warn(`SAHPool VFS lookup failed:`,e)}if(typeof e.installOpfsSAHPoolVfs!=`function`)return!1;try{await e.installOpfsSAHPoolVfs({name:t,directory:`/unisqlite-sahpool`})}catch(e){return console.warn(`SAHPool VFS installation failed:`,e),!1}try{return!!e.capi.sqlite3_vfs_find?.(t)}catch{return!0}}createWorkerFromConfig(){if(!this.config.workerUrl||typeof Worker>`u`)return;let e=typeof this.config.workerUrl==`string`?this.config.workerUrl:this.config.workerUrl.href;try{return new Worker(e,{type:`module`})}catch(e){console.warn(`Failed to create Worker from custom workerUrl:`,e);return}}createWorkerFromCdn(e){if(typeof Worker>`u`||typeof Blob>`u`||typeof URL>`u`)return;let t=this.config.cdnBaseUrl,n=this.config.version;if(!t||!n)return;let r=`${`${t}@${n}/sqlite-wasm/jswasm`}/sqlite3-bundler-friendly.mjs`,i=e.installSahpool?[` if (typeof sqlite3.installOpfsSAHPoolVfs === "function") {`,` await sqlite3.installOpfsSAHPoolVfs({ name: "opfs-sahpool", directory: "/unisqlite-sahpool" });`,` }`].join(` | ||
| - Your sqlite load strategy can load sqlite3Worker1Promiser (use sqlite.loadStrategy = 'npm' or 'cdn', or provide it globally)`}async tryCreateOpfsDatabase(e,t,n){if(n===`opfs`){if(e.oo1.OpfsDb)try{return l.log(`Creating OPFS-backed database (OpfsDb):`,t),this.db=new e.oo1.OpfsDb(t),this.workerDbId=void 0,this.activeStorageBackend=`opfs`,this.activeOpfsVfs=`opfs`,l.log(`Successfully created OPFS-backed database (OpfsDb)`),!0}catch(e){l.warn(`OPFS database creation via OpfsDb failed:`,e)}return await this.tryCreateWrappedWorkerOpfsDatabase(t,n)}if(await this.ensureSahpoolVfs(e))try{return l.log(`Creating SAHPool OPFS-backed database:`,t),this.db=new e.oo1.DB(t,`c`,`opfs-sahpool`),this.workerDbId=void 0,this.activeStorageBackend=`opfs`,this.activeOpfsVfs=`opfs-sahpool`,l.log(`Successfully created SAHPool OPFS-backed database`),!0}catch(e){l.warn(`SAHPool OPFS database creation failed:`,e)}return await this.tryCreateWrappedWorkerOpfsDatabase(t,n)}async ensureSahpoolVfs(e){if(globalThis.importScripts===void 0)return!1;let t=`opfs-sahpool`;try{if(e.capi.sqlite3_vfs_find?.(t))return!0}catch(e){l.warn(`SAHPool VFS lookup failed:`,e)}if(typeof e.installOpfsSAHPoolVfs!=`function`)return!1;try{await e.installOpfsSAHPoolVfs({name:t,directory:`/unisqlite-sahpool`})}catch(e){return l.warn(`SAHPool VFS installation failed:`,e),!1}try{return!!e.capi.sqlite3_vfs_find?.(t)}catch{return!0}}createWorkerFromConfig(){if(!this.config.workerUrl||typeof Worker>`u`)return;let e=typeof this.config.workerUrl==`string`?this.config.workerUrl:this.config.workerUrl.href;try{return new Worker(e,{type:`module`})}catch(e){l.warn(`Failed to create Worker from custom workerUrl:`,e);return}}createWorkerFromCdn(e){if(typeof Worker>`u`||typeof Blob>`u`||typeof URL>`u`)return;let t=this.config.cdnBaseUrl,n=this.config.version;if(!t||!n)return;let r=`${`${t}@${n}/sqlite-wasm/jswasm`}/sqlite3-bundler-friendly.mjs`,i=e.installSahpool?[` if (typeof sqlite3.installOpfsSAHPoolVfs === "function") {`,` await sqlite3.installOpfsSAHPoolVfs({ name: "opfs-sahpool", directory: "/unisqlite-sahpool" });`,` }`].join(` | ||
| `):``,a=[`import sqlite3InitModule from ${JSON.stringify(r)};`,`sqlite3InitModule().then(async (sqlite3) => {`,` try {`,i||` // no-op`,` } catch (e) {`,` console.warn("SAHPool VFS installation failed:", e);`,` }`,` sqlite3.initWorker1API();`,`});`,``].join(` | ||
| `),o=new Blob([a],{type:`text/javascript`}),s=URL.createObjectURL(o),c=new Worker(s,{type:`module`});return c.addEventListener(`message`,()=>{URL.revokeObjectURL(s)},{once:!0}),c.addEventListener(`error`,()=>{URL.revokeObjectURL(s)},{once:!0}),c}async getOrCreateWorkerPromiser(e){if(this.workerPromiser)return this.workerPromiser;if(this.workerPromiserInitPromise)return await this.workerPromiserInitPromise;let t=await this.loadSQLiteWorkerPromiserFactory(),n=this.config.storageBackend===`opfs`||this.config.opfsVfsType===`opfs`||this.config.opfsVfsType===`sahpool`,r=this.config.loadStrategy===`global`&&!n?5e3:2e4;this.workerPromiserInitPromise=new Promise((n,i)=>{let a=!1,o=setTimeout(()=>{a||(a=!0,i(Error(`SQLite worker initialization timed out after ${r}ms`)))},r),s=(e,t)=>{a||(a=!0,clearTimeout(o),e(t))},c=e=>{s(i,e instanceof Error?e:Error(String(e)))},l;try{l=t({...e?.worker?{worker:e.worker}:{},onready:e=>{if(typeof e==`function`){s(n,e);return}if(typeof l==`function`){s(n,l);return}if(l&&typeof l.then==`function`){l.then(e=>s(n,e),e=>c(e));return}c(Error(`sqlite3Worker1Promiser did not provide a usable promiser`))},onerror:e=>{let t=e instanceof Error?e.message:String(e);c(Error(`SQLite worker error: ${t}`))}}),l&&typeof l.then==`function`&&l.then(e=>s(n,e),e=>c(e))}catch(e){c(e)}});let i=await this.workerPromiserInitPromise;return this.workerPromiser=i,i}async tryCreateWrappedWorkerOpfsDatabase(e,t){try{let n=!this.workerPromiser&&!this.workerPromiserInitPromise?(()=>{let e=this.createWorkerFromConfig()??(t===`opfs-sahpool`?this.createWorkerFromCdn({installSahpool:!0}):this.createWorkerFromCdn({installSahpool:!1}));return e?{worker:e}:void 0})():void 0,r=await(await this.getOrCreateWorkerPromiser(n))(`open`,{filename:`file:${e}`,vfs:t}),i=r.dbId??r.result?.dbId;if(i===void 0)throw Error(`SQLite worker did not return a dbId`);if(typeof i!=`number`&&typeof i!=`string`)throw Error(`SQLite worker returned an invalid dbId (type=${typeof i})`);return this.db=void 0,this.workerDbId=i,this.activeStorageBackend=`opfs`,this.activeOpfsVfs=t,console.log(`Successfully created OPFS-backed database via wrapped worker (${t}):`,e),!0}catch(e){return console.warn(`Wrapped-worker OPFS database creation failed (vfs=${t}):`,e),!1}}},x=class{constructor(e,t,n){this.dbHost=e,this.hostElection=t,this.activeTxn=null,this.txnQueue=[],this.heartbeatTimers=new Map,this.txnPending=!1,this.rpcQueue=[],this.txnTimeoutMs=n?.txnTimeoutMs??3e4,this.opTimeoutMs=n?.opTimeoutMs??1e4,this.maxQueueSize=n?.maxQueueSize??10,this.heartbeatTimeoutMs=n?.heartbeatTimeoutMs??15e3}startWatchdog(){this.watchdogTimer||=setInterval(()=>{if(this.activeTxn){let e=Date.now()-this.activeTxn.lastActivityAt;e>this.txnTimeoutMs&&(o.warn(`Transaction ${this.activeTxn.txnId} timed out after ${e}ms, rolling back`),this.forceRollback())}let e=Date.now(),t=this.txnQueue.filter(t=>e-t.enqueuedAt>this.txnTimeoutMs);for(let e of t){let t=this.txnQueue.indexOf(e);t!==-1&&(this.txnQueue.splice(t,1),e.reject(Error(`Transaction queue wait timeout`)))}},5e3)}stopWatchdog(){this.watchdogTimer&&=(clearInterval(this.watchdogTimer),void 0)}getActiveTransaction(){return this.activeTxn}hasActiveTransaction(){return this.activeTxn!==null}isTransactionBlocking(){return this.activeTxn!==null||this.txnPending}async waitForTransactionSlot(){if(this.isTransactionBlocking())return new Promise((e,t)=>{this.rpcQueue.push({resolve:e,reject:t})})}async beginTransaction(e,t,n=`immediate`){if(this.activeTxn||this.txnPending){if(this.txnQueue.length>=this.maxQueueSize)throw Error(`Transaction queue full`);await new Promise((r,i)=>{this.txnQueue.push({txnId:e,originTabId:t,mode:n,resolve:r,reject:i,enqueuedAt:Date.now()})})}this.txnPending=!0;try{this.txnLockRelease=await this.hostElection.acquireTransactionLock();let r=n===`deferred`?`BEGIN`:n===`exclusive`?`BEGIN EXCLUSIVE`:`BEGIN IMMEDIATE`;await this.dbHost.execRaw(r),this.activeTxn={txnId:e,originTabId:t,startedAt:Date.now(),lastActivityAt:Date.now(),mode:n},this.resetHeartbeatTimer(e)}catch(e){throw this.txnLockRelease?.(),this.txnLockRelease=void 0,this.txnPending=!1,this.processQueue(),this.processRpcQueue(),e}finally{this.txnPending=!1}}async execInTransaction(e,t){return this.validateActiveTxn(e),this.activeTxn.lastActivityAt=Date.now(),this.resetHeartbeatTimer(e),await t()}recordHeartbeat(e){this.activeTxn?.txnId===e&&(this.activeTxn.lastActivityAt=Date.now(),this.resetHeartbeatTimer(e))}async commitTransaction(e){this.validateActiveTxn(e);try{await this.dbHost.execRaw(`COMMIT`)}finally{this.endTransaction()}}async rollbackTransaction(e){this.validateActiveTxn(e);try{await this.dbHost.execRaw(`ROLLBACK`)}finally{this.endTransaction()}}forceRollback(){if(this.activeTxn){try{this.dbHost.execRaw(`ROLLBACK`).catch(e=>{o.error(`Force rollback failed:`,e)})}catch(e){o.error(`Force rollback failed:`,e)}this.endTransaction()}}endTransaction(){if(this.activeTxn){let e=this.heartbeatTimers.get(this.activeTxn.txnId);e&&(clearTimeout(e),this.heartbeatTimers.delete(this.activeTxn.txnId)),this.activeTxn=null}this.txnLockRelease&&=(this.txnLockRelease(),void 0),this.processQueue(),this.processRpcQueue()}processQueue(){this.txnQueue.length>0&&!this.activeTxn&&!this.txnPending&&this.txnQueue.shift().resolve()}processRpcQueue(){if(this.activeTxn||this.txnPending)return;let e=this.rpcQueue;this.rpcQueue=[];for(let{resolve:t}of e)t()}resetHeartbeatTimer(e){let t=this.heartbeatTimers.get(e);t&&clearTimeout(t);let n=setTimeout(()=>{this.activeTxn?.txnId===e&&(o.warn(`No heartbeat for transaction ${e} in ${this.heartbeatTimeoutMs}ms, rolling back`),this.forceRollback())},this.heartbeatTimeoutMs);this.heartbeatTimers.set(e,n)}validateActiveTxn(e){if(!this.activeTxn)throw Error(`No active transaction (expected ${e})`);if(this.activeTxn.txnId!==e)throw Error(`Transaction ID mismatch: expected ${this.activeTxn.txnId}, got ${e}`);let t=Date.now()-this.activeTxn.lastActivityAt;if(t>this.txnTimeoutMs)throw this.forceRollback(),Error(`Transaction ${e} timed out after ${t}ms`)}async close(){this.stopWatchdog(),this.activeTxn&&this.forceRollback();for(let e of this.txnQueue)e.reject(Error(`Transaction session manager closed`));this.txnQueue=[];for(let e of this.rpcQueue)e.reject(Error(`Transaction session manager closed`));this.rpcQueue=[];for(let e of this.heartbeatTimers.values())clearTimeout(e);this.heartbeatTimers.clear()}},S=class{constructor(e,t,n=5e3){this.rpcChannel=e,this.txnId=t,this.heartbeatIntervalMs=n,this.committed=!1,this.rolledBack=!1,this.startHeartbeat()}startHeartbeat(){this.heartbeatInterval=setInterval(()=>{!this.committed&&!this.rolledBack&&this.rpcChannel.txnHeartbeat(this.txnId)},this.heartbeatIntervalMs)}stopHeartbeat(){this.heartbeatInterval&&=(clearInterval(this.heartbeatInterval),void 0)}ensureActive(){if(this.committed)throw Error(`Transaction already committed`);if(this.rolledBack)throw Error(`Transaction already rolled back`)}async query(e,t){return this.ensureActive(),(await this.rpcChannel.txnExec(this.txnId,`query`,{sql:e,params:t})).rows}async queryRaw(e,t){return this.ensureActive(),await this.rpcChannel.txnExec(this.txnId,`queryRaw`,{sql:e,params:t})}async run(e,t){this.ensureActive();let n=await this.rpcChannel.txnExec(this.txnId,`run`,{sql:e,params:t});return{rowsAffected:n.rowsAffected??0,lastInsertRowId:n.lastInsertRowId??0}}async exec(e){this.ensureActive(),await this.rpcChannel.txnExec(this.txnId,`exec`,{sql:e})}async transaction(e){this.ensureActive();let t=e(this);return t instanceof Promise?await t:t}async asyncTransaction(e,t){return this.ensureActive(),await e(this)}getConnectionType(){return`asyncTxn`}async close(){}async _commit(){this.ensureActive(),this.stopHeartbeat();try{await this.rpcChannel.txnCommit(this.txnId),this.committed=!0}catch(e){throw this.rolledBack=!0,e}}async _rollback(){if(!(this.committed||this.rolledBack)){this.stopHeartbeat();try{await this.rpcChannel.txnRollback(this.txnId)}finally{this.rolledBack=!0}}}isCommitted(){return this.committed}isRolledBack(){return this.rolledBack}},C=class{constructor(e,t){this.dbHost=e,this.isAsync=t}async query(e,t){return(await this.dbHost.executeSqlRaw(e,t)).rows}async queryRaw(e,t){return await this.dbHost.executeSqlRaw(e,t)}async run(e,t){let n=await this.dbHost.executeSqlRaw(e,t);return{rowsAffected:n.rowsAffected??0,lastInsertRowId:n.lastInsertRowId??0}}async exec(e){await this.dbHost.execRaw(e)}async transaction(e){let t=e(this);return t instanceof Promise?await t:t}async asyncTransaction(e){return await e(this)}getConnectionType(){return this.isAsync?`asyncTxn`:`syncTxn`}async close(){}},w=class e extends t.t{constructor(e){let t=e.path??e.name??`default`;super({...e,path:t}),this.dbHost=null,this.txnSessionManager=null,this.initialized=!1,this.closed=!1,this.options={...e,path:t},this.tabId=h(),this.sqliteConfig={loadStrategy:`global`,storageBackend:`auto`,opfsVfsType:`auto`,cdnBaseUrl:`https://cdn.jsdelivr.net/npm/@sqlite.org/sqlite-wasm`,version:`3.50.1-build1`,bundlerFriendly:!1,...e.sqlite},c.isSupported()||(s.warn(`Web Locks API not supported. Falling back to memory-only storage.`),this.sqliteConfig.storageBackend=`memory`),this.visibilityManager=new l,this.rpcChannel=new _(t,this.tabId),this.hostElection=new c({dbName:t,tabId:this.tabId,onBecomeHost:()=>this.becomeHost(),onLoseHost:()=>this.loseHost(),checkVisibility:()=>this.visibilityManager.isVisible()}),this.visibilityUnsubscribe=this.visibilityManager.onVisibilityChange(e=>{this.handleVisibilityChange(e)})}static async create(t){let n=new e(t);return await n.initialize(),n}getTabId(){return this.tabId}get isHost(){return this.hostElection.isHost}async initialize(){if(!this.initialized){if(this.initPromise)return this.initPromise;this.initPromise=this.doInitialize(),await this.initPromise,this.initialized=!0}}async doInitialize(){this.becomeHostPromise=new Promise(e=>{this.becomeHostResolver=e}),await this.hostElection.start();let e=new Promise(e=>{setTimeout(()=>e(`timeout`),500)});await Promise.race([this.becomeHostPromise.then(()=>`host`),e])===`host`||this.hostElection.isHost&&await this.becomeHostPromise}async becomeHost(){s.log(`Tab ${this.tabId} becoming Host for ${this.options.path}`),this.dbHost=await b.create({dbName:this.options.path,config:this.sqliteConfig}),this.txnSessionManager=new x(this.dbHost,this.hostElection),this.txnSessionManager.startWatchdog(),this.rpcChannel.setRequestHandler(this.handleRequest.bind(this)),this.becomeHostResolver&&=(this.becomeHostResolver(),void 0)}loseHost(){s.log(`Tab ${this.tabId} losing Host for ${this.options.path}`),this.rpcChannel.setRequestHandler(void 0),this.txnSessionManager&&=(this.txnSessionManager.close(),null),this.dbHost&&=(this.dbHost.close(),null)}handleVisibilityChange(e){e&&!this.hostElection.isHost&&!this.closed&&this.hostElection.start()}async handleRequest(e){if(!this.dbHost)throw Error(`Not Host`);switch(e.t){case`req`:return await this.handleRpcRequest(e);case`txn_begin`:return await this.handleTxnBegin(e);case`txn_exec`:return await this.handleTxnExec(e);case`txn_commit`:return await this.handleTxnCommit(e);case`txn_rollback`:return await this.handleTxnRollback(e);case`txn_heartbeat`:this.handleTxnHeartbeat(e);return;default:throw Error(`Unknown request type: ${e.t}`)}}async handleRpcRequest(e){let{op:t,payload:n}=e,{sql:r,params:i}=n;switch(this.txnSessionManager&&await this.txnSessionManager.waitForTransactionSlot(),t){case`query`:return{rows:await this.dbHost.query(r,i),columns:[]};case`queryRaw`:return await this.dbHost.queryRaw(r,i);case`run`:return await this.dbHost.run(r,i);case`exec`:return await this.dbHost.exec(r),null;default:throw Error(`Unknown RPC operation: ${String(t)}`)}}async handleTxnBegin(e){await this.txnSessionManager.beginTransaction(e.txnId,e.from,e.mode)}async handleTxnExec(e){let{txnId:t,op:n,payload:r}=e,{sql:i,params:a}=r;return await this.txnSessionManager.execInTransaction(t,async()=>{switch(n){case`query`:return{rows:await this.dbHost.query(i,a),columns:[]};case`queryRaw`:return await this.dbHost.queryRaw(i,a);case`run`:return await this.dbHost.run(i,a);case`exec`:return await this.dbHost.exec(i),null;default:throw Error(`Unknown transaction operation: ${String(n)}`)}})}async handleTxnCommit(e){await this.txnSessionManager.commitTransaction(e.txnId)}async handleTxnRollback(e){await this.txnSessionManager.rollbackTransaction(e.txnId)}handleTxnHeartbeat(e){this.txnSessionManager?.recordHeartbeat(e.txnId)}async query(e,t){return await this.initialize(),this.isHost&&this.dbHost?await this.dbHost.query(e,t):(await this.rpcChannel.request(`query`,{sql:e,params:t})).rows}async queryRaw(e,t){return await this.initialize(),this.isHost&&this.dbHost?await this.dbHost.queryRaw(e,t):await this.rpcChannel.request(`queryRaw`,{sql:e,params:t})}async run(e,t){return await this.initialize(),this.isHost&&this.dbHost?await this.dbHost.run(e,t):await this.rpcChannel.request(`run`,{sql:e,params:t})}async exec(e){if(await this.initialize(),this.isHost&&this.dbHost){await this.dbHost.exec(e);return}await this.rpcChannel.request(`exec`,{sql:e})}async transaction(e){return await this.initialize(),this.isHost&&this.dbHost?await this.executeLocalTransaction(e,!1):await this.executeRemoteTransaction(e)}async asyncTransaction(e,t){return await this.initialize(),this.isHost&&this.dbHost?await this.executeLocalAsyncTransaction(e,t):await this.executeRemoteTransaction(e,t)}getConnectionType(){return`direct`}async close(){this.closed||(this.closed=!0,this.visibilityUnsubscribe?.(),await this.hostElection.close(),this.rpcChannel.close(),this.visibilityManager.destroy(),this.txnSessionManager&&=(await this.txnSessionManager.close(),null),this.dbHost&&=(await this.dbHost.close(),null))}async executeLocalTransaction(e,t){await this.dbHost.execRaw(`BEGIN`);let n=new C(this.dbHost,t);try{let t=e(n),r=t instanceof Promise?await t:t;return await this.dbHost.execRaw(`COMMIT`),r}catch(e){try{await this.dbHost.execRaw(`ROLLBACK`)}catch(e){console.error(`Rollback failed:`,e)}throw e}}async executeLocalAsyncTransaction(e,t){let n=t?.timeoutMs??3e4;await this.dbHost.execRaw(`BEGIN IMMEDIATE`);let r=new C(this.dbHost,!0),i,a=!1;try{let t=new Promise((e,t)=>{i=setTimeout(()=>{a||t(Error(`Async transaction timeout after ${n}ms`))},n)}),o=await Promise.race([e(r),t]);return a=!0,i&&clearTimeout(i),await this.dbHost.execRaw(`COMMIT`),o}catch(e){a=!0,i&&clearTimeout(i);try{await this.dbHost.execRaw(`ROLLBACK`)}catch(e){console.error(`Rollback failed:`,e)}throw e}}async executeRemoteTransaction(e,t){let n=g(),r=t?.timeoutMs??3e4;await this.rpcChannel.txnBegin(n,`immediate`,r);let i=new S(this.rpcChannel,n),a,o=!1;try{let t=new Promise((e,t)=>{a=setTimeout(()=>{o||t(Error(`Remote transaction timeout after ${r}ms`))},r)}),n=e(i),s=n instanceof Promise?n:Promise.resolve(n),c=await Promise.race([s,t]);return o=!0,a&&clearTimeout(a),await i._commit(),c}catch(e){o=!0,a&&clearTimeout(a);try{await i._rollback()}catch(e){console.error(`Remote rollback failed:`,e)}throw e}}getSQLiteInfo(){let e=this.isHost?this.dbHost!==null:this.initialized&&!this.closed;return{config:this.sqliteConfig,isInitialized:this.initialized,isHost:this.isHost,isReady:e,tabId:this.tabId,hasDatabase:this.dbHost!==null,usesWorker:this.dbHost?.isWorkerDbActive()??!1,activeStorageBackend:this.dbHost?.getActiveStorageBackend()??`unknown`,activeOpfsVfs:this.dbHost?.getActiveOpfsVfs()}}getActiveStorageBackend(){return this.dbHost?.getActiveStorageBackend()??`unknown`}};Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return f}}); | ||
| `),o=new Blob([a],{type:`text/javascript`}),s=URL.createObjectURL(o),c=new Worker(s,{type:`module`});return c.addEventListener(`message`,()=>{URL.revokeObjectURL(s)},{once:!0}),c.addEventListener(`error`,()=>{URL.revokeObjectURL(s)},{once:!0}),c}async getOrCreateWorkerPromiser(e){if(this.workerPromiser)return this.workerPromiser;if(this.workerPromiserInitPromise)return await this.workerPromiserInitPromise;let t=await this.loadSQLiteWorkerPromiserFactory(),n=this.config.storageBackend===`opfs`||this.config.opfsVfsType===`opfs`||this.config.opfsVfsType===`sahpool`,r=this.config.loadStrategy===`global`&&!n?5e3:2e4;this.workerPromiserInitPromise=new Promise((n,i)=>{let a=!1,o=setTimeout(()=>{a||(a=!0,i(Error(`SQLite worker initialization timed out after ${r}ms`)))},r),s=(e,t)=>{a||(a=!0,clearTimeout(o),e(t))},c=e=>{s(i,e instanceof Error?e:Error(String(e)))},l;try{l=t({...e?.worker?{worker:e.worker}:{},onready:e=>{if(typeof e==`function`){s(n,e);return}if(typeof l==`function`){s(n,l);return}if(l&&typeof l.then==`function`){l.then(e=>s(n,e),e=>c(e));return}c(Error(`sqlite3Worker1Promiser did not provide a usable promiser`))},onerror:e=>{let t=e instanceof Error?e.message:String(e);c(Error(`SQLite worker error: ${t}`))}}),l&&typeof l.then==`function`&&l.then(e=>s(n,e),e=>c(e))}catch(e){c(e)}});let i=await this.workerPromiserInitPromise;return this.workerPromiser=i,i}async tryCreateWrappedWorkerOpfsDatabase(e,t){try{let n=!this.workerPromiser&&!this.workerPromiserInitPromise?(()=>{let e=this.createWorkerFromConfig()??(t===`opfs-sahpool`?this.createWorkerFromCdn({installSahpool:!0}):this.createWorkerFromCdn({installSahpool:!1}));return e?{worker:e}:void 0})():void 0,r=await(await this.getOrCreateWorkerPromiser(n))(`open`,{filename:`file:${e}`,vfs:t}),i=r.dbId??r.result?.dbId;if(i===void 0)throw Error(`SQLite worker did not return a dbId`);if(typeof i!=`number`&&typeof i!=`string`)throw Error(`SQLite worker returned an invalid dbId (type=${typeof i})`);return this.db=void 0,this.workerDbId=i,this.activeStorageBackend=`opfs`,this.activeOpfsVfs=t,l.log(`Successfully created OPFS-backed database via wrapped worker (${t}):`,e),!0}catch(e){return l.warn(`Wrapped-worker OPFS database creation failed (vfs=${t}):`,e),!1}}},w=class{constructor(e,t,n){this.dbHost=e,this.hostElection=t,this.activeTxn=null,this.txnQueue=[],this.heartbeatTimers=new Map,this.txnPending=!1,this.rpcQueue=[],this.txnTimeoutMs=n?.txnTimeoutMs??3e4,this.opTimeoutMs=n?.opTimeoutMs??1e4,this.maxQueueSize=n?.maxQueueSize??10,this.heartbeatTimeoutMs=n?.heartbeatTimeoutMs??15e3}startWatchdog(){this.watchdogTimer||=setInterval(()=>{if(this.activeTxn){let e=Date.now()-this.activeTxn.lastActivityAt;e>this.txnTimeoutMs&&(s.warn(`Transaction ${this.activeTxn.txnId} timed out after ${e}ms, rolling back`),this.forceRollback())}let e=Date.now(),t=this.txnQueue.filter(t=>e-t.enqueuedAt>this.txnTimeoutMs);for(let e of t){let t=this.txnQueue.indexOf(e);t!==-1&&(this.txnQueue.splice(t,1),e.reject(Error(`Transaction queue wait timeout`)))}},5e3)}stopWatchdog(){this.watchdogTimer&&=(clearInterval(this.watchdogTimer),void 0)}getActiveTransaction(){return this.activeTxn}hasActiveTransaction(){return this.activeTxn!==null}isTransactionBlocking(){return this.activeTxn!==null||this.txnPending}async waitForTransactionSlot(){if(this.isTransactionBlocking())return new Promise((e,t)=>{this.rpcQueue.push({resolve:e,reject:t})})}async beginTransaction(e,t,n=`immediate`){if(this.activeTxn||this.txnPending){if(this.txnQueue.length>=this.maxQueueSize)throw Error(`Transaction queue full`);await new Promise((r,i)=>{this.txnQueue.push({txnId:e,originTabId:t,mode:n,resolve:r,reject:i,enqueuedAt:Date.now()})})}this.txnPending=!0;try{this.txnLockRelease=await this.hostElection.acquireTransactionLock();let r=n===`deferred`?`BEGIN`:n===`exclusive`?`BEGIN EXCLUSIVE`:`BEGIN IMMEDIATE`;await this.dbHost.execRaw(r),this.activeTxn={txnId:e,originTabId:t,startedAt:Date.now(),lastActivityAt:Date.now(),mode:n},this.resetHeartbeatTimer(e)}catch(e){throw this.txnLockRelease?.(),this.txnLockRelease=void 0,this.txnPending=!1,this.processQueue(),this.processRpcQueue(),e}finally{this.txnPending=!1}}async execInTransaction(e,t){return this.validateActiveTxn(e),this.activeTxn.lastActivityAt=Date.now(),this.resetHeartbeatTimer(e),await t()}recordHeartbeat(e){this.activeTxn?.txnId===e&&(this.activeTxn.lastActivityAt=Date.now(),this.resetHeartbeatTimer(e))}async commitTransaction(e){this.validateActiveTxn(e);try{await this.dbHost.execRaw(`COMMIT`)}finally{this.endTransaction()}}async rollbackTransaction(e){this.validateActiveTxn(e);try{await this.dbHost.execRaw(`ROLLBACK`)}finally{this.endTransaction()}}forceRollback(){if(this.activeTxn){try{this.dbHost.execRaw(`ROLLBACK`).catch(e=>{s.error(`Force rollback failed:`,e)})}catch(e){s.error(`Force rollback failed:`,e)}this.endTransaction()}}endTransaction(){if(this.activeTxn){let e=this.heartbeatTimers.get(this.activeTxn.txnId);e&&(clearTimeout(e),this.heartbeatTimers.delete(this.activeTxn.txnId)),this.activeTxn=null}this.txnLockRelease&&=(this.txnLockRelease(),void 0),this.processQueue(),this.processRpcQueue()}processQueue(){this.txnQueue.length>0&&!this.activeTxn&&!this.txnPending&&this.txnQueue.shift().resolve()}processRpcQueue(){if(this.activeTxn||this.txnPending)return;let e=this.rpcQueue;this.rpcQueue=[];for(let{resolve:t}of e)t()}resetHeartbeatTimer(e){let t=this.heartbeatTimers.get(e);t&&clearTimeout(t);let n=setTimeout(()=>{this.activeTxn?.txnId===e&&(s.warn(`No heartbeat for transaction ${e} in ${this.heartbeatTimeoutMs}ms, rolling back`),this.forceRollback())},this.heartbeatTimeoutMs);this.heartbeatTimers.set(e,n)}validateActiveTxn(e){if(!this.activeTxn)throw Error(`No active transaction (expected ${e})`);if(this.activeTxn.txnId!==e)throw Error(`Transaction ID mismatch: expected ${this.activeTxn.txnId}, got ${e}`);let t=Date.now()-this.activeTxn.lastActivityAt;if(t>this.txnTimeoutMs)throw this.forceRollback(),Error(`Transaction ${e} timed out after ${t}ms`)}async close(){this.stopWatchdog(),this.activeTxn&&this.forceRollback();for(let e of this.txnQueue)e.reject(Error(`Transaction session manager closed`));this.txnQueue=[];for(let e of this.rpcQueue)e.reject(Error(`Transaction session manager closed`));this.rpcQueue=[];for(let e of this.heartbeatTimers.values())clearTimeout(e);this.heartbeatTimers.clear()}},T=class{constructor(e,t,n=5e3){this.rpcChannel=e,this.txnId=t,this.heartbeatIntervalMs=n,this.committed=!1,this.rolledBack=!1,this.startHeartbeat()}startHeartbeat(){this.heartbeatInterval=setInterval(()=>{!this.committed&&!this.rolledBack&&this.rpcChannel.txnHeartbeat(this.txnId)},this.heartbeatIntervalMs)}stopHeartbeat(){this.heartbeatInterval&&=(clearInterval(this.heartbeatInterval),void 0)}ensureActive(){if(this.committed)throw Error(`Transaction already committed`);if(this.rolledBack)throw Error(`Transaction already rolled back`)}async query(e,t){return this.ensureActive(),(await this.rpcChannel.txnExec(this.txnId,`query`,{sql:e,params:t})).rows}async queryRaw(e,t){return this.ensureActive(),await this.rpcChannel.txnExec(this.txnId,`queryRaw`,{sql:e,params:t})}async run(e,t){this.ensureActive();let n=await this.rpcChannel.txnExec(this.txnId,`run`,{sql:e,params:t});return{rowsAffected:n.rowsAffected??0,lastInsertRowId:n.lastInsertRowId??0}}async exec(e){this.ensureActive(),await this.rpcChannel.txnExec(this.txnId,`exec`,{sql:e})}async transaction(e){this.ensureActive();let t=e(this);return t instanceof Promise?await t:t}async asyncTransaction(e,t){return this.ensureActive(),await e(this)}getConnectionType(){return`asyncTxn`}async close(){}async _commit(){this.ensureActive(),this.stopHeartbeat();try{await this.rpcChannel.txnCommit(this.txnId),this.committed=!0}catch(e){throw this.rolledBack=!0,e}}async _rollback(){if(!(this.committed||this.rolledBack)){this.stopHeartbeat();try{await this.rpcChannel.txnRollback(this.txnId)}finally{this.rolledBack=!0}}}isCommitted(){return this.committed}isRolledBack(){return this.rolledBack}},E=class{constructor(e,t){this.dbHost=e,this.isAsync=t}async query(e,t){return(await this.dbHost.executeSqlRaw(e,t)).rows}async queryRaw(e,t){return await this.dbHost.executeSqlRaw(e,t)}async run(e,t){let n=await this.dbHost.executeSqlRaw(e,t);return{rowsAffected:n.rowsAffected??0,lastInsertRowId:n.lastInsertRowId??0}}async exec(e){await this.dbHost.execRaw(e)}async transaction(e){let t=e(this);return t instanceof Promise?await t:t}async asyncTransaction(e){return await e(this)}getConnectionType(){return this.isAsync?`asyncTxn`:`syncTxn`}async close(){}},D=class e extends t.t{constructor(e){let t=e.path??e.name??`default`;super({...e,path:t}),this.dbHost=null,this.txnSessionManager=null,this.initialized=!1,this.closed=!1,this.options={...e,path:t},this.tabId=v(),this.sqliteConfig={loadStrategy:`global`,storageBackend:`auto`,opfsVfsType:`auto`,cdnBaseUrl:`https://cdn.jsdelivr.net/npm/@sqlite.org/sqlite-wasm`,version:`3.50.1-build1`,bundlerFriendly:!1,...e.sqlite},d.isSupported()||(c.warn(`Web Locks API not supported. Falling back to memory-only storage.`),this.sqliteConfig.storageBackend=`memory`),this.visibilityManager=new f,this.rpcChannel=new b(t,this.tabId),this.hostElection=new d({dbName:t,tabId:this.tabId,onBecomeHost:()=>this.becomeHost(),onLoseHost:()=>this.loseHost(),checkVisibility:()=>this.visibilityManager.isVisible()}),this.visibilityUnsubscribe=this.visibilityManager.onVisibilityChange(e=>{this.handleVisibilityChange(e)})}static async create(t){let n=new e(t);return await n.initialize(),n}getTabId(){return this.tabId}get isHost(){return this.hostElection.isHost}async initialize(){if(!this.initialized){if(this.initPromise)return this.initPromise;this.initPromise=this.doInitialize(),await this.initPromise,this.initialized=!0}}async doInitialize(){this.becomeHostPromise=new Promise(e=>{this.becomeHostResolver=e}),await this.hostElection.start();let e=new Promise(e=>{setTimeout(()=>e(`timeout`),500)});await Promise.race([this.becomeHostPromise.then(()=>`host`),e])===`host`||this.hostElection.isHost&&await this.becomeHostPromise}async becomeHost(){c.log(`Tab ${this.tabId} becoming Host for ${this.options.path}`),this.dbHost=await C.create({dbName:this.options.path,config:this.sqliteConfig}),this.txnSessionManager=new w(this.dbHost,this.hostElection),this.txnSessionManager.startWatchdog(),this.rpcChannel.setRequestHandler(this.handleRequest.bind(this)),this.becomeHostResolver&&=(this.becomeHostResolver(),void 0)}loseHost(){c.log(`Tab ${this.tabId} losing Host for ${this.options.path}`),this.rpcChannel.setRequestHandler(void 0),this.txnSessionManager&&=(this.txnSessionManager.close(),null),this.dbHost&&=(this.dbHost.close(),null)}handleVisibilityChange(e){e&&!this.hostElection.isHost&&!this.closed&&this.hostElection.start()}async handleRequest(e){if(!this.dbHost)throw Error(`Not Host`);switch(e.t){case`req`:return await this.handleRpcRequest(e);case`txn_begin`:return await this.handleTxnBegin(e);case`txn_exec`:return await this.handleTxnExec(e);case`txn_commit`:return await this.handleTxnCommit(e);case`txn_rollback`:return await this.handleTxnRollback(e);case`txn_heartbeat`:this.handleTxnHeartbeat(e);return;default:throw Error(`Unknown request type: ${e.t}`)}}async handleRpcRequest(e){let{op:t,payload:n}=e,{sql:r,params:i}=n;switch(this.txnSessionManager&&await this.txnSessionManager.waitForTransactionSlot(),t){case`query`:return{rows:await this.dbHost.query(r,i),columns:[]};case`queryRaw`:return await this.dbHost.queryRaw(r,i);case`run`:return await this.dbHost.run(r,i);case`exec`:return await this.dbHost.exec(r),null;default:throw Error(`Unknown RPC operation: ${String(t)}`)}}async handleTxnBegin(e){await this.txnSessionManager.beginTransaction(e.txnId,e.from,e.mode)}async handleTxnExec(e){let{txnId:t,op:n,payload:r}=e,{sql:i,params:a}=r;return await this.txnSessionManager.execInTransaction(t,async()=>{switch(n){case`query`:return{rows:await this.dbHost.query(i,a),columns:[]};case`queryRaw`:return await this.dbHost.queryRaw(i,a);case`run`:return await this.dbHost.run(i,a);case`exec`:return await this.dbHost.exec(i),null;default:throw Error(`Unknown transaction operation: ${String(n)}`)}})}async handleTxnCommit(e){await this.txnSessionManager.commitTransaction(e.txnId)}async handleTxnRollback(e){await this.txnSessionManager.rollbackTransaction(e.txnId)}handleTxnHeartbeat(e){this.txnSessionManager?.recordHeartbeat(e.txnId)}async query(e,t){return await this.initialize(),this.isHost&&this.dbHost?await this.dbHost.query(e,t):(await this.rpcChannel.request(`query`,{sql:e,params:t})).rows}async queryRaw(e,t){return await this.initialize(),this.isHost&&this.dbHost?await this.dbHost.queryRaw(e,t):await this.rpcChannel.request(`queryRaw`,{sql:e,params:t})}async run(e,t){return await this.initialize(),this.isHost&&this.dbHost?await this.dbHost.run(e,t):await this.rpcChannel.request(`run`,{sql:e,params:t})}async exec(e){if(await this.initialize(),this.isHost&&this.dbHost){await this.dbHost.exec(e);return}await this.rpcChannel.request(`exec`,{sql:e})}async transaction(e){return await this.initialize(),this.isHost&&this.dbHost?await this.executeLocalTransaction(e,!1):await this.executeRemoteTransaction(e)}async asyncTransaction(e,t){return await this.initialize(),this.isHost&&this.dbHost?await this.executeLocalAsyncTransaction(e,t):await this.executeRemoteTransaction(e,t)}getConnectionType(){return`direct`}async close(){this.closed||(this.closed=!0,this.visibilityUnsubscribe?.(),await this.hostElection.close(),this.rpcChannel.close(),this.visibilityManager.destroy(),this.txnSessionManager&&=(await this.txnSessionManager.close(),null),this.dbHost&&=(await this.dbHost.close(),null))}async executeLocalTransaction(e,t){await this.dbHost.execRaw(`BEGIN`);let n=new E(this.dbHost,t);try{let t=e(n),r=t instanceof Promise?await t:t;return await this.dbHost.execRaw(`COMMIT`),r}catch(e){try{await this.dbHost.execRaw(`ROLLBACK`)}catch(e){c.error(`Rollback failed:`,e)}throw e}}async executeLocalAsyncTransaction(e,t){let n=t?.timeoutMs??3e4;await this.dbHost.execRaw(`BEGIN IMMEDIATE`);let r=new E(this.dbHost,!0),i,a=!1;try{let t=new Promise((e,t)=>{i=setTimeout(()=>{a||t(Error(`Async transaction timeout after ${n}ms`))},n)}),o=await Promise.race([e(r),t]);return a=!0,i&&clearTimeout(i),await this.dbHost.execRaw(`COMMIT`),o}catch(e){a=!0,i&&clearTimeout(i);try{await this.dbHost.execRaw(`ROLLBACK`)}catch(e){c.error(`Rollback failed:`,e)}throw e}}async executeRemoteTransaction(e,t){let n=y(),r=t?.timeoutMs??3e4;await this.rpcChannel.txnBegin(n,`immediate`,r);let i=new T(this.rpcChannel,n),a,o=!1;try{let t=new Promise((e,t)=>{a=setTimeout(()=>{o||t(Error(`Remote transaction timeout after ${r}ms`))},r)}),n=e(i),s=n instanceof Promise?n:Promise.resolve(n),c=await Promise.race([s,t]);return o=!0,a&&clearTimeout(a),await i._commit(),c}catch(e){o=!0,a&&clearTimeout(a);try{await i._rollback()}catch(e){c.error(`Remote rollback failed:`,e)}throw e}}getSQLiteInfo(){let e=this.isHost?this.dbHost!==null:this.initialized&&!this.closed;return{config:this.sqliteConfig,isInitialized:this.initialized,isHost:this.isHost,isReady:e,tabId:this.tabId,hasDatabase:this.dbHost!==null,usesWorker:this.dbHost?.isWorkerDbActive()??!1,activeStorageBackend:this.dbHost?.getActiveStorageBackend()??`unknown`,activeOpfsVfs:this.dbHost?.getActiveOpfsVfs()}}getActiveStorageBackend(){return this.dbHost?.getActiveStorageBackend()??`unknown`}};Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return D}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return h}}); | ||
| //# sourceMappingURL=browser2.cjs.map |
@@ -1,8 +0,8 @@ | ||
| import{t as e}from"./base.mjs";import t from"debug";const n=`unisqlite`;function r(e){let r=t(`${n}:${e}`),i=t(`${n}:${e}:warn`),a=t(`${n}:${e}:error`);return a.enabled=!0,{log:r,warn:i,error:a}}const i=r(`host`),a=r(`txn`),o=r(`adapter`);var s=class e{constructor(e){this.options=e,this.abortController=null,this._isHost=!1,this._isStarted=!1,this.releaseResolver=null,this.hostReadyResolver=null,this.hostReadyPromise=null,this.lockName=`sqlite:host:${e.dbName}`,this.txnLockName=`sqlite:txn:${e.dbName}`}static isSupported(){return typeof navigator<`u`&&navigator.locks!==void 0}get isHost(){return this._isHost}async start(){if(!this._isStarted){if(!e.isSupported()){i.warn(`Web Locks API not supported. Running in local-only mode.`),this._isStarted=!0,this._isHost=!0,this.options.onBecomeHost().catch(e=>{i.error(`Error in onBecomeHost callback:`,e),this._isHost=!1});return}this.options.checkVisibility&&!this.options.checkVisibility()||(this._isStarted=!0,this.hostReadyPromise=new Promise(e=>{this.hostReadyResolver=e}),this.tryAcquireHost().catch(e=>{i.error(`Error in host election:`,e)}))}}async waitForHost(){if(!this._isHost&&(this.hostReadyPromise||(await this.start(),this.hostReadyPromise)))return this.hostReadyPromise}async tryAcquireHost(){this.abortController=new AbortController;try{await navigator.locks.request(this.lockName,{mode:`exclusive`,signal:this.abortController.signal},async e=>{if(e){this._isHost=!0,i.log(`Tab ${this.options.tabId} became Host for ${this.options.dbName}`);try{await this.options.onBecomeHost()}catch(e){throw i.error(`Error in onBecomeHost callback:`,e),this._isHost=!1,e}this.hostReadyResolver&&(this.hostReadyResolver(),this.hostReadyResolver=null,this.hostReadyPromise=null),await new Promise(e=>{this.releaseResolver=e,this.abortController.signal.addEventListener(`abort`,()=>{e()})}),this._isHost=!1,this.releaseResolver=null,i.log(`Tab ${this.options.tabId} lost Host role for ${this.options.dbName}`);try{this.options.onLoseHost()}catch(e){i.error(`Error in onLoseHost callback:`,e)}}})}catch(e){if(e.name===`AbortError`)return;throw i.error(`Error acquiring Host lock:`,e),e}finally{this._isStarted=!1,this.abortController=null}}releaseHost(){this.releaseResolver&&=(this.releaseResolver(),null),this.abortController&&=(this.abortController.abort(),null)}async acquireTransactionLock(){if(!e.isSupported())return()=>{};let t=new AbortController,n=null,r=null,a=new Promise(e=>{r=e});return navigator.locks.request(this.txnLockName,{mode:`exclusive`,signal:t.signal},async e=>{e&&(r?.(),await new Promise(e=>{n=e}))}).catch(e=>{e.name!==`AbortError`&&i.error(`Error acquiring transaction lock:`,e),r?.()}),await a,()=>{n?n():t.abort()}}async hasTransactionLock(){if(!e.isSupported())return!1;try{return(await navigator.locks.query()).held?.some(e=>e.name===this.txnLockName)??!1}catch{return!1}}async close(){this.releaseHost()}},c=class{constructor(){this.listeners=new Set,this.boundHandler=this.handleVisibilityChange.bind(this),typeof document<`u`&&document.addEventListener(`visibilitychange`,this.boundHandler)}handleVisibilityChange(){let e=this.isVisible();this.listeners.forEach(t=>{try{t(e)}catch(e){console.error(`Error in visibility change listener:`,e)}})}isVisible(){return typeof document>`u`?!0:document.visibilityState===`visible`}onVisibilityChange(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}destroy(){typeof document<`u`&&document.removeEventListener(`visibilitychange`,this.boundHandler),this.listeners.clear()}};function l(e){return e instanceof Error?{name:e.name,message:e.message,stack:e.stack}:{name:`Error`,message:String(e)}}function u(e){let t=Error(e.message);return t.name=e.name,e.stack&&(t.stack=e.stack),t}function d(e){return e.t===`req`||e.t===`txn_begin`||e.t===`txn_exec`||e.t===`txn_commit`||e.t===`txn_rollback`||e.t===`txn_heartbeat`}function f(e){return e.t===`res`||e.t===`txn_ack`||e.t===`txn_result`||e.t===`txn_done`||e.t===`txn_error`}function p(){return crypto.randomUUID()}function m(){return crypto.randomUUID()}function h(){return crypto.randomUUID()}var g=class{constructor(e,t,n=3e4){this.dbName=e,this.tabId=t,this.defaultTimeoutMs=n,this.pending=new Map,this.closed=!1,this.channel=new BroadcastChannel(`sqlite:rpc:${e}`),this.channel.onmessage=this.handleMessage.bind(this)}handleMessage(e){if(this.closed)return;let t=e.data;!t||typeof t.t!=`string`||(f(t)?this.handleResponse(t):d(t)&&this.requestHandler&&`from`in t&&t.from!==this.tabId&&this.handleRequest(t))}handleResponse(e){if(`to`in e&&e.to!==this.tabId||!(`id`in e))return;let t=this.pending.get(e.id);if(t)switch(clearTimeout(t.timer),this.pending.delete(e.id),e.t){case`res`:e.ok?t.resolve(e.result):t.reject(u(e.error));break;case`txn_ack`:case`txn_done`:t.resolve(void 0);break;case`txn_result`:e.ok?t.resolve(e.result):t.reject(u(e.error));break;case`txn_error`:t.reject(u(e.error));break}}async handleRequest(e){if(this.requestHandler)try{let t=await this.requestHandler(e);this.sendResponse(e,t)}catch(t){this.sendErrorResponse(e,t)}}sendResponse(e,t){if(this.closed)return;let n=`from`in e?e.from:void 0,r=`id`in e?e.id:void 0;if(!(!n||!r))switch(e.t){case`req`:this.channel.postMessage({t:`res`,to:n,id:r,ok:!0,result:t});break;case`txn_begin`:this.channel.postMessage({t:`txn_ack`,to:n,id:r,txnId:e.txnId});break;case`txn_exec`:this.channel.postMessage({t:`txn_result`,to:n,id:r,txnId:e.txnId,ok:!0,result:t});break;case`txn_commit`:case`txn_rollback`:this.channel.postMessage({t:`txn_done`,to:n,id:r,txnId:e.txnId});break;case`txn_heartbeat`:break}}sendErrorResponse(e,t){if(this.closed)return;let n=`from`in e?e.from:void 0,r=`id`in e?e.id:void 0;if(!n||!r)return;let i=l(t);switch(e.t){case`req`:this.channel.postMessage({t:`res`,to:n,id:r,ok:!1,error:i});break;case`txn_begin`:case`txn_exec`:case`txn_commit`:case`txn_rollback`:this.channel.postMessage({t:`txn_error`,to:n,id:r,txnId:e.txnId,error:i});break}}setRequestHandler(e){this.requestHandler=e}async request(e,t,n){let r=p(),i=n??this.defaultTimeoutMs;return new Promise((n,a)=>{let o=setTimeout(()=>{this.pending.delete(r),a(Error(`RPC timeout after ${i}ms for ${e}`))},i);this.pending.set(r,{resolve:n,reject:a,timer:o}),this.channel.postMessage({t:`req`,from:this.tabId,id:r,op:e,payload:t})})}async txnBegin(e,t=`immediate`,n){let r=p(),i=n??this.defaultTimeoutMs;return new Promise((n,a)=>{let o=setTimeout(()=>{this.pending.delete(r),a(Error(`Transaction begin timeout after ${i}ms`))},i);this.pending.set(r,{resolve:n,reject:a,timer:o}),this.channel.postMessage({t:`txn_begin`,from:this.tabId,id:r,txnId:e,mode:t})})}async txnExec(e,t,n,r){let i=p(),a=r??1e4;return new Promise((r,o)=>{let s=setTimeout(()=>{this.pending.delete(i),o(Error(`Transaction SQL timeout after ${a}ms`))},a);this.pending.set(i,{resolve:r,reject:o,timer:s}),this.channel.postMessage({t:`txn_exec`,from:this.tabId,id:i,txnId:e,op:t,payload:n})})}async txnCommit(e,t){let n=p(),r=t??1e4;return new Promise((t,i)=>{let a=setTimeout(()=>{this.pending.delete(n),i(Error(`Transaction commit timeout after ${r}ms`))},r);this.pending.set(n,{resolve:t,reject:i,timer:a}),this.channel.postMessage({t:`txn_commit`,from:this.tabId,id:n,txnId:e})})}async txnRollback(e,t){let n=p(),r=t??1e4;return new Promise((t,i)=>{let a=setTimeout(()=>{this.pending.delete(n),i(Error(`Transaction rollback timeout after ${r}ms`))},r);this.pending.set(n,{resolve:t,reject:i,timer:a}),this.channel.postMessage({t:`txn_rollback`,from:this.tabId,id:n,txnId:e})})}txnHeartbeat(e){this.closed||this.channel.postMessage({t:`txn_heartbeat`,from:this.tabId,txnId:e})}close(){this.closed=!0,this.channel.close();for(let e of this.pending.values())clearTimeout(e.timer),e.reject(Error(`RPC channel closed`));this.pending.clear()}};const _=new Map,v=new Map;var y=class e{constructor(e,t){this.dbName=e,this.config=t,this.workerQueue=Promise.resolve(),this.activeStorageBackend=`memory`,this.closed=!1}static async create(t){let n=new e(t.dbName,t.config);return await n.initialize(),n}async initialize(){console.log(`Loading SQLite WASM using strategy: ${this.config.loadStrategy}`);let e=await this.loadSQLiteWasm(),t={print:console.log,printErr:console.error};if(this.config.locateFile)t.locateFile=this.config.locateFile;else if(typeof window<`u`){let e=window;e.sqlite3InitModuleState?.locateFile&&(t.locateFile=e.sqlite3InitModuleState.locateFile)}if(console.log(`Initializing SQLite WASM module...`),this.sqlite3=await e(t),!this.sqlite3)throw Error(`Failed to initialize SQLite WASM module`);let n=this.sqlite3;console.log(`SQLite WASM module initialized successfully`);let r=this.config.storageBackend??`auto`,i=this.dbName===`:memory:`?`:memory:`:`/unisqlite/${this.dbName}`;r===`memory`||this.dbName===`:memory:`?(console.log(`Using in-memory database`),this.db=new n.oo1.DB(`:memory:`),this.activeStorageBackend=`memory`):await this.tryCreatePersistentDatabase(n,i,r)||(console.log(`All persistent storage backends failed, using in-memory database`),this.db=new n.oo1.DB(`:memory:`),this.activeStorageBackend=`memory`);try{await this.execInternal(`PRAGMA journal_mode=WAL`),console.log(`Enabled WAL mode`)}catch(e){console.warn(`Could not enable WAL mode:`,e)}}async query(e,t){return(await this.executeSql(e,t)).rows}async queryRaw(e,t){return await this.executeSql(e,t)}async run(e,t){let n=await this.executeSql(e,t);return{rowsAffected:n.rowsAffected??0,lastInsertRowId:n.lastInsertRowId??0}}async exec(e){await this.execInternal(e)}async execRaw(e){await this.execInternal(e,{bypassQueue:!0})}async executeSqlRaw(e,t){return await this.executeSql(e,t,{bypassQueue:!0})}getActiveStorageBackend(){return this.activeStorageBackend}getActiveOpfsVfs(){return this.activeOpfsVfs}isWorkerDbActive(){return!!this.workerPromiser&&this.workerDbId!==void 0}async close(){if(!this.closed){if(this.closed=!0,this.workerPromiser){let e=this.workerPromiser,t=this.workerDbId;try{t!==void 0&&await this.enqueueWorker(async()=>{await e(`close`,{dbId:t})})}catch(e){console.warn(`Failed to close SQLite worker database:`,e)}finally{this.workerDbId=void 0;let t=e.worker;t?.terminate&&t.terminate(),this.workerPromiser=void 0}}this.db&&=(this.db.close(),void 0)}}enqueueWorker(e){let t=async()=>e(),n=this.workerQueue.then(t,t);return this.workerQueue=n.then(()=>void 0,()=>void 0),n}normalizeParams(e){if(!e)return;if(Array.isArray(e))return e;let t=Object.keys(e),n=e;return t.map(e=>n[e])}async execInternal(e,t){if(this.isWorkerDbActive()){let n=async()=>{if(!this.workerPromiser||this.workerDbId===void 0)throw Error(`Database not initialized`);await this.workerPromiser(`exec`,{dbId:this.workerDbId,sql:e})};t?.bypassQueue?await n():await this.enqueueWorker(n);return}if(!this.db)throw Error(`Database not initialized`);this.db.exec(e)}async executeSql(e,t,n){try{if(this.isWorkerDbActive()){let r=async()=>{if(!this.workerPromiser||this.workerDbId===void 0)throw Error(`Database not initialized`);let n=this.normalizeParams(t),r={dbId:this.workerDbId,sql:e,rowMode:`object`,resultRows:[],columnNames:[],countChanges:!0};n&&(r.bind=n);let i=await this.workerPromiser(`exec`,r),a=i.result??i,o=Array.isArray(a.resultRows)?a.resultRows:[],s=Array.isArray(a.columnNames)?a.columnNames:[],c=typeof a.changeCount==`number`?a.changeCount:0,l={dbId:this.workerDbId,sql:`SELECT last_insert_rowid() AS lastInsertRowId`,rowMode:`object`,resultRows:[],columnNames:[]},u=await this.workerPromiser(`exec`,l),d=u.result??u,f=Array.isArray(d.resultRows)?d.resultRows:[];return{rows:o,columns:s,rowsAffected:c,lastInsertRowId:Number(f[0]?.lastInsertRowId??0)}};return n?.bypassQueue?await r():await this.enqueueWorker(r)}if(!this.db||!this.sqlite3)throw Error(`Database not initialized`);let r=this.normalizeParams(t),i=[],a=[],o=this.db.prepare(e);try{let e=o;r&&o.bind(r);let t=typeof e.getColumnCount==`function`?e.getColumnCount():typeof e.columnCount==`number`?e.columnCount:0;if(t>0)if(typeof e.getColumnNames==`function`)a=e.getColumnNames();else for(let e=0;e<t;e++)a.push(o.getColumnName(e));for(;o.step();){let e={};for(let n=0;n<t;n++)e[a[n]]=o.get(n);i.push(e)}return{rows:i,columns:a,rowsAffected:this.db.changes(),lastInsertRowId:Number(this.sqlite3.capi.sqlite3_last_insert_rowid(this.db.pointer)||0)}}finally{o.finalize()}}catch(e){let t=e instanceof Error?e.message:String(e),n=Error(`SQLite error: ${t}`);throw e instanceof Error&&(n.cause=e),n}}async loadSQLiteWasm(){let e=`${this.config.loadStrategy}-${this.config.wasmUrl||this.config.cdnBaseUrl}-${this.config.version}`;if(_.has(e))return _.get(e);let t=this.loadSQLiteWasmInternal();return _.set(e,t),t}async loadSQLiteWasmInternal(){let{loadStrategy:e,wasmUrl:t,cdnBaseUrl:n,version:r,bundlerFriendly:i}=this.config;switch(e){case`npm`:return await this.loadFromNpm();case`cdn`:return await this.loadFromCdn(n,r,i);case`url`:if(!t)throw Error(`wasmUrl must be provided when using 'url' loading strategy`);return await this.loadFromUrl(t);case`module`:return await this.loadAsModule();case`global`:default:return this.loadFromGlobal()}}async loadFromNpm(){try{let e=await import(`@sqlite.org/sqlite-wasm`);return e.default||e}catch(e){return console.warn(`Failed to load SQLite WASM from npm, falling back to CDN:`,e),this.loadFromCdn(this.config.cdnBaseUrl,this.config.version,this.config.bundlerFriendly)}}async loadFromCdn(e,t,n){let r=n?`sqlite3-bundler-friendly.mjs`:`index.mjs`,i=[`https://cdn.jsdelivr.net/npm/@sqlite.org/sqlite-wasm@${t}/${r}`,`https://cdn.jsdelivr.net/npm/@sqlite.org/sqlite-wasm@${t}/dist/${r}`],a;for(let e of i)try{console.log(`Trying to load SQLite WASM from: ${e}`);let t=await import(e);return console.log(`Successfully loaded SQLite WASM from: ${e}`),t.default||t}catch(t){a=t,console.warn(`Failed to load SQLite WASM from ${e}:`,t)}let o=a instanceof Error?a.message:String(a);throw Error(`Failed to load SQLite WASM from any CDN source. Last error: ${o}`)}async loadFromUrl(e){let t=await import(e);return t.default||t.sqlite3InitModule}async loadAsModule(){if(globalThis.importScripts!==void 0)throw Error(`ES6 module loading not supported in Web Worker context`);for(let e of[`./sqlite3.mjs`,`./sqlite3-bundler-friendly.mjs`,`/sqlite3.mjs`])try{let t=await import(e);return t.default||t.sqlite3InitModule}catch(t){console.warn(`Failed to load SQLite WASM from ${e}:`,t)}throw Error(`Could not load SQLite WASM as ES6 module from any known path`)}loadFromGlobal(){if(typeof window<`u`){let e=window;if(e.sqlite3InitModule)return e.sqlite3InitModule}throw Error(`SQLite WASM module not found globally. Please: | ||
| import{t as e}from"./base.mjs";import t from"debug";const n=`unisqlite`;function r(e){let r=t(`${n}:${e}`),i=t(`${n}:${e}:warn`),a=t(`${n}:${e}:error`);return a.enabled=!0,{log:r,warn:i,error:a}}const i=r(`host`),a=r(`txn`),o=r(`adapter`),s=r(`wasm`),c=r(`visibility`);var l=class e{constructor(e){this.options=e,this.abortController=null,this._isHost=!1,this._isStarted=!1,this.releaseResolver=null,this.hostReadyResolver=null,this.hostReadyPromise=null,this.lockName=`sqlite:host:${e.dbName}`,this.txnLockName=`sqlite:txn:${e.dbName}`}static isSupported(){return typeof navigator<`u`&&navigator.locks!==void 0}get isHost(){return this._isHost}async start(){if(!this._isStarted){if(!e.isSupported()){i.warn(`Web Locks API not supported. Running in local-only mode.`),this._isStarted=!0,this._isHost=!0,this.options.onBecomeHost().catch(e=>{i.error(`Error in onBecomeHost callback:`,e),this._isHost=!1});return}this.options.checkVisibility&&!this.options.checkVisibility()||(this._isStarted=!0,this.hostReadyPromise=new Promise(e=>{this.hostReadyResolver=e}),this.tryAcquireHost().catch(e=>{i.error(`Error in host election:`,e)}))}}async waitForHost(){if(!this._isHost&&(this.hostReadyPromise||(await this.start(),this.hostReadyPromise)))return this.hostReadyPromise}async tryAcquireHost(){this.abortController=new AbortController;try{await navigator.locks.request(this.lockName,{mode:`exclusive`,signal:this.abortController.signal},async e=>{if(e){this._isHost=!0,i.log(`Tab ${this.options.tabId} became Host for ${this.options.dbName}`);try{await this.options.onBecomeHost()}catch(e){throw i.error(`Error in onBecomeHost callback:`,e),this._isHost=!1,e}this.hostReadyResolver&&(this.hostReadyResolver(),this.hostReadyResolver=null,this.hostReadyPromise=null),await new Promise(e=>{this.releaseResolver=e,this.abortController.signal.addEventListener(`abort`,()=>{e()})}),this._isHost=!1,this.releaseResolver=null,i.log(`Tab ${this.options.tabId} lost Host role for ${this.options.dbName}`);try{this.options.onLoseHost()}catch(e){i.error(`Error in onLoseHost callback:`,e)}}})}catch(e){if(e.name===`AbortError`)return;throw i.error(`Error acquiring Host lock:`,e),e}finally{this._isStarted=!1,this.abortController=null}}releaseHost(){this.releaseResolver&&=(this.releaseResolver(),null),this.abortController&&=(this.abortController.abort(),null)}async acquireTransactionLock(){if(!e.isSupported())return()=>{};let t=new AbortController,n=null,r=null,a=new Promise(e=>{r=e});return navigator.locks.request(this.txnLockName,{mode:`exclusive`,signal:t.signal},async e=>{e&&(r?.(),await new Promise(e=>{n=e}))}).catch(e=>{e.name!==`AbortError`&&i.error(`Error acquiring transaction lock:`,e),r?.()}),await a,()=>{n?n():t.abort()}}async hasTransactionLock(){if(!e.isSupported())return!1;try{return(await navigator.locks.query()).held?.some(e=>e.name===this.txnLockName)??!1}catch{return!1}}async close(){this.releaseHost()}},u=class{constructor(){this.listeners=new Set,this.boundHandler=this.handleVisibilityChange.bind(this),typeof document<`u`&&document.addEventListener(`visibilitychange`,this.boundHandler)}handleVisibilityChange(){let e=this.isVisible();this.listeners.forEach(t=>{try{t(e)}catch(e){c.error(`Error in visibility change listener:`,e)}})}isVisible(){return typeof document>`u`?!0:document.visibilityState===`visible`}onVisibilityChange(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}destroy(){typeof document<`u`&&document.removeEventListener(`visibilitychange`,this.boundHandler),this.listeners.clear()}};function d(e){return e instanceof Error?{name:e.name,message:e.message,stack:e.stack}:{name:`Error`,message:String(e)}}function f(e){let t=Error(e.message);return t.name=e.name,e.stack&&(t.stack=e.stack),t}function p(e){return e.t===`req`||e.t===`txn_begin`||e.t===`txn_exec`||e.t===`txn_commit`||e.t===`txn_rollback`||e.t===`txn_heartbeat`}function m(e){return e.t===`res`||e.t===`txn_ack`||e.t===`txn_result`||e.t===`txn_done`||e.t===`txn_error`}function h(){return crypto.randomUUID()}function g(){return crypto.randomUUID()}function _(){return crypto.randomUUID()}var v=class{constructor(e,t,n=3e4){this.dbName=e,this.tabId=t,this.defaultTimeoutMs=n,this.pending=new Map,this.closed=!1,this.channel=new BroadcastChannel(`sqlite:rpc:${e}`),this.channel.onmessage=this.handleMessage.bind(this)}handleMessage(e){if(this.closed)return;let t=e.data;!t||typeof t.t!=`string`||(m(t)?this.handleResponse(t):p(t)&&this.requestHandler&&`from`in t&&t.from!==this.tabId&&this.handleRequest(t))}handleResponse(e){if(`to`in e&&e.to!==this.tabId||!(`id`in e))return;let t=this.pending.get(e.id);if(t)switch(clearTimeout(t.timer),this.pending.delete(e.id),e.t){case`res`:e.ok?t.resolve(e.result):t.reject(f(e.error));break;case`txn_ack`:case`txn_done`:t.resolve(void 0);break;case`txn_result`:e.ok?t.resolve(e.result):t.reject(f(e.error));break;case`txn_error`:t.reject(f(e.error));break}}async handleRequest(e){if(this.requestHandler)try{let t=await this.requestHandler(e);this.sendResponse(e,t)}catch(t){this.sendErrorResponse(e,t)}}sendResponse(e,t){if(this.closed)return;let n=`from`in e?e.from:void 0,r=`id`in e?e.id:void 0;if(!(!n||!r))switch(e.t){case`req`:this.channel.postMessage({t:`res`,to:n,id:r,ok:!0,result:t});break;case`txn_begin`:this.channel.postMessage({t:`txn_ack`,to:n,id:r,txnId:e.txnId});break;case`txn_exec`:this.channel.postMessage({t:`txn_result`,to:n,id:r,txnId:e.txnId,ok:!0,result:t});break;case`txn_commit`:case`txn_rollback`:this.channel.postMessage({t:`txn_done`,to:n,id:r,txnId:e.txnId});break;case`txn_heartbeat`:break}}sendErrorResponse(e,t){if(this.closed)return;let n=`from`in e?e.from:void 0,r=`id`in e?e.id:void 0;if(!n||!r)return;let i=d(t);switch(e.t){case`req`:this.channel.postMessage({t:`res`,to:n,id:r,ok:!1,error:i});break;case`txn_begin`:case`txn_exec`:case`txn_commit`:case`txn_rollback`:this.channel.postMessage({t:`txn_error`,to:n,id:r,txnId:e.txnId,error:i});break}}setRequestHandler(e){this.requestHandler=e}async request(e,t,n){let r=h(),i=n??this.defaultTimeoutMs;return new Promise((n,a)=>{let o=setTimeout(()=>{this.pending.delete(r),a(Error(`RPC timeout after ${i}ms for ${e}`))},i);this.pending.set(r,{resolve:n,reject:a,timer:o}),this.channel.postMessage({t:`req`,from:this.tabId,id:r,op:e,payload:t})})}async txnBegin(e,t=`immediate`,n){let r=h(),i=n??this.defaultTimeoutMs;return new Promise((n,a)=>{let o=setTimeout(()=>{this.pending.delete(r),a(Error(`Transaction begin timeout after ${i}ms`))},i);this.pending.set(r,{resolve:n,reject:a,timer:o}),this.channel.postMessage({t:`txn_begin`,from:this.tabId,id:r,txnId:e,mode:t})})}async txnExec(e,t,n,r){let i=h(),a=r??1e4;return new Promise((r,o)=>{let s=setTimeout(()=>{this.pending.delete(i),o(Error(`Transaction SQL timeout after ${a}ms`))},a);this.pending.set(i,{resolve:r,reject:o,timer:s}),this.channel.postMessage({t:`txn_exec`,from:this.tabId,id:i,txnId:e,op:t,payload:n})})}async txnCommit(e,t){let n=h(),r=t??1e4;return new Promise((t,i)=>{let a=setTimeout(()=>{this.pending.delete(n),i(Error(`Transaction commit timeout after ${r}ms`))},r);this.pending.set(n,{resolve:t,reject:i,timer:a}),this.channel.postMessage({t:`txn_commit`,from:this.tabId,id:n,txnId:e})})}async txnRollback(e,t){let n=h(),r=t??1e4;return new Promise((t,i)=>{let a=setTimeout(()=>{this.pending.delete(n),i(Error(`Transaction rollback timeout after ${r}ms`))},r);this.pending.set(n,{resolve:t,reject:i,timer:a}),this.channel.postMessage({t:`txn_rollback`,from:this.tabId,id:n,txnId:e})})}txnHeartbeat(e){this.closed||this.channel.postMessage({t:`txn_heartbeat`,from:this.tabId,txnId:e})}close(){this.closed=!0,this.channel.close();for(let e of this.pending.values())clearTimeout(e.timer),e.reject(Error(`RPC channel closed`));this.pending.clear()}};const y=new Map,b=new Map;var x=class e{constructor(e,t){this.dbName=e,this.config=t,this.workerQueue=Promise.resolve(),this.activeStorageBackend=`memory`,this.closed=!1}static async create(t){let n=new e(t.dbName,t.config);return await n.initialize(),n}async initialize(){s.log(`UniSQLite v0.4.0 - Loading SQLite WASM using strategy: ${this.config.loadStrategy}`);let e=await this.loadSQLiteWasm(),t={print:(...e)=>s.log(...e),printErr:(...e)=>s.error(...e)};if(this.config.locateFile)t.locateFile=this.config.locateFile;else if(typeof window<`u`){let e=window;e.sqlite3InitModuleState?.locateFile&&(t.locateFile=e.sqlite3InitModuleState.locateFile)}if(s.log(`Initializing SQLite WASM module...`),this.sqlite3=await e(t),!this.sqlite3)throw Error(`Failed to initialize SQLite WASM module`);let n=this.sqlite3;s.log(`SQLite WASM module initialized successfully`);let r=this.config.storageBackend??`auto`,i=this.dbName===`:memory:`?`:memory:`:`/unisqlite/${this.dbName}`;r===`memory`||this.dbName===`:memory:`?(s.log(`Using in-memory database`),this.db=new n.oo1.DB(`:memory:`),this.activeStorageBackend=`memory`):await this.tryCreatePersistentDatabase(n,i,r)||(s.log(`All persistent storage backends failed, using in-memory database`),this.db=new n.oo1.DB(`:memory:`),this.activeStorageBackend=`memory`);try{await this.execInternal(`PRAGMA journal_mode=WAL`),s.log(`Enabled WAL mode`)}catch(e){s.warn(`Could not enable WAL mode:`,e)}}async query(e,t){return(await this.executeSql(e,t)).rows}async queryRaw(e,t){return await this.executeSql(e,t)}async run(e,t){let n=await this.executeSql(e,t);return{rowsAffected:n.rowsAffected??0,lastInsertRowId:n.lastInsertRowId??0}}async exec(e){await this.execInternal(e)}async execRaw(e){await this.execInternal(e,{bypassQueue:!0})}async executeSqlRaw(e,t){return await this.executeSql(e,t,{bypassQueue:!0})}getActiveStorageBackend(){return this.activeStorageBackend}getActiveOpfsVfs(){return this.activeOpfsVfs}isWorkerDbActive(){return!!this.workerPromiser&&this.workerDbId!==void 0}async close(){if(!this.closed){if(this.closed=!0,this.workerPromiser){let e=this.workerPromiser,t=this.workerDbId;try{t!==void 0&&await this.enqueueWorker(async()=>{await e(`close`,{dbId:t})})}catch(e){s.warn(`Failed to close SQLite worker database:`,e)}finally{this.workerDbId=void 0;let t=e.worker;t?.terminate&&t.terminate(),this.workerPromiser=void 0}}this.db&&=(this.db.close(),void 0)}}enqueueWorker(e){let t=async()=>e(),n=this.workerQueue.then(t,t);return this.workerQueue=n.then(()=>void 0,()=>void 0),n}normalizeParams(e){if(!e)return;if(Array.isArray(e))return e;let t=Object.keys(e),n=e;return t.map(e=>n[e])}async execInternal(e,t){if(this.isWorkerDbActive()){let n=async()=>{if(!this.workerPromiser||this.workerDbId===void 0)throw Error(`Database not initialized`);await this.workerPromiser(`exec`,{dbId:this.workerDbId,sql:e})};t?.bypassQueue?await n():await this.enqueueWorker(n);return}if(!this.db)throw Error(`Database not initialized`);this.db.exec(e)}async executeSql(e,t,n){try{if(this.isWorkerDbActive()){let r=async()=>{if(!this.workerPromiser||this.workerDbId===void 0)throw Error(`Database not initialized`);let n=this.normalizeParams(t),r={dbId:this.workerDbId,sql:e,rowMode:`object`,resultRows:[],columnNames:[],countChanges:!0};n&&(r.bind=n);let i=await this.workerPromiser(`exec`,r),a=i.result??i,o=Array.isArray(a.resultRows)?a.resultRows:[],s=Array.isArray(a.columnNames)?a.columnNames:[],c=typeof a.changeCount==`number`?a.changeCount:0,l={dbId:this.workerDbId,sql:`SELECT last_insert_rowid() AS lastInsertRowId`,rowMode:`object`,resultRows:[],columnNames:[]},u=await this.workerPromiser(`exec`,l),d=u.result??u,f=Array.isArray(d.resultRows)?d.resultRows:[];return{rows:o,columns:s,rowsAffected:c,lastInsertRowId:Number(f[0]?.lastInsertRowId??0)}};return n?.bypassQueue?await r():await this.enqueueWorker(r)}if(!this.db||!this.sqlite3)throw Error(`Database not initialized`);let r=this.normalizeParams(t),i=[],a=[],o=this.db.prepare(e);try{let e=o;r&&o.bind(r);let t=typeof e.getColumnCount==`function`?e.getColumnCount():typeof e.columnCount==`number`?e.columnCount:0;if(t>0)if(typeof e.getColumnNames==`function`)a=e.getColumnNames();else for(let e=0;e<t;e++)a.push(o.getColumnName(e));for(;o.step();){let e={};for(let n=0;n<t;n++)e[a[n]]=o.get(n);i.push(e)}return{rows:i,columns:a,rowsAffected:this.db.changes(),lastInsertRowId:Number(this.sqlite3.capi.sqlite3_last_insert_rowid(this.db.pointer)||0)}}finally{o.finalize()}}catch(e){let t=e instanceof Error?e.message:String(e),n=Error(`SQLite error: ${t}`);throw e instanceof Error&&(n.cause=e),n}}async loadSQLiteWasm(){let e=`${this.config.loadStrategy}-${this.config.wasmUrl||this.config.cdnBaseUrl}-${this.config.version}`;if(y.has(e))return y.get(e);let t=this.loadSQLiteWasmInternal();return y.set(e,t),t}async loadSQLiteWasmInternal(){let{loadStrategy:e,wasmUrl:t,cdnBaseUrl:n,version:r,bundlerFriendly:i}=this.config;switch(e){case`npm`:return await this.loadFromNpm();case`cdn`:return await this.loadFromCdn(n,r,i);case`url`:if(!t)throw Error(`wasmUrl must be provided when using 'url' loading strategy`);return await this.loadFromUrl(t);case`module`:return await this.loadAsModule();case`global`:default:return this.loadFromGlobal()}}async loadFromNpm(){try{let e=await import(`@sqlite.org/sqlite-wasm`);return e.default||e}catch(e){return s.warn(`Failed to load SQLite WASM from npm, falling back to CDN:`,e),this.loadFromCdn(this.config.cdnBaseUrl,this.config.version,this.config.bundlerFriendly)}}async loadFromCdn(e,t,n){let r=n?`sqlite3-bundler-friendly.mjs`:`index.mjs`,i=[`https://cdn.jsdelivr.net/npm/@sqlite.org/sqlite-wasm@${t}/${r}`,`https://cdn.jsdelivr.net/npm/@sqlite.org/sqlite-wasm@${t}/dist/${r}`],a;for(let e of i)try{s.log(`Trying to load SQLite WASM from: ${e}`);let t=await import(e);return s.log(`Successfully loaded SQLite WASM from: ${e}`),t.default||t}catch(t){a=t,s.warn(`Failed to load SQLite WASM from ${e}:`,t)}let o=a instanceof Error?a.message:String(a);throw Error(`Failed to load SQLite WASM from any CDN source. Last error: ${o}`)}async loadFromUrl(e){let t=await import(e);return t.default||t.sqlite3InitModule}async loadAsModule(){if(globalThis.importScripts!==void 0)throw Error(`ES6 module loading not supported in Web Worker context`);for(let e of[`./sqlite3.mjs`,`./sqlite3-bundler-friendly.mjs`,`/sqlite3.mjs`])try{let t=await import(e);return t.default||t.sqlite3InitModule}catch(t){s.warn(`Failed to load SQLite WASM from ${e}:`,t)}throw Error(`Could not load SQLite WASM as ES6 module from any known path`)}loadFromGlobal(){if(typeof window<`u`){let e=window;if(e.sqlite3InitModule)return e.sqlite3InitModule}throw Error(`SQLite WASM module not found globally. Please: | ||
| 1. Install via npm: npm install @sqlite.org/sqlite-wasm | ||
| 2. Or set loadStrategy to 'cdn' for automatic CDN loading | ||
| 3. Or include SQLite WASM script in your HTML before using UniSqlite`)}async loadSQLiteWorkerPromiserFactory(){let e=`worker-${this.config.loadStrategy}-${this.config.wasmUrl||this.config.cdnBaseUrl}-${this.config.version}`;if(v.has(e))return v.get(e);let t=this.loadSQLiteWorkerPromiserFactoryInternal();return v.set(e,t),t}async loadSQLiteWorkerPromiserFactoryInternal(){let{loadStrategy:e,wasmUrl:t,cdnBaseUrl:n,version:r,bundlerFriendly:i}=this.config;switch(e){case`npm`:return await this.loadWorkerPromiserFromNpm();case`cdn`:return await this.loadWorkerPromiserFromCdn(n,r,i);case`url`:if(!t)throw Error(`wasmUrl must be provided when using 'url' loading strategy`);return await this.loadWorkerPromiserFromUrl(t);case`module`:return await this.loadWorkerPromiserAsModule();case`global`:default:return this.loadWorkerPromiserFromGlobal()}}async loadWorkerPromiserFromNpm(){try{let e=(await import(`@sqlite.org/sqlite-wasm`)).sqlite3Worker1Promiser;if(typeof e==`function`)return e;throw Error(`sqlite3Worker1Promiser export not found`)}catch(e){return console.warn(`Failed to load SQLite WASM worker promiser from npm, falling back to CDN:`,e),this.loadWorkerPromiserFromCdn(this.config.cdnBaseUrl,this.config.version,this.config.bundlerFriendly)}}async loadWorkerPromiserFromCdn(e,t,n){let r=n?`sqlite3-bundler-friendly.mjs`:`index.mjs`,i=[`${e}@${t}/${r}`,`${e}@${t}/dist/${r}`],a;for(let e of i)try{console.log(`Trying to load SQLite WASM worker promiser from: ${e}`);let t=(await import(e)).sqlite3Worker1Promiser;if(typeof t==`function`)return console.log(`Successfully loaded SQLite WASM worker promiser from: ${e}`),t;throw Error(`sqlite3Worker1Promiser export not found`)}catch(t){a=t,console.warn(`Failed to load SQLite WASM worker promiser from ${e}:`,t)}let o=a instanceof Error?a.message:String(a);throw Error(`Failed to load sqlite3Worker1Promiser from any CDN source. Last error: ${o}`)}async loadWorkerPromiserFromUrl(e){let t=(await import(e)).sqlite3Worker1Promiser;if(typeof t!=`function`)throw Error(`sqlite3Worker1Promiser export not found in module loaded from ${e}`);return t}async loadWorkerPromiserAsModule(){if(globalThis.importScripts!==void 0)throw Error(`ES6 module loading not supported in Web Worker context`);for(let e of[`./sqlite3.mjs`,`./sqlite3-bundler-friendly.mjs`,`/sqlite3.mjs`])try{let t=(await import(e)).sqlite3Worker1Promiser;if(typeof t==`function`)return t}catch(t){console.warn(`Failed to load SQLite WASM worker promiser from ${e}:`,t)}throw Error(`Could not load sqlite3Worker1Promiser as ES6 module from any known path`)}loadWorkerPromiserFromGlobal(){let e=globalThis;if(typeof e.sqlite3Worker1Promiser==`function`)return e.sqlite3Worker1Promiser;throw Error(`SQLite WASM worker promiser not found globally. Please: | ||
| 3. Or include SQLite WASM script in your HTML before using UniSqlite`)}async loadSQLiteWorkerPromiserFactory(){let e=`worker-${this.config.loadStrategy}-${this.config.wasmUrl||this.config.cdnBaseUrl}-${this.config.version}`;if(b.has(e))return b.get(e);let t=this.loadSQLiteWorkerPromiserFactoryInternal();return b.set(e,t),t}async loadSQLiteWorkerPromiserFactoryInternal(){let{loadStrategy:e,wasmUrl:t,cdnBaseUrl:n,version:r,bundlerFriendly:i}=this.config;switch(e){case`npm`:return await this.loadWorkerPromiserFromNpm();case`cdn`:return await this.loadWorkerPromiserFromCdn(n,r,i);case`url`:if(!t)throw Error(`wasmUrl must be provided when using 'url' loading strategy`);return await this.loadWorkerPromiserFromUrl(t);case`module`:return await this.loadWorkerPromiserAsModule();case`global`:default:return this.loadWorkerPromiserFromGlobal()}}async loadWorkerPromiserFromNpm(){try{let e=(await import(`@sqlite.org/sqlite-wasm`)).sqlite3Worker1Promiser;if(typeof e==`function`)return e;throw Error(`sqlite3Worker1Promiser export not found`)}catch(e){return s.warn(`Failed to load SQLite WASM worker promiser from npm, falling back to CDN:`,e),this.loadWorkerPromiserFromCdn(this.config.cdnBaseUrl,this.config.version,this.config.bundlerFriendly)}}async loadWorkerPromiserFromCdn(e,t,n){let r=n?`sqlite3-bundler-friendly.mjs`:`index.mjs`,i=[`${e}@${t}/${r}`,`${e}@${t}/dist/${r}`],a;for(let e of i)try{s.log(`Trying to load SQLite WASM worker promiser from: ${e}`);let t=(await import(e)).sqlite3Worker1Promiser;if(typeof t==`function`)return s.log(`Successfully loaded SQLite WASM worker promiser from: ${e}`),t;throw Error(`sqlite3Worker1Promiser export not found`)}catch(t){a=t,s.warn(`Failed to load SQLite WASM worker promiser from ${e}:`,t)}let o=a instanceof Error?a.message:String(a);throw Error(`Failed to load sqlite3Worker1Promiser from any CDN source. Last error: ${o}`)}async loadWorkerPromiserFromUrl(e){let t=(await import(e)).sqlite3Worker1Promiser;if(typeof t!=`function`)throw Error(`sqlite3Worker1Promiser export not found in module loaded from ${e}`);return t}async loadWorkerPromiserAsModule(){if(globalThis.importScripts!==void 0)throw Error(`ES6 module loading not supported in Web Worker context`);for(let e of[`./sqlite3.mjs`,`./sqlite3-bundler-friendly.mjs`,`/sqlite3.mjs`])try{let t=(await import(e)).sqlite3Worker1Promiser;if(typeof t==`function`)return t}catch(t){s.warn(`Failed to load SQLite WASM worker promiser from ${e}:`,t)}throw Error(`Could not load sqlite3Worker1Promiser as ES6 module from any known path`)}loadWorkerPromiserFromGlobal(){let e=globalThis;if(typeof e.sqlite3Worker1Promiser==`function`)return e.sqlite3Worker1Promiser;throw Error(`SQLite WASM worker promiser not found globally. Please: | ||
| 1. Install via npm: npm install @sqlite.org/sqlite-wasm and set loadStrategy to 'npm' | ||
| 2. Or set loadStrategy to 'cdn' for automatic CDN loading | ||
| 3. Or include SQLite WASM worker promiser script in your HTML before using UniSqlite`)}async tryCreatePersistentDatabase(e,t,n){if(n===`opfs`||n===`auto`){let r=this.config.opfsVfsType??`auto`,i=r===`auto`?e.oo1.OpfsDb?[`opfs`]:[`opfs-sahpool`,`opfs`]:r===`sahpool`?[`opfs-sahpool`]:[`opfs`];for(let n of i)if(await this.tryCreateOpfsDatabase(e,t,n))return!0;if(n===`opfs`)throw Error(this.getOpfsUnavailableError())}if(n===`localStorage`||n===`auto`){if(e.oo1.JsStorageDb)if(this.dbName===`local`||this.dbName===`session`)try{return console.log(`Creating localStorage-backed database:`,this.dbName),this.db=new e.oo1.JsStorageDb(this.dbName),this.activeStorageBackend=`localStorage`,console.log(`Successfully created localStorage-backed database`),!0}catch(e){if(console.warn(`localStorage database creation failed:`,e),n===`localStorage`)throw Error(`localStorage database creation failed: ${e instanceof Error?e.message:String(e)}`)}else if(n===`localStorage`)throw Error(`localStorage storage backend requires path to be 'local' or 'session', got '${this.dbName}'. Use storageBackend: 'opfs' for custom database names with persistence.`);else console.log(`Skipping localStorage: path '${this.dbName}' is not 'local' or 'session'`);else if(n===`localStorage`)throw Error(`JsStorageDb is not available in this environment.`)}return!1}getOpfsUnavailableError(){return`OPFS is not available. | ||
| 3. Or include SQLite WASM worker promiser script in your HTML before using UniSqlite`)}async tryCreatePersistentDatabase(e,t,n){if(n===`opfs`||n===`auto`){let r=this.config.opfsVfsType??`auto`,i=r===`auto`?e.oo1.OpfsDb?[`opfs`]:[`opfs-sahpool`,`opfs`]:r===`sahpool`?[`opfs-sahpool`]:[`opfs`];for(let n of i)if(await this.tryCreateOpfsDatabase(e,t,n))return!0;if(n===`opfs`)throw Error(this.getOpfsUnavailableError())}if(n===`localStorage`||n===`auto`){if(e.oo1.JsStorageDb)if(this.dbName===`local`||this.dbName===`session`)try{return s.log(`Creating localStorage-backed database:`,this.dbName),this.db=new e.oo1.JsStorageDb(this.dbName),this.activeStorageBackend=`localStorage`,s.log(`Successfully created localStorage-backed database`),!0}catch(e){if(s.warn(`localStorage database creation failed:`,e),n===`localStorage`)throw Error(`localStorage database creation failed: ${e instanceof Error?e.message:String(e)}`)}else if(n===`localStorage`)throw Error(`localStorage storage backend requires path to be 'local' or 'session', got '${this.dbName}'. Use storageBackend: 'opfs' for custom database names with persistence.`);else s.log(`Skipping localStorage: path '${this.dbName}' is not 'local' or 'session'`);else if(n===`localStorage`)throw Error(`JsStorageDb is not available in this environment.`)}return!1}getOpfsUnavailableError(){return`OPFS is not available. | ||
@@ -14,5 +14,5 @@ SQLite WASM OPFS backends only work in Worker contexts. When running on the main thread, UniSQLite will try to use SQLite WASM's wrapped-worker API (sqlite3Worker1Promiser) under the hood. | ||
| - For VFS 'opfs': COOP/COEP headers are set and SharedArrayBuffer is available | ||
| - Your sqlite load strategy can load sqlite3Worker1Promiser (use sqlite.loadStrategy = 'npm' or 'cdn', or provide it globally)`}async tryCreateOpfsDatabase(e,t,n){if(n===`opfs`){if(e.oo1.OpfsDb)try{return console.log(`Creating OPFS-backed database (OpfsDb):`,t),this.db=new e.oo1.OpfsDb(t),this.workerDbId=void 0,this.activeStorageBackend=`opfs`,this.activeOpfsVfs=`opfs`,console.log(`Successfully created OPFS-backed database (OpfsDb)`),!0}catch(e){console.warn(`OPFS database creation via OpfsDb failed:`,e)}return await this.tryCreateWrappedWorkerOpfsDatabase(t,n)}if(await this.ensureSahpoolVfs(e))try{return console.log(`Creating SAHPool OPFS-backed database:`,t),this.db=new e.oo1.DB(t,`c`,`opfs-sahpool`),this.workerDbId=void 0,this.activeStorageBackend=`opfs`,this.activeOpfsVfs=`opfs-sahpool`,console.log(`Successfully created SAHPool OPFS-backed database`),!0}catch(e){console.warn(`SAHPool OPFS database creation failed:`,e)}return await this.tryCreateWrappedWorkerOpfsDatabase(t,n)}async ensureSahpoolVfs(e){if(globalThis.importScripts===void 0)return!1;let t=`opfs-sahpool`;try{if(e.capi.sqlite3_vfs_find?.(t))return!0}catch(e){console.warn(`SAHPool VFS lookup failed:`,e)}if(typeof e.installOpfsSAHPoolVfs!=`function`)return!1;try{await e.installOpfsSAHPoolVfs({name:t,directory:`/unisqlite-sahpool`})}catch(e){return console.warn(`SAHPool VFS installation failed:`,e),!1}try{return!!e.capi.sqlite3_vfs_find?.(t)}catch{return!0}}createWorkerFromConfig(){if(!this.config.workerUrl||typeof Worker>`u`)return;let e=typeof this.config.workerUrl==`string`?this.config.workerUrl:this.config.workerUrl.href;try{return new Worker(e,{type:`module`})}catch(e){console.warn(`Failed to create Worker from custom workerUrl:`,e);return}}createWorkerFromCdn(e){if(typeof Worker>`u`||typeof Blob>`u`||typeof URL>`u`)return;let t=this.config.cdnBaseUrl,n=this.config.version;if(!t||!n)return;let r=`${`${t}@${n}/sqlite-wasm/jswasm`}/sqlite3-bundler-friendly.mjs`,i=e.installSahpool?[` if (typeof sqlite3.installOpfsSAHPoolVfs === "function") {`,` await sqlite3.installOpfsSAHPoolVfs({ name: "opfs-sahpool", directory: "/unisqlite-sahpool" });`,` }`].join(` | ||
| - Your sqlite load strategy can load sqlite3Worker1Promiser (use sqlite.loadStrategy = 'npm' or 'cdn', or provide it globally)`}async tryCreateOpfsDatabase(e,t,n){if(n===`opfs`){if(e.oo1.OpfsDb)try{return s.log(`Creating OPFS-backed database (OpfsDb):`,t),this.db=new e.oo1.OpfsDb(t),this.workerDbId=void 0,this.activeStorageBackend=`opfs`,this.activeOpfsVfs=`opfs`,s.log(`Successfully created OPFS-backed database (OpfsDb)`),!0}catch(e){s.warn(`OPFS database creation via OpfsDb failed:`,e)}return await this.tryCreateWrappedWorkerOpfsDatabase(t,n)}if(await this.ensureSahpoolVfs(e))try{return s.log(`Creating SAHPool OPFS-backed database:`,t),this.db=new e.oo1.DB(t,`c`,`opfs-sahpool`),this.workerDbId=void 0,this.activeStorageBackend=`opfs`,this.activeOpfsVfs=`opfs-sahpool`,s.log(`Successfully created SAHPool OPFS-backed database`),!0}catch(e){s.warn(`SAHPool OPFS database creation failed:`,e)}return await this.tryCreateWrappedWorkerOpfsDatabase(t,n)}async ensureSahpoolVfs(e){if(globalThis.importScripts===void 0)return!1;let t=`opfs-sahpool`;try{if(e.capi.sqlite3_vfs_find?.(t))return!0}catch(e){s.warn(`SAHPool VFS lookup failed:`,e)}if(typeof e.installOpfsSAHPoolVfs!=`function`)return!1;try{await e.installOpfsSAHPoolVfs({name:t,directory:`/unisqlite-sahpool`})}catch(e){return s.warn(`SAHPool VFS installation failed:`,e),!1}try{return!!e.capi.sqlite3_vfs_find?.(t)}catch{return!0}}createWorkerFromConfig(){if(!this.config.workerUrl||typeof Worker>`u`)return;let e=typeof this.config.workerUrl==`string`?this.config.workerUrl:this.config.workerUrl.href;try{return new Worker(e,{type:`module`})}catch(e){s.warn(`Failed to create Worker from custom workerUrl:`,e);return}}createWorkerFromCdn(e){if(typeof Worker>`u`||typeof Blob>`u`||typeof URL>`u`)return;let t=this.config.cdnBaseUrl,n=this.config.version;if(!t||!n)return;let r=`${`${t}@${n}/sqlite-wasm/jswasm`}/sqlite3-bundler-friendly.mjs`,i=e.installSahpool?[` if (typeof sqlite3.installOpfsSAHPoolVfs === "function") {`,` await sqlite3.installOpfsSAHPoolVfs({ name: "opfs-sahpool", directory: "/unisqlite-sahpool" });`,` }`].join(` | ||
| `):``,a=[`import sqlite3InitModule from ${JSON.stringify(r)};`,`sqlite3InitModule().then(async (sqlite3) => {`,` try {`,i||` // no-op`,` } catch (e) {`,` console.warn("SAHPool VFS installation failed:", e);`,` }`,` sqlite3.initWorker1API();`,`});`,``].join(` | ||
| `),o=new Blob([a],{type:`text/javascript`}),s=URL.createObjectURL(o),c=new Worker(s,{type:`module`});return c.addEventListener(`message`,()=>{URL.revokeObjectURL(s)},{once:!0}),c.addEventListener(`error`,()=>{URL.revokeObjectURL(s)},{once:!0}),c}async getOrCreateWorkerPromiser(e){if(this.workerPromiser)return this.workerPromiser;if(this.workerPromiserInitPromise)return await this.workerPromiserInitPromise;let t=await this.loadSQLiteWorkerPromiserFactory(),n=this.config.storageBackend===`opfs`||this.config.opfsVfsType===`opfs`||this.config.opfsVfsType===`sahpool`,r=this.config.loadStrategy===`global`&&!n?5e3:2e4;this.workerPromiserInitPromise=new Promise((n,i)=>{let a=!1,o=setTimeout(()=>{a||(a=!0,i(Error(`SQLite worker initialization timed out after ${r}ms`)))},r),s=(e,t)=>{a||(a=!0,clearTimeout(o),e(t))},c=e=>{s(i,e instanceof Error?e:Error(String(e)))},l;try{l=t({...e?.worker?{worker:e.worker}:{},onready:e=>{if(typeof e==`function`){s(n,e);return}if(typeof l==`function`){s(n,l);return}if(l&&typeof l.then==`function`){l.then(e=>s(n,e),e=>c(e));return}c(Error(`sqlite3Worker1Promiser did not provide a usable promiser`))},onerror:e=>{let t=e instanceof Error?e.message:String(e);c(Error(`SQLite worker error: ${t}`))}}),l&&typeof l.then==`function`&&l.then(e=>s(n,e),e=>c(e))}catch(e){c(e)}});let i=await this.workerPromiserInitPromise;return this.workerPromiser=i,i}async tryCreateWrappedWorkerOpfsDatabase(e,t){try{let n=!this.workerPromiser&&!this.workerPromiserInitPromise?(()=>{let e=this.createWorkerFromConfig()??(t===`opfs-sahpool`?this.createWorkerFromCdn({installSahpool:!0}):this.createWorkerFromCdn({installSahpool:!1}));return e?{worker:e}:void 0})():void 0,r=await(await this.getOrCreateWorkerPromiser(n))(`open`,{filename:`file:${e}`,vfs:t}),i=r.dbId??r.result?.dbId;if(i===void 0)throw Error(`SQLite worker did not return a dbId`);if(typeof i!=`number`&&typeof i!=`string`)throw Error(`SQLite worker returned an invalid dbId (type=${typeof i})`);return this.db=void 0,this.workerDbId=i,this.activeStorageBackend=`opfs`,this.activeOpfsVfs=t,console.log(`Successfully created OPFS-backed database via wrapped worker (${t}):`,e),!0}catch(e){return console.warn(`Wrapped-worker OPFS database creation failed (vfs=${t}):`,e),!1}}},b=class{constructor(e,t,n){this.dbHost=e,this.hostElection=t,this.activeTxn=null,this.txnQueue=[],this.heartbeatTimers=new Map,this.txnPending=!1,this.rpcQueue=[],this.txnTimeoutMs=n?.txnTimeoutMs??3e4,this.opTimeoutMs=n?.opTimeoutMs??1e4,this.maxQueueSize=n?.maxQueueSize??10,this.heartbeatTimeoutMs=n?.heartbeatTimeoutMs??15e3}startWatchdog(){this.watchdogTimer||=setInterval(()=>{if(this.activeTxn){let e=Date.now()-this.activeTxn.lastActivityAt;e>this.txnTimeoutMs&&(a.warn(`Transaction ${this.activeTxn.txnId} timed out after ${e}ms, rolling back`),this.forceRollback())}let e=Date.now(),t=this.txnQueue.filter(t=>e-t.enqueuedAt>this.txnTimeoutMs);for(let e of t){let t=this.txnQueue.indexOf(e);t!==-1&&(this.txnQueue.splice(t,1),e.reject(Error(`Transaction queue wait timeout`)))}},5e3)}stopWatchdog(){this.watchdogTimer&&=(clearInterval(this.watchdogTimer),void 0)}getActiveTransaction(){return this.activeTxn}hasActiveTransaction(){return this.activeTxn!==null}isTransactionBlocking(){return this.activeTxn!==null||this.txnPending}async waitForTransactionSlot(){if(this.isTransactionBlocking())return new Promise((e,t)=>{this.rpcQueue.push({resolve:e,reject:t})})}async beginTransaction(e,t,n=`immediate`){if(this.activeTxn||this.txnPending){if(this.txnQueue.length>=this.maxQueueSize)throw Error(`Transaction queue full`);await new Promise((r,i)=>{this.txnQueue.push({txnId:e,originTabId:t,mode:n,resolve:r,reject:i,enqueuedAt:Date.now()})})}this.txnPending=!0;try{this.txnLockRelease=await this.hostElection.acquireTransactionLock();let r=n===`deferred`?`BEGIN`:n===`exclusive`?`BEGIN EXCLUSIVE`:`BEGIN IMMEDIATE`;await this.dbHost.execRaw(r),this.activeTxn={txnId:e,originTabId:t,startedAt:Date.now(),lastActivityAt:Date.now(),mode:n},this.resetHeartbeatTimer(e)}catch(e){throw this.txnLockRelease?.(),this.txnLockRelease=void 0,this.txnPending=!1,this.processQueue(),this.processRpcQueue(),e}finally{this.txnPending=!1}}async execInTransaction(e,t){return this.validateActiveTxn(e),this.activeTxn.lastActivityAt=Date.now(),this.resetHeartbeatTimer(e),await t()}recordHeartbeat(e){this.activeTxn?.txnId===e&&(this.activeTxn.lastActivityAt=Date.now(),this.resetHeartbeatTimer(e))}async commitTransaction(e){this.validateActiveTxn(e);try{await this.dbHost.execRaw(`COMMIT`)}finally{this.endTransaction()}}async rollbackTransaction(e){this.validateActiveTxn(e);try{await this.dbHost.execRaw(`ROLLBACK`)}finally{this.endTransaction()}}forceRollback(){if(this.activeTxn){try{this.dbHost.execRaw(`ROLLBACK`).catch(e=>{a.error(`Force rollback failed:`,e)})}catch(e){a.error(`Force rollback failed:`,e)}this.endTransaction()}}endTransaction(){if(this.activeTxn){let e=this.heartbeatTimers.get(this.activeTxn.txnId);e&&(clearTimeout(e),this.heartbeatTimers.delete(this.activeTxn.txnId)),this.activeTxn=null}this.txnLockRelease&&=(this.txnLockRelease(),void 0),this.processQueue(),this.processRpcQueue()}processQueue(){this.txnQueue.length>0&&!this.activeTxn&&!this.txnPending&&this.txnQueue.shift().resolve()}processRpcQueue(){if(this.activeTxn||this.txnPending)return;let e=this.rpcQueue;this.rpcQueue=[];for(let{resolve:t}of e)t()}resetHeartbeatTimer(e){let t=this.heartbeatTimers.get(e);t&&clearTimeout(t);let n=setTimeout(()=>{this.activeTxn?.txnId===e&&(a.warn(`No heartbeat for transaction ${e} in ${this.heartbeatTimeoutMs}ms, rolling back`),this.forceRollback())},this.heartbeatTimeoutMs);this.heartbeatTimers.set(e,n)}validateActiveTxn(e){if(!this.activeTxn)throw Error(`No active transaction (expected ${e})`);if(this.activeTxn.txnId!==e)throw Error(`Transaction ID mismatch: expected ${this.activeTxn.txnId}, got ${e}`);let t=Date.now()-this.activeTxn.lastActivityAt;if(t>this.txnTimeoutMs)throw this.forceRollback(),Error(`Transaction ${e} timed out after ${t}ms`)}async close(){this.stopWatchdog(),this.activeTxn&&this.forceRollback();for(let e of this.txnQueue)e.reject(Error(`Transaction session manager closed`));this.txnQueue=[];for(let e of this.rpcQueue)e.reject(Error(`Transaction session manager closed`));this.rpcQueue=[];for(let e of this.heartbeatTimers.values())clearTimeout(e);this.heartbeatTimers.clear()}},x=class{constructor(e,t,n=5e3){this.rpcChannel=e,this.txnId=t,this.heartbeatIntervalMs=n,this.committed=!1,this.rolledBack=!1,this.startHeartbeat()}startHeartbeat(){this.heartbeatInterval=setInterval(()=>{!this.committed&&!this.rolledBack&&this.rpcChannel.txnHeartbeat(this.txnId)},this.heartbeatIntervalMs)}stopHeartbeat(){this.heartbeatInterval&&=(clearInterval(this.heartbeatInterval),void 0)}ensureActive(){if(this.committed)throw Error(`Transaction already committed`);if(this.rolledBack)throw Error(`Transaction already rolled back`)}async query(e,t){return this.ensureActive(),(await this.rpcChannel.txnExec(this.txnId,`query`,{sql:e,params:t})).rows}async queryRaw(e,t){return this.ensureActive(),await this.rpcChannel.txnExec(this.txnId,`queryRaw`,{sql:e,params:t})}async run(e,t){this.ensureActive();let n=await this.rpcChannel.txnExec(this.txnId,`run`,{sql:e,params:t});return{rowsAffected:n.rowsAffected??0,lastInsertRowId:n.lastInsertRowId??0}}async exec(e){this.ensureActive(),await this.rpcChannel.txnExec(this.txnId,`exec`,{sql:e})}async transaction(e){this.ensureActive();let t=e(this);return t instanceof Promise?await t:t}async asyncTransaction(e,t){return this.ensureActive(),await e(this)}getConnectionType(){return`asyncTxn`}async close(){}async _commit(){this.ensureActive(),this.stopHeartbeat();try{await this.rpcChannel.txnCommit(this.txnId),this.committed=!0}catch(e){throw this.rolledBack=!0,e}}async _rollback(){if(!(this.committed||this.rolledBack)){this.stopHeartbeat();try{await this.rpcChannel.txnRollback(this.txnId)}finally{this.rolledBack=!0}}}isCommitted(){return this.committed}isRolledBack(){return this.rolledBack}},S=class{constructor(e,t){this.dbHost=e,this.isAsync=t}async query(e,t){return(await this.dbHost.executeSqlRaw(e,t)).rows}async queryRaw(e,t){return await this.dbHost.executeSqlRaw(e,t)}async run(e,t){let n=await this.dbHost.executeSqlRaw(e,t);return{rowsAffected:n.rowsAffected??0,lastInsertRowId:n.lastInsertRowId??0}}async exec(e){await this.dbHost.execRaw(e)}async transaction(e){let t=e(this);return t instanceof Promise?await t:t}async asyncTransaction(e){return await e(this)}getConnectionType(){return this.isAsync?`asyncTxn`:`syncTxn`}async close(){}},C=class t extends e{constructor(e){let t=e.path??e.name??`default`;super({...e,path:t}),this.dbHost=null,this.txnSessionManager=null,this.initialized=!1,this.closed=!1,this.options={...e,path:t},this.tabId=m(),this.sqliteConfig={loadStrategy:`global`,storageBackend:`auto`,opfsVfsType:`auto`,cdnBaseUrl:`https://cdn.jsdelivr.net/npm/@sqlite.org/sqlite-wasm`,version:`3.50.1-build1`,bundlerFriendly:!1,...e.sqlite},s.isSupported()||(o.warn(`Web Locks API not supported. Falling back to memory-only storage.`),this.sqliteConfig.storageBackend=`memory`),this.visibilityManager=new c,this.rpcChannel=new g(t,this.tabId),this.hostElection=new s({dbName:t,tabId:this.tabId,onBecomeHost:()=>this.becomeHost(),onLoseHost:()=>this.loseHost(),checkVisibility:()=>this.visibilityManager.isVisible()}),this.visibilityUnsubscribe=this.visibilityManager.onVisibilityChange(e=>{this.handleVisibilityChange(e)})}static async create(e){let n=new t(e);return await n.initialize(),n}getTabId(){return this.tabId}get isHost(){return this.hostElection.isHost}async initialize(){if(!this.initialized){if(this.initPromise)return this.initPromise;this.initPromise=this.doInitialize(),await this.initPromise,this.initialized=!0}}async doInitialize(){this.becomeHostPromise=new Promise(e=>{this.becomeHostResolver=e}),await this.hostElection.start();let e=new Promise(e=>{setTimeout(()=>e(`timeout`),500)});await Promise.race([this.becomeHostPromise.then(()=>`host`),e])===`host`||this.hostElection.isHost&&await this.becomeHostPromise}async becomeHost(){o.log(`Tab ${this.tabId} becoming Host for ${this.options.path}`),this.dbHost=await y.create({dbName:this.options.path,config:this.sqliteConfig}),this.txnSessionManager=new b(this.dbHost,this.hostElection),this.txnSessionManager.startWatchdog(),this.rpcChannel.setRequestHandler(this.handleRequest.bind(this)),this.becomeHostResolver&&=(this.becomeHostResolver(),void 0)}loseHost(){o.log(`Tab ${this.tabId} losing Host for ${this.options.path}`),this.rpcChannel.setRequestHandler(void 0),this.txnSessionManager&&=(this.txnSessionManager.close(),null),this.dbHost&&=(this.dbHost.close(),null)}handleVisibilityChange(e){e&&!this.hostElection.isHost&&!this.closed&&this.hostElection.start()}async handleRequest(e){if(!this.dbHost)throw Error(`Not Host`);switch(e.t){case`req`:return await this.handleRpcRequest(e);case`txn_begin`:return await this.handleTxnBegin(e);case`txn_exec`:return await this.handleTxnExec(e);case`txn_commit`:return await this.handleTxnCommit(e);case`txn_rollback`:return await this.handleTxnRollback(e);case`txn_heartbeat`:this.handleTxnHeartbeat(e);return;default:throw Error(`Unknown request type: ${e.t}`)}}async handleRpcRequest(e){let{op:t,payload:n}=e,{sql:r,params:i}=n;switch(this.txnSessionManager&&await this.txnSessionManager.waitForTransactionSlot(),t){case`query`:return{rows:await this.dbHost.query(r,i),columns:[]};case`queryRaw`:return await this.dbHost.queryRaw(r,i);case`run`:return await this.dbHost.run(r,i);case`exec`:return await this.dbHost.exec(r),null;default:throw Error(`Unknown RPC operation: ${String(t)}`)}}async handleTxnBegin(e){await this.txnSessionManager.beginTransaction(e.txnId,e.from,e.mode)}async handleTxnExec(e){let{txnId:t,op:n,payload:r}=e,{sql:i,params:a}=r;return await this.txnSessionManager.execInTransaction(t,async()=>{switch(n){case`query`:return{rows:await this.dbHost.query(i,a),columns:[]};case`queryRaw`:return await this.dbHost.queryRaw(i,a);case`run`:return await this.dbHost.run(i,a);case`exec`:return await this.dbHost.exec(i),null;default:throw Error(`Unknown transaction operation: ${String(n)}`)}})}async handleTxnCommit(e){await this.txnSessionManager.commitTransaction(e.txnId)}async handleTxnRollback(e){await this.txnSessionManager.rollbackTransaction(e.txnId)}handleTxnHeartbeat(e){this.txnSessionManager?.recordHeartbeat(e.txnId)}async query(e,t){return await this.initialize(),this.isHost&&this.dbHost?await this.dbHost.query(e,t):(await this.rpcChannel.request(`query`,{sql:e,params:t})).rows}async queryRaw(e,t){return await this.initialize(),this.isHost&&this.dbHost?await this.dbHost.queryRaw(e,t):await this.rpcChannel.request(`queryRaw`,{sql:e,params:t})}async run(e,t){return await this.initialize(),this.isHost&&this.dbHost?await this.dbHost.run(e,t):await this.rpcChannel.request(`run`,{sql:e,params:t})}async exec(e){if(await this.initialize(),this.isHost&&this.dbHost){await this.dbHost.exec(e);return}await this.rpcChannel.request(`exec`,{sql:e})}async transaction(e){return await this.initialize(),this.isHost&&this.dbHost?await this.executeLocalTransaction(e,!1):await this.executeRemoteTransaction(e)}async asyncTransaction(e,t){return await this.initialize(),this.isHost&&this.dbHost?await this.executeLocalAsyncTransaction(e,t):await this.executeRemoteTransaction(e,t)}getConnectionType(){return`direct`}async close(){this.closed||(this.closed=!0,this.visibilityUnsubscribe?.(),await this.hostElection.close(),this.rpcChannel.close(),this.visibilityManager.destroy(),this.txnSessionManager&&=(await this.txnSessionManager.close(),null),this.dbHost&&=(await this.dbHost.close(),null))}async executeLocalTransaction(e,t){await this.dbHost.execRaw(`BEGIN`);let n=new S(this.dbHost,t);try{let t=e(n),r=t instanceof Promise?await t:t;return await this.dbHost.execRaw(`COMMIT`),r}catch(e){try{await this.dbHost.execRaw(`ROLLBACK`)}catch(e){console.error(`Rollback failed:`,e)}throw e}}async executeLocalAsyncTransaction(e,t){let n=t?.timeoutMs??3e4;await this.dbHost.execRaw(`BEGIN IMMEDIATE`);let r=new S(this.dbHost,!0),i,a=!1;try{let t=new Promise((e,t)=>{i=setTimeout(()=>{a||t(Error(`Async transaction timeout after ${n}ms`))},n)}),o=await Promise.race([e(r),t]);return a=!0,i&&clearTimeout(i),await this.dbHost.execRaw(`COMMIT`),o}catch(e){a=!0,i&&clearTimeout(i);try{await this.dbHost.execRaw(`ROLLBACK`)}catch(e){console.error(`Rollback failed:`,e)}throw e}}async executeRemoteTransaction(e,t){let n=h(),r=t?.timeoutMs??3e4;await this.rpcChannel.txnBegin(n,`immediate`,r);let i=new x(this.rpcChannel,n),a,o=!1;try{let t=new Promise((e,t)=>{a=setTimeout(()=>{o||t(Error(`Remote transaction timeout after ${r}ms`))},r)}),n=e(i),s=n instanceof Promise?n:Promise.resolve(n),c=await Promise.race([s,t]);return o=!0,a&&clearTimeout(a),await i._commit(),c}catch(e){o=!0,a&&clearTimeout(a);try{await i._rollback()}catch(e){console.error(`Remote rollback failed:`,e)}throw e}}getSQLiteInfo(){let e=this.isHost?this.dbHost!==null:this.initialized&&!this.closed;return{config:this.sqliteConfig,isInitialized:this.initialized,isHost:this.isHost,isReady:e,tabId:this.tabId,hasDatabase:this.dbHost!==null,usesWorker:this.dbHost?.isWorkerDbActive()??!1,activeStorageBackend:this.dbHost?.getActiveStorageBackend()??`unknown`,activeOpfsVfs:this.dbHost?.getActiveOpfsVfs()}}getActiveStorageBackend(){return this.dbHost?.getActiveStorageBackend()??`unknown`}};export{g as a,m as c,f as d,l as f,y as i,h as l,s as m,x as n,u as o,c as p,b as r,p as s,C as t,d as u}; | ||
| `),o=new Blob([a],{type:`text/javascript`}),s=URL.createObjectURL(o),c=new Worker(s,{type:`module`});return c.addEventListener(`message`,()=>{URL.revokeObjectURL(s)},{once:!0}),c.addEventListener(`error`,()=>{URL.revokeObjectURL(s)},{once:!0}),c}async getOrCreateWorkerPromiser(e){if(this.workerPromiser)return this.workerPromiser;if(this.workerPromiserInitPromise)return await this.workerPromiserInitPromise;let t=await this.loadSQLiteWorkerPromiserFactory(),n=this.config.storageBackend===`opfs`||this.config.opfsVfsType===`opfs`||this.config.opfsVfsType===`sahpool`,r=this.config.loadStrategy===`global`&&!n?5e3:2e4;this.workerPromiserInitPromise=new Promise((n,i)=>{let a=!1,o=setTimeout(()=>{a||(a=!0,i(Error(`SQLite worker initialization timed out after ${r}ms`)))},r),s=(e,t)=>{a||(a=!0,clearTimeout(o),e(t))},c=e=>{s(i,e instanceof Error?e:Error(String(e)))},l;try{l=t({...e?.worker?{worker:e.worker}:{},onready:e=>{if(typeof e==`function`){s(n,e);return}if(typeof l==`function`){s(n,l);return}if(l&&typeof l.then==`function`){l.then(e=>s(n,e),e=>c(e));return}c(Error(`sqlite3Worker1Promiser did not provide a usable promiser`))},onerror:e=>{let t=e instanceof Error?e.message:String(e);c(Error(`SQLite worker error: ${t}`))}}),l&&typeof l.then==`function`&&l.then(e=>s(n,e),e=>c(e))}catch(e){c(e)}});let i=await this.workerPromiserInitPromise;return this.workerPromiser=i,i}async tryCreateWrappedWorkerOpfsDatabase(e,t){try{let n=!this.workerPromiser&&!this.workerPromiserInitPromise?(()=>{let e=this.createWorkerFromConfig()??(t===`opfs-sahpool`?this.createWorkerFromCdn({installSahpool:!0}):this.createWorkerFromCdn({installSahpool:!1}));return e?{worker:e}:void 0})():void 0,r=await(await this.getOrCreateWorkerPromiser(n))(`open`,{filename:`file:${e}`,vfs:t}),i=r.dbId??r.result?.dbId;if(i===void 0)throw Error(`SQLite worker did not return a dbId`);if(typeof i!=`number`&&typeof i!=`string`)throw Error(`SQLite worker returned an invalid dbId (type=${typeof i})`);return this.db=void 0,this.workerDbId=i,this.activeStorageBackend=`opfs`,this.activeOpfsVfs=t,s.log(`Successfully created OPFS-backed database via wrapped worker (${t}):`,e),!0}catch(e){return s.warn(`Wrapped-worker OPFS database creation failed (vfs=${t}):`,e),!1}}},S=class{constructor(e,t,n){this.dbHost=e,this.hostElection=t,this.activeTxn=null,this.txnQueue=[],this.heartbeatTimers=new Map,this.txnPending=!1,this.rpcQueue=[],this.txnTimeoutMs=n?.txnTimeoutMs??3e4,this.opTimeoutMs=n?.opTimeoutMs??1e4,this.maxQueueSize=n?.maxQueueSize??10,this.heartbeatTimeoutMs=n?.heartbeatTimeoutMs??15e3}startWatchdog(){this.watchdogTimer||=setInterval(()=>{if(this.activeTxn){let e=Date.now()-this.activeTxn.lastActivityAt;e>this.txnTimeoutMs&&(a.warn(`Transaction ${this.activeTxn.txnId} timed out after ${e}ms, rolling back`),this.forceRollback())}let e=Date.now(),t=this.txnQueue.filter(t=>e-t.enqueuedAt>this.txnTimeoutMs);for(let e of t){let t=this.txnQueue.indexOf(e);t!==-1&&(this.txnQueue.splice(t,1),e.reject(Error(`Transaction queue wait timeout`)))}},5e3)}stopWatchdog(){this.watchdogTimer&&=(clearInterval(this.watchdogTimer),void 0)}getActiveTransaction(){return this.activeTxn}hasActiveTransaction(){return this.activeTxn!==null}isTransactionBlocking(){return this.activeTxn!==null||this.txnPending}async waitForTransactionSlot(){if(this.isTransactionBlocking())return new Promise((e,t)=>{this.rpcQueue.push({resolve:e,reject:t})})}async beginTransaction(e,t,n=`immediate`){if(this.activeTxn||this.txnPending){if(this.txnQueue.length>=this.maxQueueSize)throw Error(`Transaction queue full`);await new Promise((r,i)=>{this.txnQueue.push({txnId:e,originTabId:t,mode:n,resolve:r,reject:i,enqueuedAt:Date.now()})})}this.txnPending=!0;try{this.txnLockRelease=await this.hostElection.acquireTransactionLock();let r=n===`deferred`?`BEGIN`:n===`exclusive`?`BEGIN EXCLUSIVE`:`BEGIN IMMEDIATE`;await this.dbHost.execRaw(r),this.activeTxn={txnId:e,originTabId:t,startedAt:Date.now(),lastActivityAt:Date.now(),mode:n},this.resetHeartbeatTimer(e)}catch(e){throw this.txnLockRelease?.(),this.txnLockRelease=void 0,this.txnPending=!1,this.processQueue(),this.processRpcQueue(),e}finally{this.txnPending=!1}}async execInTransaction(e,t){return this.validateActiveTxn(e),this.activeTxn.lastActivityAt=Date.now(),this.resetHeartbeatTimer(e),await t()}recordHeartbeat(e){this.activeTxn?.txnId===e&&(this.activeTxn.lastActivityAt=Date.now(),this.resetHeartbeatTimer(e))}async commitTransaction(e){this.validateActiveTxn(e);try{await this.dbHost.execRaw(`COMMIT`)}finally{this.endTransaction()}}async rollbackTransaction(e){this.validateActiveTxn(e);try{await this.dbHost.execRaw(`ROLLBACK`)}finally{this.endTransaction()}}forceRollback(){if(this.activeTxn){try{this.dbHost.execRaw(`ROLLBACK`).catch(e=>{a.error(`Force rollback failed:`,e)})}catch(e){a.error(`Force rollback failed:`,e)}this.endTransaction()}}endTransaction(){if(this.activeTxn){let e=this.heartbeatTimers.get(this.activeTxn.txnId);e&&(clearTimeout(e),this.heartbeatTimers.delete(this.activeTxn.txnId)),this.activeTxn=null}this.txnLockRelease&&=(this.txnLockRelease(),void 0),this.processQueue(),this.processRpcQueue()}processQueue(){this.txnQueue.length>0&&!this.activeTxn&&!this.txnPending&&this.txnQueue.shift().resolve()}processRpcQueue(){if(this.activeTxn||this.txnPending)return;let e=this.rpcQueue;this.rpcQueue=[];for(let{resolve:t}of e)t()}resetHeartbeatTimer(e){let t=this.heartbeatTimers.get(e);t&&clearTimeout(t);let n=setTimeout(()=>{this.activeTxn?.txnId===e&&(a.warn(`No heartbeat for transaction ${e} in ${this.heartbeatTimeoutMs}ms, rolling back`),this.forceRollback())},this.heartbeatTimeoutMs);this.heartbeatTimers.set(e,n)}validateActiveTxn(e){if(!this.activeTxn)throw Error(`No active transaction (expected ${e})`);if(this.activeTxn.txnId!==e)throw Error(`Transaction ID mismatch: expected ${this.activeTxn.txnId}, got ${e}`);let t=Date.now()-this.activeTxn.lastActivityAt;if(t>this.txnTimeoutMs)throw this.forceRollback(),Error(`Transaction ${e} timed out after ${t}ms`)}async close(){this.stopWatchdog(),this.activeTxn&&this.forceRollback();for(let e of this.txnQueue)e.reject(Error(`Transaction session manager closed`));this.txnQueue=[];for(let e of this.rpcQueue)e.reject(Error(`Transaction session manager closed`));this.rpcQueue=[];for(let e of this.heartbeatTimers.values())clearTimeout(e);this.heartbeatTimers.clear()}},C=class{constructor(e,t,n=5e3){this.rpcChannel=e,this.txnId=t,this.heartbeatIntervalMs=n,this.committed=!1,this.rolledBack=!1,this.startHeartbeat()}startHeartbeat(){this.heartbeatInterval=setInterval(()=>{!this.committed&&!this.rolledBack&&this.rpcChannel.txnHeartbeat(this.txnId)},this.heartbeatIntervalMs)}stopHeartbeat(){this.heartbeatInterval&&=(clearInterval(this.heartbeatInterval),void 0)}ensureActive(){if(this.committed)throw Error(`Transaction already committed`);if(this.rolledBack)throw Error(`Transaction already rolled back`)}async query(e,t){return this.ensureActive(),(await this.rpcChannel.txnExec(this.txnId,`query`,{sql:e,params:t})).rows}async queryRaw(e,t){return this.ensureActive(),await this.rpcChannel.txnExec(this.txnId,`queryRaw`,{sql:e,params:t})}async run(e,t){this.ensureActive();let n=await this.rpcChannel.txnExec(this.txnId,`run`,{sql:e,params:t});return{rowsAffected:n.rowsAffected??0,lastInsertRowId:n.lastInsertRowId??0}}async exec(e){this.ensureActive(),await this.rpcChannel.txnExec(this.txnId,`exec`,{sql:e})}async transaction(e){this.ensureActive();let t=e(this);return t instanceof Promise?await t:t}async asyncTransaction(e,t){return this.ensureActive(),await e(this)}getConnectionType(){return`asyncTxn`}async close(){}async _commit(){this.ensureActive(),this.stopHeartbeat();try{await this.rpcChannel.txnCommit(this.txnId),this.committed=!0}catch(e){throw this.rolledBack=!0,e}}async _rollback(){if(!(this.committed||this.rolledBack)){this.stopHeartbeat();try{await this.rpcChannel.txnRollback(this.txnId)}finally{this.rolledBack=!0}}}isCommitted(){return this.committed}isRolledBack(){return this.rolledBack}},w=class{constructor(e,t){this.dbHost=e,this.isAsync=t}async query(e,t){return(await this.dbHost.executeSqlRaw(e,t)).rows}async queryRaw(e,t){return await this.dbHost.executeSqlRaw(e,t)}async run(e,t){let n=await this.dbHost.executeSqlRaw(e,t);return{rowsAffected:n.rowsAffected??0,lastInsertRowId:n.lastInsertRowId??0}}async exec(e){await this.dbHost.execRaw(e)}async transaction(e){let t=e(this);return t instanceof Promise?await t:t}async asyncTransaction(e){return await e(this)}getConnectionType(){return this.isAsync?`asyncTxn`:`syncTxn`}async close(){}},T=class t extends e{constructor(e){let t=e.path??e.name??`default`;super({...e,path:t}),this.dbHost=null,this.txnSessionManager=null,this.initialized=!1,this.closed=!1,this.options={...e,path:t},this.tabId=g(),this.sqliteConfig={loadStrategy:`global`,storageBackend:`auto`,opfsVfsType:`auto`,cdnBaseUrl:`https://cdn.jsdelivr.net/npm/@sqlite.org/sqlite-wasm`,version:`3.50.1-build1`,bundlerFriendly:!1,...e.sqlite},l.isSupported()||(o.warn(`Web Locks API not supported. Falling back to memory-only storage.`),this.sqliteConfig.storageBackend=`memory`),this.visibilityManager=new u,this.rpcChannel=new v(t,this.tabId),this.hostElection=new l({dbName:t,tabId:this.tabId,onBecomeHost:()=>this.becomeHost(),onLoseHost:()=>this.loseHost(),checkVisibility:()=>this.visibilityManager.isVisible()}),this.visibilityUnsubscribe=this.visibilityManager.onVisibilityChange(e=>{this.handleVisibilityChange(e)})}static async create(e){let n=new t(e);return await n.initialize(),n}getTabId(){return this.tabId}get isHost(){return this.hostElection.isHost}async initialize(){if(!this.initialized){if(this.initPromise)return this.initPromise;this.initPromise=this.doInitialize(),await this.initPromise,this.initialized=!0}}async doInitialize(){this.becomeHostPromise=new Promise(e=>{this.becomeHostResolver=e}),await this.hostElection.start();let e=new Promise(e=>{setTimeout(()=>e(`timeout`),500)});await Promise.race([this.becomeHostPromise.then(()=>`host`),e])===`host`||this.hostElection.isHost&&await this.becomeHostPromise}async becomeHost(){o.log(`Tab ${this.tabId} becoming Host for ${this.options.path}`),this.dbHost=await x.create({dbName:this.options.path,config:this.sqliteConfig}),this.txnSessionManager=new S(this.dbHost,this.hostElection),this.txnSessionManager.startWatchdog(),this.rpcChannel.setRequestHandler(this.handleRequest.bind(this)),this.becomeHostResolver&&=(this.becomeHostResolver(),void 0)}loseHost(){o.log(`Tab ${this.tabId} losing Host for ${this.options.path}`),this.rpcChannel.setRequestHandler(void 0),this.txnSessionManager&&=(this.txnSessionManager.close(),null),this.dbHost&&=(this.dbHost.close(),null)}handleVisibilityChange(e){e&&!this.hostElection.isHost&&!this.closed&&this.hostElection.start()}async handleRequest(e){if(!this.dbHost)throw Error(`Not Host`);switch(e.t){case`req`:return await this.handleRpcRequest(e);case`txn_begin`:return await this.handleTxnBegin(e);case`txn_exec`:return await this.handleTxnExec(e);case`txn_commit`:return await this.handleTxnCommit(e);case`txn_rollback`:return await this.handleTxnRollback(e);case`txn_heartbeat`:this.handleTxnHeartbeat(e);return;default:throw Error(`Unknown request type: ${e.t}`)}}async handleRpcRequest(e){let{op:t,payload:n}=e,{sql:r,params:i}=n;switch(this.txnSessionManager&&await this.txnSessionManager.waitForTransactionSlot(),t){case`query`:return{rows:await this.dbHost.query(r,i),columns:[]};case`queryRaw`:return await this.dbHost.queryRaw(r,i);case`run`:return await this.dbHost.run(r,i);case`exec`:return await this.dbHost.exec(r),null;default:throw Error(`Unknown RPC operation: ${String(t)}`)}}async handleTxnBegin(e){await this.txnSessionManager.beginTransaction(e.txnId,e.from,e.mode)}async handleTxnExec(e){let{txnId:t,op:n,payload:r}=e,{sql:i,params:a}=r;return await this.txnSessionManager.execInTransaction(t,async()=>{switch(n){case`query`:return{rows:await this.dbHost.query(i,a),columns:[]};case`queryRaw`:return await this.dbHost.queryRaw(i,a);case`run`:return await this.dbHost.run(i,a);case`exec`:return await this.dbHost.exec(i),null;default:throw Error(`Unknown transaction operation: ${String(n)}`)}})}async handleTxnCommit(e){await this.txnSessionManager.commitTransaction(e.txnId)}async handleTxnRollback(e){await this.txnSessionManager.rollbackTransaction(e.txnId)}handleTxnHeartbeat(e){this.txnSessionManager?.recordHeartbeat(e.txnId)}async query(e,t){return await this.initialize(),this.isHost&&this.dbHost?await this.dbHost.query(e,t):(await this.rpcChannel.request(`query`,{sql:e,params:t})).rows}async queryRaw(e,t){return await this.initialize(),this.isHost&&this.dbHost?await this.dbHost.queryRaw(e,t):await this.rpcChannel.request(`queryRaw`,{sql:e,params:t})}async run(e,t){return await this.initialize(),this.isHost&&this.dbHost?await this.dbHost.run(e,t):await this.rpcChannel.request(`run`,{sql:e,params:t})}async exec(e){if(await this.initialize(),this.isHost&&this.dbHost){await this.dbHost.exec(e);return}await this.rpcChannel.request(`exec`,{sql:e})}async transaction(e){return await this.initialize(),this.isHost&&this.dbHost?await this.executeLocalTransaction(e,!1):await this.executeRemoteTransaction(e)}async asyncTransaction(e,t){return await this.initialize(),this.isHost&&this.dbHost?await this.executeLocalAsyncTransaction(e,t):await this.executeRemoteTransaction(e,t)}getConnectionType(){return`direct`}async close(){this.closed||(this.closed=!0,this.visibilityUnsubscribe?.(),await this.hostElection.close(),this.rpcChannel.close(),this.visibilityManager.destroy(),this.txnSessionManager&&=(await this.txnSessionManager.close(),null),this.dbHost&&=(await this.dbHost.close(),null))}async executeLocalTransaction(e,t){await this.dbHost.execRaw(`BEGIN`);let n=new w(this.dbHost,t);try{let t=e(n),r=t instanceof Promise?await t:t;return await this.dbHost.execRaw(`COMMIT`),r}catch(e){try{await this.dbHost.execRaw(`ROLLBACK`)}catch(e){o.error(`Rollback failed:`,e)}throw e}}async executeLocalAsyncTransaction(e,t){let n=t?.timeoutMs??3e4;await this.dbHost.execRaw(`BEGIN IMMEDIATE`);let r=new w(this.dbHost,!0),i,a=!1;try{let t=new Promise((e,t)=>{i=setTimeout(()=>{a||t(Error(`Async transaction timeout after ${n}ms`))},n)}),o=await Promise.race([e(r),t]);return a=!0,i&&clearTimeout(i),await this.dbHost.execRaw(`COMMIT`),o}catch(e){a=!0,i&&clearTimeout(i);try{await this.dbHost.execRaw(`ROLLBACK`)}catch(e){o.error(`Rollback failed:`,e)}throw e}}async executeRemoteTransaction(e,t){let n=_(),r=t?.timeoutMs??3e4;await this.rpcChannel.txnBegin(n,`immediate`,r);let i=new C(this.rpcChannel,n),a,s=!1;try{let t=new Promise((e,t)=>{a=setTimeout(()=>{s||t(Error(`Remote transaction timeout after ${r}ms`))},r)}),n=e(i),o=n instanceof Promise?n:Promise.resolve(n),c=await Promise.race([o,t]);return s=!0,a&&clearTimeout(a),await i._commit(),c}catch(e){s=!0,a&&clearTimeout(a);try{await i._rollback()}catch(e){o.error(`Remote rollback failed:`,e)}throw e}}getSQLiteInfo(){let e=this.isHost?this.dbHost!==null:this.initialized&&!this.closed;return{config:this.sqliteConfig,isInitialized:this.initialized,isHost:this.isHost,isReady:e,tabId:this.tabId,hasDatabase:this.dbHost!==null,usesWorker:this.dbHost?.isWorkerDbActive()??!1,activeStorageBackend:this.dbHost?.getActiveStorageBackend()??`unknown`,activeOpfsVfs:this.dbHost?.getActiveOpfsVfs()}}getActiveStorageBackend(){return this.dbHost?.getActiveStorageBackend()??`unknown`}};export{v as a,g as c,m as d,d as f,x as i,_ as l,l as m,C as n,f as o,u as p,S as r,h as s,T as t,p as u}; | ||
| //# sourceMappingURL=browser2.mjs.map |
+1
-1
@@ -1,2 +0,2 @@ | ||
| const e=require(`./cloudflare-do2.cjs`);async function t(e){let t=n();switch(t){case`node`:let{NodeAdapter:n}=await Promise.resolve().then(()=>require(`./node2.cjs`));return new n(e);case`browser`:let{BrowserAdapter:r}=await Promise.resolve().then(()=>require(`./browser3.cjs`));return r.create(e);case`cloudflare`:let{CloudflareDOAdapter:i}=await Promise.resolve().then(()=>require(`./cloudflare-do.cjs`));return new i(e);default:throw Error(`Unsupported platform: ${t}`)}}function n(){if(typeof globalThis<`u`){if(globalThis.process?.versions?.node)return`node`;if(globalThis.navigator?.userAgent===`Cloudflare-Workers`)return`cloudflare`;if(globalThis.navigator?.userAgent)return`browser`}return`unknown`}exports.CloudflareDOAdapter=e.t,exports.createCloudflareDOAdapter=e.n,exports.openStore=t; | ||
| const e=require(`./cloudflare-do2.cjs`);async function t(e){let t=n();switch(t){case`node`:let{NodeAdapter:n}=await Promise.resolve().then(()=>require(`./node3.cjs`));return new n(e);case`browser`:let{BrowserAdapter:r}=await Promise.resolve().then(()=>require(`./browser3.cjs`));return r.create(e);case`cloudflare`:let{CloudflareDOAdapter:i}=await Promise.resolve().then(()=>require(`./cloudflare-do.cjs`));return new i(e);default:throw Error(`Unsupported platform: ${t}`)}}function n(){if(typeof globalThis<`u`){if(globalThis.process?.versions?.node)return`node`;if(globalThis.navigator?.userAgent===`Cloudflare-Workers`)return`cloudflare`;if(globalThis.navigator?.userAgent)return`browser`}return`unknown`}exports.CloudflareDOAdapter=e.t,exports.createCloudflareDOAdapter=e.n,exports.openStore=t; | ||
| //# sourceMappingURL=index.cjs.map |
+1
-1
@@ -1,2 +0,2 @@ | ||
| import{n as e,t}from"./cloudflare-do2.mjs";async function n(e){let t=r();switch(t){case`node`:let{NodeAdapter:n}=await import(`./node2.mjs`);return new n(e);case`browser`:let{BrowserAdapter:r}=await import(`./browser3.mjs`);return r.create(e);case`cloudflare`:let{CloudflareDOAdapter:i}=await import(`./cloudflare-do.mjs`);return new i(e);default:throw Error(`Unsupported platform: ${t}`)}}function r(){if(typeof globalThis<`u`){if(globalThis.process?.versions?.node)return`node`;if(globalThis.navigator?.userAgent===`Cloudflare-Workers`)return`cloudflare`;if(globalThis.navigator?.userAgent)return`browser`}return`unknown`}export{t as CloudflareDOAdapter,e as createCloudflareDOAdapter,n as openStore}; | ||
| import{n as e,t}from"./cloudflare-do2.mjs";async function n(e){let t=r();switch(t){case`node`:let{NodeAdapter:n}=await import(`./node3.mjs`);return new n(e);case`browser`:let{BrowserAdapter:r}=await import(`./browser3.mjs`);return r.create(e);case`cloudflare`:let{CloudflareDOAdapter:i}=await import(`./cloudflare-do.mjs`);return new i(e);default:throw Error(`Unsupported platform: ${t}`)}}function r(){if(typeof globalThis<`u`){if(globalThis.process?.versions?.node)return`node`;if(globalThis.navigator?.userAgent===`Cloudflare-Workers`)return`cloudflare`;if(globalThis.navigator?.userAgent)return`browser`}return`unknown`}export{t as CloudflareDOAdapter,e as createCloudflareDOAdapter,n as openStore}; | ||
| //# sourceMappingURL=index.mjs.map |
+1
-1
@@ -1,2 +0,2 @@ | ||
| const e=require(`./node3.cjs`);function t(t){return new e.t(t)}exports.NodeAdapter=e.t,exports.openNodeStore=t; | ||
| const e=require(`./node2.cjs`);function t(t){return new e.t(t)}exports.NodeAdapter=e.t,exports.openNodeStore=t; | ||
| //# sourceMappingURL=node.cjs.map |
+1
-1
@@ -1,2 +0,2 @@ | ||
| import{t as e}from"./node3.mjs";function t(t){return new e(t)}export{e as NodeAdapter,t as openNodeStore}; | ||
| import{t as e}from"./node2.mjs";function t(t){return new e(t)}export{e as NodeAdapter,t as openNodeStore}; | ||
| //# sourceMappingURL=node.mjs.map |
+2
-1
@@ -1,1 +0,2 @@ | ||
| const e=require(`./node3.cjs`);exports.NodeAdapter=e.t; | ||
| const e=require(`./chunk.cjs`),t=require(`./base.cjs`);let n=require(`debug`);n=e.t(n);let r=require(`better-sqlite3`);r=e.t(r);const i=`unisqlite`,a=`0.4.0`;function o(e){let t=(0,n.default)(`${i}:${e}`),r=(0,n.default)(`${i}:${e}:warn`),a=(0,n.default)(`${i}:${e}:error`);return a.enabled=!0,{log:t,warn:r,error:a}}const s=o(`node`);var c=class extends t.t{constructor(e){super(e),this._closed=!1,s.log(`UniSQLite v0.4.0 - Opening database: ${e.path}`),this.db=new r.default(e.path,{fileMustExist:!1}),this.db.pragma(`journal_mode = WAL`),this.db.pragma(`busy_timeout = 5000`),s.log(`Database opened with WAL mode`)}normalizeParams(e){return e?Array.isArray(e)?e:Object.values(e):[]}convertBuffersToUint8Array(e){if(e==null)return e;if(Buffer.isBuffer(e))return new Uint8Array(e);if(Array.isArray(e))return e.map(e=>this.convertBuffersToUint8Array(e));if(typeof e==`object`){let t={};for(let[n,r]of Object.entries(e))t[n]=this.convertBuffersToUint8Array(r);return t}return e}checkConnection(){if(this._closed||!this.db.open)throw Error(`Database connection is closed`)}async query(e,t){this.checkConnection();let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r);return this.convertBuffersToUint8Array(i)}async queryRaw(e,t){this.checkConnection();let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r),a=n.columns().map(e=>e.name);return{rows:this.convertBuffersToUint8Array(i),columns:a,rowsAffected:0,lastInsertRowId:0}}async run(e,t){this.checkConnection();let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.run(r);return{rowsAffected:i.changes,lastInsertRowId:i.lastInsertRowid}}async exec(e){this.checkConnection(),this.db.exec(e)}transaction(e){this.checkConnection(),this.db.exec(`BEGIN`);let t=new u(this.db);return(async()=>{try{let n=await e(t);return this.db.exec(`COMMIT`),n}catch(e){throw this.db.exec(`ROLLBACK`),e}})()}async asyncTransaction(e,t){this.checkConnection();let n=t?.timeoutMs??3e4,r=!1;try{this.db.exec(`BEGIN IMMEDIATE`)}catch(e){if(e.message.includes(`cannot start a transaction within a transaction`))r=!0;else throw e}let i,a=!1;try{let t=new Promise((e,t)=>{i=setTimeout(()=>{a||t(Error(`Async transaction timeout after ${n}ms`))},n)}),o=new d(this.db),s=await Promise.race([e(o),t]);return a=!0,i&&clearTimeout(i),r||this.db.exec(`COMMIT`),s}catch(e){a=!0,i&&clearTimeout(i);try{this.db.exec(`ROLLBACK`)}catch(e){s.error(`Rollback failed:`,e)}throw e}}getConnectionType(){return`direct`}async close(){!this._closed&&this.db.open&&(this.db.close(),this._closed=!0)}get isOpen(){return!this._closed&&this.db.open}},l=class{constructor(e){this.db=e,this.inTransaction=!0}normalizeParams(e){return e?Array.isArray(e)?e:Object.values(e):[]}convertBuffersToUint8Array(e){if(e==null)return e;if(Buffer.isBuffer(e))return new Uint8Array(e);if(Array.isArray(e))return e.map(e=>this.convertBuffersToUint8Array(e));if(typeof e==`object`){let t={};for(let[n,r]of Object.entries(e))t[n]=this.convertBuffersToUint8Array(r);return t}return e}query(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r),a=this.convertBuffersToUint8Array(i);return Promise.resolve(a)}queryRaw(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r),a=n.columns().map(e=>e.name),o={rows:this.convertBuffersToUint8Array(i),columns:a,rowsAffected:0,lastInsertRowId:0};return Promise.resolve(o)}run(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.run(r),a={rowsAffected:i.changes,lastInsertRowId:i.lastInsertRowid};return Promise.resolve(a)}exec(e){return this.db.exec(e),Promise.resolve()}querySync(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r);return this.convertBuffersToUint8Array(i)}runSync(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.run(r);return{rowsAffected:i.changes,lastInsertRowId:i.lastInsertRowid}}execSync(e){this.db.exec(e)}async close(){}},u=class extends l{getConnectionType(){return`syncTxn`}async transaction(e){return await e(this)}async asyncTransaction(e,t){throw Error(`asyncTransaction is not supported in syncTxn connections. Use transaction() instead or create a direct connection.`)}},d=class extends l{getConnectionType(){return`asyncTxn`}async transaction(e){return await e(this)}async asyncTransaction(e,t){return await e(this)}};Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return c}}); | ||
| //# sourceMappingURL=node2.cjs.map |
+2
-1
@@ -1,1 +0,2 @@ | ||
| import{t as e}from"./node3.mjs";export{e as NodeAdapter}; | ||
| import{t as e}from"./base.mjs";import t from"debug";import n from"better-sqlite3";const r=`unisqlite`;function i(e){let n=t(`${r}:${e}`),i=t(`${r}:${e}:warn`),a=t(`${r}:${e}:error`);return a.enabled=!0,{log:n,warn:i,error:a}}const a=i(`node`);var o=class extends e{constructor(e){super(e),this._closed=!1,a.log(`UniSQLite v0.4.0 - Opening database: ${e.path}`),this.db=new n(e.path,{fileMustExist:!1}),this.db.pragma(`journal_mode = WAL`),this.db.pragma(`busy_timeout = 5000`),a.log(`Database opened with WAL mode`)}normalizeParams(e){return e?Array.isArray(e)?e:Object.values(e):[]}convertBuffersToUint8Array(e){if(e==null)return e;if(Buffer.isBuffer(e))return new Uint8Array(e);if(Array.isArray(e))return e.map(e=>this.convertBuffersToUint8Array(e));if(typeof e==`object`){let t={};for(let[n,r]of Object.entries(e))t[n]=this.convertBuffersToUint8Array(r);return t}return e}checkConnection(){if(this._closed||!this.db.open)throw Error(`Database connection is closed`)}async query(e,t){this.checkConnection();let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r);return this.convertBuffersToUint8Array(i)}async queryRaw(e,t){this.checkConnection();let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r),a=n.columns().map(e=>e.name);return{rows:this.convertBuffersToUint8Array(i),columns:a,rowsAffected:0,lastInsertRowId:0}}async run(e,t){this.checkConnection();let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.run(r);return{rowsAffected:i.changes,lastInsertRowId:i.lastInsertRowid}}async exec(e){this.checkConnection(),this.db.exec(e)}transaction(e){this.checkConnection(),this.db.exec(`BEGIN`);let t=new c(this.db);return(async()=>{try{let n=await e(t);return this.db.exec(`COMMIT`),n}catch(e){throw this.db.exec(`ROLLBACK`),e}})()}async asyncTransaction(e,t){this.checkConnection();let n=t?.timeoutMs??3e4,r=!1;try{this.db.exec(`BEGIN IMMEDIATE`)}catch(e){if(e.message.includes(`cannot start a transaction within a transaction`))r=!0;else throw e}let i,o=!1;try{let t=new Promise((e,t)=>{i=setTimeout(()=>{o||t(Error(`Async transaction timeout after ${n}ms`))},n)}),a=new l(this.db),s=await Promise.race([e(a),t]);return o=!0,i&&clearTimeout(i),r||this.db.exec(`COMMIT`),s}catch(e){o=!0,i&&clearTimeout(i);try{this.db.exec(`ROLLBACK`)}catch(e){a.error(`Rollback failed:`,e)}throw e}}getConnectionType(){return`direct`}async close(){!this._closed&&this.db.open&&(this.db.close(),this._closed=!0)}get isOpen(){return!this._closed&&this.db.open}},s=class{constructor(e){this.db=e,this.inTransaction=!0}normalizeParams(e){return e?Array.isArray(e)?e:Object.values(e):[]}convertBuffersToUint8Array(e){if(e==null)return e;if(Buffer.isBuffer(e))return new Uint8Array(e);if(Array.isArray(e))return e.map(e=>this.convertBuffersToUint8Array(e));if(typeof e==`object`){let t={};for(let[n,r]of Object.entries(e))t[n]=this.convertBuffersToUint8Array(r);return t}return e}query(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r),a=this.convertBuffersToUint8Array(i);return Promise.resolve(a)}queryRaw(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r),a=n.columns().map(e=>e.name),o={rows:this.convertBuffersToUint8Array(i),columns:a,rowsAffected:0,lastInsertRowId:0};return Promise.resolve(o)}run(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.run(r),a={rowsAffected:i.changes,lastInsertRowId:i.lastInsertRowid};return Promise.resolve(a)}exec(e){return this.db.exec(e),Promise.resolve()}querySync(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r);return this.convertBuffersToUint8Array(i)}runSync(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.run(r);return{rowsAffected:i.changes,lastInsertRowId:i.lastInsertRowid}}execSync(e){this.db.exec(e)}async close(){}},c=class extends s{getConnectionType(){return`syncTxn`}async transaction(e){return await e(this)}async asyncTransaction(e,t){throw Error(`asyncTransaction is not supported in syncTxn connections. Use transaction() instead or create a direct connection.`)}},l=class extends s{getConnectionType(){return`asyncTxn`}async transaction(e){return await e(this)}async asyncTransaction(e,t){return await e(this)}};export{o as t}; | ||
| //# sourceMappingURL=node2.mjs.map |
+1
-2
@@ -1,2 +0,1 @@ | ||
| const e=require(`./chunk.cjs`),t=require(`./base.cjs`);let n=require(`better-sqlite3`);n=e.t(n);var r=class extends t.t{constructor(e){super(e),this._closed=!1,this.db=new n.default(e.path,{fileMustExist:!1}),this.db.pragma(`journal_mode = WAL`),this.db.pragma(`busy_timeout = 5000`)}normalizeParams(e){return e?Array.isArray(e)?e:Object.values(e):[]}convertBuffersToUint8Array(e){if(e==null)return e;if(Buffer.isBuffer(e))return new Uint8Array(e);if(Array.isArray(e))return e.map(e=>this.convertBuffersToUint8Array(e));if(typeof e==`object`){let t={};for(let[n,r]of Object.entries(e))t[n]=this.convertBuffersToUint8Array(r);return t}return e}checkConnection(){if(this._closed||!this.db.open)throw Error(`Database connection is closed`)}async query(e,t){this.checkConnection();let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r);return this.convertBuffersToUint8Array(i)}async queryRaw(e,t){this.checkConnection();let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r),a=n.columns().map(e=>e.name);return{rows:this.convertBuffersToUint8Array(i),columns:a,rowsAffected:0,lastInsertRowId:0}}async run(e,t){this.checkConnection();let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.run(r);return{rowsAffected:i.changes,lastInsertRowId:i.lastInsertRowid}}async exec(e){this.checkConnection(),this.db.exec(e)}transaction(e){this.checkConnection(),this.db.exec(`BEGIN`);let t=new a(this.db);return(async()=>{try{let n=await e(t);return this.db.exec(`COMMIT`),n}catch(e){throw this.db.exec(`ROLLBACK`),e}})()}async asyncTransaction(e,t){this.checkConnection();let n=t?.timeoutMs??3e4,r=!1;try{this.db.exec(`BEGIN IMMEDIATE`)}catch(e){if(e.message.includes(`cannot start a transaction within a transaction`))r=!0;else throw e}let i,a=!1;try{let t=new Promise((e,t)=>{i=setTimeout(()=>{a||t(Error(`Async transaction timeout after ${n}ms`))},n)}),s=new o(this.db),c=await Promise.race([e(s),t]);return a=!0,i&&clearTimeout(i),r||this.db.exec(`COMMIT`),c}catch(e){a=!0,i&&clearTimeout(i);try{this.db.exec(`ROLLBACK`)}catch(e){console.error(`Rollback failed:`,e)}throw e}}getConnectionType(){return`direct`}async close(){!this._closed&&this.db.open&&(this.db.close(),this._closed=!0)}get isOpen(){return!this._closed&&this.db.open}},i=class{constructor(e){this.db=e,this.inTransaction=!0}normalizeParams(e){return e?Array.isArray(e)?e:Object.values(e):[]}convertBuffersToUint8Array(e){if(e==null)return e;if(Buffer.isBuffer(e))return new Uint8Array(e);if(Array.isArray(e))return e.map(e=>this.convertBuffersToUint8Array(e));if(typeof e==`object`){let t={};for(let[n,r]of Object.entries(e))t[n]=this.convertBuffersToUint8Array(r);return t}return e}query(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r),a=this.convertBuffersToUint8Array(i);return Promise.resolve(a)}queryRaw(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r),a=n.columns().map(e=>e.name),o={rows:this.convertBuffersToUint8Array(i),columns:a,rowsAffected:0,lastInsertRowId:0};return Promise.resolve(o)}run(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.run(r),a={rowsAffected:i.changes,lastInsertRowId:i.lastInsertRowid};return Promise.resolve(a)}exec(e){return this.db.exec(e),Promise.resolve()}querySync(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r);return this.convertBuffersToUint8Array(i)}runSync(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.run(r);return{rowsAffected:i.changes,lastInsertRowId:i.lastInsertRowid}}execSync(e){this.db.exec(e)}async close(){}},a=class extends i{getConnectionType(){return`syncTxn`}async transaction(e){return await e(this)}async asyncTransaction(e,t){throw Error(`asyncTransaction is not supported in syncTxn connections. Use transaction() instead or create a direct connection.`)}},o=class extends i{getConnectionType(){return`asyncTxn`}async transaction(e){return await e(this)}async asyncTransaction(e,t){return await e(this)}};Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return r}}); | ||
| //# sourceMappingURL=node3.cjs.map | ||
| const e=require(`./node2.cjs`);exports.NodeAdapter=e.t; |
+1
-2
@@ -1,2 +0,1 @@ | ||
| import{t as e}from"./base.mjs";import t from"better-sqlite3";var n=class extends e{constructor(e){super(e),this._closed=!1,this.db=new t(e.path,{fileMustExist:!1}),this.db.pragma(`journal_mode = WAL`),this.db.pragma(`busy_timeout = 5000`)}normalizeParams(e){return e?Array.isArray(e)?e:Object.values(e):[]}convertBuffersToUint8Array(e){if(e==null)return e;if(Buffer.isBuffer(e))return new Uint8Array(e);if(Array.isArray(e))return e.map(e=>this.convertBuffersToUint8Array(e));if(typeof e==`object`){let t={};for(let[n,r]of Object.entries(e))t[n]=this.convertBuffersToUint8Array(r);return t}return e}checkConnection(){if(this._closed||!this.db.open)throw Error(`Database connection is closed`)}async query(e,t){this.checkConnection();let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r);return this.convertBuffersToUint8Array(i)}async queryRaw(e,t){this.checkConnection();let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r),a=n.columns().map(e=>e.name);return{rows:this.convertBuffersToUint8Array(i),columns:a,rowsAffected:0,lastInsertRowId:0}}async run(e,t){this.checkConnection();let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.run(r);return{rowsAffected:i.changes,lastInsertRowId:i.lastInsertRowid}}async exec(e){this.checkConnection(),this.db.exec(e)}transaction(e){this.checkConnection(),this.db.exec(`BEGIN`);let t=new i(this.db);return(async()=>{try{let n=await e(t);return this.db.exec(`COMMIT`),n}catch(e){throw this.db.exec(`ROLLBACK`),e}})()}async asyncTransaction(e,t){this.checkConnection();let n=t?.timeoutMs??3e4,r=!1;try{this.db.exec(`BEGIN IMMEDIATE`)}catch(e){if(e.message.includes(`cannot start a transaction within a transaction`))r=!0;else throw e}let i,o=!1;try{let t=new Promise((e,t)=>{i=setTimeout(()=>{o||t(Error(`Async transaction timeout after ${n}ms`))},n)}),s=new a(this.db),c=await Promise.race([e(s),t]);return o=!0,i&&clearTimeout(i),r||this.db.exec(`COMMIT`),c}catch(e){o=!0,i&&clearTimeout(i);try{this.db.exec(`ROLLBACK`)}catch(e){console.error(`Rollback failed:`,e)}throw e}}getConnectionType(){return`direct`}async close(){!this._closed&&this.db.open&&(this.db.close(),this._closed=!0)}get isOpen(){return!this._closed&&this.db.open}},r=class{constructor(e){this.db=e,this.inTransaction=!0}normalizeParams(e){return e?Array.isArray(e)?e:Object.values(e):[]}convertBuffersToUint8Array(e){if(e==null)return e;if(Buffer.isBuffer(e))return new Uint8Array(e);if(Array.isArray(e))return e.map(e=>this.convertBuffersToUint8Array(e));if(typeof e==`object`){let t={};for(let[n,r]of Object.entries(e))t[n]=this.convertBuffersToUint8Array(r);return t}return e}query(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r),a=this.convertBuffersToUint8Array(i);return Promise.resolve(a)}queryRaw(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r),a=n.columns().map(e=>e.name),o={rows:this.convertBuffersToUint8Array(i),columns:a,rowsAffected:0,lastInsertRowId:0};return Promise.resolve(o)}run(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.run(r),a={rowsAffected:i.changes,lastInsertRowId:i.lastInsertRowid};return Promise.resolve(a)}exec(e){return this.db.exec(e),Promise.resolve()}querySync(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.all(r);return this.convertBuffersToUint8Array(i)}runSync(e,t){let n=this.db.prepare(e),r=this.normalizeParams(t),i=n.run(r);return{rowsAffected:i.changes,lastInsertRowId:i.lastInsertRowid}}execSync(e){this.db.exec(e)}async close(){}},i=class extends r{getConnectionType(){return`syncTxn`}async transaction(e){return await e(this)}async asyncTransaction(e,t){throw Error(`asyncTransaction is not supported in syncTxn connections. Use transaction() instead or create a direct connection.`)}},a=class extends r{getConnectionType(){return`asyncTxn`}async transaction(e){return await e(this)}async asyncTransaction(e,t){return await e(this)}};export{n as t}; | ||
| //# sourceMappingURL=node3.mjs.map | ||
| import{t as e}from"./node2.mjs";export{e as NodeAdapter}; |
+1
-1
| { | ||
| "name": "@loro-dev/unisqlite", | ||
| "type": "module", | ||
| "version": "0.4.0", | ||
| "version": "0.5.0", | ||
| "description": "Cross-platform concurrent SQLite access layer", | ||
@@ -6,0 +6,0 @@ "author": "", |
@@ -529,3 +529,3 @@ /** | ||
| } catch (rollbackError) { | ||
| console.error("Rollback failed:", rollbackError); | ||
| logger.error("Rollback failed:", rollbackError); | ||
| } | ||
@@ -576,3 +576,3 @@ throw e; | ||
| } catch (rollbackError) { | ||
| console.error("Rollback failed:", rollbackError); | ||
| logger.error("Rollback failed:", rollbackError); | ||
| } | ||
@@ -632,3 +632,3 @@ | ||
| } catch (rollbackError) { | ||
| console.error("Remote rollback failed:", rollbackError); | ||
| logger.error("Remote rollback failed:", rollbackError); | ||
| } | ||
@@ -635,0 +635,0 @@ |
@@ -17,2 +17,3 @@ /** | ||
| } from "../../types.js"; | ||
| import { wasmLogger as logger, VERSION } from "./logger.js"; | ||
@@ -115,3 +116,3 @@ // ============================================================================= | ||
| async initialize(): Promise<void> { | ||
| console.log(`Loading SQLite WASM using strategy: ${this.config.loadStrategy}`); | ||
| logger.log(`UniSQLite v${VERSION} - Loading SQLite WASM using strategy: ${this.config.loadStrategy}`); | ||
@@ -121,4 +122,4 @@ const sqlite3InitModule = await this.loadSQLiteWasm(); | ||
| const initOptions: SQLiteInitOptions = { | ||
| print: console.log, | ||
| printErr: console.error, | ||
| print: (...args: unknown[]) => logger.log(...args), | ||
| printErr: (...args: unknown[]) => logger.error(...args), | ||
| }; | ||
@@ -135,3 +136,3 @@ | ||
| console.log("Initializing SQLite WASM module..."); | ||
| logger.log("Initializing SQLite WASM module..."); | ||
| this.sqlite3 = await sqlite3InitModule(initOptions); | ||
@@ -142,3 +143,3 @@ if (!this.sqlite3) { | ||
| const sqlite3 = this.sqlite3; | ||
| console.log("SQLite WASM module initialized successfully"); | ||
| logger.log("SQLite WASM module initialized successfully"); | ||
@@ -149,3 +150,3 @@ const storageBackend = this.config.storageBackend ?? "auto"; | ||
| if (storageBackend === "memory" || this.dbName === ":memory:") { | ||
| console.log("Using in-memory database"); | ||
| logger.log("Using in-memory database"); | ||
| this.db = new sqlite3.oo1.DB(":memory:"); | ||
@@ -156,3 +157,3 @@ this.activeStorageBackend = "memory"; | ||
| if (!dbCreated) { | ||
| console.log("All persistent storage backends failed, using in-memory database"); | ||
| logger.log("All persistent storage backends failed, using in-memory database"); | ||
| this.db = new sqlite3.oo1.DB(":memory:"); | ||
@@ -166,5 +167,5 @@ this.activeStorageBackend = "memory"; | ||
| await this.execInternal("PRAGMA journal_mode=WAL"); | ||
| console.log("Enabled WAL mode"); | ||
| logger.log("Enabled WAL mode"); | ||
| } catch (e) { | ||
| console.warn("Could not enable WAL mode:", e); | ||
| logger.warn("Could not enable WAL mode:", e); | ||
| } | ||
@@ -239,3 +240,3 @@ } | ||
| } catch (e) { | ||
| console.warn("Failed to close SQLite worker database:", e); | ||
| logger.warn("Failed to close SQLite worker database:", e); | ||
| } finally { | ||
@@ -478,3 +479,3 @@ this.workerDbId = undefined; | ||
| } catch (error) { | ||
| console.warn("Failed to load SQLite WASM from npm, falling back to CDN:", error); | ||
| logger.warn("Failed to load SQLite WASM from npm, falling back to CDN:", error); | ||
| return this.loadFromCdn(this.config.cdnBaseUrl!, this.config.version!, this.config.bundlerFriendly); | ||
@@ -494,9 +495,9 @@ } | ||
| try { | ||
| console.log(`Trying to load SQLite WASM from: ${url}`); | ||
| logger.log(`Trying to load SQLite WASM from: ${url}`); | ||
| const module = await import(url); | ||
| console.log(`Successfully loaded SQLite WASM from: ${url}`); | ||
| logger.log(`Successfully loaded SQLite WASM from: ${url}`); | ||
| return (module.default || module) as SQLiteInitModule; | ||
| } catch (error) { | ||
| lastError = error; | ||
| console.warn(`Failed to load SQLite WASM from ${url}:`, error); | ||
| logger.warn(`Failed to load SQLite WASM from ${url}:`, error); | ||
| } | ||
@@ -525,3 +526,3 @@ } | ||
| } catch (error) { | ||
| console.warn(`Failed to load SQLite WASM from ${path}:`, error); | ||
| logger.warn(`Failed to load SQLite WASM from ${path}:`, error); | ||
| } | ||
@@ -596,3 +597,3 @@ } | ||
| } catch (error) { | ||
| console.warn("Failed to load SQLite WASM worker promiser from npm, falling back to CDN:", error); | ||
| logger.warn("Failed to load SQLite WASM worker promiser from npm, falling back to CDN:", error); | ||
| return this.loadWorkerPromiserFromCdn(this.config.cdnBaseUrl!, this.config.version!, this.config.bundlerFriendly); | ||
@@ -613,3 +614,3 @@ } | ||
| try { | ||
| console.log(`Trying to load SQLite WASM worker promiser from: ${url}`); | ||
| logger.log(`Trying to load SQLite WASM worker promiser from: ${url}`); | ||
| const module = await import(url); | ||
@@ -619,3 +620,3 @@ const promiser = (module as unknown as { sqlite3Worker1Promiser?: SQLiteWorker1PromiserFactory }) | ||
| if (typeof promiser === "function") { | ||
| console.log(`Successfully loaded SQLite WASM worker promiser from: ${url}`); | ||
| logger.log(`Successfully loaded SQLite WASM worker promiser from: ${url}`); | ||
| return promiser; | ||
@@ -626,3 +627,3 @@ } | ||
| lastError = error; | ||
| console.warn(`Failed to load SQLite WASM worker promiser from ${url}:`, error); | ||
| logger.warn(`Failed to load SQLite WASM worker promiser from ${url}:`, error); | ||
| } | ||
@@ -660,3 +661,3 @@ } | ||
| } catch (error) { | ||
| console.warn(`Failed to load SQLite WASM worker promiser from ${path}:`, error); | ||
| logger.warn(`Failed to load SQLite WASM worker promiser from ${path}:`, error); | ||
| } | ||
@@ -720,9 +721,9 @@ } | ||
| try { | ||
| console.log("Creating localStorage-backed database:", this.dbName); | ||
| logger.log("Creating localStorage-backed database:", this.dbName); | ||
| this.db = new sqlite3.oo1.JsStorageDb(this.dbName); | ||
| this.activeStorageBackend = "localStorage"; | ||
| console.log("Successfully created localStorage-backed database"); | ||
| logger.log("Successfully created localStorage-backed database"); | ||
| return true; | ||
| } catch (e) { | ||
| console.warn("localStorage database creation failed:", e); | ||
| logger.warn("localStorage database creation failed:", e); | ||
| if (storageBackend === "localStorage") { | ||
@@ -738,3 +739,3 @@ throw new Error(`localStorage database creation failed: ${e instanceof Error ? e.message : String(e)}`); | ||
| } else { | ||
| console.log(`Skipping localStorage: path '${this.dbName}' is not 'local' or 'session'`); | ||
| logger.log(`Skipping localStorage: path '${this.dbName}' is not 'local' or 'session'`); | ||
| } | ||
@@ -769,3 +770,3 @@ } else if (storageBackend === "localStorage") { | ||
| try { | ||
| console.log("Creating OPFS-backed database (OpfsDb):", dbFileName); | ||
| logger.log("Creating OPFS-backed database (OpfsDb):", dbFileName); | ||
| this.db = new sqlite3.oo1.OpfsDb(dbFileName); | ||
@@ -775,6 +776,6 @@ this.workerDbId = undefined; | ||
| this.activeOpfsVfs = "opfs"; | ||
| console.log("Successfully created OPFS-backed database (OpfsDb)"); | ||
| logger.log("Successfully created OPFS-backed database (OpfsDb)"); | ||
| return true; | ||
| } catch (e) { | ||
| console.warn("OPFS database creation via OpfsDb failed:", e); | ||
| logger.warn("OPFS database creation via OpfsDb failed:", e); | ||
| } | ||
@@ -789,3 +790,3 @@ } | ||
| try { | ||
| console.log("Creating SAHPool OPFS-backed database:", dbFileName); | ||
| logger.log("Creating SAHPool OPFS-backed database:", dbFileName); | ||
| this.db = new sqlite3.oo1.DB(dbFileName, "c", "opfs-sahpool"); | ||
@@ -795,6 +796,6 @@ this.workerDbId = undefined; | ||
| this.activeOpfsVfs = "opfs-sahpool"; | ||
| console.log("Successfully created SAHPool OPFS-backed database"); | ||
| logger.log("Successfully created SAHPool OPFS-backed database"); | ||
| return true; | ||
| } catch (e) { | ||
| console.warn("SAHPool OPFS database creation failed:", e); | ||
| logger.warn("SAHPool OPFS database creation failed:", e); | ||
| } | ||
@@ -818,3 +819,3 @@ } | ||
| } catch (e) { | ||
| console.warn("SAHPool VFS lookup failed:", e); | ||
| logger.warn("SAHPool VFS lookup failed:", e); | ||
| } | ||
@@ -832,3 +833,3 @@ | ||
| } catch (e) { | ||
| console.warn("SAHPool VFS installation failed:", e); | ||
| logger.warn("SAHPool VFS installation failed:", e); | ||
| return false; | ||
@@ -869,3 +870,3 @@ } | ||
| } catch (e) { | ||
| console.warn("Failed to create Worker from custom workerUrl:", e); | ||
| logger.warn("Failed to create Worker from custom workerUrl:", e); | ||
| return undefined; | ||
@@ -1050,6 +1051,6 @@ } | ||
| this.activeOpfsVfs = vfsName; | ||
| console.log(`Successfully created OPFS-backed database via wrapped worker (${vfsName}):`, dbFileName); | ||
| logger.log(`Successfully created OPFS-backed database via wrapped worker (${vfsName}):`, dbFileName); | ||
| return true; | ||
| } catch (e) { | ||
| console.warn(`Wrapped-worker OPFS database creation failed (vfs=${vfsName}):`, e); | ||
| logger.warn(`Wrapped-worker OPFS database creation failed (vfs=${vfsName}):`, e); | ||
| return false; | ||
@@ -1056,0 +1057,0 @@ } |
@@ -11,2 +11,5 @@ /** | ||
| * - `unisqlite:adapter` - Browser adapter logs only | ||
| * - `unisqlite:wasm` - SQLite WASM loading and database creation logs | ||
| * - `unisqlite:node` - Node.js adapter logs | ||
| * - `unisqlite:visibility` - Visibility manager logs | ||
| * | ||
@@ -24,2 +27,5 @@ * In browser console: | ||
| // Package version - will be output on initialization | ||
| export const VERSION = "0.4.0"; | ||
| /** | ||
@@ -56,2 +62,4 @@ * Logger interface with log, warn, and error methods | ||
| export const adapterLogger = createModuleLogger("adapter"); | ||
| export const wasmLogger = createModuleLogger("wasm"); | ||
| export const visibilityLogger = createModuleLogger("visibility"); | ||
@@ -58,0 +66,0 @@ /** |
@@ -9,2 +9,4 @@ /** | ||
| import { visibilityLogger as logger } from "./logger.js"; | ||
| export type VisibilityChangeListener = (visible: boolean) => void; | ||
@@ -33,3 +35,3 @@ | ||
| } catch (e) { | ||
| console.error("Error in visibility change listener:", e); | ||
| logger.error("Error in visibility change listener:", e); | ||
| } | ||
@@ -36,0 +38,0 @@ }); |
@@ -12,2 +12,3 @@ import { BaseAdapter } from "./base.js"; | ||
| import Database from "better-sqlite3"; | ||
| import { nodeLogger as logger, VERSION } from "./logger.js"; | ||
@@ -20,2 +21,3 @@ export class NodeAdapter extends BaseAdapter { | ||
| super(options); | ||
| logger.log(`UniSQLite v${VERSION} - Opening database: ${options.path}`); | ||
| // Open database with WAL mode for better concurrency | ||
@@ -25,2 +27,3 @@ this.db = new Database(options.path, { fileMustExist: false }); | ||
| this.db.pragma("busy_timeout = 5000"); // 5 second timeout for locks | ||
| logger.log("Database opened with WAL mode"); | ||
| } | ||
@@ -185,3 +188,3 @@ | ||
| } catch (rollbackError) { | ||
| console.error("Rollback failed:", rollbackError); | ||
| logger.error("Rollback failed:", rollbackError); | ||
| } | ||
@@ -188,0 +191,0 @@ |
| {"version":3,"file":"node3.cjs","names":["BaseAdapter","Database"],"sources":["../src/adapters/node.ts"],"sourcesContent":["import { BaseAdapter } from \"./base.js\";\nimport type {\n QueryResult,\n RunResult,\n SQLiteParams,\n SQLiteValue,\n UniStoreConnection,\n UniStoreOptions,\n ConnectionType,\n} from \"../types.js\";\nimport Database from \"better-sqlite3\";\n\nexport class NodeAdapter extends BaseAdapter {\n private db: Database.Database;\n private _closed: boolean = false;\n\n constructor(options: UniStoreOptions) {\n super(options);\n // Open database with WAL mode for better concurrency\n this.db = new Database(options.path, { fileMustExist: false });\n this.db.pragma(\"journal_mode = WAL\");\n this.db.pragma(\"busy_timeout = 5000\"); // 5 second timeout for locks\n }\n\n private normalizeParams(params?: SQLiteParams): unknown[] {\n if (!params) return [];\n if (Array.isArray(params)) return params;\n // Convert object params to array format for better-sqlite3\n // This is a simplified conversion - in practice you'd need to handle named parameters\n return Object.values(params);\n }\n\n private convertBuffersToUint8Array<T>(value: T): T {\n if (value === null || value === undefined) {\n return value;\n }\n\n if (Buffer.isBuffer(value)) {\n return new Uint8Array(value) as T;\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => this.convertBuffersToUint8Array(item)) as T;\n }\n\n if (typeof value === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value)) {\n result[key] = this.convertBuffersToUint8Array(val);\n }\n return result as T;\n }\n\n return value;\n }\n\n private checkConnection(): void {\n if (this._closed || !this.db.open) {\n throw new Error(\"Database connection is closed\");\n }\n }\n\n async query<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): Promise<T[]> {\n this.checkConnection();\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n return this.convertBuffersToUint8Array(rows);\n }\n\n async queryRaw<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): Promise<QueryResult<T>> {\n this.checkConnection();\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n const columns = stmt.columns().map((col) => col.name);\n\n return {\n rows: this.convertBuffersToUint8Array(rows),\n columns,\n rowsAffected: 0,\n lastInsertRowId: 0,\n };\n }\n\n async run(sql: string, params?: SQLiteParams): Promise<RunResult> {\n this.checkConnection();\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const info = stmt.run(paramsArray);\n\n return {\n rowsAffected: info.changes,\n lastInsertRowId: info.lastInsertRowid as number,\n };\n }\n\n async exec(sql: string): Promise<void> {\n this.checkConnection();\n this.db.exec(sql);\n }\n\n transaction<T>(fn: (tx: UniStoreConnection) => Promise<T> | T): Promise<T> {\n this.checkConnection();\n // better-sqlite3 supports synchronous transactions\n this.db.exec(\"BEGIN\");\n const transactionAdapter = new SyncTransactionAdapter(this.db);\n return (async () => {\n try {\n const result = await fn(transactionAdapter);\n this.db.exec(\"COMMIT\");\n return result;\n } catch (error) {\n this.db.exec(\"ROLLBACK\");\n throw error;\n }\n })();\n }\n\n /**\n * Execute an async transaction with manual transaction management.\n * This allows async operations within the transaction but comes with timeout support\n * to prevent long-running transactions from blocking the database.\n *\n * @param fn Transaction function that can contain async operations\n * @param options Transaction options including timeout (default: 30000ms)\n */\n async asyncTransaction<T>(fn: (tx: UniStoreConnection) => Promise<T>, options?: { timeoutMs?: number }): Promise<T> {\n this.checkConnection();\n\n const timeoutMs = options?.timeoutMs ?? 30000; // Default 30 seconds\n let alreadyInTransaction = false;\n\n // Manual transaction management using BEGIN/COMMIT/ROLLBACK\n try {\n this.db.exec(\"BEGIN IMMEDIATE\");\n } catch (e) {\n if ((e as Error).message.includes(\"cannot start a transaction within a transaction\")) {\n alreadyInTransaction = true;\n } else {\n throw e;\n }\n }\n\n let timeoutHandle: NodeJS.Timeout | undefined;\n let transactionCompleted = false;\n\n try {\n // Set up timeout\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutHandle = setTimeout(() => {\n if (!transactionCompleted) {\n reject(new Error(`Async transaction timeout after ${timeoutMs}ms`));\n }\n }, timeoutMs);\n });\n\n const transactionAdapter = new AsyncTransactionAdapter(this.db);\n\n // Race between transaction execution and timeout\n const result = await Promise.race([fn(transactionAdapter), timeoutPromise]);\n\n transactionCompleted = true;\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n\n // If we get here, the transaction completed successfully\n if (!alreadyInTransaction) {\n this.db.exec(\"COMMIT\");\n }\n return result;\n } catch (error) {\n transactionCompleted = true;\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n\n try {\n this.db.exec(\"ROLLBACK\");\n } catch (rollbackError) {\n console.error(\"Rollback failed:\", rollbackError);\n }\n\n throw error;\n }\n }\n\n getConnectionType(): ConnectionType {\n return \"direct\";\n }\n\n async close(): Promise<void> {\n if (!this._closed && this.db.open) {\n this.db.close();\n this._closed = true;\n }\n }\n\n get isOpen(): boolean {\n return !this._closed && this.db.open;\n }\n}\n\nabstract class BaseTransactionAdapter implements UniStoreConnection {\n public readonly inTransaction = true;\n\n constructor(protected db: Database.Database) {}\n\n private normalizeParams(params?: SQLiteParams): unknown[] {\n if (!params) return [];\n if (Array.isArray(params)) return params;\n return Object.values(params);\n }\n\n private convertBuffersToUint8Array<T>(value: T): T {\n if (value === null || value === undefined) {\n return value;\n }\n\n if (Buffer.isBuffer(value)) {\n return new Uint8Array(value) as T;\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => this.convertBuffersToUint8Array(item)) as T;\n }\n\n if (typeof value === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value)) {\n result[key] = this.convertBuffersToUint8Array(val);\n }\n return result as T;\n }\n\n return value;\n }\n\n // Synchronous database methods for use in transactions\n query<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): Promise<T[]> {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n const result = this.convertBuffersToUint8Array(rows);\n return Promise.resolve(result);\n }\n\n queryRaw<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): Promise<QueryResult<T>> {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n const columns = stmt.columns().map((col) => col.name);\n\n const result = {\n rows: this.convertBuffersToUint8Array(rows),\n columns,\n rowsAffected: 0,\n lastInsertRowId: 0,\n };\n return Promise.resolve(result);\n }\n\n run(sql: string, params?: SQLiteParams): Promise<RunResult> {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const info = stmt.run(paramsArray);\n\n const result = {\n rowsAffected: info.changes,\n lastInsertRowId: info.lastInsertRowid as number,\n };\n return Promise.resolve(result);\n }\n\n exec(sql: string): Promise<void> {\n this.db.exec(sql);\n return Promise.resolve();\n }\n\n // Synchronous versions for use in sync transactions\n querySync<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): T[] {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n return this.convertBuffersToUint8Array(rows);\n }\n\n runSync(sql: string, params?: SQLiteParams): RunResult {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const info = stmt.run(paramsArray);\n\n return {\n rowsAffected: info.changes,\n lastInsertRowId: info.lastInsertRowid as number,\n };\n }\n\n execSync(sql: string): void {\n this.db.exec(sql);\n }\n\n abstract getConnectionType(): ConnectionType;\n abstract transaction<T>(fn: (tx: UniStoreConnection) => Promise<T> | T): Promise<T>;\n abstract asyncTransaction<T>(\n fn: (tx: UniStoreConnection) => Promise<T>,\n options?: { timeoutMs?: number }\n ): Promise<T>;\n\n async close(): Promise<void> {\n // No-op for transaction\n }\n}\n\nclass SyncTransactionAdapter extends BaseTransactionAdapter {\n getConnectionType(): ConnectionType {\n return \"syncTxn\";\n }\n\n async transaction<T>(fn: (tx: UniStoreConnection) => Promise<T> | T): Promise<T> {\n // For syncTxn, we can execute the transaction using itself as the connection\n // This allows nested operations within the same transaction\n return await fn(this);\n }\n\n async asyncTransaction<T>(\n _fn: (tx: UniStoreConnection) => Promise<T>,\n _options?: { timeoutMs?: number }\n ): Promise<T> {\n // syncTxn connections cannot run asyncTransaction\n throw new Error(\n \"asyncTransaction is not supported in syncTxn connections. Use transaction() instead or create a direct connection.\"\n );\n }\n}\n\nclass AsyncTransactionAdapter extends BaseTransactionAdapter {\n getConnectionType(): ConnectionType {\n return \"asyncTxn\";\n }\n\n async transaction<T>(fn: (tx: UniStoreConnection) => Promise<T> | T): Promise<T> {\n // For asyncTxn, we can execute the transaction using itself as the connection\n // This allows nested operations within the same transaction\n return await fn(this);\n }\n\n async asyncTransaction<T>(fn: (tx: UniStoreConnection) => Promise<T>, _options?: { timeoutMs?: number }): Promise<T> {\n // For asyncTxn, we can execute asyncTransaction using itself as the connection\n // This allows nested async operations within the same transaction\n return await fn(this);\n }\n}\n"],"mappings":"gGAYA,IAAa,EAAb,cAAiCA,EAAAA,CAAY,CAI3C,YAAY,EAA0B,CACpC,MAAM,EAAQ,cAHW,GAKzB,KAAK,GAAK,IAAIC,EAAAA,QAAS,EAAQ,KAAM,CAAE,cAAe,GAAO,CAAC,CAC9D,KAAK,GAAG,OAAO,qBAAqB,CACpC,KAAK,GAAG,OAAO,sBAAsB,CAGvC,gBAAwB,EAAkC,CAKxD,OAJK,EACD,MAAM,QAAQ,EAAO,CAAS,EAG3B,OAAO,OAAO,EAAO,CAJR,EAAE,CAOxB,2BAAsC,EAAa,CACjD,GAAI,GAAU,KACZ,OAAO,EAGT,GAAI,OAAO,SAAS,EAAM,CACxB,OAAO,IAAI,WAAW,EAAM,CAG9B,GAAI,MAAM,QAAQ,EAAM,CACtB,OAAO,EAAM,IAAK,GAAS,KAAK,2BAA2B,EAAK,CAAC,CAGnE,GAAI,OAAO,GAAU,SAAU,CAC7B,IAAM,EAAkC,EAAE,CAC1C,IAAK,GAAM,CAAC,EAAK,KAAQ,OAAO,QAAQ,EAAM,CAC5C,EAAO,GAAO,KAAK,2BAA2B,EAAI,CAEpD,OAAO,EAGT,OAAO,EAGT,iBAAgC,CAC9B,GAAI,KAAK,SAAW,CAAC,KAAK,GAAG,KAC3B,MAAU,MAAM,gCAAgC,CAIpD,MAAM,MAAuC,EAAa,EAAqC,CAC7F,KAAK,iBAAiB,CACtB,IAAM,EAAO,KAAK,GAAG,QAAQ,EAAI,CAC3B,EAAc,KAAK,gBAAgB,EAAO,CAC1C,EAAO,EAAK,IAAI,EAAY,CAClC,OAAO,KAAK,2BAA2B,EAAK,CAG9C,MAAM,SAA0C,EAAa,EAAgD,CAC3G,KAAK,iBAAiB,CACtB,IAAM,EAAO,KAAK,GAAG,QAAQ,EAAI,CAC3B,EAAc,KAAK,gBAAgB,EAAO,CAC1C,EAAO,EAAK,IAAI,EAAY,CAC5B,EAAU,EAAK,SAAS,CAAC,IAAK,GAAQ,EAAI,KAAK,CAErD,MAAO,CACL,KAAM,KAAK,2BAA2B,EAAK,CAC3C,UACA,aAAc,EACd,gBAAiB,EAClB,CAGH,MAAM,IAAI,EAAa,EAA2C,CAChE,KAAK,iBAAiB,CACtB,IAAM,EAAO,KAAK,GAAG,QAAQ,EAAI,CAC3B,EAAc,KAAK,gBAAgB,EAAO,CAC1C,EAAO,EAAK,IAAI,EAAY,CAElC,MAAO,CACL,aAAc,EAAK,QACnB,gBAAiB,EAAK,gBACvB,CAGH,MAAM,KAAK,EAA4B,CACrC,KAAK,iBAAiB,CACtB,KAAK,GAAG,KAAK,EAAI,CAGnB,YAAe,EAA4D,CACzE,KAAK,iBAAiB,CAEtB,KAAK,GAAG,KAAK,QAAQ,CACrB,IAAM,EAAqB,IAAI,EAAuB,KAAK,GAAG,CAC9D,OAAQ,SAAY,CAClB,GAAI,CACF,IAAM,EAAS,MAAM,EAAG,EAAmB,CAE3C,OADA,KAAK,GAAG,KAAK,SAAS,CACf,QACA,EAAO,CAEd,MADA,KAAK,GAAG,KAAK,WAAW,CAClB,MAEN,CAWN,MAAM,iBAAoB,EAA4C,EAA8C,CAClH,KAAK,iBAAiB,CAEtB,IAAM,EAAY,GAAS,WAAa,IACpC,EAAuB,GAG3B,GAAI,CACF,KAAK,GAAG,KAAK,kBAAkB,OACxB,EAAG,CACV,GAAK,EAAY,QAAQ,SAAS,kDAAkD,CAClF,EAAuB,QAEvB,MAAM,EAIV,IAAI,EACA,EAAuB,GAE3B,GAAI,CAEF,IAAM,EAAiB,IAAI,SAAgB,EAAG,IAAW,CACvD,EAAgB,eAAiB,CAC1B,GACH,EAAW,MAAM,mCAAmC,EAAU,IAAI,CAAC,EAEpE,EAAU,EACb,CAEI,EAAqB,IAAI,EAAwB,KAAK,GAAG,CAGzD,EAAS,MAAM,QAAQ,KAAK,CAAC,EAAG,EAAmB,CAAE,EAAe,CAAC,CAW3E,MATA,GAAuB,GACnB,GACF,aAAa,EAAc,CAIxB,GACH,KAAK,GAAG,KAAK,SAAS,CAEjB,QACA,EAAO,CACd,EAAuB,GACnB,GACF,aAAa,EAAc,CAG7B,GAAI,CACF,KAAK,GAAG,KAAK,WAAW,OACjB,EAAe,CACtB,QAAQ,MAAM,mBAAoB,EAAc,CAGlD,MAAM,GAIV,mBAAoC,CAClC,MAAO,SAGT,MAAM,OAAuB,CACvB,CAAC,KAAK,SAAW,KAAK,GAAG,OAC3B,KAAK,GAAG,OAAO,CACf,KAAK,QAAU,IAInB,IAAI,QAAkB,CACpB,MAAO,CAAC,KAAK,SAAW,KAAK,GAAG,OAIrB,EAAf,KAAoE,CAGlE,YAAY,EAAiC,CAAvB,KAAA,GAAA,qBAFU,GAIhC,gBAAwB,EAAkC,CAGxD,OAFK,EACD,MAAM,QAAQ,EAAO,CAAS,EAC3B,OAAO,OAAO,EAAO,CAFR,EAAE,CAKxB,2BAAsC,EAAa,CACjD,GAAI,GAAU,KACZ,OAAO,EAGT,GAAI,OAAO,SAAS,EAAM,CACxB,OAAO,IAAI,WAAW,EAAM,CAG9B,GAAI,MAAM,QAAQ,EAAM,CACtB,OAAO,EAAM,IAAK,GAAS,KAAK,2BAA2B,EAAK,CAAC,CAGnE,GAAI,OAAO,GAAU,SAAU,CAC7B,IAAM,EAAkC,EAAE,CAC1C,IAAK,GAAM,CAAC,EAAK,KAAQ,OAAO,QAAQ,EAAM,CAC5C,EAAO,GAAO,KAAK,2BAA2B,EAAI,CAEpD,OAAO,EAGT,OAAO,EAIT,MAAuC,EAAa,EAAqC,CACvF,IAAM,EAAO,KAAK,GAAG,QAAQ,EAAI,CAC3B,EAAc,KAAK,gBAAgB,EAAO,CAC1C,EAAO,EAAK,IAAI,EAAY,CAC5B,EAAS,KAAK,2BAA2B,EAAK,CACpD,OAAO,QAAQ,QAAQ,EAAO,CAGhC,SAA0C,EAAa,EAAgD,CACrG,IAAM,EAAO,KAAK,GAAG,QAAQ,EAAI,CAC3B,EAAc,KAAK,gBAAgB,EAAO,CAC1C,EAAO,EAAK,IAAI,EAAY,CAC5B,EAAU,EAAK,SAAS,CAAC,IAAK,GAAQ,EAAI,KAAK,CAE/C,EAAS,CACb,KAAM,KAAK,2BAA2B,EAAK,CAC3C,UACA,aAAc,EACd,gBAAiB,EAClB,CACD,OAAO,QAAQ,QAAQ,EAAO,CAGhC,IAAI,EAAa,EAA2C,CAC1D,IAAM,EAAO,KAAK,GAAG,QAAQ,EAAI,CAC3B,EAAc,KAAK,gBAAgB,EAAO,CAC1C,EAAO,EAAK,IAAI,EAAY,CAE5B,EAAS,CACb,aAAc,EAAK,QACnB,gBAAiB,EAAK,gBACvB,CACD,OAAO,QAAQ,QAAQ,EAAO,CAGhC,KAAK,EAA4B,CAE/B,OADA,KAAK,GAAG,KAAK,EAAI,CACV,QAAQ,SAAS,CAI1B,UAA2C,EAAa,EAA4B,CAClF,IAAM,EAAO,KAAK,GAAG,QAAQ,EAAI,CAC3B,EAAc,KAAK,gBAAgB,EAAO,CAC1C,EAAO,EAAK,IAAI,EAAY,CAClC,OAAO,KAAK,2BAA2B,EAAK,CAG9C,QAAQ,EAAa,EAAkC,CACrD,IAAM,EAAO,KAAK,GAAG,QAAQ,EAAI,CAC3B,EAAc,KAAK,gBAAgB,EAAO,CAC1C,EAAO,EAAK,IAAI,EAAY,CAElC,MAAO,CACL,aAAc,EAAK,QACnB,gBAAiB,EAAK,gBACvB,CAGH,SAAS,EAAmB,CAC1B,KAAK,GAAG,KAAK,EAAI,CAUnB,MAAM,OAAuB,IAKzB,EAAN,cAAqC,CAAuB,CAC1D,mBAAoC,CAClC,MAAO,UAGT,MAAM,YAAe,EAA4D,CAG/E,OAAO,MAAM,EAAG,KAAK,CAGvB,MAAM,iBACJ,EACA,EACY,CAEZ,MAAU,MACR,qHACD,GAIC,EAAN,cAAsC,CAAuB,CAC3D,mBAAoC,CAClC,MAAO,WAGT,MAAM,YAAe,EAA4D,CAG/E,OAAO,MAAM,EAAG,KAAK,CAGvB,MAAM,iBAAoB,EAA4C,EAA+C,CAGnH,OAAO,MAAM,EAAG,KAAK"} |
| {"version":3,"file":"node3.mjs","names":[],"sources":["../src/adapters/node.ts"],"sourcesContent":["import { BaseAdapter } from \"./base.js\";\nimport type {\n QueryResult,\n RunResult,\n SQLiteParams,\n SQLiteValue,\n UniStoreConnection,\n UniStoreOptions,\n ConnectionType,\n} from \"../types.js\";\nimport Database from \"better-sqlite3\";\n\nexport class NodeAdapter extends BaseAdapter {\n private db: Database.Database;\n private _closed: boolean = false;\n\n constructor(options: UniStoreOptions) {\n super(options);\n // Open database with WAL mode for better concurrency\n this.db = new Database(options.path, { fileMustExist: false });\n this.db.pragma(\"journal_mode = WAL\");\n this.db.pragma(\"busy_timeout = 5000\"); // 5 second timeout for locks\n }\n\n private normalizeParams(params?: SQLiteParams): unknown[] {\n if (!params) return [];\n if (Array.isArray(params)) return params;\n // Convert object params to array format for better-sqlite3\n // This is a simplified conversion - in practice you'd need to handle named parameters\n return Object.values(params);\n }\n\n private convertBuffersToUint8Array<T>(value: T): T {\n if (value === null || value === undefined) {\n return value;\n }\n\n if (Buffer.isBuffer(value)) {\n return new Uint8Array(value) as T;\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => this.convertBuffersToUint8Array(item)) as T;\n }\n\n if (typeof value === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value)) {\n result[key] = this.convertBuffersToUint8Array(val);\n }\n return result as T;\n }\n\n return value;\n }\n\n private checkConnection(): void {\n if (this._closed || !this.db.open) {\n throw new Error(\"Database connection is closed\");\n }\n }\n\n async query<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): Promise<T[]> {\n this.checkConnection();\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n return this.convertBuffersToUint8Array(rows);\n }\n\n async queryRaw<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): Promise<QueryResult<T>> {\n this.checkConnection();\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n const columns = stmt.columns().map((col) => col.name);\n\n return {\n rows: this.convertBuffersToUint8Array(rows),\n columns,\n rowsAffected: 0,\n lastInsertRowId: 0,\n };\n }\n\n async run(sql: string, params?: SQLiteParams): Promise<RunResult> {\n this.checkConnection();\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const info = stmt.run(paramsArray);\n\n return {\n rowsAffected: info.changes,\n lastInsertRowId: info.lastInsertRowid as number,\n };\n }\n\n async exec(sql: string): Promise<void> {\n this.checkConnection();\n this.db.exec(sql);\n }\n\n transaction<T>(fn: (tx: UniStoreConnection) => Promise<T> | T): Promise<T> {\n this.checkConnection();\n // better-sqlite3 supports synchronous transactions\n this.db.exec(\"BEGIN\");\n const transactionAdapter = new SyncTransactionAdapter(this.db);\n return (async () => {\n try {\n const result = await fn(transactionAdapter);\n this.db.exec(\"COMMIT\");\n return result;\n } catch (error) {\n this.db.exec(\"ROLLBACK\");\n throw error;\n }\n })();\n }\n\n /**\n * Execute an async transaction with manual transaction management.\n * This allows async operations within the transaction but comes with timeout support\n * to prevent long-running transactions from blocking the database.\n *\n * @param fn Transaction function that can contain async operations\n * @param options Transaction options including timeout (default: 30000ms)\n */\n async asyncTransaction<T>(fn: (tx: UniStoreConnection) => Promise<T>, options?: { timeoutMs?: number }): Promise<T> {\n this.checkConnection();\n\n const timeoutMs = options?.timeoutMs ?? 30000; // Default 30 seconds\n let alreadyInTransaction = false;\n\n // Manual transaction management using BEGIN/COMMIT/ROLLBACK\n try {\n this.db.exec(\"BEGIN IMMEDIATE\");\n } catch (e) {\n if ((e as Error).message.includes(\"cannot start a transaction within a transaction\")) {\n alreadyInTransaction = true;\n } else {\n throw e;\n }\n }\n\n let timeoutHandle: NodeJS.Timeout | undefined;\n let transactionCompleted = false;\n\n try {\n // Set up timeout\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutHandle = setTimeout(() => {\n if (!transactionCompleted) {\n reject(new Error(`Async transaction timeout after ${timeoutMs}ms`));\n }\n }, timeoutMs);\n });\n\n const transactionAdapter = new AsyncTransactionAdapter(this.db);\n\n // Race between transaction execution and timeout\n const result = await Promise.race([fn(transactionAdapter), timeoutPromise]);\n\n transactionCompleted = true;\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n\n // If we get here, the transaction completed successfully\n if (!alreadyInTransaction) {\n this.db.exec(\"COMMIT\");\n }\n return result;\n } catch (error) {\n transactionCompleted = true;\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n\n try {\n this.db.exec(\"ROLLBACK\");\n } catch (rollbackError) {\n console.error(\"Rollback failed:\", rollbackError);\n }\n\n throw error;\n }\n }\n\n getConnectionType(): ConnectionType {\n return \"direct\";\n }\n\n async close(): Promise<void> {\n if (!this._closed && this.db.open) {\n this.db.close();\n this._closed = true;\n }\n }\n\n get isOpen(): boolean {\n return !this._closed && this.db.open;\n }\n}\n\nabstract class BaseTransactionAdapter implements UniStoreConnection {\n public readonly inTransaction = true;\n\n constructor(protected db: Database.Database) {}\n\n private normalizeParams(params?: SQLiteParams): unknown[] {\n if (!params) return [];\n if (Array.isArray(params)) return params;\n return Object.values(params);\n }\n\n private convertBuffersToUint8Array<T>(value: T): T {\n if (value === null || value === undefined) {\n return value;\n }\n\n if (Buffer.isBuffer(value)) {\n return new Uint8Array(value) as T;\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => this.convertBuffersToUint8Array(item)) as T;\n }\n\n if (typeof value === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value)) {\n result[key] = this.convertBuffersToUint8Array(val);\n }\n return result as T;\n }\n\n return value;\n }\n\n // Synchronous database methods for use in transactions\n query<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): Promise<T[]> {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n const result = this.convertBuffersToUint8Array(rows);\n return Promise.resolve(result);\n }\n\n queryRaw<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): Promise<QueryResult<T>> {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n const columns = stmt.columns().map((col) => col.name);\n\n const result = {\n rows: this.convertBuffersToUint8Array(rows),\n columns,\n rowsAffected: 0,\n lastInsertRowId: 0,\n };\n return Promise.resolve(result);\n }\n\n run(sql: string, params?: SQLiteParams): Promise<RunResult> {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const info = stmt.run(paramsArray);\n\n const result = {\n rowsAffected: info.changes,\n lastInsertRowId: info.lastInsertRowid as number,\n };\n return Promise.resolve(result);\n }\n\n exec(sql: string): Promise<void> {\n this.db.exec(sql);\n return Promise.resolve();\n }\n\n // Synchronous versions for use in sync transactions\n querySync<T = Record<string, SQLiteValue>>(sql: string, params?: SQLiteParams): T[] {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const rows = stmt.all(paramsArray) as T[];\n return this.convertBuffersToUint8Array(rows);\n }\n\n runSync(sql: string, params?: SQLiteParams): RunResult {\n const stmt = this.db.prepare(sql);\n const paramsArray = this.normalizeParams(params);\n const info = stmt.run(paramsArray);\n\n return {\n rowsAffected: info.changes,\n lastInsertRowId: info.lastInsertRowid as number,\n };\n }\n\n execSync(sql: string): void {\n this.db.exec(sql);\n }\n\n abstract getConnectionType(): ConnectionType;\n abstract transaction<T>(fn: (tx: UniStoreConnection) => Promise<T> | T): Promise<T>;\n abstract asyncTransaction<T>(\n fn: (tx: UniStoreConnection) => Promise<T>,\n options?: { timeoutMs?: number }\n ): Promise<T>;\n\n async close(): Promise<void> {\n // No-op for transaction\n }\n}\n\nclass SyncTransactionAdapter extends BaseTransactionAdapter {\n getConnectionType(): ConnectionType {\n return \"syncTxn\";\n }\n\n async transaction<T>(fn: (tx: UniStoreConnection) => Promise<T> | T): Promise<T> {\n // For syncTxn, we can execute the transaction using itself as the connection\n // This allows nested operations within the same transaction\n return await fn(this);\n }\n\n async asyncTransaction<T>(\n _fn: (tx: UniStoreConnection) => Promise<T>,\n _options?: { timeoutMs?: number }\n ): Promise<T> {\n // syncTxn connections cannot run asyncTransaction\n throw new Error(\n \"asyncTransaction is not supported in syncTxn connections. Use transaction() instead or create a direct connection.\"\n );\n }\n}\n\nclass AsyncTransactionAdapter extends BaseTransactionAdapter {\n getConnectionType(): ConnectionType {\n return \"asyncTxn\";\n }\n\n async transaction<T>(fn: (tx: UniStoreConnection) => Promise<T> | T): Promise<T> {\n // For asyncTxn, we can execute the transaction using itself as the connection\n // This allows nested operations within the same transaction\n return await fn(this);\n }\n\n async asyncTransaction<T>(fn: (tx: UniStoreConnection) => Promise<T>, _options?: { timeoutMs?: number }): Promise<T> {\n // For asyncTxn, we can execute asyncTransaction using itself as the connection\n // This allows nested async operations within the same transaction\n return await fn(this);\n }\n}\n"],"mappings":"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"} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
682973
1.43%85
1.19%5900
1.39%7
-12.5%34
3.03%