livesheets-sdk
v0.2.0
Published
LiveSheets SDK for Google Sheets integration with Lovable apps. OAuth onboarding URL: https://livesheets-backend-624058308714.europe-north1.run.app/onboarding
Downloads
43
Maintainers
Readme
LiveSheets SDK
Official SDK for integrating Google Sheets with Lovable applications. Provides OAuth authentication, sheet selection, and data access with built-in React hooks support.
Installation
npm install livesheets-sdkQuick Start
Using React Hooks (Recommended for Lovable Apps)
import { useLiveSheets } from 'livesheets-sdk/react';
function GoogleSheetsConnector() {
const {
isAuthenticated,
hasSheet,
data,
isLoading,
error,
connect,
selectSheet,
disconnect,
refresh
} = useLiveSheets();
if (!isAuthenticated) {
return <button onClick={connect}>Connect Google Sheets</button>;
}
if (!hasSheet) {
return <button onClick={selectSheet}>Select a Sheet</button>;
}
return (
<div>
<h3>Sheet Data ({data.length} rows)</h3>
<button onClick={refresh}>Refresh</button>
<button onClick={disconnect}>Disconnect</button>
{/* Render your data */}
</div>
);
}Using the Core SDK
import { LiveSheetsClient, LiveSheetsAuth } from 'livesheets-sdk';
// Initialize auth
const auth = new LiveSheetsAuth();
// Check if authenticated
if (!auth.isAuthenticated()) {
// Start OAuth flow
auth.startOAuth();
}
// Get JWT token
const jwt = auth.getJWT();
// Create client and fetch data
const client = new LiveSheetsClient(jwt);
const rows = await client.listRows();
const metadata = await client.getMetadata();
const schema = await client.getSchema();Features
🔐 OAuth Authentication
Built-in OAuth flow management with automatic JWT handling:
import { auth } from 'livesheets-sdk';
// Start OAuth flow (redirects to Google)
auth.startOAuth();
// Check authentication status
if (auth.isAuthenticated()) {
const jwt = auth.getJWT();
// Use JWT for API calls
}
// Logout
auth.logout();📊 Sheet Selection
Interactive Google Picker integration:
import { LiveSheetsClient } from 'livesheets-sdk';
await LiveSheetsClient.openSheetPicker({
jwt: 'your-jwt-token',
onSuccess: (result) => {
console.log('Selected:', result.spreadsheetId, result.sheetName);
},
onCancel: () => {
console.log('Selection cancelled');
}
});🎣 React Hooks
Complete hook with all features:
const {
// Auth state
isAuthenticated, // boolean
isConnecting, // boolean
// Sheet state
hasSheet, // boolean
isSelectingSheet, // boolean
sheetMetadata, // { spreadsheetId, sheetName, rowCount, columnCount }
// Data state
data, // SheetRow[]
isLoading, // boolean
error, // Error | null
// Actions
connect, // () => void
disconnect, // () => void
selectSheet, // () => Promise<void>
refresh, // () => Promise<void>
// Direct access
client // LiveSheetsClient | null
} = useLiveSheets(options);Simple data-only hook:
const { data, loading, error } = useSheetData(jwt);API Reference
LiveSheetsAuth
class LiveSheetsAuth {
constructor(config?: {
backendUrl?: string;
storageKey?: string;
userIdKey?: string;
})
startOAuth(returnUrl?: string): void
getJWT(): string | null
isAuthenticated(): boolean
logout(): void
}LiveSheetsClient
class LiveSheetsClient {
constructor(jwt?: string, baseUrl?: string)
// Data methods
async listRows(): Promise<SheetRow[]>
async getMetadata(): Promise<SheetMetadata>
async getSchema(): Promise<SheetSchema[]>
// Static methods
static getAuth(config?: AuthConfig): LiveSheetsAuth
static async openSheetPicker(config: SheetPickerConfig): Promise<void>
}Types
interface SheetRow {
[key: string]: any;
}
interface SheetMetadata {
spreadsheetId: string;
sheetName: string;
rowCount: number;
columnCount: number;
}
interface SheetSchema {
name: string;
type: string;
}Complete Example
import React from 'react';
import { useLiveSheets } from 'livesheets-sdk/react';
export default function DataTable() {
const {
isAuthenticated,
hasSheet,
data,
isLoading,
error,
connect,
selectSheet,
refresh,
sheetMetadata
} = useLiveSheets({
autoLoadData: true,
onDataLoaded: (rows) => {
console.log(`Loaded ${rows.length} rows`);
}
});
if (error) {
return <div>Error: {error.message}</div>;
}
if (!isAuthenticated) {
return (
<button onClick={connect} disabled={isLoading}>
{isLoading ? 'Connecting...' : 'Connect Google Sheets'}
</button>
);
}
if (!hasSheet) {
return (
<button onClick={selectSheet} disabled={isLoading}>
{isLoading ? 'Opening picker...' : 'Select a Sheet'}
</button>
);
}
return (
<div>
<h2>{sheetMetadata?.sheetName}</h2>
<p>{data.length} rows × {sheetMetadata?.columnCount} columns</p>
<button onClick={refresh} disabled={isLoading}>
{isLoading ? 'Loading...' : 'Refresh'}
</button>
<table>
<thead>
<tr>
{data[0] && Object.keys(data[0]).map(key => (
<th key={key}>{key}</th>
))}
</tr>
</thead>
<tbody>
{data.map((row, i) => (
<tr key={i}>
{Object.values(row).map((val, j) => (
<td key={j}>{String(val)}</td>
))}
</tr>
))}
</tbody>
</table>
</div>
);
}Lovable Integration Instructions
Simple Component for Lovable
Here's a complete GoogleSheetsConnector component that works perfectly with Lovable:
import React from 'react';
import { useLiveSheets } from 'livesheets-sdk/react';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Loader2 } from 'lucide-react';
export default function GoogleSheetsConnector() {
const {
isAuthenticated,
hasSheet,
data,
isLoading,
error,
connect,
selectSheet,
disconnect,
refresh,
sheetMetadata
} = useLiveSheets();
if (!isAuthenticated) {
return (
<Card>
<CardHeader>
<CardTitle>Connect Google Sheets</CardTitle>
</CardHeader>
<CardContent className="text-center">
<Button onClick={connect} disabled={isLoading}>
{isLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Connecting...
</>
) : (
'Connect Google Sheets'
)}
</Button>
</CardContent>
</Card>
);
}
if (!hasSheet) {
return (
<Card>
<CardHeader>
<CardTitle>Select a Spreadsheet</CardTitle>
</CardHeader>
<CardContent className="text-center space-y-4">
<Button onClick={selectSheet} disabled={isLoading}>
{isLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Opening picker...
</>
) : (
'Select Sheet'
)}
</Button>
<Button variant="ghost" onClick={disconnect}>
Disconnect
</Button>
</CardContent>
</Card>
);
}
return (
<Card>
<CardHeader>
<CardTitle>{sheetMetadata?.sheetName || 'Sheet Data'}</CardTitle>
</CardHeader>
<CardContent>
<div className="mb-4 flex gap-2">
<Button onClick={refresh} disabled={isLoading} size="sm">
{isLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Loading...
</>
) : (
'Refresh'
)}
</Button>
<Button onClick={selectSheet} variant="outline" size="sm">
Change Sheet
</Button>
<Button onClick={disconnect} variant="ghost" size="sm">
Disconnect
</Button>
</div>
{error && (
<div className="text-red-500 mb-4">{error.message}</div>
)}
{data.length > 0 && (
<div className="overflow-x-auto">
<table className="w-full border">
<thead>
<tr>
{Object.keys(data[0]).map(key => (
<th key={key} className="border p-2 text-left">
{key}
</th>
))}
</tr>
</thead>
<tbody>
{data.slice(0, 10).map((row, i) => (
<tr key={i}>
{Object.values(row).map((val, j) => (
<td key={j} className="border p-2">
{String(val)}
</td>
))}
</tr>
))}
</tbody>
</table>
{data.length > 10 && (
<p className="text-center mt-2 text-sm text-muted-foreground">
Showing 10 of {data.length} rows
</p>
)}
</div>
)}
</CardContent>
</Card>
);
}Integration Steps for Lovable
- Install the SDK: Add
livesheets-sdkto your dependencies - Copy the component above into your project
- Add it to your page: Just drop
<GoogleSheetsConnector />anywhere - That's it! The component handles everything else
Configuration
Backend URL
Default: https://livesheets-backend-624058308714.europe-north1.run.app
To use a custom backend:
const auth = new LiveSheetsAuth({
backendUrl: 'https://your-backend-url.com'
});
// Or with hooks
const { connect } = useLiveSheets({
backendUrl: 'https://your-backend-url.com'
});Storage Keys
Customize localStorage keys:
const auth = new LiveSheetsAuth({
storageKey: 'my_app_jwt',
userIdKey: 'my_app_user_id'
});OAuth Setup
The SDK handles the complete OAuth flow:
- User clicks "Connect" → Redirects to Google OAuth
- User authorizes → Redirects back with JWT
- SDK stores JWT in localStorage
- All subsequent API calls use the JWT
Required Google OAuth Scopes
https://www.googleapis.com/auth/spreadsheets.readonlyhttps://www.googleapis.com/auth/drive.readonly
OAuth Onboarding URL
For manual integration or testing:
https://livesheets-backend-624058308714.europe-north1.run.app/onboardingAlternative Usage: readSheet Helper
For simple use cases, you can use the readSheet helper:
import { readSheet } from 'livesheets-sdk';
// Option 1: Pass JWT directly
const rows = await readSheet(jwt);
// Option 2: Auto-detect JWT from localStorage
const rows = await readSheet();
// Option 3: Pass options
const rows = await readSheet({
jwt: jwt, // Optional if stored in localStorage
sheetId: 'abc123', // For future use
sheet: 'Sheet1' // For future use
});Common Issues
Import Errors
Always use named imports with the new keyword:
// ✅ CORRECT
import { LiveSheetsClient } from 'livesheets-sdk';
const client = new LiveSheetsClient(jwt);
// ❌ WRONG - Missing 'new' keyword
import { LiveSheetsClient } from 'livesheets-sdk';
const client = LiveSheetsClient(jwt); // Error!TypeScript Errors
When rendering data, convert to strings:
// ✅ CORRECT
<td>{String(cell)}</td>
// ❌ WRONG - Type error
<td>{cell}</td>Browser Support
- Chrome, Firefox, Safari, Edge (latest versions)
- Requires localStorage and postMessage support
- Popup blockers must allow the sheet picker
License
MIT
