@pol-studios/powersync 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/attachments/index.js +1 -1
- package/dist/{chunk-PANEMMTU.js → chunk-3AYXHQ4W.js} +17 -11
- package/dist/chunk-3AYXHQ4W.js.map +1 -0
- package/dist/{chunk-BJ36QDFN.js → chunk-7EMDVIZX.js} +1 -1
- package/dist/chunk-7EMDVIZX.js.map +1 -0
- package/dist/{chunk-MB2RC3NS.js → chunk-C2RSTGDC.js} +129 -89
- package/dist/chunk-C2RSTGDC.js.map +1 -0
- package/dist/{chunk-NPNBGCRC.js → chunk-EJ23MXPQ.js} +1 -1
- package/dist/{chunk-NPNBGCRC.js.map → chunk-EJ23MXPQ.js.map} +1 -1
- package/dist/{chunk-CHRTN5PF.js → chunk-FPTDATY5.js} +1 -1
- package/dist/chunk-FPTDATY5.js.map +1 -0
- package/dist/chunk-GMFDCVMZ.js +1285 -0
- package/dist/chunk-GMFDCVMZ.js.map +1 -0
- package/dist/chunk-OLHGI472.js +1 -0
- package/dist/chunk-OLHGI472.js.map +1 -0
- package/dist/{chunk-CFCK2LHI.js → chunk-OTJXIRWX.js} +45 -40
- package/dist/chunk-OTJXIRWX.js.map +1 -0
- package/dist/{chunk-GBGATW2S.js → chunk-V6LJ6MR2.js} +86 -95
- package/dist/chunk-V6LJ6MR2.js.map +1 -0
- package/dist/connector/index.d.ts +1 -1
- package/dist/connector/index.js +2 -2
- package/dist/core/index.js +2 -2
- package/dist/{index-D952Qr38.d.ts → index-Cb-NI0Ct.d.ts} +9 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +8 -9
- package/dist/index.native.d.ts +1 -1
- package/dist/index.native.js +9 -10
- package/dist/index.web.d.ts +1 -1
- package/dist/index.web.js +9 -10
- package/dist/platform/index.js.map +1 -1
- package/dist/platform/index.native.js +1 -1
- package/dist/platform/index.web.js +1 -1
- package/dist/provider/index.d.ts +6 -1
- package/dist/provider/index.js +6 -6
- package/dist/sync/index.js +3 -3
- package/package.json +3 -1
- package/dist/chunk-42IJ25Q4.js +0 -45
- package/dist/chunk-42IJ25Q4.js.map +0 -1
- package/dist/chunk-BJ36QDFN.js.map +0 -1
- package/dist/chunk-CFCK2LHI.js.map +0 -1
- package/dist/chunk-CHRTN5PF.js.map +0 -1
- package/dist/chunk-GBGATW2S.js.map +0 -1
- package/dist/chunk-H7HZMI4H.js +0 -925
- package/dist/chunk-H7HZMI4H.js.map +0 -1
- package/dist/chunk-MB2RC3NS.js.map +0 -1
- package/dist/chunk-PANEMMTU.js.map +0 -1
|
@@ -41,10 +41,10 @@ function createNativePlatformAdapter(logger) {
|
|
|
41
41
|
if (!FileSystem) await loadDependencies();
|
|
42
42
|
const parentDir = uri.substring(0, uri.lastIndexOf("/"));
|
|
43
43
|
if (parentDir) {
|
|
44
|
-
await FileSystem.makeDirectoryAsync(parentDir, {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
);
|
|
44
|
+
await FileSystem.makeDirectoryAsync(parentDir, {
|
|
45
|
+
intermediates: true
|
|
46
|
+
}).catch(() => {
|
|
47
|
+
});
|
|
48
48
|
}
|
|
49
49
|
await FileSystem.writeAsStringAsync(uri, data, {
|
|
50
50
|
encoding: encoding === "base64" ? FileSystem.EncodingType.Base64 : FileSystem.EncodingType.UTF8
|
|
@@ -52,15 +52,23 @@ function createNativePlatformAdapter(logger) {
|
|
|
52
52
|
},
|
|
53
53
|
async deleteFile(uri) {
|
|
54
54
|
if (!FileSystem) await loadDependencies();
|
|
55
|
-
await FileSystem.deleteAsync(uri, {
|
|
55
|
+
await FileSystem.deleteAsync(uri, {
|
|
56
|
+
idempotent: true
|
|
57
|
+
});
|
|
56
58
|
},
|
|
57
59
|
async copyFile(source, destination) {
|
|
58
60
|
if (!FileSystem) await loadDependencies();
|
|
59
|
-
await FileSystem.copyAsync({
|
|
61
|
+
await FileSystem.copyAsync({
|
|
62
|
+
from: source,
|
|
63
|
+
to: destination
|
|
64
|
+
});
|
|
60
65
|
},
|
|
61
66
|
async moveFile(source, destination) {
|
|
62
67
|
if (!FileSystem) await loadDependencies();
|
|
63
|
-
await FileSystem.moveAsync({
|
|
68
|
+
await FileSystem.moveAsync({
|
|
69
|
+
from: source,
|
|
70
|
+
to: destination
|
|
71
|
+
});
|
|
64
72
|
},
|
|
65
73
|
async getFileInfo(uri) {
|
|
66
74
|
if (!FileSystem) await loadDependencies();
|
|
@@ -135,9 +143,7 @@ function createNativePlatformAdapter(logger) {
|
|
|
135
143
|
},
|
|
136
144
|
addConnectionListener(callback) {
|
|
137
145
|
if (!NetInfo) {
|
|
138
|
-
logger.warn(
|
|
139
|
-
"[Platform] NetInfo not loaded, connection listener may not work immediately"
|
|
140
|
-
);
|
|
146
|
+
logger.warn("[Platform] NetInfo not loaded, connection listener may not work immediately");
|
|
141
147
|
loadDependencies().then(() => {
|
|
142
148
|
NetInfo.addEventListener((state) => {
|
|
143
149
|
callback(state.isConnected ?? false);
|
|
@@ -229,4 +235,4 @@ function createNativePlatformAdapter(logger) {
|
|
|
229
235
|
export {
|
|
230
236
|
createNativePlatformAdapter
|
|
231
237
|
};
|
|
232
|
-
//# sourceMappingURL=chunk-
|
|
238
|
+
//# sourceMappingURL=chunk-3AYXHQ4W.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/platform/index.native.ts"],"sourcesContent":["/**\n * React Native Platform Adapter for @pol-studios/powersync\n *\n * Implements the PlatformAdapter interface using React Native specific APIs:\n * - @powersync/react-native for SQLite database\n * - expo-file-system for file operations\n * - @react-native-async-storage/async-storage for key-value storage\n * - @react-native-community/netinfo for network monitoring\n * - expo-image-manipulator for image compression\n */\n\nimport type { PlatformAdapter, DatabaseOptions, FileSystemAdapter, AsyncStorageAdapter, NetworkAdapter, LoggerAdapter, ImageProcessorAdapter, FileInfo, CompressedImage, CompressionOptions, ConnectionType } from './types';\nimport type { AbstractPowerSyncDatabase } from '../core/types';\n\n/**\n * Create a React Native platform adapter\n *\n * @param logger - Logger implementation to use\n * @returns Platform adapter configured for React Native\n *\n * @example\n * ```typescript\n * import { createNativePlatformAdapter } from '@pol-studios/powersync/platform';\n *\n * const logger = {\n * debug: console.log,\n * info: console.log,\n * warn: console.warn,\n * error: console.error,\n * };\n *\n * const platform = createNativePlatformAdapter(logger);\n * ```\n */\nexport function createNativePlatformAdapter(logger: LoggerAdapter): PlatformAdapter {\n // Lazy imports to avoid loading these modules until needed\n // This also helps with tree-shaking in web builds\n let PowerSyncDatabase: typeof import('@powersync/react-native').PowerSyncDatabase;\n let OPSqliteOpenFactory: typeof import('@powersync/op-sqlite').OPSqliteOpenFactory;\n // Use 'any' for FileSystem to handle type changes between expo-file-system versions\n let FileSystem: any;\n let AsyncStorage: typeof import('@react-native-async-storage/async-storage').default;\n let NetInfo: typeof import('@react-native-community/netinfo').default;\n let ImageManipulator: typeof import('expo-image-manipulator');\n const loadDependencies = async () => {\n if (!PowerSyncDatabase) {\n const psModule = await import('@powersync/react-native');\n PowerSyncDatabase = psModule.PowerSyncDatabase;\n }\n if (!OPSqliteOpenFactory) {\n const opSqliteModule = await import('@powersync/op-sqlite');\n OPSqliteOpenFactory = opSqliteModule.OPSqliteOpenFactory;\n }\n if (!FileSystem) {\n FileSystem = await import('expo-file-system');\n }\n if (!AsyncStorage) {\n const asModule = await import('@react-native-async-storage/async-storage');\n AsyncStorage = asModule.default;\n }\n if (!NetInfo) {\n const niModule = await import('@react-native-community/netinfo');\n NetInfo = niModule.default;\n }\n if (!ImageManipulator) {\n ImageManipulator = await import('expo-image-manipulator');\n }\n };\n\n // File system adapter implementation\n const fileSystem: FileSystemAdapter = {\n async readFile(uri: string, encoding: 'base64' | 'utf8' = 'utf8'): Promise<string> {\n if (!FileSystem) await loadDependencies();\n return FileSystem!.readAsStringAsync(uri, {\n encoding: encoding === 'base64' ? FileSystem!.EncodingType.Base64 : FileSystem!.EncodingType.UTF8\n });\n },\n async writeFile(uri: string, data: string, encoding: 'base64' | 'utf8' = 'utf8'): Promise<void> {\n if (!FileSystem) await loadDependencies();\n // Ensure parent directory exists\n const parentDir = uri.substring(0, uri.lastIndexOf('/'));\n if (parentDir) {\n await FileSystem!.makeDirectoryAsync(parentDir, {\n intermediates: true\n }).catch(() => {\n // Directory may already exist\n });\n }\n await FileSystem!.writeAsStringAsync(uri, data, {\n encoding: encoding === 'base64' ? FileSystem!.EncodingType.Base64 : FileSystem!.EncodingType.UTF8\n });\n },\n async deleteFile(uri: string): Promise<void> {\n if (!FileSystem) await loadDependencies();\n await FileSystem!.deleteAsync(uri, {\n idempotent: true\n });\n },\n async copyFile(source: string, destination: string): Promise<void> {\n if (!FileSystem) await loadDependencies();\n await FileSystem!.copyAsync({\n from: source,\n to: destination\n });\n },\n async moveFile(source: string, destination: string): Promise<void> {\n if (!FileSystem) await loadDependencies();\n await FileSystem!.moveAsync({\n from: source,\n to: destination\n });\n },\n async getFileInfo(uri: string): Promise<FileInfo | null> {\n if (!FileSystem) await loadDependencies();\n try {\n const info = await FileSystem!.getInfoAsync(uri);\n if (!info.exists) return null;\n return {\n exists: true,\n size: 'size' in info ? info.size ?? 0 : 0,\n isDirectory: info.isDirectory ?? false,\n modificationTime: 'modificationTime' in info && info.modificationTime ? new Date(info.modificationTime * 1000) : undefined\n };\n } catch {\n return null;\n }\n },\n async makeDirectory(uri: string, options?: {\n intermediates?: boolean;\n }): Promise<void> {\n if (!FileSystem) await loadDependencies();\n await FileSystem!.makeDirectoryAsync(uri, {\n intermediates: options?.intermediates ?? true\n });\n },\n getDocumentsDirectory(): string {\n // Note: This will be set after first load\n // Return a placeholder that will work for path construction\n return FileSystem?.documentDirectory ?? '';\n },\n getCacheDirectory(): string {\n return FileSystem?.cacheDirectory ?? '';\n },\n async getFreeDiskSpace(): Promise<number> {\n if (!FileSystem) await loadDependencies();\n return FileSystem!.getFreeDiskStorageAsync();\n }\n };\n\n // Async storage adapter implementation\n const storage: AsyncStorageAdapter = {\n async getItem(key: string): Promise<string | null> {\n if (!AsyncStorage) await loadDependencies();\n return AsyncStorage!.getItem(key);\n },\n async setItem(key: string, value: string): Promise<void> {\n if (!AsyncStorage) await loadDependencies();\n await AsyncStorage!.setItem(key, value);\n },\n async removeItem(key: string): Promise<void> {\n if (!AsyncStorage) await loadDependencies();\n await AsyncStorage!.removeItem(key);\n },\n async multiGet(keys: string[]): Promise<[string, string | null][]> {\n if (!AsyncStorage) await loadDependencies();\n const result = await AsyncStorage!.multiGet(keys);\n return result as [string, string | null][];\n },\n async multiSet(entries: [string, string][]): Promise<void> {\n if (!AsyncStorage) await loadDependencies();\n await AsyncStorage!.multiSet(entries);\n }\n };\n\n // Network adapter implementation\n const network: NetworkAdapter = {\n async isConnected(): Promise<boolean> {\n if (!NetInfo) await loadDependencies();\n const state = await NetInfo!.fetch();\n return state.isConnected ?? false;\n },\n async getConnectionType(): Promise<ConnectionType> {\n if (!NetInfo) await loadDependencies();\n const state = await NetInfo!.fetch();\n const type = state.type;\n if (type === 'wifi') return 'wifi';\n if (type === 'cellular') return 'cellular';\n if (type === 'ethernet') return 'ethernet';\n if (type === 'none') return 'none';\n return 'unknown';\n },\n addConnectionListener(callback: (isConnected: boolean) => void): () => void {\n // NetInfo must be loaded synchronously for listener setup\n // This is typically called after initialization\n if (!NetInfo) {\n logger.warn('[Platform] NetInfo not loaded, connection listener may not work immediately');\n // Load and set up listener asynchronously\n loadDependencies().then(() => {\n NetInfo!.addEventListener(state => {\n callback(state.isConnected ?? false);\n });\n });\n return () => {};\n }\n const unsubscribe = NetInfo.addEventListener(state => {\n callback(state.isConnected ?? false);\n });\n return unsubscribe;\n }\n };\n\n // Image processor adapter implementation\n const imageProcessor: ImageProcessorAdapter = {\n async compress(uri: string, options: CompressionOptions): Promise<CompressedImage> {\n if (!ImageManipulator) await loadDependencies();\n const actions: import('expo-image-manipulator').Action[] = [];\n\n // Add resize action if maxWidth or maxHeight specified\n if (options.maxWidth || options.maxHeight) {\n actions.push({\n resize: {\n width: options.maxWidth,\n height: options.maxHeight\n }\n });\n }\n\n // Determine output format\n let format: import('expo-image-manipulator').SaveFormat;\n switch (options.format) {\n case 'png':\n format = ImageManipulator!.SaveFormat.PNG;\n break;\n case 'webp':\n format = ImageManipulator!.SaveFormat.WEBP;\n break;\n case 'jpeg':\n default:\n format = ImageManipulator!.SaveFormat.JPEG;\n break;\n }\n const result = await ImageManipulator!.manipulateAsync(uri, actions, {\n compress: options.quality,\n format\n });\n return {\n uri: result.uri,\n width: result.width,\n height: result.height\n };\n }\n };\n\n // Main platform adapter\n return {\n async createDatabase(options: DatabaseOptions): Promise<AbstractPowerSyncDatabase> {\n if (!PowerSyncDatabase) await loadDependencies();\n logger.info('[Platform] Creating PowerSync database:', options.dbFilename);\n const db = new PowerSyncDatabase!({\n schema: options.schema as any,\n database: new OPSqliteOpenFactory!({\n dbFilename: options.dbFilename\n })\n });\n logger.info('[Platform] Initializing database...');\n await db.init();\n\n // Verify database is queryable before returning\n // This prevents race conditions where db.connect() is called before SQLite is truly ready\n const maxAttempts = 3;\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n await db.get('SELECT 1');\n logger.info('[Platform] Database initialized and verified');\n return db as unknown as AbstractPowerSyncDatabase;\n } catch (err) {\n if (attempt < maxAttempts - 1) {\n logger.warn(`[Platform] Database readiness check failed (attempt ${attempt + 1}/${maxAttempts}), retrying...`);\n await new Promise(r => setTimeout(r, 100 * Math.pow(2, attempt))); // 100ms, 200ms, 400ms\n } else {\n logger.error('[Platform] Database failed readiness verification after all attempts');\n throw new Error(`Database failed readiness verification: ${err instanceof Error ? err.message : err}`);\n }\n }\n }\n\n // TypeScript: unreachable but needed for return type\n throw new Error('Database readiness verification failed');\n },\n fileSystem,\n storage,\n network,\n logger,\n imageProcessor\n };\n}\n\n// Re-export types for convenience\nexport type { PlatformAdapter, LoggerAdapter } from './types';"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/platform/index.web.ts"],"sourcesContent":["/**\n * Web Platform Adapter for @pol-studios/powersync\n *\n * Implements the PlatformAdapter interface using Web APIs:\n * - @powersync/web for SQLite database (via wa-sqlite)\n * - IndexedDB for file storage (via idb-keyval pattern)\n * - localStorage for key-value storage\n * - navigator.onLine + events for network monitoring\n * - Canvas API for image compression\n */\n\nimport type { PlatformAdapter, DatabaseOptions, FileSystemAdapter, AsyncStorageAdapter, NetworkAdapter, LoggerAdapter, ImageProcessorAdapter, FileInfo, CompressedImage, CompressionOptions, ConnectionType } from './types';\nimport type { AbstractPowerSyncDatabase } from '../core/types';\n\n// IndexedDB database name for file storage\nconst FILE_STORAGE_DB_NAME = 'powersync-files';\nconst FILE_STORAGE_STORE_NAME = 'files';\n\n/**\n * Simple IndexedDB wrapper for file storage\n */\nclass IndexedDBFileStorage {\n private dbPromise: Promise<IDBDatabase> | null = null;\n private getDB(): Promise<IDBDatabase> {\n if (!this.dbPromise) {\n this.dbPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(FILE_STORAGE_DB_NAME, 1);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result);\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(FILE_STORAGE_STORE_NAME)) {\n db.createObjectStore(FILE_STORAGE_STORE_NAME);\n }\n };\n });\n }\n return this.dbPromise;\n }\n async get(key: string): Promise<string | null> {\n const db = await this.getDB();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(FILE_STORAGE_STORE_NAME, 'readonly');\n const store = transaction.objectStore(FILE_STORAGE_STORE_NAME);\n const request = store.get(key);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result ?? null);\n });\n }\n async set(key: string, value: string): Promise<void> {\n const db = await this.getDB();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(FILE_STORAGE_STORE_NAME, 'readwrite');\n const store = transaction.objectStore(FILE_STORAGE_STORE_NAME);\n const request = store.put(value, key);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n });\n }\n async delete(key: string): Promise<void> {\n const db = await this.getDB();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(FILE_STORAGE_STORE_NAME, 'readwrite');\n const store = transaction.objectStore(FILE_STORAGE_STORE_NAME);\n const request = store.delete(key);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve();\n });\n }\n async has(key: string): Promise<boolean> {\n const db = await this.getDB();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(FILE_STORAGE_STORE_NAME, 'readonly');\n const store = transaction.objectStore(FILE_STORAGE_STORE_NAME);\n const request = store.count(key);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result > 0);\n });\n }\n}\n\n/**\n * Create a Web platform adapter\n *\n * @param logger - Logger implementation to use\n * @returns Platform adapter configured for Web/PWA\n *\n * @example\n * ```typescript\n * import { createWebPlatformAdapter } from '@pol-studios/powersync/platform';\n *\n * const logger = {\n * debug: console.log,\n * info: console.log,\n * warn: console.warn,\n * error: console.error,\n * };\n *\n * const platform = createWebPlatformAdapter(logger);\n * ```\n */\nexport function createWebPlatformAdapter(logger: LoggerAdapter): PlatformAdapter {\n const fileStorage = new IndexedDBFileStorage();\n\n // Lazy load PowerSync web\n let PowerSyncDatabase: typeof import('@powersync/web').PowerSyncDatabase;\n let WASQLiteOpenFactory: typeof import('@powersync/web').WASQLiteOpenFactory;\n const loadPowerSync = async () => {\n if (!PowerSyncDatabase) {\n const psModule = await import('@powersync/web');\n PowerSyncDatabase = psModule.PowerSyncDatabase;\n WASQLiteOpenFactory = psModule.WASQLiteOpenFactory;\n }\n };\n\n // File system adapter implementation using IndexedDB\n const fileSystem: FileSystemAdapter = {\n async readFile(uri: string, encoding: 'base64' | 'utf8' = 'utf8'): Promise<string> {\n const content = await fileStorage.get(uri);\n if (content === null) {\n throw new Error(`File not found: ${uri}`);\n }\n return content;\n },\n async writeFile(uri: string, data: string, encoding: 'base64' | 'utf8' = 'utf8'): Promise<void> {\n await fileStorage.set(uri, data);\n },\n async deleteFile(uri: string): Promise<void> {\n await fileStorage.delete(uri);\n },\n async copyFile(source: string, destination: string): Promise<void> {\n const content = await fileStorage.get(source);\n if (content === null) {\n throw new Error(`Source file not found: ${source}`);\n }\n await fileStorage.set(destination, content);\n },\n async moveFile(source: string, destination: string): Promise<void> {\n const content = await fileStorage.get(source);\n if (content === null) {\n throw new Error(`Source file not found: ${source}`);\n }\n await fileStorage.set(destination, content);\n await fileStorage.delete(source);\n },\n async getFileInfo(uri: string): Promise<FileInfo | null> {\n const exists = await fileStorage.has(uri);\n if (!exists) return null;\n const content = await fileStorage.get(uri);\n return {\n exists: true,\n size: content ? content.length : 0,\n isDirectory: false // IndexedDB doesn't have directories\n };\n },\n async makeDirectory(uri: string, options?: {\n intermediates?: boolean;\n }): Promise<void> {\n // No-op for IndexedDB - directories are virtual\n },\n getDocumentsDirectory(): string {\n return '/powersync-docs/';\n },\n getCacheDirectory(): string {\n return '/powersync-cache/';\n },\n async getFreeDiskSpace(): Promise<number> {\n // Try to use Storage API if available\n if ('storage' in navigator && 'estimate' in navigator.storage) {\n try {\n const estimate = await navigator.storage.estimate();\n const quota = estimate.quota ?? 0;\n const usage = estimate.usage ?? 0;\n return quota - usage;\n } catch {\n // Fall through to default\n }\n }\n // Return a large default value if Storage API not available\n return 10 * 1024 * 1024 * 1024; // 10 GB default\n }\n };\n\n // Async storage adapter using localStorage\n const storage: AsyncStorageAdapter = {\n async getItem(key: string): Promise<string | null> {\n try {\n return localStorage.getItem(key);\n } catch {\n logger.warn('[Platform] localStorage.getItem failed for:', key);\n return null;\n }\n },\n async setItem(key: string, value: string): Promise<void> {\n try {\n localStorage.setItem(key, value);\n } catch (e) {\n logger.error('[Platform] localStorage.setItem failed:', e);\n throw e;\n }\n },\n async removeItem(key: string): Promise<void> {\n try {\n localStorage.removeItem(key);\n } catch {\n // Ignore removal errors\n }\n },\n async multiGet(keys: string[]): Promise<[string, string | null][]> {\n return keys.map(key => [key, localStorage.getItem(key)]);\n },\n async multiSet(entries: [string, string][]): Promise<void> {\n for (const [key, value] of entries) {\n localStorage.setItem(key, value);\n }\n }\n };\n\n // Network adapter using navigator.onLine and events\n const network: NetworkAdapter = {\n async isConnected(): Promise<boolean> {\n return navigator.onLine;\n },\n async getConnectionType(): Promise<ConnectionType> {\n if (!navigator.onLine) return 'none';\n\n // Try to use Network Information API if available\n const nav = navigator as Navigator & {\n connection?: {\n effectiveType?: string;\n type?: string;\n };\n };\n if (nav.connection) {\n const type = nav.connection.type;\n if (type === 'wifi') return 'wifi';\n if (type === 'cellular') return 'cellular';\n if (type === 'ethernet') return 'ethernet';\n }\n return 'unknown';\n },\n addConnectionListener(callback: (isConnected: boolean) => void): () => void {\n const handleOnline = () => callback(true);\n const handleOffline = () => callback(false);\n window.addEventListener('online', handleOnline);\n window.addEventListener('offline', handleOffline);\n return () => {\n window.removeEventListener('online', handleOnline);\n window.removeEventListener('offline', handleOffline);\n };\n }\n };\n\n // Image processor using Canvas API\n const imageProcessor: ImageProcessorAdapter = {\n async compress(uri: string, options: CompressionOptions): Promise<CompressedImage> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n img.onload = () => {\n try {\n // Calculate target dimensions\n let width = img.width;\n let height = img.height;\n if (options.maxWidth && width > options.maxWidth) {\n height = height * options.maxWidth / width;\n width = options.maxWidth;\n }\n if (options.maxHeight && height > options.maxHeight) {\n width = width * options.maxHeight / height;\n height = options.maxHeight;\n }\n\n // Create canvas and draw image\n const canvas = document.createElement('canvas');\n canvas.width = Math.round(width);\n canvas.height = Math.round(height);\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n reject(new Error('Failed to get canvas context'));\n return;\n }\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height);\n\n // Determine mime type\n let mimeType: string;\n switch (options.format) {\n case 'png':\n mimeType = 'image/png';\n break;\n case 'webp':\n mimeType = 'image/webp';\n break;\n case 'jpeg':\n default:\n mimeType = 'image/jpeg';\n break;\n }\n\n // Convert to data URL\n const dataUrl = canvas.toDataURL(mimeType, options.quality);\n resolve({\n uri: dataUrl,\n width: canvas.width,\n height: canvas.height\n });\n } catch (e) {\n reject(e);\n }\n };\n img.onerror = () => {\n reject(new Error(`Failed to load image: ${uri}`));\n };\n img.src = uri;\n });\n }\n };\n\n // Main platform adapter\n return {\n async createDatabase(options: DatabaseOptions): Promise<AbstractPowerSyncDatabase> {\n await loadPowerSync();\n logger.info('[Platform] Creating PowerSync web database:', options.dbFilename);\n const db = new PowerSyncDatabase!({\n schema: options.schema as any,\n database: new WASQLiteOpenFactory!({\n dbFilename: options.dbFilename\n })\n });\n logger.info('[Platform] Initializing database...');\n await db.init();\n\n // Verify database is queryable before returning\n // This prevents race conditions where db.connect() is called before SQLite is truly ready\n const maxAttempts = 3;\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n await db.get('SELECT 1');\n logger.info('[Platform] Database initialized and verified');\n return db as unknown as AbstractPowerSyncDatabase;\n } catch (err) {\n if (attempt < maxAttempts - 1) {\n logger.warn(`[Platform] Database readiness check failed (attempt ${attempt + 1}/${maxAttempts}), retrying...`);\n await new Promise(r => setTimeout(r, 100 * Math.pow(2, attempt))); // 100ms, 200ms, 400ms\n } else {\n logger.error('[Platform] Database failed readiness verification after all attempts');\n throw new Error(`Database failed readiness verification: ${err instanceof Error ? err.message : err}`);\n }\n }\n }\n\n // TypeScript: unreachable but needed for return type\n throw new Error('Database readiness verification failed');\n },\n fileSystem,\n storage,\n network,\n logger,\n imageProcessor\n };\n}\n\n// Re-export types for convenience\nexport type { PlatformAdapter, LoggerAdapter } from './types';"],"mappings":";AAeA,IAAM,uBAAuB;AAC7B,IAAM,0BAA0B;AAKhC,IAAM,uBAAN,MAA2B;AAAA,EACjB,YAAyC;AAAA,EACzC,QAA8B;AACpC,QAAI,CAAC,KAAK,WAAW;AACnB,WAAK,YAAY,IAAI,QAAQ,CAAC,SAAS,WAAW;AAChD,cAAM,UAAU,UAAU,KAAK,sBAAsB,CAAC;AACtD,gBAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAC5C,gBAAQ,YAAY,MAAM,QAAQ,QAAQ,MAAM;AAChD,gBAAQ,kBAAkB,MAAM;AAC9B,gBAAM,KAAK,QAAQ;AACnB,cAAI,CAAC,GAAG,iBAAiB,SAAS,uBAAuB,GAAG;AAC1D,eAAG,kBAAkB,uBAAuB;AAAA,UAC9C;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EACA,MAAM,IAAI,KAAqC;AAC7C,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,cAAc,GAAG,YAAY,yBAAyB,UAAU;AACtE,YAAM,QAAQ,YAAY,YAAY,uBAAuB;AAC7D,YAAM,UAAU,MAAM,IAAI,GAAG;AAC7B,cAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAC5C,cAAQ,YAAY,MAAM,QAAQ,QAAQ,UAAU,IAAI;AAAA,IAC1D,CAAC;AAAA,EACH;AAAA,EACA,MAAM,IAAI,KAAa,OAA8B;AACnD,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,cAAc,GAAG,YAAY,yBAAyB,WAAW;AACvE,YAAM,QAAQ,YAAY,YAAY,uBAAuB;AAC7D,YAAM,UAAU,MAAM,IAAI,OAAO,GAAG;AACpC,cAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAC5C,cAAQ,YAAY,MAAM,QAAQ;AAAA,IACpC,CAAC;AAAA,EACH;AAAA,EACA,MAAM,OAAO,KAA4B;AACvC,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,cAAc,GAAG,YAAY,yBAAyB,WAAW;AACvE,YAAM,QAAQ,YAAY,YAAY,uBAAuB;AAC7D,YAAM,UAAU,MAAM,OAAO,GAAG;AAChC,cAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAC5C,cAAQ,YAAY,MAAM,QAAQ;AAAA,IACpC,CAAC;AAAA,EACH;AAAA,EACA,MAAM,IAAI,KAA+B;AACvC,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,cAAc,GAAG,YAAY,yBAAyB,UAAU;AACtE,YAAM,QAAQ,YAAY,YAAY,uBAAuB;AAC7D,YAAM,UAAU,MAAM,MAAM,GAAG;AAC/B,cAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAC5C,cAAQ,YAAY,MAAM,QAAQ,QAAQ,SAAS,CAAC;AAAA,IACtD,CAAC;AAAA,EACH;AACF;AAsBO,SAAS,yBAAyB,QAAwC;AAC/E,QAAM,cAAc,IAAI,qBAAqB;AAG7C,MAAI;AACJ,MAAI;AACJ,QAAM,gBAAgB,YAAY;AAChC,QAAI,CAAC,mBAAmB;AACtB,YAAM,WAAW,MAAM,OAAO,gBAAgB;AAC9C,0BAAoB,SAAS;AAC7B,4BAAsB,SAAS;AAAA,IACjC;AAAA,EACF;AAGA,QAAM,aAAgC;AAAA,IACpC,MAAM,SAAS,KAAa,WAA8B,QAAyB;AACjF,YAAM,UAAU,MAAM,YAAY,IAAI,GAAG;AACzC,UAAI,YAAY,MAAM;AACpB,cAAM,IAAI,MAAM,mBAAmB,GAAG,EAAE;AAAA,MAC1C;AACA,aAAO;AAAA,IACT;AAAA,IACA,MAAM,UAAU,KAAa,MAAc,WAA8B,QAAuB;AAC9F,YAAM,YAAY,IAAI,KAAK,IAAI;AAAA,IACjC;AAAA,IACA,MAAM,WAAW,KAA4B;AAC3C,YAAM,YAAY,OAAO,GAAG;AAAA,IAC9B;AAAA,IACA,MAAM,SAAS,QAAgB,aAAoC;AACjE,YAAM,UAAU,MAAM,YAAY,IAAI,MAAM;AAC5C,UAAI,YAAY,MAAM;AACpB,cAAM,IAAI,MAAM,0BAA0B,MAAM,EAAE;AAAA,MACpD;AACA,YAAM,YAAY,IAAI,aAAa,OAAO;AAAA,IAC5C;AAAA,IACA,MAAM,SAAS,QAAgB,aAAoC;AACjE,YAAM,UAAU,MAAM,YAAY,IAAI,MAAM;AAC5C,UAAI,YAAY,MAAM;AACpB,cAAM,IAAI,MAAM,0BAA0B,MAAM,EAAE;AAAA,MACpD;AACA,YAAM,YAAY,IAAI,aAAa,OAAO;AAC1C,YAAM,YAAY,OAAO,MAAM;AAAA,IACjC;AAAA,IACA,MAAM,YAAY,KAAuC;AACvD,YAAM,SAAS,MAAM,YAAY,IAAI,GAAG;AACxC,UAAI,CAAC,OAAQ,QAAO;AACpB,YAAM,UAAU,MAAM,YAAY,IAAI,GAAG;AACzC,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,MAAM,UAAU,QAAQ,SAAS;AAAA,QACjC,aAAa;AAAA;AAAA,MACf;AAAA,IACF;AAAA,IACA,MAAM,cAAc,KAAa,SAEf;AAAA,IAElB;AAAA,IACA,wBAAgC;AAC9B,aAAO;AAAA,IACT;AAAA,IACA,oBAA4B;AAC1B,aAAO;AAAA,IACT;AAAA,IACA,MAAM,mBAAoC;AAExC,UAAI,aAAa,aAAa,cAAc,UAAU,SAAS;AAC7D,YAAI;AACF,gBAAM,WAAW,MAAM,UAAU,QAAQ,SAAS;AAClD,gBAAM,QAAQ,SAAS,SAAS;AAChC,gBAAM,QAAQ,SAAS,SAAS;AAChC,iBAAO,QAAQ;AAAA,QACjB,QAAQ;AAAA,QAER;AAAA,MACF;AAEA,aAAO,KAAK,OAAO,OAAO;AAAA,IAC5B;AAAA,EACF;AAGA,QAAM,UAA+B;AAAA,IACnC,MAAM,QAAQ,KAAqC;AACjD,UAAI;AACF,eAAO,aAAa,QAAQ,GAAG;AAAA,MACjC,QAAQ;AACN,eAAO,KAAK,+CAA+C,GAAG;AAC9D,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,MAAM,QAAQ,KAAa,OAA8B;AACvD,UAAI;AACF,qBAAa,QAAQ,KAAK,KAAK;AAAA,MACjC,SAAS,GAAG;AACV,eAAO,MAAM,2CAA2C,CAAC;AACzD,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,MAAM,WAAW,KAA4B;AAC3C,UAAI;AACF,qBAAa,WAAW,GAAG;AAAA,MAC7B,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,IACA,MAAM,SAAS,MAAoD;AACjE,aAAO,KAAK,IAAI,SAAO,CAAC,KAAK,aAAa,QAAQ,GAAG,CAAC,CAAC;AAAA,IACzD;AAAA,IACA,MAAM,SAAS,SAA4C;AACzD,iBAAW,CAAC,KAAK,KAAK,KAAK,SAAS;AAClC,qBAAa,QAAQ,KAAK,KAAK;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAGA,QAAM,UAA0B;AAAA,IAC9B,MAAM,cAAgC;AACpC,aAAO,UAAU;AAAA,IACnB;AAAA,IACA,MAAM,oBAA6C;AACjD,UAAI,CAAC,UAAU,OAAQ,QAAO;AAG9B,YAAM,MAAM;AAMZ,UAAI,IAAI,YAAY;AAClB,cAAM,OAAO,IAAI,WAAW;AAC5B,YAAI,SAAS,OAAQ,QAAO;AAC5B,YAAI,SAAS,WAAY,QAAO;AAChC,YAAI,SAAS,WAAY,QAAO;AAAA,MAClC;AACA,aAAO;AAAA,IACT;AAAA,IACA,sBAAsB,UAAsD;AAC1E,YAAM,eAAe,MAAM,SAAS,IAAI;AACxC,YAAM,gBAAgB,MAAM,SAAS,KAAK;AAC1C,aAAO,iBAAiB,UAAU,YAAY;AAC9C,aAAO,iBAAiB,WAAW,aAAa;AAChD,aAAO,MAAM;AACX,eAAO,oBAAoB,UAAU,YAAY;AACjD,eAAO,oBAAoB,WAAW,aAAa;AAAA,MACrD;AAAA,IACF;AAAA,EACF;AAGA,QAAM,iBAAwC;AAAA,IAC5C,MAAM,SAAS,KAAa,SAAuD;AACjF,aAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,cAAM,MAAM,IAAI,MAAM;AACtB,YAAI,cAAc;AAClB,YAAI,SAAS,MAAM;AACjB,cAAI;AAEF,gBAAI,QAAQ,IAAI;AAChB,gBAAI,SAAS,IAAI;AACjB,gBAAI,QAAQ,YAAY,QAAQ,QAAQ,UAAU;AAChD,uBAAS,SAAS,QAAQ,WAAW;AACrC,sBAAQ,QAAQ;AAAA,YAClB;AACA,gBAAI,QAAQ,aAAa,SAAS,QAAQ,WAAW;AACnD,sBAAQ,QAAQ,QAAQ,YAAY;AACpC,uBAAS,QAAQ;AAAA,YACnB;AAGA,kBAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,mBAAO,QAAQ,KAAK,MAAM,KAAK;AAC/B,mBAAO,SAAS,KAAK,MAAM,MAAM;AACjC,kBAAM,MAAM,OAAO,WAAW,IAAI;AAClC,gBAAI,CAAC,KAAK;AACR,qBAAO,IAAI,MAAM,8BAA8B,CAAC;AAChD;AAAA,YACF;AACA,gBAAI,UAAU,KAAK,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AAGpD,gBAAI;AACJ,oBAAQ,QAAQ,QAAQ;AAAA,cACtB,KAAK;AACH,2BAAW;AACX;AAAA,cACF,KAAK;AACH,2BAAW;AACX;AAAA,cACF,KAAK;AAAA,cACL;AACE,2BAAW;AACX;AAAA,YACJ;AAGA,kBAAM,UAAU,OAAO,UAAU,UAAU,QAAQ,OAAO;AAC1D,oBAAQ;AAAA,cACN,KAAK;AAAA,cACL,OAAO,OAAO;AAAA,cACd,QAAQ,OAAO;AAAA,YACjB,CAAC;AAAA,UACH,SAAS,GAAG;AACV,mBAAO,CAAC;AAAA,UACV;AAAA,QACF;AACA,YAAI,UAAU,MAAM;AAClB,iBAAO,IAAI,MAAM,yBAAyB,GAAG,EAAE,CAAC;AAAA,QAClD;AACA,YAAI,MAAM;AAAA,MACZ,CAAC;AAAA,IACH;AAAA,EACF;AAGA,SAAO;AAAA,IACL,MAAM,eAAe,SAA8D;AACjF,YAAM,cAAc;AACpB,aAAO,KAAK,+CAA+C,QAAQ,UAAU;AAC7E,YAAM,KAAK,IAAI,kBAAmB;AAAA,QAChC,QAAQ,QAAQ;AAAA,QAChB,UAAU,IAAI,oBAAqB;AAAA,UACjC,YAAY,QAAQ;AAAA,QACtB,CAAC;AAAA,MACH,CAAC;AACD,aAAO,KAAK,qCAAqC;AACjD,YAAM,GAAG,KAAK;AAId,YAAM,cAAc;AACpB,eAAS,UAAU,GAAG,UAAU,aAAa,WAAW;AACtD,YAAI;AACF,gBAAM,GAAG,IAAI,UAAU;AACvB,iBAAO,KAAK,8CAA8C;AAC1D,iBAAO;AAAA,QACT,SAAS,KAAK;AACZ,cAAI,UAAU,cAAc,GAAG;AAC7B,mBAAO,KAAK,uDAAuD,UAAU,CAAC,IAAI,WAAW,gBAAgB;AAC7G,kBAAM,IAAI,QAAQ,OAAK,WAAW,GAAG,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC;AAAA,UAClE,OAAO;AACL,mBAAO,MAAM,sEAAsE;AACnF,kBAAM,IAAI,MAAM,2CAA2C,eAAe,QAAQ,IAAI,UAAU,GAAG,EAAE;AAAA,UACvG;AAAA,QACF;AAAA,MACF;AAGA,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
classifySupabaseError
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FPTDATY5.js";
|
|
4
4
|
|
|
5
5
|
// src/connector/types.ts
|
|
6
6
|
var defaultSchemaRouter = () => "public";
|
|
@@ -14,10 +14,7 @@ function validateTableName(table) {
|
|
|
14
14
|
}
|
|
15
15
|
var DEFAULT_IGNORED_FIELDS = ["updatedAt", "createdAt", "_version", "id"];
|
|
16
16
|
async function detectConflicts(table, recordId, localVersion, serverVersion, pendingChanges, supabase, config) {
|
|
17
|
-
const ignoredFields = /* @__PURE__ */ new Set([
|
|
18
|
-
...DEFAULT_IGNORED_FIELDS,
|
|
19
|
-
...config?.ignoredFields ?? []
|
|
20
|
-
]);
|
|
17
|
+
const ignoredFields = /* @__PURE__ */ new Set([...DEFAULT_IGNORED_FIELDS, ...config?.ignoredFields ?? []]);
|
|
21
18
|
const filteredPendingChanges = {};
|
|
22
19
|
for (const [field, value] of Object.entries(pendingChanges)) {
|
|
23
20
|
if (!ignoredFields.has(field)) {
|
|
@@ -33,7 +30,12 @@ async function detectConflicts(table, recordId, localVersion, serverVersion, pen
|
|
|
33
30
|
recordId
|
|
34
31
|
};
|
|
35
32
|
}
|
|
36
|
-
const {
|
|
33
|
+
const {
|
|
34
|
+
data: auditLogs,
|
|
35
|
+
error
|
|
36
|
+
} = await supabase.schema("core").from("AuditLog").select("oldRecord, newRecord, changeBy, changeAt").eq("tableName", table).eq("recordId_text", recordId).order("changeAt", {
|
|
37
|
+
ascending: false
|
|
38
|
+
}).limit(20);
|
|
37
39
|
if (error) {
|
|
38
40
|
console.warn("[detectConflicts] Failed to query AuditLog:", error);
|
|
39
41
|
return {
|
|
@@ -87,9 +89,7 @@ async function detectConflicts(table, recordId, localVersion, serverVersion, pen
|
|
|
87
89
|
async function hasVersionColumn(table, db) {
|
|
88
90
|
try {
|
|
89
91
|
validateTableName(table);
|
|
90
|
-
const result = await db.getAll(
|
|
91
|
-
`PRAGMA table_info("${table}")`
|
|
92
|
-
);
|
|
92
|
+
const result = await db.getAll(`PRAGMA table_info("${table}")`);
|
|
93
93
|
return result.some((col) => col.name === "_version");
|
|
94
94
|
} catch {
|
|
95
95
|
return false;
|
|
@@ -97,7 +97,10 @@ async function hasVersionColumn(table, db) {
|
|
|
97
97
|
}
|
|
98
98
|
async function fetchServerVersion(table, recordId, schema, supabase) {
|
|
99
99
|
const query = schema === "public" ? supabase.from(table) : supabase.schema(schema).from(table);
|
|
100
|
-
const {
|
|
100
|
+
const {
|
|
101
|
+
data,
|
|
102
|
+
error
|
|
103
|
+
} = await query.select("_version").eq("id", recordId).single();
|
|
101
104
|
if (error || !data) {
|
|
102
105
|
return null;
|
|
103
106
|
}
|
|
@@ -105,10 +108,7 @@ async function fetchServerVersion(table, recordId, schema, supabase) {
|
|
|
105
108
|
}
|
|
106
109
|
async function getLocalVersion(table, recordId, db) {
|
|
107
110
|
validateTableName(table);
|
|
108
|
-
const result = await db.get(
|
|
109
|
-
`SELECT _version FROM "${table}" WHERE id = ?`,
|
|
110
|
-
[recordId]
|
|
111
|
-
);
|
|
111
|
+
const result = await db.get(`SELECT _version FROM "${table}" WHERE id = ?`, [recordId]);
|
|
112
112
|
return result?._version ?? null;
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -131,6 +131,11 @@ var SupabaseConnector = class {
|
|
|
131
131
|
versionColumnCache = /* @__PURE__ */ new Map();
|
|
132
132
|
// Active project IDs for scoped sync (optional feature)
|
|
133
133
|
activeProjectIds = [];
|
|
134
|
+
// Store resolutions for retry - when PowerSync retries, we apply stored resolutions
|
|
135
|
+
// instead of re-detecting conflicts that the user already resolved
|
|
136
|
+
resolvedConflicts = /* @__PURE__ */ new Map();
|
|
137
|
+
// Cleanup function for resolution listener subscription
|
|
138
|
+
unsubscribeResolution;
|
|
134
139
|
constructor(options) {
|
|
135
140
|
this.supabase = options.supabaseClient;
|
|
136
141
|
this.powerSyncUrl = options.powerSyncUrl;
|
|
@@ -144,6 +149,31 @@ var SupabaseConnector = class {
|
|
|
144
149
|
this.conflictDetection = options.conflictDetection;
|
|
145
150
|
this.conflictHandler = options.conflictHandler;
|
|
146
151
|
this.conflictBus = options.conflictBus;
|
|
152
|
+
if (this.conflictBus) {
|
|
153
|
+
this.unsubscribeResolution = this.conflictBus.onResolution((table, recordId, resolution) => {
|
|
154
|
+
const key = `${table}:${recordId}`;
|
|
155
|
+
if (__DEV__) {
|
|
156
|
+
console.log("[Connector] Storing resolution for retry:", {
|
|
157
|
+
table,
|
|
158
|
+
recordId,
|
|
159
|
+
key,
|
|
160
|
+
resolution
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
this.resolvedConflicts.set(key, resolution);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Clean up resources (unsubscribe from event listeners).
|
|
169
|
+
* Call this when the connector is no longer needed.
|
|
170
|
+
*/
|
|
171
|
+
destroy() {
|
|
172
|
+
if (this.unsubscribeResolution) {
|
|
173
|
+
this.unsubscribeResolution();
|
|
174
|
+
this.unsubscribeResolution = void 0;
|
|
175
|
+
}
|
|
176
|
+
this.resolvedConflicts.clear();
|
|
147
177
|
}
|
|
148
178
|
/**
|
|
149
179
|
* Set the active project IDs for scoped sync.
|
|
@@ -168,7 +198,9 @@ var SupabaseConnector = class {
|
|
|
168
198
|
async fetchCredentials() {
|
|
169
199
|
this.logger?.debug("[Connector] Fetching credentials...");
|
|
170
200
|
const {
|
|
171
|
-
data: {
|
|
201
|
+
data: {
|
|
202
|
+
session
|
|
203
|
+
},
|
|
172
204
|
error
|
|
173
205
|
} = await this.supabase.auth.getSession();
|
|
174
206
|
if (error) {
|
|
@@ -179,10 +211,7 @@ var SupabaseConnector = class {
|
|
|
179
211
|
this.logger?.error("[Connector] No active session");
|
|
180
212
|
throw new Error("No active Supabase session");
|
|
181
213
|
}
|
|
182
|
-
this.logger?.debug(
|
|
183
|
-
"[Connector] Credentials fetched, token expires at:",
|
|
184
|
-
session.expires_at
|
|
185
|
-
);
|
|
214
|
+
this.logger?.debug("[Connector] Credentials fetched, token expires at:", session.expires_at);
|
|
186
215
|
return {
|
|
187
216
|
endpoint: this.powerSyncUrl,
|
|
188
217
|
token: session.access_token,
|
|
@@ -234,7 +263,9 @@ var SupabaseConnector = class {
|
|
|
234
263
|
await this.processTransaction(transaction, database);
|
|
235
264
|
return;
|
|
236
265
|
}
|
|
237
|
-
const {
|
|
266
|
+
const {
|
|
267
|
+
crud
|
|
268
|
+
} = transaction;
|
|
238
269
|
const skipTables = new Set(this.conflictDetection?.skipTables ?? []);
|
|
239
270
|
const entriesToProcess = [];
|
|
240
271
|
const entriesQueuedForUI = [];
|
|
@@ -249,6 +280,35 @@ var SupabaseConnector = class {
|
|
|
249
280
|
entriesToProcess.push(entry);
|
|
250
281
|
continue;
|
|
251
282
|
}
|
|
283
|
+
const resolutionKey = `${entry.table}:${entry.id}`;
|
|
284
|
+
const existingResolution = this.resolvedConflicts.get(resolutionKey);
|
|
285
|
+
if (existingResolution) {
|
|
286
|
+
if (__DEV__) {
|
|
287
|
+
console.log("[Connector] Applying stored resolution for retry:", {
|
|
288
|
+
table: entry.table,
|
|
289
|
+
id: entry.id,
|
|
290
|
+
key: resolutionKey,
|
|
291
|
+
resolution: existingResolution
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
this.resolvedConflicts.delete(resolutionKey);
|
|
295
|
+
switch (existingResolution.action) {
|
|
296
|
+
case "overwrite":
|
|
297
|
+
entriesToProcess.push(entry);
|
|
298
|
+
break;
|
|
299
|
+
case "keep-server":
|
|
300
|
+
entriesDiscarded.push(entry);
|
|
301
|
+
break;
|
|
302
|
+
case "partial":
|
|
303
|
+
const partialEntry = {
|
|
304
|
+
...entry,
|
|
305
|
+
opData: this.filterFields(entry.opData ?? {}, existingResolution.fields)
|
|
306
|
+
};
|
|
307
|
+
entriesToProcess.push(partialEntry);
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
252
312
|
const hasVersion = await this.checkVersionColumn(entry.table, database);
|
|
253
313
|
if (!hasVersion) {
|
|
254
314
|
entriesToProcess.push(entry);
|
|
@@ -256,25 +316,12 @@ var SupabaseConnector = class {
|
|
|
256
316
|
}
|
|
257
317
|
const localVersion = await getLocalVersion(entry.table, entry.id, database);
|
|
258
318
|
const schema = this.schemaRouter(entry.table);
|
|
259
|
-
const serverVersion = await fetchServerVersion(
|
|
260
|
-
entry.table,
|
|
261
|
-
entry.id,
|
|
262
|
-
schema,
|
|
263
|
-
this.supabase
|
|
264
|
-
);
|
|
319
|
+
const serverVersion = await fetchServerVersion(entry.table, entry.id, schema, this.supabase);
|
|
265
320
|
if (localVersion === null || serverVersion === null) {
|
|
266
321
|
entriesToProcess.push(entry);
|
|
267
322
|
continue;
|
|
268
323
|
}
|
|
269
|
-
const conflictResult = await detectConflicts(
|
|
270
|
-
entry.table,
|
|
271
|
-
entry.id,
|
|
272
|
-
localVersion,
|
|
273
|
-
serverVersion,
|
|
274
|
-
entry.opData ?? {},
|
|
275
|
-
this.supabase,
|
|
276
|
-
this.conflictDetection
|
|
277
|
-
);
|
|
324
|
+
const conflictResult = await detectConflicts(entry.table, entry.id, localVersion, serverVersion, entry.opData ?? {}, this.supabase, this.conflictDetection);
|
|
278
325
|
if (!conflictResult.hasConflict) {
|
|
279
326
|
entriesToProcess.push(entry);
|
|
280
327
|
continue;
|
|
@@ -348,11 +395,7 @@ var SupabaseConnector = class {
|
|
|
348
395
|
this.onTransactionComplete?.(entriesDiscarded);
|
|
349
396
|
} catch (error) {
|
|
350
397
|
const classified = classifySupabaseError(error);
|
|
351
|
-
this.onTransactionFailure?.(
|
|
352
|
-
entriesDiscarded,
|
|
353
|
-
error instanceof Error ? error : new Error(String(error)),
|
|
354
|
-
classified
|
|
355
|
-
);
|
|
398
|
+
this.onTransactionFailure?.(entriesDiscarded, error instanceof Error ? error : new Error(String(error)), classified);
|
|
356
399
|
throw error;
|
|
357
400
|
}
|
|
358
401
|
return;
|
|
@@ -380,11 +423,12 @@ var SupabaseConnector = class {
|
|
|
380
423
|
});
|
|
381
424
|
}
|
|
382
425
|
if (this.conflictBus && partialResolutions.length > 0) {
|
|
383
|
-
for (const {
|
|
426
|
+
for (const {
|
|
427
|
+
originalConflict,
|
|
428
|
+
syncedFields
|
|
429
|
+
} of partialResolutions) {
|
|
384
430
|
const syncedFieldSet = new Set(syncedFields);
|
|
385
|
-
const remainingConflicts = originalConflict.conflicts.filter(
|
|
386
|
-
(c) => !syncedFieldSet.has(c.field)
|
|
387
|
-
);
|
|
431
|
+
const remainingConflicts = originalConflict.conflicts.filter((c) => !syncedFieldSet.has(c.field));
|
|
388
432
|
if (remainingConflicts.length > 0) {
|
|
389
433
|
if (__DEV__) {
|
|
390
434
|
console.log("[Connector] Re-emitting conflict for remaining fields:", {
|
|
@@ -423,13 +467,13 @@ var SupabaseConnector = class {
|
|
|
423
467
|
this.logger?.error("[Connector] Upload error:", {
|
|
424
468
|
error,
|
|
425
469
|
classified,
|
|
426
|
-
entries: entriesToProcess.map((e) => ({
|
|
470
|
+
entries: entriesToProcess.map((e) => ({
|
|
471
|
+
table: e.table,
|
|
472
|
+
op: e.op,
|
|
473
|
+
id: e.id
|
|
474
|
+
}))
|
|
427
475
|
});
|
|
428
|
-
this.onTransactionFailure?.(
|
|
429
|
-
entriesToProcess,
|
|
430
|
-
error instanceof Error ? error : new Error(String(error)),
|
|
431
|
-
classified
|
|
432
|
-
);
|
|
476
|
+
this.onTransactionFailure?.(entriesToProcess, error instanceof Error ? error : new Error(String(error)), classified);
|
|
433
477
|
throw error;
|
|
434
478
|
}
|
|
435
479
|
}
|
|
@@ -478,13 +522,13 @@ var SupabaseConnector = class {
|
|
|
478
522
|
this.logger?.error("[Connector] Upload error:", {
|
|
479
523
|
error,
|
|
480
524
|
classified,
|
|
481
|
-
entries: transaction.crud.map((e) => ({
|
|
525
|
+
entries: transaction.crud.map((e) => ({
|
|
526
|
+
table: e.table,
|
|
527
|
+
op: e.op,
|
|
528
|
+
id: e.id
|
|
529
|
+
}))
|
|
482
530
|
});
|
|
483
|
-
this.onTransactionFailure?.(
|
|
484
|
-
transaction.crud,
|
|
485
|
-
error instanceof Error ? error : new Error(String(error)),
|
|
486
|
-
classified
|
|
487
|
-
);
|
|
531
|
+
this.onTransactionFailure?.(transaction.crud, error instanceof Error ? error : new Error(String(error)), classified);
|
|
488
532
|
throw error;
|
|
489
533
|
}
|
|
490
534
|
}
|
|
@@ -535,24 +579,14 @@ var SupabaseConnector = class {
|
|
|
535
579
|
handled = await this.crudHandler.handlePut?.(entry, this.supabase, schema) ?? false;
|
|
536
580
|
break;
|
|
537
581
|
case "PATCH" /* PATCH */:
|
|
538
|
-
handled = await this.crudHandler.handlePatch?.(
|
|
539
|
-
entry,
|
|
540
|
-
this.supabase,
|
|
541
|
-
schema
|
|
542
|
-
) ?? false;
|
|
582
|
+
handled = await this.crudHandler.handlePatch?.(entry, this.supabase, schema) ?? false;
|
|
543
583
|
break;
|
|
544
584
|
case "DELETE" /* DELETE */:
|
|
545
|
-
handled = await this.crudHandler.handleDelete?.(
|
|
546
|
-
entry,
|
|
547
|
-
this.supabase,
|
|
548
|
-
schema
|
|
549
|
-
) ?? false;
|
|
585
|
+
handled = await this.crudHandler.handleDelete?.(entry, this.supabase, schema) ?? false;
|
|
550
586
|
break;
|
|
551
587
|
}
|
|
552
588
|
if (handled) {
|
|
553
|
-
this.logger?.debug(
|
|
554
|
-
`[Connector] Custom handler processed ${entry.op} for ${schema}.${table}`
|
|
555
|
-
);
|
|
589
|
+
this.logger?.debug(`[Connector] Custom handler processed ${entry.op} for ${schema}.${table}`);
|
|
556
590
|
return;
|
|
557
591
|
}
|
|
558
592
|
}
|
|
@@ -564,13 +598,21 @@ var SupabaseConnector = class {
|
|
|
564
598
|
schema,
|
|
565
599
|
table,
|
|
566
600
|
id,
|
|
567
|
-
data: {
|
|
601
|
+
data: {
|
|
602
|
+
id,
|
|
603
|
+
...entry.opData
|
|
604
|
+
}
|
|
568
605
|
});
|
|
569
606
|
}
|
|
570
|
-
const {
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
607
|
+
const {
|
|
608
|
+
data: upsertData,
|
|
609
|
+
error: upsertError
|
|
610
|
+
} = await query.upsert({
|
|
611
|
+
id,
|
|
612
|
+
...entry.opData
|
|
613
|
+
}, {
|
|
614
|
+
onConflict: "id"
|
|
615
|
+
}).select();
|
|
574
616
|
if (upsertError) {
|
|
575
617
|
if (__DEV__) {
|
|
576
618
|
console.error("[Connector] PUT/UPSERT FAILED:", {
|
|
@@ -584,9 +626,7 @@ var SupabaseConnector = class {
|
|
|
584
626
|
errorHint: upsertError.hint
|
|
585
627
|
});
|
|
586
628
|
}
|
|
587
|
-
throw new Error(
|
|
588
|
-
`Upsert failed for ${schema}.${table}: ${upsertError.message}`
|
|
589
|
-
);
|
|
629
|
+
throw new Error(`Upsert failed for ${schema}.${table}: ${upsertError.message}`);
|
|
590
630
|
}
|
|
591
631
|
if (__DEV__) {
|
|
592
632
|
console.log("[Connector] PUT/UPSERT SUCCESS:", {
|
|
@@ -606,7 +646,10 @@ var SupabaseConnector = class {
|
|
|
606
646
|
opData: entry.opData
|
|
607
647
|
});
|
|
608
648
|
}
|
|
609
|
-
const {
|
|
649
|
+
const {
|
|
650
|
+
data: updateData,
|
|
651
|
+
error: updateError
|
|
652
|
+
} = await query.update(entry.opData).eq("id", id).select();
|
|
610
653
|
if (updateError) {
|
|
611
654
|
if (__DEV__) {
|
|
612
655
|
console.error("[Connector] PATCH/UPDATE FAILED:", {
|
|
@@ -620,9 +663,7 @@ var SupabaseConnector = class {
|
|
|
620
663
|
errorHint: updateError.hint
|
|
621
664
|
});
|
|
622
665
|
}
|
|
623
|
-
throw new Error(
|
|
624
|
-
`Update failed for ${schema}.${table}: ${updateError.message}`
|
|
625
|
-
);
|
|
666
|
+
throw new Error(`Update failed for ${schema}.${table}: ${updateError.message}`);
|
|
626
667
|
}
|
|
627
668
|
if (__DEV__) {
|
|
628
669
|
console.log("[Connector] PATCH/UPDATE SUCCESS:", {
|
|
@@ -641,7 +682,10 @@ var SupabaseConnector = class {
|
|
|
641
682
|
id
|
|
642
683
|
});
|
|
643
684
|
}
|
|
644
|
-
const {
|
|
685
|
+
const {
|
|
686
|
+
data: deleteData,
|
|
687
|
+
error: deleteError
|
|
688
|
+
} = await query.delete().eq("id", id).select();
|
|
645
689
|
if (deleteError) {
|
|
646
690
|
if (__DEV__) {
|
|
647
691
|
console.error("[Connector] DELETE FAILED:", {
|
|
@@ -655,9 +699,7 @@ var SupabaseConnector = class {
|
|
|
655
699
|
errorHint: deleteError.hint
|
|
656
700
|
});
|
|
657
701
|
}
|
|
658
|
-
throw new Error(
|
|
659
|
-
`Delete failed for ${schema}.${table}: ${deleteError.message}`
|
|
660
|
-
);
|
|
702
|
+
throw new Error(`Delete failed for ${schema}.${table}: ${deleteError.message}`);
|
|
661
703
|
}
|
|
662
704
|
if (__DEV__) {
|
|
663
705
|
console.log("[Connector] DELETE SUCCESS:", {
|
|
@@ -669,9 +711,7 @@ var SupabaseConnector = class {
|
|
|
669
711
|
}
|
|
670
712
|
break;
|
|
671
713
|
}
|
|
672
|
-
this.logger?.debug(
|
|
673
|
-
`[Connector] Processed ${entry.op} for ${schema}.${table} (id: ${id})`
|
|
674
|
-
);
|
|
714
|
+
this.logger?.debug(`[Connector] Processed ${entry.op} for ${schema}.${table} (id: ${id})`);
|
|
675
715
|
}
|
|
676
716
|
};
|
|
677
717
|
|
|
@@ -683,4 +723,4 @@ export {
|
|
|
683
723
|
getLocalVersion,
|
|
684
724
|
SupabaseConnector
|
|
685
725
|
};
|
|
686
|
-
//# sourceMappingURL=chunk-
|
|
726
|
+
//# sourceMappingURL=chunk-C2RSTGDC.js.map
|