@pol-studios/powersync 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-42IJ25Q4.js +45 -0
- package/dist/chunk-42IJ25Q4.js.map +1 -0
- package/dist/{chunk-Q3LFFMRR.js → chunk-H7HZMI4H.js} +2 -2
- package/dist/chunk-MB2RC3NS.js +686 -0
- package/dist/chunk-MB2RC3NS.js.map +1 -0
- package/dist/{chunk-4FJVBR3X.js → chunk-PANEMMTU.js} +8 -3
- package/dist/chunk-PANEMMTU.js.map +1 -0
- package/dist/chunk-VJCL2SWD.js +1 -0
- package/dist/connector/index.d.ts +1 -2
- package/dist/connector/index.js +2 -5
- package/dist/{supabase-connector-D14-kl5v.d.ts → index-D952Qr38.d.ts} +152 -2
- package/dist/index.d.ts +2 -3
- package/dist/index.js +9 -9
- package/dist/index.native.d.ts +1 -2
- package/dist/index.native.js +10 -10
- package/dist/index.web.d.ts +1 -2
- package/dist/index.web.js +9 -9
- package/dist/platform/index.native.js +1 -1
- package/dist/provider/index.d.ts +1 -1
- package/dist/provider/index.js +2 -2
- package/package.json +33 -10
- package/dist/chunk-4FJVBR3X.js.map +0 -1
- package/dist/chunk-7BPTGEVG.js +0 -1
- package/dist/chunk-FLHDT4TS.js +0 -327
- package/dist/chunk-FLHDT4TS.js.map +0 -1
- package/dist/chunk-T225XEML.js +0 -298
- package/dist/chunk-T225XEML.js.map +0 -1
- package/dist/index-nae7nzib.d.ts +0 -147
- /package/dist/{chunk-Q3LFFMRR.js.map → chunk-H7HZMI4H.js.map} +0 -0
- /package/dist/{chunk-7BPTGEVG.js.map → chunk-VJCL2SWD.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/connector/types.ts","../src/conflicts/detect.ts","../src/connector/supabase-connector.ts"],"sourcesContent":["/**\n * Connector Types for @pol-studios/powersync\n *\n * Defines interfaces for PowerSync backend connectors.\n */\n\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport type { AbstractPowerSyncDatabase, ClassifiedError, CrudEntry } from '../core/types';\nimport type { LoggerAdapter } from '../platform/types';\nimport type { ConflictHandler, ConflictDetectionConfig } from '../conflicts/types';\nimport type { ConflictBus } from '../conflicts/conflict-bus';\n\n// Re-export ConflictBus type for convenience\nexport type { ConflictBus } from '../conflicts/conflict-bus';\n\n// ─── Connector Configuration ─────────────────────────────────────────────────\n\n/**\n * Options for creating a SupabaseConnector\n */\nexport interface SupabaseConnectorOptions {\n /** Supabase client instance */\n supabaseClient: SupabaseClient;\n /** PowerSync service URL */\n powerSyncUrl: string;\n /**\n * Optional: Custom schema routing function.\n * Determines which Supabase schema a table belongs to.\n * @default Returns 'public' for all tables\n */\n schemaRouter?: SchemaRouter;\n /**\n * Optional: Custom CRUD handler for complex mutations.\n * Allows overriding default upsert/update/delete behavior.\n */\n crudHandler?: CrudHandler;\n /** Logger for debugging */\n logger?: LoggerAdapter;\n /** Called when a transaction is successfully uploaded */\n onTransactionSuccess?: (entries: CrudEntry[]) => void;\n /** Called when a transaction fails to upload */\n onTransactionFailure?: (\n entries: CrudEntry[],\n error: Error,\n classified: ClassifiedError\n ) => void;\n /** Called when a transaction is fully completed (after transaction.complete()) */\n onTransactionComplete?: (entries: CrudEntry[]) => void;\n /** Function to check if upload should proceed. Used for sync mode gating. */\n shouldUpload?: () => boolean;\n /**\n * Optional: Configuration for version-based conflict detection.\n * When enabled, checks for conflicts before uploading changes.\n */\n conflictDetection?: ConflictDetectionConfig;\n /**\n * Optional: Handler for conflict resolution.\n * If not provided, conflicts are logged and upload proceeds.\n */\n conflictHandler?: ConflictHandler;\n /**\n * Optional: Event bus for publishing conflict events.\n * Use this to notify the UI layer about detected conflicts.\n */\n conflictBus?: ConflictBus;\n}\n\n/**\n * Configuration passed to PowerSyncProvider for connector setup\n */\nexport interface ConnectorConfig {\n /**\n * Custom schema routing function.\n * Determines which Supabase schema a table belongs to.\n * @default Returns 'public' for all tables\n *\n * @example\n * ```typescript\n * schemaRouter: (table) => {\n * if (['Profile', 'Comment'].includes(table)) return 'core';\n * return 'public';\n * }\n * ```\n */\n schemaRouter?: SchemaRouter;\n\n /**\n * Custom CRUD handler for complex mutations.\n * @default Uses standard upsert/update/delete operations\n */\n crudHandler?: CrudHandler;\n\n /**\n * Token refresh configuration.\n */\n tokenRefresh?: {\n /** Refresh token when it expires within this many seconds (default: 60) */\n refreshThresholdSeconds?: number;\n };\n}\n\n// ─── Schema Routing ──────────────────────────────────────────────────────────\n\n/**\n * Function that determines which Supabase schema a table belongs to.\n *\n * @param tableName - The name of the table\n * @returns The schema name (e.g., 'public', 'core')\n */\nexport type SchemaRouter = (tableName: string) => string;\n\n/**\n * Default schema router that returns 'public' for all tables\n */\nexport const defaultSchemaRouter: SchemaRouter = () => 'public';\n\n// ─── CRUD Handling ───────────────────────────────────────────────────────────\n\n/**\n * Custom handler for CRUD operations.\n *\n * Return `true` from a handler to indicate the operation was handled.\n * Return `false` to fall back to default behavior.\n */\nexport interface CrudHandler {\n /**\n * Handle a PUT operation (insert or replace).\n * @param entry - The CRUD entry\n * @param supabase - Supabase client\n * @param schema - The resolved schema for this table\n * @returns true if handled, false to use default behavior\n */\n handlePut?(\n entry: CrudEntry,\n supabase: SupabaseClient,\n schema: string\n ): Promise<boolean>;\n\n /**\n * Handle a PATCH operation (update).\n * @param entry - The CRUD entry\n * @param supabase - Supabase client\n * @param schema - The resolved schema for this table\n * @returns true if handled, false to use default behavior\n */\n handlePatch?(\n entry: CrudEntry,\n supabase: SupabaseClient,\n schema: string\n ): Promise<boolean>;\n\n /**\n * Handle a DELETE operation.\n * @param entry - The CRUD entry\n * @param supabase - Supabase client\n * @param schema - The resolved schema for this table\n * @returns true if handled, false to use default behavior\n */\n handleDelete?(\n entry: CrudEntry,\n supabase: SupabaseClient,\n schema: string\n ): Promise<boolean>;\n}\n\n// ─── Credentials ─────────────────────────────────────────────────────────────\n\n/**\n * Credentials returned by fetchCredentials\n */\nexport interface PowerSyncCredentials {\n /** PowerSync service endpoint URL */\n endpoint: string;\n /** JWT token for authentication */\n token: string;\n /** When the token expires */\n expiresAt?: Date;\n}\n\n// ─── Re-export from Core ─────────────────────────────────────────────────────\n\n// Re-export PowerSyncBackendConnector from core/types to maintain API compatibility\nexport type { PowerSyncBackendConnector } from '../core/types';\n","/**\n * Conflict Detection for @pol-studios/powersync\n *\n * Provides version-based conflict detection using AuditLog attribution.\n * Only queries AuditLog when version mismatch is detected.\n */\n\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport type { AbstractPowerSyncDatabase } from '../core/types';\nimport type { FieldConflict, ConflictCheckResult, ConflictDetectionConfig } from './types';\n\n/**\n * Regex to validate table names and prevent SQL injection.\n * Only allows alphanumeric characters and underscores, starting with a letter or underscore.\n */\nconst TABLE_NAME_REGEX = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\n/**\n * Validates a table name to prevent SQL injection.\n * @throws Error if the table name is invalid\n */\nfunction validateTableName(table: string): void {\n if (!TABLE_NAME_REGEX.test(table)) {\n throw new Error(`Invalid table name: ${table}`);\n }\n}\n\nconst DEFAULT_IGNORED_FIELDS = ['updatedAt', 'createdAt', '_version', 'id'];\n\n/**\n * Detect conflicts between local pending changes and server state.\n *\n * Uses a two-step approach:\n * 1. Version match (local._version == server._version) → Sync immediately\n * 2. Version mismatch → Query AuditLog for field changes and attribution\n *\n * @param table - The table name\n * @param recordId - The record ID\n * @param localVersion - Version number from local SQLite\n * @param serverVersion - Version number from server (fetched separately)\n * @param pendingChanges - Fields with local changes to sync\n * @param supabase - Supabase client for AuditLog queries\n * @param config - Optional detection configuration\n * @returns Conflict check result with field-level details\n */\nexport async function detectConflicts(\n table: string,\n recordId: string,\n localVersion: number,\n serverVersion: number,\n pendingChanges: Record<string, unknown>,\n supabase: SupabaseClient,\n config?: ConflictDetectionConfig\n): Promise<ConflictCheckResult> {\n const ignoredFields = new Set([\n ...DEFAULT_IGNORED_FIELDS,\n ...(config?.ignoredFields ?? []),\n ]);\n\n // Filter out ignored fields from pending changes\n const filteredPendingChanges: Record<string, unknown> = {};\n for (const [field, value] of Object.entries(pendingChanges)) {\n if (!ignoredFields.has(field)) {\n filteredPendingChanges[field] = value;\n }\n }\n\n // Step 1: Version match = no conflict possible\n if (localVersion === serverVersion) {\n return {\n hasConflict: false,\n conflicts: [],\n nonConflictingChanges: Object.keys(filteredPendingChanges),\n table,\n recordId,\n };\n }\n\n // Step 2: Version mismatch - query AuditLog for changes since our version\n const { data: auditLogs, error } = await supabase\n .schema('core')\n .from('AuditLog')\n .select('oldRecord, newRecord, changeBy, changeAt')\n .eq('tableName', table)\n .eq('recordId_text', recordId)\n .order('changeAt', { ascending: false })\n .limit(20); // Recent changes should be sufficient\n\n if (error) {\n console.warn('[detectConflicts] Failed to query AuditLog:', error);\n // On error, assume no conflict and let sync proceed\n // (Server will reject if there's a real issue)\n return {\n hasConflict: false,\n conflicts: [],\n nonConflictingChanges: Object.keys(filteredPendingChanges),\n table,\n recordId,\n };\n }\n\n // Build map of server-changed fields with attribution\n // Key: field name, Value: most recent change info\n const serverChanges = new Map<string, {\n newValue: unknown;\n changedBy: string | null;\n changedAt: Date;\n }>();\n\n for (const log of auditLogs ?? []) {\n const oldRec = log.oldRecord as Record<string, unknown> | null;\n const newRec = log.newRecord as Record<string, unknown> | null;\n if (!oldRec || !newRec) continue;\n\n for (const [field, newValue] of Object.entries(newRec)) {\n // Skip ignored fields\n if (ignoredFields.has(field)) continue;\n\n // Only track if field actually changed AND we don't already have a more recent change\n if (oldRec[field] !== newValue && !serverChanges.has(field)) {\n serverChanges.set(field, {\n newValue,\n changedBy: log.changeBy as string | null,\n changedAt: new Date(log.changeAt as string),\n });\n }\n }\n }\n\n // Compare pending changes against server changes\n const conflicts: FieldConflict[] = [];\n const nonConflictingChanges: string[] = [];\n\n for (const [field, localValue] of Object.entries(filteredPendingChanges)) {\n if (serverChanges.has(field)) {\n // This field was changed on server - conflict!\n const serverChange = serverChanges.get(field)!;\n conflicts.push({\n field,\n localValue,\n serverValue: serverChange.newValue,\n changedBy: serverChange.changedBy,\n changedAt: serverChange.changedAt,\n });\n } else {\n // Field wasn't changed on server - safe to sync\n nonConflictingChanges.push(field);\n }\n }\n\n return {\n hasConflict: conflicts.length > 0,\n conflicts,\n nonConflictingChanges,\n table,\n recordId,\n };\n}\n\n/**\n * Check if a table has a _version column for conflict detection.\n *\n * @param table - The table name\n * @param db - PowerSync database instance\n * @returns True if the table has version tracking\n */\nexport async function hasVersionColumn(\n table: string,\n db: AbstractPowerSyncDatabase\n): Promise<boolean> {\n try {\n // Validate table name to prevent SQL injection\n validateTableName(table);\n\n // Query the PowerSync internal schema for column info\n const result = await db.getAll<{ name: string }>(\n `PRAGMA table_info(\"${table}\")`\n );\n return result.some(col => col.name === '_version');\n } catch {\n return false;\n }\n}\n\n/**\n * Fetch the current server version for a record.\n *\n * @param table - The table name\n * @param recordId - The record ID\n * @param schema - The Supabase schema (default: 'public')\n * @param supabase - Supabase client\n * @returns The server version number, or null if record not found\n */\nexport async function fetchServerVersion(\n table: string,\n recordId: string,\n schema: string,\n supabase: SupabaseClient\n): Promise<number | null> {\n const query = schema === 'public'\n ? supabase.from(table)\n : (supabase.schema(schema) as unknown as ReturnType<typeof supabase.schema>).from(table);\n\n const { data, error } = await query\n .select('_version')\n .eq('id', recordId)\n .single();\n\n if (error || !data) {\n return null;\n }\n\n return (data as { _version?: number })._version ?? null;\n}\n\n/**\n * Get the local version for a record from PowerSync SQLite.\n *\n * @param table - The table name\n * @param recordId - The record ID\n * @param db - PowerSync database instance\n * @returns The local version number, or null if not found\n */\nexport async function getLocalVersion(\n table: string,\n recordId: string,\n db: AbstractPowerSyncDatabase\n): Promise<number | null> {\n // Validate table name to prevent SQL injection\n validateTableName(table);\n\n const result = await db.get<{ _version?: number }>(\n `SELECT _version FROM \"${table}\" WHERE id = ?`,\n [recordId]\n );\n return result?._version ?? null;\n}\n","/**\n * Supabase Connector for PowerSync\n *\n * A generic, configurable connector that handles:\n * - Authentication with Supabase JWT tokens\n * - Uploading local changes back to Supabase\n * - Schema routing for multi-schema databases\n * - Custom CRUD handling for complex operations\n * - Version-based conflict detection (when enabled)\n */\n\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport type { AbstractPowerSyncDatabase, ClassifiedError, CrudEntry } from '../core/types';\nimport type { LoggerAdapter } from '../platform/types';\nimport type {\n SupabaseConnectorOptions,\n PowerSyncBackendConnector,\n PowerSyncCredentials,\n SchemaRouter,\n CrudHandler,\n} from './types';\nimport type { ConflictBus } from '../conflicts/conflict-bus';\nimport type { ConflictHandler, ConflictDetectionConfig, ConflictCheckResult } from '../conflicts/types';\nimport { defaultSchemaRouter } from './types';\nimport { classifySupabaseError } from '../core/errors';\nimport { detectConflicts, fetchServerVersion, getLocalVersion, hasVersionColumn } from '../conflicts/detect';\n\n/**\n * Update type enum matching @powersync/common\n */\nenum UpdateType {\n PUT = 'PUT',\n PATCH = 'PATCH',\n DELETE = 'DELETE',\n}\n\n/**\n * Generic Supabase connector for PowerSync.\n *\n * This connector handles authentication and CRUD uploads to Supabase.\n * It supports configurable schema routing and custom CRUD handlers\n * for complex use cases.\n *\n * @example Basic usage\n * ```typescript\n * const connector = new SupabaseConnector({\n * supabaseClient: supabase,\n * powerSyncUrl: 'https://your-powersync-instance.com',\n * });\n * ```\n *\n * @example With schema routing\n * ```typescript\n * const connector = new SupabaseConnector({\n * supabaseClient: supabase,\n * powerSyncUrl: 'https://your-powersync-instance.com',\n * schemaRouter: (table) => {\n * if (['Profile', 'Comment', 'CommentSection'].includes(table)) {\n * return 'core';\n * }\n * return 'public';\n * },\n * });\n * ```\n *\n * @example With custom CRUD handler\n * ```typescript\n * const connector = new SupabaseConnector({\n * supabaseClient: supabase,\n * powerSyncUrl: 'https://your-powersync-instance.com',\n * crudHandler: {\n * async handlePut(entry, supabase, schema) {\n * // Custom handling for specific tables\n * if (entry.table === 'SpecialTable') {\n * await myCustomUpsert(entry);\n * return true; // Handled\n * }\n * return false; // Use default\n * },\n * },\n * });\n * ```\n */\nexport class SupabaseConnector implements PowerSyncBackendConnector {\n private readonly supabase: SupabaseClient;\n private readonly powerSyncUrl: string;\n private readonly schemaRouter: SchemaRouter;\n private readonly crudHandler?: CrudHandler;\n private readonly logger?: LoggerAdapter;\n private readonly onTransactionSuccess?: (entries: CrudEntry[]) => void;\n private readonly onTransactionFailure?: (\n entries: CrudEntry[],\n error: Error,\n classified: ClassifiedError\n ) => void;\n private readonly onTransactionComplete?: (entries: CrudEntry[]) => void;\n private readonly shouldUploadFn?: () => boolean;\n\n // Conflict detection configuration\n private readonly conflictDetection?: ConflictDetectionConfig;\n private readonly conflictHandler?: ConflictHandler;\n private readonly conflictBus?: ConflictBus;\n\n // Cache for version column existence checks (table -> hasVersionColumn)\n private versionColumnCache = new Map<string, boolean>();\n\n // Active project IDs for scoped sync (optional feature)\n private activeProjectIds: string[] = [];\n\n constructor(options: SupabaseConnectorOptions) {\n this.supabase = options.supabaseClient;\n this.powerSyncUrl = options.powerSyncUrl;\n this.schemaRouter = options.schemaRouter ?? defaultSchemaRouter;\n this.crudHandler = options.crudHandler;\n this.logger = options.logger;\n this.onTransactionSuccess = options.onTransactionSuccess;\n this.onTransactionFailure = options.onTransactionFailure;\n this.onTransactionComplete = options.onTransactionComplete;\n this.shouldUploadFn = options.shouldUpload;\n\n // Conflict detection options\n this.conflictDetection = options.conflictDetection;\n this.conflictHandler = options.conflictHandler;\n this.conflictBus = options.conflictBus;\n }\n\n /**\n * Set the active project IDs for scoped sync.\n * Call this when user selects/opens projects.\n */\n setActiveProjectIds(projectIds: string[]): void {\n this.activeProjectIds = projectIds;\n }\n\n /**\n * Get the current active project IDs.\n */\n getActiveProjectIds(): string[] {\n return this.activeProjectIds;\n }\n\n /**\n * Get credentials for PowerSync connection.\n * Uses Supabase session token.\n *\n * Note: Token refresh is handled by Supabase's startAutoRefresh() which must be\n * called on app initialization. getSession() returns the auto-refreshed token.\n */\n async fetchCredentials(): Promise<PowerSyncCredentials> {\n this.logger?.debug('[Connector] Fetching credentials...');\n\n const {\n data: { session },\n error,\n } = await this.supabase.auth.getSession();\n\n if (error) {\n this.logger?.error('[Connector] Auth error:', error);\n throw new Error(`Failed to get Supabase session: ${error.message}`);\n }\n\n if (!session) {\n this.logger?.error('[Connector] No active session');\n throw new Error('No active Supabase session');\n }\n\n this.logger?.debug(\n '[Connector] Credentials fetched, token expires at:',\n session.expires_at\n );\n\n return {\n endpoint: this.powerSyncUrl,\n token: session.access_token,\n expiresAt: session.expires_at\n ? new Date(session.expires_at * 1000)\n : undefined,\n };\n }\n\n /**\n * Upload local changes to Supabase.\n * Called automatically by PowerSync when there are pending uploads.\n *\n * When conflict detection is enabled:\n * 1. Checks if table has _version column (cached)\n * 2. If yes, compares local vs server version\n * 3. On version mismatch, queries AuditLog for field conflicts\n * 4. If conflicts found, calls handler or publishes to conflict bus\n * 5. Applies resolution or skips entry based on handler response\n */\n async uploadData(database: AbstractPowerSyncDatabase): Promise<void> {\n // Check if uploads are allowed based on sync mode\n if (this.shouldUploadFn && !this.shouldUploadFn()) {\n if (__DEV__) {\n console.log('[Connector] Upload skipped - sync mode does not allow uploads');\n }\n this.logger?.debug('[Connector] Upload skipped - sync mode does not allow uploads');\n return;\n }\n\n if (__DEV__) {\n console.log('[Connector] uploadData called, fetching next CRUD transaction...');\n }\n\n const transaction = await database.getNextCrudTransaction();\n\n if (!transaction) {\n if (__DEV__) {\n console.log('[Connector] No pending CRUD transaction found');\n }\n return;\n }\n\n if (__DEV__) {\n console.log('[Connector] Transaction fetched:', {\n crudCount: transaction.crud.length,\n entries: transaction.crud.map(e => ({\n table: e.table,\n op: e.op,\n id: e.id,\n opDataKeys: e.opData ? Object.keys(e.opData) : [],\n })),\n });\n }\n\n // If conflict detection is disabled, use standard upload\n const conflictDetectionEnabled = this.conflictDetection?.enabled !== false;\n if (!conflictDetectionEnabled) {\n await this.processTransaction(transaction, database);\n return;\n }\n\n // Process with conflict detection\n const { crud } = transaction;\n const skipTables = new Set(this.conflictDetection?.skipTables ?? []);\n const entriesToProcess: CrudEntry[] = [];\n // Entries queued for UI resolution - these should NOT complete the transaction (leave in queue)\n const entriesQueuedForUI: CrudEntry[] = [];\n // Entries resolved with keep-server - these WILL complete the transaction (discard local changes)\n const entriesDiscarded: CrudEntry[] = [];\n\n // Track partial resolutions to re-emit remaining conflicts after sync completes\n const partialResolutions: Array<{\n originalConflict: ConflictCheckResult;\n syncedFields: string[];\n }> = [];\n\n for (const entry of crud) {\n // Skip DELETE operations - no conflict checking needed\n if (entry.op === 'DELETE') {\n entriesToProcess.push(entry);\n continue;\n }\n\n // Skip tables in the skip list\n if (skipTables.has(entry.table)) {\n entriesToProcess.push(entry);\n continue;\n }\n\n // Check for version column (cached)\n const hasVersion = await this.checkVersionColumn(entry.table, database);\n if (!hasVersion) {\n entriesToProcess.push(entry);\n continue;\n }\n\n // Get local and server versions\n const localVersion = await getLocalVersion(entry.table, entry.id, database);\n const schema = this.schemaRouter(entry.table);\n const serverVersion = await fetchServerVersion(\n entry.table,\n entry.id,\n schema,\n this.supabase\n );\n\n // If we can't get versions, skip conflict check and proceed\n if (localVersion === null || serverVersion === null) {\n entriesToProcess.push(entry);\n continue;\n }\n\n // Detect conflicts\n const conflictResult = await detectConflicts(\n entry.table,\n entry.id,\n localVersion,\n serverVersion,\n entry.opData ?? {},\n this.supabase,\n this.conflictDetection\n );\n\n if (!conflictResult.hasConflict) {\n entriesToProcess.push(entry);\n continue;\n }\n\n // Emit conflict event to bus if available\n this.conflictBus?.emitConflict(conflictResult);\n\n // Handle conflict with handler if available\n if (this.conflictHandler) {\n const resolution = await this.conflictHandler.onConflict(conflictResult);\n\n if (resolution === null) {\n // Queue for UI - skip this entry, leave in queue for later resolution\n entriesQueuedForUI.push(entry);\n if (__DEV__) {\n console.log('[Connector] Conflict queued for UI resolution:', {\n table: entry.table,\n id: entry.id,\n conflicts: conflictResult.conflicts.map(c => c.field),\n });\n }\n continue;\n }\n\n switch (resolution.action) {\n case 'overwrite':\n // Proceed with upload (overwrite server)\n entriesToProcess.push(entry);\n break;\n\n case 'keep-server':\n // Discard local changes - mark for completion (removes from queue)\n entriesDiscarded.push(entry);\n if (__DEV__) {\n console.log('[Connector] Conflict resolved with keep-server, discarding local changes:', {\n table: entry.table,\n id: entry.id,\n });\n }\n break;\n\n case 'partial':\n // Only sync specified fields\n const partialEntry: CrudEntry = {\n ...entry,\n opData: this.filterFields(entry.opData ?? {}, resolution.fields),\n };\n entriesToProcess.push(partialEntry);\n\n // Track this partial resolution to re-emit remaining conflicts after sync\n partialResolutions.push({\n originalConflict: conflictResult,\n syncedFields: resolution.fields,\n });\n break;\n }\n } else {\n // No handler - log conflict and proceed with upload\n console.warn('[Connector] Conflict detected but no handler:', {\n table: entry.table,\n id: entry.id,\n conflicts: conflictResult.conflicts,\n });\n entriesToProcess.push(entry);\n }\n }\n\n // If any entries are queued for UI resolution, we must NOT complete the transaction\n // This leaves those entries in the PowerSync queue for later resolution\n if (entriesQueuedForUI.length > 0) {\n if (__DEV__) {\n console.log('[Connector] Entries queued for UI resolution, leaving in queue:', {\n queuedForUI: entriesQueuedForUI.length,\n discarded: entriesDiscarded.length,\n toProcess: entriesToProcess.length,\n });\n }\n // Fire onTransactionComplete to notify listeners, but NOT onTransactionSuccess\n // because we're not completing the transaction. Entries remain in the queue.\n this.onTransactionComplete?.(entriesQueuedForUI);\n return;\n }\n\n // If all entries were discarded (keep-server) with none to process,\n // still complete the transaction to remove them from the queue\n if (entriesToProcess.length === 0 && entriesDiscarded.length > 0) {\n if (__DEV__) {\n console.log('[Connector] All entries resolved with keep-server, completing transaction to discard local changes');\n }\n try {\n await transaction.complete();\n // Fire success (entries were \"successfully\" discarded)\n this.onTransactionSuccess?.(entriesDiscarded);\n this.onTransactionComplete?.(entriesDiscarded);\n } catch (error) {\n const classified = classifySupabaseError(error);\n this.onTransactionFailure?.(\n entriesDiscarded,\n error instanceof Error ? error : new Error(String(error)),\n classified\n );\n throw error;\n }\n return;\n }\n\n // Process remaining entries\n try {\n for (const entry of entriesToProcess) {\n if (__DEV__) {\n console.log('[Connector] Processing CRUD entry:', {\n table: entry.table,\n op: entry.op,\n id: entry.id,\n opData: entry.opData,\n });\n }\n await this.processCrudEntry(entry);\n }\n\n if (__DEV__) {\n console.log('[Connector] All CRUD entries processed, completing transaction...');\n }\n\n await transaction.complete();\n\n if (__DEV__) {\n console.log('[Connector] Transaction completed successfully:', {\n entriesCount: entriesToProcess.length,\n discardedCount: entriesDiscarded.length,\n });\n }\n\n // After partial sync completes, re-emit conflicts for remaining fields\n if (this.conflictBus && partialResolutions.length > 0) {\n for (const { originalConflict, syncedFields } of partialResolutions) {\n const syncedFieldSet = new Set(syncedFields);\n\n // Find conflicts that weren't synced\n const remainingConflicts = originalConflict.conflicts.filter(\n c => !syncedFieldSet.has(c.field)\n );\n\n if (remainingConflicts.length > 0) {\n if (__DEV__) {\n console.log('[Connector] Re-emitting conflict for remaining fields:', {\n table: originalConflict.table,\n recordId: originalConflict.recordId,\n syncedFields,\n remainingConflictFields: remainingConflicts.map(c => c.field),\n });\n }\n\n // Emit new conflict for remaining fields\n this.conflictBus.emitConflict({\n ...originalConflict,\n conflicts: remainingConflicts,\n // All remaining are conflicts now - clear nonConflictingChanges since\n // the non-conflicting ones were already synced in the partial resolution\n nonConflictingChanges: [],\n });\n }\n }\n }\n\n // Notify success\n this.onTransactionSuccess?.(entriesToProcess);\n\n // Notify completion (after transaction.complete() succeeds)\n this.onTransactionComplete?.(entriesToProcess);\n } catch (error) {\n const classified = classifySupabaseError(error);\n\n // Always log to console for debugging\n console.error('[PowerSync Connector] Upload FAILED:', {\n errorMessage: error instanceof Error ? error.message : String(error),\n errorKeys: error && typeof error === 'object' ? Object.keys(error) : [],\n errorObject: JSON.stringify(error, null, 2),\n classified,\n isPermanent: classified.isPermanent,\n entries: entriesToProcess.map(e => ({\n table: e.table,\n op: e.op,\n id: e.id,\n })),\n });\n\n this.logger?.error('[Connector] Upload error:', {\n error,\n classified,\n entries: entriesToProcess.map(e => ({ table: e.table, op: e.op, id: e.id })),\n });\n\n // Notify failure with classification\n this.onTransactionFailure?.(\n entriesToProcess,\n error instanceof Error ? error : new Error(String(error)),\n classified\n );\n\n // Re-throw for PowerSync's native retry mechanism\n throw error;\n }\n }\n\n /**\n * Process a transaction without conflict detection.\n * Used when conflict detection is disabled.\n */\n private async processTransaction(\n transaction: { crud: CrudEntry[]; complete: () => Promise<void> },\n _database: AbstractPowerSyncDatabase\n ): Promise<void> {\n try {\n for (const entry of transaction.crud) {\n if (__DEV__) {\n console.log('[Connector] Processing CRUD entry:', {\n table: entry.table,\n op: entry.op,\n id: entry.id,\n opData: entry.opData,\n });\n }\n await this.processCrudEntry(entry);\n }\n\n if (__DEV__) {\n console.log('[Connector] All CRUD entries processed, completing transaction...');\n }\n\n await transaction.complete();\n\n if (__DEV__) {\n console.log('[Connector] Transaction completed successfully:', {\n entriesCount: transaction.crud.length,\n });\n }\n\n // Notify success\n this.onTransactionSuccess?.(transaction.crud);\n\n // Notify completion (after transaction.complete() succeeds)\n this.onTransactionComplete?.(transaction.crud);\n } catch (error) {\n const classified = classifySupabaseError(error);\n\n // Always log to console for debugging\n console.error('[PowerSync Connector] Upload FAILED:', {\n errorMessage: error instanceof Error ? error.message : String(error),\n errorKeys: error && typeof error === 'object' ? Object.keys(error) : [],\n errorObject: JSON.stringify(error, null, 2),\n classified,\n isPermanent: classified.isPermanent,\n entries: transaction.crud.map(e => ({\n table: e.table,\n op: e.op,\n id: e.id,\n })),\n });\n\n this.logger?.error('[Connector] Upload error:', {\n error,\n classified,\n entries: transaction.crud.map(e => ({ table: e.table, op: e.op, id: e.id })),\n });\n\n // Notify failure with classification\n this.onTransactionFailure?.(\n transaction.crud,\n error instanceof Error ? error : new Error(String(error)),\n classified\n );\n\n // Re-throw for PowerSync's native retry mechanism\n throw error;\n }\n }\n\n /**\n * Check if a table has a _version column (cached).\n */\n private async checkVersionColumn(\n table: string,\n db: AbstractPowerSyncDatabase\n ): Promise<boolean> {\n if (this.versionColumnCache.has(table)) {\n return this.versionColumnCache.get(table)!;\n }\n\n const hasVersion = await hasVersionColumn(table, db);\n this.versionColumnCache.set(table, hasVersion);\n return hasVersion;\n }\n\n /**\n * Filter opData to only include specified fields.\n * Used for partial sync resolution.\n */\n private filterFields(\n opData: Record<string, unknown>,\n fields: string[]\n ): Record<string, unknown> {\n const fieldSet = new Set(fields);\n const filtered: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(opData)) {\n if (fieldSet.has(key)) {\n filtered[key] = value;\n }\n }\n return filtered;\n }\n\n /**\n * Process a single CRUD operation.\n *\n * UUID-native tables (public schema, post-migration) use `id` as the UUID column.\n * Core schema tables (Profile, Comment, CommentSection) still use a separate `uuid` column.\n */\n /**\n * Process a single CRUD operation.\n *\n * All synced tables use `id` as their UUID primary key column.\n */\n private async processCrudEntry(entry: CrudEntry): Promise<void> {\n const table = entry.table;\n const id = entry.id; // PowerSync sends UUID as the entry.id\n const schema = this.schemaRouter(table);\n\n // Try custom handler first\n if (this.crudHandler) {\n let handled = false;\n\n switch (entry.op) {\n case UpdateType.PUT:\n handled =\n (await this.crudHandler.handlePut?.(entry, this.supabase, schema)) ??\n false;\n break;\n case UpdateType.PATCH:\n handled =\n (await this.crudHandler.handlePatch?.(\n entry,\n this.supabase,\n schema\n )) ?? false;\n break;\n case UpdateType.DELETE:\n handled =\n (await this.crudHandler.handleDelete?.(\n entry,\n this.supabase,\n schema\n )) ?? false;\n break;\n }\n\n if (handled) {\n this.logger?.debug(\n `[Connector] Custom handler processed ${entry.op} for ${schema}.${table}`\n );\n return;\n }\n }\n\n // Default behavior\n // Get the correct Supabase query builder for this table's schema\n const query =\n schema === 'public'\n ? this.supabase.from(table)\n : (this.supabase.schema(schema) as unknown as ReturnType<typeof this.supabase.schema>).from(table);\n\n switch (entry.op) {\n case UpdateType.PUT:\n if (__DEV__) {\n console.log('[Connector] Executing PUT/UPSERT:', {\n schema,\n table,\n id,\n data: { id, ...entry.opData },\n });\n }\n // Insert/upsert using id column\n const { data: upsertData, error: upsertError } = await query.upsert(\n { id, ...entry.opData },\n { onConflict: 'id' }\n ).select();\n\n if (upsertError) {\n if (__DEV__) {\n console.error('[Connector] PUT/UPSERT FAILED:', {\n schema,\n table,\n id,\n error: upsertError,\n errorMessage: upsertError.message,\n errorCode: upsertError.code,\n errorDetails: upsertError.details,\n errorHint: upsertError.hint,\n });\n }\n throw new Error(\n `Upsert failed for ${schema}.${table}: ${upsertError.message}`\n );\n }\n if (__DEV__) {\n console.log('[Connector] PUT/UPSERT SUCCESS:', {\n schema,\n table,\n id,\n responseData: upsertData,\n });\n }\n break;\n\n case UpdateType.PATCH:\n if (__DEV__) {\n console.log('[Connector] Executing PATCH/UPDATE:', {\n schema,\n table,\n id,\n opData: entry.opData,\n });\n }\n // Update by id column\n const { data: updateData, error: updateError } = await query\n .update(entry.opData)\n .eq('id', id)\n .select();\n\n if (updateError) {\n if (__DEV__) {\n console.error('[Connector] PATCH/UPDATE FAILED:', {\n schema,\n table,\n id,\n error: updateError,\n errorMessage: updateError.message,\n errorCode: updateError.code,\n errorDetails: updateError.details,\n errorHint: updateError.hint,\n });\n }\n throw new Error(\n `Update failed for ${schema}.${table}: ${updateError.message}`\n );\n }\n if (__DEV__) {\n console.log('[Connector] PATCH/UPDATE SUCCESS:', {\n schema,\n table,\n id,\n responseData: updateData,\n });\n }\n break;\n\n case UpdateType.DELETE:\n if (__DEV__) {\n console.log('[Connector] Executing DELETE:', {\n schema,\n table,\n id,\n });\n }\n // Delete by id column\n const { data: deleteData, error: deleteError } = await query.delete().eq('id', id).select();\n\n if (deleteError) {\n if (__DEV__) {\n console.error('[Connector] DELETE FAILED:', {\n schema,\n table,\n id,\n error: deleteError,\n errorMessage: deleteError.message,\n errorCode: deleteError.code,\n errorDetails: deleteError.details,\n errorHint: deleteError.hint,\n });\n }\n throw new Error(\n `Delete failed for ${schema}.${table}: ${deleteError.message}`\n );\n }\n if (__DEV__) {\n console.log('[Connector] DELETE SUCCESS:', {\n schema,\n table,\n id,\n responseData: deleteData,\n });\n }\n break;\n }\n\n this.logger?.debug(\n `[Connector] Processed ${entry.op} for ${schema}.${table} (id: ${id})`\n );\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/platform/index.native.ts
|
|
2
2
|
function createNativePlatformAdapter(logger) {
|
|
3
3
|
let PowerSyncDatabase;
|
|
4
|
+
let OPSqliteOpenFactory;
|
|
4
5
|
let FileSystem;
|
|
5
6
|
let AsyncStorage;
|
|
6
7
|
let NetInfo;
|
|
@@ -10,6 +11,10 @@ function createNativePlatformAdapter(logger) {
|
|
|
10
11
|
const psModule = await import("@powersync/react-native");
|
|
11
12
|
PowerSyncDatabase = psModule.PowerSyncDatabase;
|
|
12
13
|
}
|
|
14
|
+
if (!OPSqliteOpenFactory) {
|
|
15
|
+
const opSqliteModule = await import("@powersync/op-sqlite");
|
|
16
|
+
OPSqliteOpenFactory = opSqliteModule.OPSqliteOpenFactory;
|
|
17
|
+
}
|
|
13
18
|
if (!FileSystem) {
|
|
14
19
|
FileSystem = await import("expo-file-system");
|
|
15
20
|
}
|
|
@@ -189,9 +194,9 @@ function createNativePlatformAdapter(logger) {
|
|
|
189
194
|
logger.info("[Platform] Creating PowerSync database:", options.dbFilename);
|
|
190
195
|
const db = new PowerSyncDatabase({
|
|
191
196
|
schema: options.schema,
|
|
192
|
-
database: {
|
|
197
|
+
database: new OPSqliteOpenFactory({
|
|
193
198
|
dbFilename: options.dbFilename
|
|
194
|
-
}
|
|
199
|
+
})
|
|
195
200
|
});
|
|
196
201
|
logger.info("[Platform] Initializing database...");
|
|
197
202
|
await db.init();
|
|
@@ -224,4 +229,4 @@ function createNativePlatformAdapter(logger) {
|
|
|
224
229
|
export {
|
|
225
230
|
createNativePlatformAdapter
|
|
226
231
|
};
|
|
227
|
-
//# sourceMappingURL=chunk-
|
|
232
|
+
//# sourceMappingURL=chunk-PANEMMTU.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 {\n PlatformAdapter,\n DatabaseOptions,\n FileSystemAdapter,\n AsyncStorageAdapter,\n NetworkAdapter,\n LoggerAdapter,\n ImageProcessorAdapter,\n FileInfo,\n CompressedImage,\n CompressionOptions,\n ConnectionType,\n} 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(\n logger: LoggerAdapter\n): 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\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:\n encoding === 'base64'\n ? FileSystem!.EncodingType.Base64\n : FileSystem!.EncodingType.UTF8,\n });\n },\n\n async writeFile(\n uri: string,\n data: string,\n encoding: 'base64' | 'utf8' = 'utf8'\n ): 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, { intermediates: true }).catch(\n () => {\n // Directory may already exist\n }\n );\n }\n await FileSystem!.writeAsStringAsync(uri, data, {\n encoding:\n encoding === 'base64'\n ? FileSystem!.EncodingType.Base64\n : FileSystem!.EncodingType.UTF8,\n });\n },\n\n async deleteFile(uri: string): Promise<void> {\n if (!FileSystem) await loadDependencies();\n await FileSystem!.deleteAsync(uri, { idempotent: true });\n },\n\n async copyFile(source: string, destination: string): Promise<void> {\n if (!FileSystem) await loadDependencies();\n await FileSystem!.copyAsync({ from: source, to: destination });\n },\n\n async moveFile(source: string, destination: string): Promise<void> {\n if (!FileSystem) await loadDependencies();\n await FileSystem!.moveAsync({ from: source, 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:\n 'modificationTime' in info && info.modificationTime\n ? new Date(info.modificationTime * 1000)\n : undefined,\n };\n } catch {\n return null;\n }\n },\n\n async makeDirectory(\n uri: string,\n options?: { intermediates?: boolean }\n ): Promise<void> {\n if (!FileSystem) await loadDependencies();\n await FileSystem!.makeDirectoryAsync(uri, {\n intermediates: options?.intermediates ?? true,\n });\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\n getCacheDirectory(): string {\n return FileSystem?.cacheDirectory ?? '';\n },\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\n async setItem(key: string, value: string): Promise<void> {\n if (!AsyncStorage) await loadDependencies();\n await AsyncStorage!.setItem(key, value);\n },\n\n async removeItem(key: string): Promise<void> {\n if (!AsyncStorage) await loadDependencies();\n await AsyncStorage!.removeItem(key);\n },\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\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\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\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(\n '[Platform] NetInfo not loaded, connection listener may not work immediately'\n );\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\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(\n uri: string,\n options: CompressionOptions\n ): Promise<CompressedImage> {\n if (!ImageManipulator) await loadDependencies();\n\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\n const result = await ImageManipulator!.manipulateAsync(uri, actions, {\n compress: options.quality,\n format,\n });\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(\n options: DatabaseOptions\n ): Promise<AbstractPowerSyncDatabase> {\n if (!PowerSyncDatabase) await loadDependencies();\n\n logger.info('[Platform] Creating PowerSync database:', options.dbFilename);\n\n const db = new PowerSyncDatabase!({\n schema: options.schema as any,\n database: new OPSqliteOpenFactory!({\n dbFilename: options.dbFilename,\n }),\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\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';\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=chunk-VJCL2SWD.js.map
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
export { C as ConnectorConfig, c as CrudHandler, P as PowerSyncCredentials, b as SchemaRouter, S as SupabaseConnector, a as SupabaseConnectorOptions, d as defaultSchemaRouter } from '../
|
|
2
|
-
export { C as ConflictAwareConnector, a as ConflictAwareConnectorOptions } from '../index-nae7nzib.js';
|
|
1
|
+
export { e as ConflictBus, C as ConnectorConfig, c as CrudHandler, P as PowerSyncCredentials, b as SchemaRouter, S as SupabaseConnector, a as SupabaseConnectorOptions, d as defaultSchemaRouter } from '../index-D952Qr38.js';
|
|
3
2
|
export { P as PowerSyncBackendConnector } from '../types-afHtE1U_.js';
|
|
4
3
|
import '@supabase/supabase-js';
|
|
5
4
|
import '../platform/index.js';
|
package/dist/connector/index.js
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
ConflictAwareConnector
|
|
3
|
-
} from "../chunk-T225XEML.js";
|
|
1
|
+
import "../chunk-VJCL2SWD.js";
|
|
4
2
|
import {
|
|
5
3
|
SupabaseConnector,
|
|
6
4
|
defaultSchemaRouter
|
|
7
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-MB2RC3NS.js";
|
|
8
6
|
import "../chunk-CHRTN5PF.js";
|
|
9
7
|
export {
|
|
10
|
-
ConflictAwareConnector,
|
|
11
8
|
SupabaseConnector,
|
|
12
9
|
defaultSchemaRouter
|
|
13
10
|
};
|
|
@@ -1,7 +1,116 @@
|
|
|
1
|
-
import { C as CrudEntry, i as ClassifiedError, P as PowerSyncBackendConnector, A as AbstractPowerSyncDatabase } from './types-afHtE1U_.js';
|
|
2
1
|
import { SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
+
import { C as CrudEntry, i as ClassifiedError, P as PowerSyncBackendConnector, A as AbstractPowerSyncDatabase } from './types-afHtE1U_.js';
|
|
3
3
|
import { LoggerAdapter } from './platform/index.js';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Conflict Types for @pol-studios/powersync
|
|
7
|
+
*
|
|
8
|
+
* Defines powersync-specific conflict types that mirror the types from @pol-studios/db.
|
|
9
|
+
* These are kept in sync with the db package to ensure type compatibility.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Represents a field-level conflict where both local and server changed the same field.
|
|
13
|
+
*/
|
|
14
|
+
interface FieldConflict {
|
|
15
|
+
/** The field name that has conflicting changes */
|
|
16
|
+
field: string;
|
|
17
|
+
/** The local (pending) value */
|
|
18
|
+
localValue: unknown;
|
|
19
|
+
/** The current server value */
|
|
20
|
+
serverValue: unknown;
|
|
21
|
+
/** User who made the server change (from AuditLog.changeBy) */
|
|
22
|
+
changedBy: string | null;
|
|
23
|
+
/** When the server change occurred (from AuditLog.changeAt) */
|
|
24
|
+
changedAt: Date;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Result of checking for conflicts between local changes and server state.
|
|
28
|
+
*/
|
|
29
|
+
interface ConflictCheckResult {
|
|
30
|
+
/** Whether any field conflicts were detected */
|
|
31
|
+
hasConflict: boolean;
|
|
32
|
+
/** List of field-level conflicts */
|
|
33
|
+
conflicts: FieldConflict[];
|
|
34
|
+
/** Fields that can safely sync (no server changes) */
|
|
35
|
+
nonConflictingChanges: string[];
|
|
36
|
+
/** The table name */
|
|
37
|
+
table: string;
|
|
38
|
+
/** The record ID */
|
|
39
|
+
recordId: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* User's resolution choice for a conflict.
|
|
43
|
+
*/
|
|
44
|
+
type ConflictResolution = {
|
|
45
|
+
action: 'overwrite';
|
|
46
|
+
} | {
|
|
47
|
+
action: 'keep-server';
|
|
48
|
+
} | {
|
|
49
|
+
action: 'partial';
|
|
50
|
+
fields: string[];
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Handler for conflict events in the connector.
|
|
54
|
+
*/
|
|
55
|
+
interface ConflictHandler {
|
|
56
|
+
/**
|
|
57
|
+
* Called when a conflict is detected during upload.
|
|
58
|
+
*
|
|
59
|
+
* @param result - The conflict check result
|
|
60
|
+
* @returns Resolution to apply, or null to queue for UI resolution
|
|
61
|
+
*/
|
|
62
|
+
onConflict: (result: ConflictCheckResult) => Promise<ConflictResolution | null>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Configuration for conflict detection behavior.
|
|
66
|
+
*/
|
|
67
|
+
interface ConflictDetectionConfig {
|
|
68
|
+
/** Tables to skip conflict detection (opt-out). Default: [] */
|
|
69
|
+
skipTables?: string[];
|
|
70
|
+
/** Fields to ignore in conflict detection. Default: ['updatedAt', 'createdAt'] */
|
|
71
|
+
ignoredFields?: string[];
|
|
72
|
+
/** Whether to enable conflict detection. Default: true */
|
|
73
|
+
enabled?: boolean;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
type ConflictListener = (conflict: ConflictCheckResult) => void;
|
|
77
|
+
type ResolutionListener = (recordId: string, resolution: ConflictResolution) => void;
|
|
78
|
+
/**
|
|
79
|
+
* Event bus for decoupling conflict detection from UI resolution.
|
|
80
|
+
*
|
|
81
|
+
* Flow:
|
|
82
|
+
* 1. Connector detects conflict -> calls bus.emitConflict()
|
|
83
|
+
* 2. ConflictContext subscribes via bus.onConflict() -> shows UI
|
|
84
|
+
* 3. User resolves -> ConflictContext calls bus.emitResolution()
|
|
85
|
+
* 4. Connector subscribes via bus.onResolution() -> triggers re-upload
|
|
86
|
+
*/
|
|
87
|
+
declare class ConflictBus {
|
|
88
|
+
private conflictListeners;
|
|
89
|
+
private resolutionListeners;
|
|
90
|
+
/**
|
|
91
|
+
* Subscribe to conflict detection events.
|
|
92
|
+
* @returns Unsubscribe function
|
|
93
|
+
*/
|
|
94
|
+
onConflict(listener: ConflictListener): () => void;
|
|
95
|
+
/**
|
|
96
|
+
* Subscribe to resolution events.
|
|
97
|
+
* @returns Unsubscribe function
|
|
98
|
+
*/
|
|
99
|
+
onResolution(listener: ResolutionListener): () => void;
|
|
100
|
+
/**
|
|
101
|
+
* Emit a conflict detection event (called by connector).
|
|
102
|
+
*/
|
|
103
|
+
emitConflict(conflict: ConflictCheckResult): void;
|
|
104
|
+
/**
|
|
105
|
+
* Emit a resolution event (called by UI/ConflictContext).
|
|
106
|
+
*/
|
|
107
|
+
emitResolution(recordId: string, resolution: ConflictResolution): void;
|
|
108
|
+
/**
|
|
109
|
+
* Clear all listeners (for cleanup).
|
|
110
|
+
*/
|
|
111
|
+
destroy(): void;
|
|
112
|
+
}
|
|
113
|
+
|
|
5
114
|
/**
|
|
6
115
|
* Connector Types for @pol-studios/powersync
|
|
7
116
|
*
|
|
@@ -37,6 +146,21 @@ interface SupabaseConnectorOptions {
|
|
|
37
146
|
onTransactionComplete?: (entries: CrudEntry[]) => void;
|
|
38
147
|
/** Function to check if upload should proceed. Used for sync mode gating. */
|
|
39
148
|
shouldUpload?: () => boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Optional: Configuration for version-based conflict detection.
|
|
151
|
+
* When enabled, checks for conflicts before uploading changes.
|
|
152
|
+
*/
|
|
153
|
+
conflictDetection?: ConflictDetectionConfig;
|
|
154
|
+
/**
|
|
155
|
+
* Optional: Handler for conflict resolution.
|
|
156
|
+
* If not provided, conflicts are logged and upload proceeds.
|
|
157
|
+
*/
|
|
158
|
+
conflictHandler?: ConflictHandler;
|
|
159
|
+
/**
|
|
160
|
+
* Optional: Event bus for publishing conflict events.
|
|
161
|
+
* Use this to notify the UI layer about detected conflicts.
|
|
162
|
+
*/
|
|
163
|
+
conflictBus?: ConflictBus;
|
|
40
164
|
}
|
|
41
165
|
/**
|
|
42
166
|
* Configuration passed to PowerSyncProvider for connector setup
|
|
@@ -132,6 +256,7 @@ interface PowerSyncCredentials {
|
|
|
132
256
|
* - Uploading local changes back to Supabase
|
|
133
257
|
* - Schema routing for multi-schema databases
|
|
134
258
|
* - Custom CRUD handling for complex operations
|
|
259
|
+
* - Version-based conflict detection (when enabled)
|
|
135
260
|
*/
|
|
136
261
|
|
|
137
262
|
/**
|
|
@@ -191,6 +316,10 @@ declare class SupabaseConnector implements PowerSyncBackendConnector {
|
|
|
191
316
|
private readonly onTransactionFailure?;
|
|
192
317
|
private readonly onTransactionComplete?;
|
|
193
318
|
private readonly shouldUploadFn?;
|
|
319
|
+
private readonly conflictDetection?;
|
|
320
|
+
private readonly conflictHandler?;
|
|
321
|
+
private readonly conflictBus?;
|
|
322
|
+
private versionColumnCache;
|
|
194
323
|
private activeProjectIds;
|
|
195
324
|
constructor(options: SupabaseConnectorOptions);
|
|
196
325
|
/**
|
|
@@ -213,8 +342,29 @@ declare class SupabaseConnector implements PowerSyncBackendConnector {
|
|
|
213
342
|
/**
|
|
214
343
|
* Upload local changes to Supabase.
|
|
215
344
|
* Called automatically by PowerSync when there are pending uploads.
|
|
345
|
+
*
|
|
346
|
+
* When conflict detection is enabled:
|
|
347
|
+
* 1. Checks if table has _version column (cached)
|
|
348
|
+
* 2. If yes, compares local vs server version
|
|
349
|
+
* 3. On version mismatch, queries AuditLog for field conflicts
|
|
350
|
+
* 4. If conflicts found, calls handler or publishes to conflict bus
|
|
351
|
+
* 5. Applies resolution or skips entry based on handler response
|
|
216
352
|
*/
|
|
217
353
|
uploadData(database: AbstractPowerSyncDatabase): Promise<void>;
|
|
354
|
+
/**
|
|
355
|
+
* Process a transaction without conflict detection.
|
|
356
|
+
* Used when conflict detection is disabled.
|
|
357
|
+
*/
|
|
358
|
+
private processTransaction;
|
|
359
|
+
/**
|
|
360
|
+
* Check if a table has a _version column (cached).
|
|
361
|
+
*/
|
|
362
|
+
private checkVersionColumn;
|
|
363
|
+
/**
|
|
364
|
+
* Filter opData to only include specified fields.
|
|
365
|
+
* Used for partial sync resolution.
|
|
366
|
+
*/
|
|
367
|
+
private filterFields;
|
|
218
368
|
/**
|
|
219
369
|
* Process a single CRUD operation.
|
|
220
370
|
*
|
|
@@ -229,4 +379,4 @@ declare class SupabaseConnector implements PowerSyncBackendConnector {
|
|
|
229
379
|
private processCrudEntry;
|
|
230
380
|
}
|
|
231
381
|
|
|
232
|
-
export { type ConnectorConfig as C, type PowerSyncCredentials as P, SupabaseConnector as S, type SupabaseConnectorOptions as a, type SchemaRouter as b, type CrudHandler as c, defaultSchemaRouter as d };
|
|
382
|
+
export { type ConnectorConfig as C, type FieldConflict as F, type PowerSyncCredentials as P, type ResolutionListener as R, SupabaseConnector as S, type SupabaseConnectorOptions as a, type SchemaRouter as b, type CrudHandler as c, defaultSchemaRouter as d, ConflictBus as e, type ConflictCheckResult as f, type ConflictResolution as g, type ConflictHandler as h, type ConflictDetectionConfig as i, type ConflictListener as j };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { A as AbstractPowerSyncDatabase } from './types-afHtE1U_.js';
|
|
2
2
|
export { k as CacheStats, i as ClassifiedError, j as CompactResult, h as CompletedTransaction, b as ConnectionHealth, o as CountRow, C as CrudEntry, l as CrudTransaction, n as DbStatRow, D as DownloadProgress, E as EntitySyncState, F as FailedTransaction, r as FreelistCountRow, s as IntegrityCheckRow, I as IntegrityResult, q as PageCountRow, p as PageSizeRow, P as PowerSyncBackendConnector, m as SqliteTableRow, c as StorageInfo, d as StorageQuota, f as SyncError, g as SyncErrorType, e as SyncMetrics, S as SyncMode, a as SyncStatus, T as TableCacheStats } from './types-afHtE1U_.js';
|
|
3
3
|
export { ATTACHMENT_DOWNLOAD_TIMEOUT_MS, ATTACHMENT_RETRY_DELAY_MS, AttachmentError, COMPRESSION_MAX_WIDTH, COMPRESSION_SKIP_SIZE_BYTES, COMPRESSION_TARGET_SIZE_BYTES, ConfigurationError, ConnectorError, DEFAULT_ATTACHMENT_CACHE_SIZE, DEFAULT_ATTACHMENT_CONCURRENCY, DEFAULT_COMPRESSION_QUALITY, DEFAULT_MAX_RETRY_ATTEMPTS, DEFAULT_RETRY_BACKOFF_MULTIPLIER, DEFAULT_RETRY_BASE_DELAY_MS, DEFAULT_RETRY_MAX_DELAY_MS, DEFAULT_SYNC_INTERVAL_MS, DEFAULT_SYNC_MODE, DOWNLOAD_STOP_THRESHOLD, EVICTION_TRIGGER_THRESHOLD, HEALTH_CHECK_INTERVAL_MS, HEALTH_CHECK_TIMEOUT_MS, InitializationError, LATENCY_DEGRADED_THRESHOLD_MS, MAX_CONSECUTIVE_FAILURES, PlatformAdapterError, PowerSyncError, STATS_CACHE_TTL_MS, STATUS_NOTIFY_THROTTLE_MS, STORAGE_CRITICAL_THRESHOLD, STORAGE_KEY_ATTACHMENT_SETTINGS, STORAGE_KEY_ENABLED, STORAGE_KEY_METRICS, STORAGE_KEY_PAUSED, STORAGE_KEY_PREFIX, STORAGE_KEY_SYNC_MODE, STORAGE_WARNING_THRESHOLD, SyncOperationError, classifyError, classifySupabaseError, createSyncError, extractEntityIds, extractTableNames, generateFailureId, toSyncOperationError } from './core/index.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export { C as ConflictAwareConnector, a as ConflictAwareConnectorOptions, d as ConflictHandler, c as ConflictResolution, F as FieldConflict } from './index-nae7nzib.js';
|
|
4
|
+
import { i as ConflictDetectionConfig, f as ConflictCheckResult } from './index-D952Qr38.js';
|
|
5
|
+
export { e as ConflictBus, h as ConflictHandler, j as ConflictListener, g as ConflictResolution, C as ConnectorConfig, c as CrudHandler, F as FieldConflict, P as PowerSyncCredentials, R as ResolutionListener, b as SchemaRouter, S as SupabaseConnector, a as SupabaseConnectorOptions, d as defaultSchemaRouter } from './index-D952Qr38.js';
|
|
7
6
|
export { AttachmentQueue, AttachmentQueueConfig, AttachmentRecord, AttachmentSourceConfig, AttachmentState, AttachmentStatsRow, AttachmentStorageAdapter, AttachmentSyncStats, AttachmentSyncStatus, CacheConfig, CacheFileRow, CachedSizeRow, CompressionConfig, DEFAULT_CACHE_CONFIG, DEFAULT_COMPRESSION_CONFIG, DEFAULT_DOWNLOAD_CONFIG, DownloadConfig, DownloadPhase, DownloadStatus, EvictRow, IdRow } from './attachments/index.js';
|
|
8
7
|
export { e as HealthCheckResult, H as HealthMonitorOptions, M as MetricsCollectorOptions, P as PowerSyncRawStatus, c as SyncControlActions, f as SyncEvent, g as SyncEventListener, d as SyncOperationData, S as SyncScope, a as SyncStatusState, b as SyncStatusTrackerOptions, U as Unsubscribe } from './types-Cd7RhNqf.js';
|
|
9
8
|
export { HealthMonitor, MetricsCollector, SyncStatusTracker } from './sync/index.js';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
ConflictBus
|
|
3
|
+
} from "./chunk-42IJ25Q4.js";
|
|
2
4
|
import "./chunk-32OLICZO.js";
|
|
3
5
|
import {
|
|
4
6
|
AttachmentQueueContext,
|
|
@@ -23,7 +25,7 @@ import {
|
|
|
23
25
|
useSyncMode,
|
|
24
26
|
useSyncStatus,
|
|
25
27
|
useUploadStatus
|
|
26
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-H7HZMI4H.js";
|
|
27
29
|
import {
|
|
28
30
|
AttachmentQueue,
|
|
29
31
|
AttachmentState,
|
|
@@ -74,17 +76,15 @@ import {
|
|
|
74
76
|
STORAGE_KEY_SYNC_MODE,
|
|
75
77
|
STORAGE_WARNING_THRESHOLD
|
|
76
78
|
} from "./chunk-NPNBGCRC.js";
|
|
79
|
+
import "./chunk-VJCL2SWD.js";
|
|
77
80
|
import {
|
|
78
|
-
|
|
81
|
+
SupabaseConnector,
|
|
82
|
+
defaultSchemaRouter,
|
|
79
83
|
detectConflicts,
|
|
80
84
|
fetchServerVersion,
|
|
81
85
|
getLocalVersion,
|
|
82
86
|
hasVersionColumn
|
|
83
|
-
} from "./chunk-
|
|
84
|
-
import {
|
|
85
|
-
SupabaseConnector,
|
|
86
|
-
defaultSchemaRouter
|
|
87
|
-
} from "./chunk-FLHDT4TS.js";
|
|
87
|
+
} from "./chunk-MB2RC3NS.js";
|
|
88
88
|
import {
|
|
89
89
|
AttachmentError,
|
|
90
90
|
ConfigurationError,
|
|
@@ -112,7 +112,7 @@ export {
|
|
|
112
112
|
COMPRESSION_SKIP_SIZE_BYTES,
|
|
113
113
|
COMPRESSION_TARGET_SIZE_BYTES,
|
|
114
114
|
ConfigurationError,
|
|
115
|
-
|
|
115
|
+
ConflictBus,
|
|
116
116
|
ConnectionHealthContext,
|
|
117
117
|
ConnectorError,
|
|
118
118
|
DEFAULT_ATTACHMENT_CACHE_SIZE,
|
package/dist/index.native.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export { A as AbstractPowerSyncDatabase, k as CacheStats, i as ClassifiedError, j as CompactResult, h as CompletedTransaction, b as ConnectionHealth, o as CountRow, C as CrudEntry, l as CrudTransaction, n as DbStatRow, D as DownloadProgress, E as EntitySyncState, F as FailedTransaction, r as FreelistCountRow, s as IntegrityCheckRow, I as IntegrityResult, q as PageCountRow, p as PageSizeRow, P as PowerSyncBackendConnector, m as SqliteTableRow, c as StorageInfo, d as StorageQuota, f as SyncError, g as SyncErrorType, e as SyncMetrics, S as SyncMode, a as SyncStatus, T as TableCacheStats } from './types-afHtE1U_.js';
|
|
2
2
|
export { ATTACHMENT_DOWNLOAD_TIMEOUT_MS, ATTACHMENT_RETRY_DELAY_MS, AttachmentError, COMPRESSION_MAX_WIDTH, COMPRESSION_SKIP_SIZE_BYTES, COMPRESSION_TARGET_SIZE_BYTES, ConfigurationError, ConnectorError, DEFAULT_ATTACHMENT_CACHE_SIZE, DEFAULT_ATTACHMENT_CONCURRENCY, DEFAULT_COMPRESSION_QUALITY, DEFAULT_MAX_RETRY_ATTEMPTS, DEFAULT_RETRY_BACKOFF_MULTIPLIER, DEFAULT_RETRY_BASE_DELAY_MS, DEFAULT_RETRY_MAX_DELAY_MS, DEFAULT_SYNC_INTERVAL_MS, DEFAULT_SYNC_MODE, DOWNLOAD_STOP_THRESHOLD, EVICTION_TRIGGER_THRESHOLD, HEALTH_CHECK_INTERVAL_MS, HEALTH_CHECK_TIMEOUT_MS, InitializationError, LATENCY_DEGRADED_THRESHOLD_MS, MAX_CONSECUTIVE_FAILURES, PlatformAdapterError, PowerSyncError, STATS_CACHE_TTL_MS, STATUS_NOTIFY_THROTTLE_MS, STORAGE_CRITICAL_THRESHOLD, STORAGE_KEY_ATTACHMENT_SETTINGS, STORAGE_KEY_ENABLED, STORAGE_KEY_METRICS, STORAGE_KEY_PAUSED, STORAGE_KEY_PREFIX, STORAGE_KEY_SYNC_MODE, STORAGE_WARNING_THRESHOLD, SyncOperationError, classifyError, classifySupabaseError, createSyncError, extractEntityIds, extractTableNames, generateFailureId, toSyncOperationError } from './core/index.js';
|
|
3
|
-
export { C as ConnectorConfig, c as CrudHandler, P as PowerSyncCredentials, b as SchemaRouter, S as SupabaseConnector, a as SupabaseConnectorOptions, d as defaultSchemaRouter } from './
|
|
4
|
-
export { C as ConflictAwareConnector, a as ConflictAwareConnectorOptions, b as ConflictCheckResult, e as ConflictDetectionConfig, d as ConflictHandler, c as ConflictResolution, F as FieldConflict } from './index-nae7nzib.js';
|
|
3
|
+
export { e as ConflictBus, f as ConflictCheckResult, i as ConflictDetectionConfig, h as ConflictHandler, j as ConflictListener, g as ConflictResolution, C as ConnectorConfig, c as CrudHandler, F as FieldConflict, P as PowerSyncCredentials, R as ResolutionListener, b as SchemaRouter, S as SupabaseConnector, a as SupabaseConnectorOptions, d as defaultSchemaRouter } from './index-D952Qr38.js';
|
|
5
4
|
export { AttachmentQueue, AttachmentQueueConfig, AttachmentRecord, AttachmentSourceConfig, AttachmentState, AttachmentStatsRow, AttachmentStorageAdapter, AttachmentSyncStats, AttachmentSyncStatus, CacheConfig, CacheFileRow, CachedSizeRow, CompressionConfig, DEFAULT_CACHE_CONFIG, DEFAULT_COMPRESSION_CONFIG, DEFAULT_DOWNLOAD_CONFIG, DownloadConfig, DownloadPhase, DownloadStatus, EvictRow, IdRow } from './attachments/index.js';
|
|
6
5
|
export { e as HealthCheckResult, H as HealthMonitorOptions, M as MetricsCollectorOptions, P as PowerSyncRawStatus, c as SyncControlActions, f as SyncEvent, g as SyncEventListener, d as SyncOperationData, S as SyncScope, a as SyncStatusState, b as SyncStatusTrackerOptions, U as Unsubscribe } from './types-Cd7RhNqf.js';
|
|
7
6
|
export { HealthMonitor, MetricsCollector, SyncStatusTracker } from './sync/index.js';
|
package/dist/index.native.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
ConflictBus
|
|
3
|
+
} from "./chunk-42IJ25Q4.js";
|
|
2
4
|
import "./chunk-32OLICZO.js";
|
|
3
5
|
import {
|
|
4
6
|
AttachmentQueueContext,
|
|
@@ -23,7 +25,7 @@ import {
|
|
|
23
25
|
useSyncMode,
|
|
24
26
|
useSyncStatus,
|
|
25
27
|
useUploadStatus
|
|
26
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-H7HZMI4H.js";
|
|
27
29
|
import {
|
|
28
30
|
AttachmentQueue,
|
|
29
31
|
AttachmentState,
|
|
@@ -76,18 +78,16 @@ import {
|
|
|
76
78
|
} from "./chunk-NPNBGCRC.js";
|
|
77
79
|
import {
|
|
78
80
|
createNativePlatformAdapter
|
|
79
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-PANEMMTU.js";
|
|
82
|
+
import "./chunk-VJCL2SWD.js";
|
|
80
83
|
import {
|
|
81
|
-
|
|
84
|
+
SupabaseConnector,
|
|
85
|
+
defaultSchemaRouter,
|
|
82
86
|
detectConflicts,
|
|
83
87
|
fetchServerVersion,
|
|
84
88
|
getLocalVersion,
|
|
85
89
|
hasVersionColumn
|
|
86
|
-
} from "./chunk-
|
|
87
|
-
import {
|
|
88
|
-
SupabaseConnector,
|
|
89
|
-
defaultSchemaRouter
|
|
90
|
-
} from "./chunk-FLHDT4TS.js";
|
|
90
|
+
} from "./chunk-MB2RC3NS.js";
|
|
91
91
|
import {
|
|
92
92
|
AttachmentError,
|
|
93
93
|
ConfigurationError,
|
|
@@ -115,7 +115,7 @@ export {
|
|
|
115
115
|
COMPRESSION_SKIP_SIZE_BYTES,
|
|
116
116
|
COMPRESSION_TARGET_SIZE_BYTES,
|
|
117
117
|
ConfigurationError,
|
|
118
|
-
|
|
118
|
+
ConflictBus,
|
|
119
119
|
ConnectionHealthContext,
|
|
120
120
|
ConnectorError,
|
|
121
121
|
DEFAULT_ATTACHMENT_CACHE_SIZE,
|
package/dist/index.web.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export { A as AbstractPowerSyncDatabase, k as CacheStats, i as ClassifiedError, j as CompactResult, h as CompletedTransaction, b as ConnectionHealth, o as CountRow, C as CrudEntry, l as CrudTransaction, n as DbStatRow, D as DownloadProgress, E as EntitySyncState, F as FailedTransaction, r as FreelistCountRow, s as IntegrityCheckRow, I as IntegrityResult, q as PageCountRow, p as PageSizeRow, P as PowerSyncBackendConnector, m as SqliteTableRow, c as StorageInfo, d as StorageQuota, f as SyncError, g as SyncErrorType, e as SyncMetrics, S as SyncMode, a as SyncStatus, T as TableCacheStats } from './types-afHtE1U_.js';
|
|
2
2
|
export { ATTACHMENT_DOWNLOAD_TIMEOUT_MS, ATTACHMENT_RETRY_DELAY_MS, AttachmentError, COMPRESSION_MAX_WIDTH, COMPRESSION_SKIP_SIZE_BYTES, COMPRESSION_TARGET_SIZE_BYTES, ConfigurationError, ConnectorError, DEFAULT_ATTACHMENT_CACHE_SIZE, DEFAULT_ATTACHMENT_CONCURRENCY, DEFAULT_COMPRESSION_QUALITY, DEFAULT_MAX_RETRY_ATTEMPTS, DEFAULT_RETRY_BACKOFF_MULTIPLIER, DEFAULT_RETRY_BASE_DELAY_MS, DEFAULT_RETRY_MAX_DELAY_MS, DEFAULT_SYNC_INTERVAL_MS, DEFAULT_SYNC_MODE, DOWNLOAD_STOP_THRESHOLD, EVICTION_TRIGGER_THRESHOLD, HEALTH_CHECK_INTERVAL_MS, HEALTH_CHECK_TIMEOUT_MS, InitializationError, LATENCY_DEGRADED_THRESHOLD_MS, MAX_CONSECUTIVE_FAILURES, PlatformAdapterError, PowerSyncError, STATS_CACHE_TTL_MS, STATUS_NOTIFY_THROTTLE_MS, STORAGE_CRITICAL_THRESHOLD, STORAGE_KEY_ATTACHMENT_SETTINGS, STORAGE_KEY_ENABLED, STORAGE_KEY_METRICS, STORAGE_KEY_PAUSED, STORAGE_KEY_PREFIX, STORAGE_KEY_SYNC_MODE, STORAGE_WARNING_THRESHOLD, SyncOperationError, classifyError, classifySupabaseError, createSyncError, extractEntityIds, extractTableNames, generateFailureId, toSyncOperationError } from './core/index.js';
|
|
3
|
-
export { C as ConnectorConfig, c as CrudHandler, P as PowerSyncCredentials, b as SchemaRouter, S as SupabaseConnector, a as SupabaseConnectorOptions, d as defaultSchemaRouter } from './
|
|
4
|
-
export { C as ConflictAwareConnector, a as ConflictAwareConnectorOptions, b as ConflictCheckResult, e as ConflictDetectionConfig, d as ConflictHandler, c as ConflictResolution, F as FieldConflict } from './index-nae7nzib.js';
|
|
3
|
+
export { e as ConflictBus, f as ConflictCheckResult, i as ConflictDetectionConfig, h as ConflictHandler, j as ConflictListener, g as ConflictResolution, C as ConnectorConfig, c as CrudHandler, F as FieldConflict, P as PowerSyncCredentials, R as ResolutionListener, b as SchemaRouter, S as SupabaseConnector, a as SupabaseConnectorOptions, d as defaultSchemaRouter } from './index-D952Qr38.js';
|
|
5
4
|
export { AttachmentQueue, AttachmentQueueConfig, AttachmentRecord, AttachmentSourceConfig, AttachmentState, AttachmentStatsRow, AttachmentStorageAdapter, AttachmentSyncStats, AttachmentSyncStatus, CacheConfig, CacheFileRow, CachedSizeRow, CompressionConfig, DEFAULT_CACHE_CONFIG, DEFAULT_COMPRESSION_CONFIG, DEFAULT_DOWNLOAD_CONFIG, DownloadConfig, DownloadPhase, DownloadStatus, EvictRow, IdRow } from './attachments/index.js';
|
|
6
5
|
export { e as HealthCheckResult, H as HealthMonitorOptions, M as MetricsCollectorOptions, P as PowerSyncRawStatus, c as SyncControlActions, f as SyncEvent, g as SyncEventListener, d as SyncOperationData, S as SyncScope, a as SyncStatusState, b as SyncStatusTrackerOptions, U as Unsubscribe } from './types-Cd7RhNqf.js';
|
|
7
6
|
export { HealthMonitor, MetricsCollector, SyncStatusTracker } from './sync/index.js';
|
package/dist/index.web.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
ConflictBus
|
|
3
|
+
} from "./chunk-42IJ25Q4.js";
|
|
2
4
|
import "./chunk-32OLICZO.js";
|
|
3
5
|
import {
|
|
4
6
|
AttachmentQueueContext,
|
|
@@ -23,7 +25,7 @@ import {
|
|
|
23
25
|
useSyncMode,
|
|
24
26
|
useSyncStatus,
|
|
25
27
|
useUploadStatus
|
|
26
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-H7HZMI4H.js";
|
|
27
29
|
import {
|
|
28
30
|
AttachmentQueue,
|
|
29
31
|
AttachmentState,
|
|
@@ -77,17 +79,15 @@ import {
|
|
|
77
79
|
import {
|
|
78
80
|
createWebPlatformAdapter
|
|
79
81
|
} from "./chunk-BJ36QDFN.js";
|
|
82
|
+
import "./chunk-VJCL2SWD.js";
|
|
80
83
|
import {
|
|
81
|
-
|
|
84
|
+
SupabaseConnector,
|
|
85
|
+
defaultSchemaRouter,
|
|
82
86
|
detectConflicts,
|
|
83
87
|
fetchServerVersion,
|
|
84
88
|
getLocalVersion,
|
|
85
89
|
hasVersionColumn
|
|
86
|
-
} from "./chunk-
|
|
87
|
-
import {
|
|
88
|
-
SupabaseConnector,
|
|
89
|
-
defaultSchemaRouter
|
|
90
|
-
} from "./chunk-FLHDT4TS.js";
|
|
90
|
+
} from "./chunk-MB2RC3NS.js";
|
|
91
91
|
import {
|
|
92
92
|
AttachmentError,
|
|
93
93
|
ConfigurationError,
|
|
@@ -115,7 +115,7 @@ export {
|
|
|
115
115
|
COMPRESSION_SKIP_SIZE_BYTES,
|
|
116
116
|
COMPRESSION_TARGET_SIZE_BYTES,
|
|
117
117
|
ConfigurationError,
|
|
118
|
-
|
|
118
|
+
ConflictBus,
|
|
119
119
|
ConnectionHealthContext,
|
|
120
120
|
ConnectorError,
|
|
121
121
|
DEFAULT_ATTACHMENT_CACHE_SIZE,
|
package/dist/provider/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { SupabaseClient } from '@supabase/supabase-js';
|
|
|
2
2
|
import { QueryClient } from '@tanstack/react-query';
|
|
3
3
|
import { A as AbstractPowerSyncDatabase, a as SyncStatus, C as CrudEntry, S as SyncMode, F as FailedTransaction, h as CompletedTransaction, b as ConnectionHealth, e as SyncMetrics, D as DownloadProgress, E as EntitySyncState, f as SyncError } from '../types-afHtE1U_.js';
|
|
4
4
|
import { PlatformAdapter } from '../platform/index.js';
|
|
5
|
-
import { C as ConnectorConfig, S as SupabaseConnector } from '../
|
|
5
|
+
import { C as ConnectorConfig, S as SupabaseConnector } from '../index-D952Qr38.js';
|
|
6
6
|
import { AttachmentQueueConfig, AttachmentQueue } from '../attachments/index.js';
|
|
7
7
|
import * as react from 'react';
|
|
8
8
|
import react__default from 'react';
|