import { STORAGE_KEYS } from '@/common/constants/storageKeys'; import type { AbstractPowerSyncDatabase, PowerSyncBackendConnector } from '@powersync/react-native'; import * as SecureStore from 'expo-secure-store'; const POWERSYNC_URL = process.env.EXPO_PUBLIC_POWERSYNC_URL!; const API_URL = process.env.EXPO_PUBLIC_API_URL!; export class SyncConnector implements PowerSyncBackendConnector { async fetchCredentials() { const sessionToken = await SecureStore.getItemAsync(STORAGE_KEYS.SESSION_TOKEN); if (!sessionToken) throw new Error('No session token'); const response = await fetch(`${API_URL}/api/auth/sync-engine-token`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${sessionToken}`, }, }); if (!response.ok) throw new Error('Failed to get sync engine token'); const { syncEngineToken } = await response.json(); return { endpoint: POWERSYNC_URL, token: syncEngineToken }; } async uploadData(database: AbstractPowerSyncDatabase): Promise { const transaction = await database.getNextCrudTransaction(); if (!transaction) return; const operations = transaction.crud .filter(op => !this.isDemoData(op.opData)) .map(op => ({ id: op.id, table: op.table, op: op.op, opData: op.opData })); if (operations.length === 0) { await transaction.complete(); return; } const sessionToken = await SecureStore.getItemAsync(STORAGE_KEYS.SESSION_TOKEN); const response = await fetch(`${API_URL}/api/sync/upload`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${sessionToken}`, }, body: JSON.stringify({ operations }), }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || 'Upload failed'); } await transaction.complete(); } private isDemoData(opData: Record | undefined): boolean { if (!opData) return false; return opData.profile_id === 'demo' || opData.workos_user_id === 'demo'; } }