UNPKG

livesheets-sdk

Version:

LiveSheets SDK for Google Sheets integration with Lovable apps. OAuth onboarding URL: https://livesheets-backend-624058308714.europe-north1.run.app/onboarding

235 lines (234 loc) 8.53 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.livesheets = exports.auth = exports.LiveSheetsClient = exports.LiveSheetsAuth = void 0; exports.readSheet = readSheet; /** * LiveSheetsAuth - Helper class for OAuth authentication */ class LiveSheetsAuth { constructor(config = {}) { this.backendUrl = config.backendUrl || LiveSheetsAuth.DEFAULT_BACKEND_URL; this.jwtKey = config.storageKey || LiveSheetsAuth.DEFAULT_JWT_KEY; this.userIdKey = config.userIdKey || LiveSheetsAuth.DEFAULT_USER_KEY; } /** * Start OAuth flow * @param returnUrl - Optional return URL after OAuth completion */ startOAuth(returnUrl) { // Generate or retrieve user ID const userId = this.getUserId(); // Use current URL as return URL if not provided const currentUrl = returnUrl || (typeof window !== 'undefined' ? window.location.href.split('#')[0] : ''); const encodedReturnUrl = encodeURIComponent(currentUrl); // Redirect to OAuth endpoint if (typeof window !== 'undefined') { window.location.href = `${this.backendUrl}/google-sheets/auth?sub=${userId}&return_url=${encodedReturnUrl}`; } } /** * Get JWT from storage or URL hash */ getJWT() { if (typeof window === 'undefined') return null; // Check localStorage first const storedJWT = localStorage.getItem(this.jwtKey); if (storedJWT) return storedJWT; // Check URL hash for JWT (after OAuth redirect) const hash = window.location.hash; const match = hash.match(/jwt=([^&]+)/); if (match) { const jwt = match[1]; localStorage.setItem(this.jwtKey, jwt); // Clean up URL window.history.replaceState({}, document.title, window.location.pathname); return jwt; } return null; } /** * Check if user is authenticated */ isAuthenticated() { return !!this.getJWT(); } /** * Clear authentication data */ logout() { if (typeof window === 'undefined') return; localStorage.removeItem(this.jwtKey); localStorage.removeItem(this.userIdKey); } /** * Get or generate user ID */ getUserId() { if (typeof window === 'undefined') return 'user_server'; let userId = localStorage.getItem(this.userIdKey); if (!userId) { userId = `user_${Date.now()}`; localStorage.setItem(this.userIdKey, userId); } return userId; } } exports.LiveSheetsAuth = LiveSheetsAuth; LiveSheetsAuth.DEFAULT_BACKEND_URL = 'https://livesheets-backend-624058308714.europe-north1.run.app'; LiveSheetsAuth.DEFAULT_JWT_KEY = 'livesheets_jwt'; LiveSheetsAuth.DEFAULT_USER_KEY = 'livesheets_user_id'; /** * LiveSheetsClient SDK * * Example usage: * * import { LiveSheetsClient } from "livesheets-sdk"; * const client = new LiveSheetsClient("<your_jwt>"); * const rows = await client.listRows(); * const schema = await client.getSchema(); * const metadata = await client.getMetadata(); */ class LiveSheetsClient { constructor(jwt, baseUrl = "https://vfxfbuwrzbknqpwqmbqp.supabase.co/functions/v1") { // Try to get JWT from auth helper if not provided if (!jwt && typeof window !== 'undefined') { const authHelper = LiveSheetsClient.getAuth(); jwt = authHelper.getJWT(); } if (!jwt) { throw new Error('JWT is required. Use LiveSheetsAuth to authenticate first.'); } this.jwt = jwt; this.baseUrl = baseUrl; } /** * Get or create auth helper instance */ static getAuth(config) { if (!this.auth) { this.auth = new LiveSheetsAuth(config); } return this.auth; } /** * Open sheet picker in popup window */ static async openSheetPicker(config) { if (typeof window === 'undefined') { throw new Error('Sheet picker can only be used in browser environment'); } const { jwt, onSuccess, onCancel, width = 800, height = 600 } = config; const backendUrl = this.auth?.backendUrl || 'https://livesheets-backend-624058308714.europe-north1.run.app'; // Calculate popup position const left = (window.innerWidth - width) / 2; const top = (window.innerHeight - height) / 2; const popup = window.open(`${backendUrl}/onboarding#jwt=${jwt}`, 'GoogleSheetsPicker', `width=${width},height=${height},left=${left},top=${top}`); if (!popup) { throw new Error('Failed to open sheet picker popup. Please allow popups for this site.'); } // Listen for sheet selection message const handleMessage = (event) => { if (event.origin !== backendUrl) return; if (event.data.type === 'sheet-selected') { window.removeEventListener('message', handleMessage); onSuccess?.({ spreadsheetId: event.data.spreadsheetId, sheetName: event.data.sheetName }); } }; window.addEventListener('message', handleMessage); // Handle popup close const checkClosed = setInterval(() => { if (popup.closed) { clearInterval(checkClosed); window.removeEventListener('message', handleMessage); onCancel?.(); } }, 500); } async request(endpoint) { const response = await fetch(`${this.baseUrl}${endpoint}`, { headers: { Authorization: `Bearer ${this.jwt}`, "Content-Type": "application/json", }, }); if (!response.ok) { let errorMessage = `HTTP error! status: ${response.status}`; try { const errorData = await response.json(); errorMessage = errorData.detail || errorData.message || errorMessage; } catch { // Ignore JSON parse errors } throw new Error(errorMessage); } return response.json(); } async listRows() { const data = await this.request("/sheets-listRows"); return data.rows; } async getSchema() { const data = await this.request("/sheets-schema"); return data.schema; } async getMetadata() { const data = await this.request("/sheets-metadata"); // Handle both old and new metadata format return { spreadsheetId: data.spreadsheetId || data.spreadsheet_id || '', sheetName: data.sheetName || data.sheet_name || '', rowCount: data.rowCount || data.row_count || 0, columnCount: data.columnCount || data.column_count || 0 }; } } exports.LiveSheetsClient = LiveSheetsClient; exports.livesheets = LiveSheetsClient; // Helper function for simpler usage - supports multiple call signatures async function readSheet(jwtOrParams, sheetIdOrOptions) { let jwt; let sheetId; let sheet; // Handle different parameter combinations if (typeof jwtOrParams === 'string') { // Called as readSheet(jwt) or readSheet(jwt, sheetId) jwt = jwtOrParams; if (typeof sheetIdOrOptions === 'string') { sheetId = sheetIdOrOptions; } else if (sheetIdOrOptions) { sheetId = sheetIdOrOptions.sheetId; sheet = sheetIdOrOptions.sheet; } } else if (jwtOrParams) { // Called as readSheet({ jwt, sheetId, sheet }) jwt = jwtOrParams.jwt; sheetId = jwtOrParams.sheetId; sheet = jwtOrParams.sheet; } // Try to get JWT from auth helper if not provided if (!jwt && typeof window !== 'undefined') { const auth = LiveSheetsClient.getAuth(); jwt = auth.getJWT() || undefined; } if (!jwt) { throw new Error('JWT is required to read sheet data. Either pass it as parameter or authenticate first.'); } const client = new LiveSheetsClient(jwt); // Note: sheetId and sheet are captured for future use but not used yet return client.listRows(); } // Export auth helper for standalone use exports.auth = LiveSheetsClient.getAuth(); // Default export exports.default = LiveSheetsClient;