#!/usr/bin/env node const fs = require("fs"); const https = require("https"); const { homedir } = require("os"); const { join } = require("path"); function httpsRequest(url, options = {}) { return new Promise((resolve, reject) => { const req = https.request(url, options, (res) => { let data = ""; res.on("data", (chunk) => (data += chunk)); res.on("end", () => { if (res.statusCode >= 400) { reject(new Error(`HTTP ${res.statusCode}: ${data}`)); } else { resolve(JSON.parse(data)); } }); }); req.on("error", reject); if (options.body) req.write(options.body); req.end(); }); } async function getAccessToken(creds) { const body = new URLSearchParams({ client_id: creds.client_id, client_secret: creds.client_secret, refresh_token: creds.refresh_token, grant_type: "refresh_token", }).toString(); const data = await httpsRequest("https://oauth2.googleapis.com/token", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", "Content-Length": Buffer.byteLength(body), }, body, }); return data.access_token; } async function main() { const spreadsheetId = process.argv[2] || "1G6KEBQER_qBI3Hau8GUBrhEOf4FrHMtmKypPjD_8pBw"; const credsPath = join(homedir(), ".openclaw/secrets/google-oauth.json"); const creds = JSON.parse(fs.readFileSync(credsPath, "utf8")); const accessToken = await getAccessToken(creds); console.log(`šŸ“Š Fetching Google Sheet: ${spreadsheetId}\n`); // Get spreadsheet metadata const metaUrl = `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}`; const metadata = await httpsRequest(metaUrl, { headers: { Authorization: `Bearer ${accessToken}` }, }); console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); console.log(`šŸ“„ Title: ${metadata.properties.title}`); console.log( `šŸ“… Last updated: ${new Date(metadata.properties.modifiedTime).toLocaleString("da-DK")}`, ); console.log(`šŸ“‘ Sheets: ${metadata.sheets.length}`); console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); // List all sheets for (const sheet of metadata.sheets) { const title = sheet.properties.title; const rows = sheet.properties.gridProperties.rowCount; const cols = sheet.properties.gridProperties.columnCount; console.log(`šŸ“Š Sheet: "${title}" (${rows} rows Ɨ ${cols} columns)`); } console.log("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); // Get data from first sheet const firstSheet = metadata.sheets[0].properties.title; const range = `${firstSheet}!A1:Z100`; // Get first 100 rows const dataUrl = `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}/values/${encodeURIComponent(range)}`; const data = await httpsRequest(dataUrl, { headers: { Authorization: `Bearer ${accessToken}` }, }); if (data.values && data.values.length > 0) { console.log(`šŸ“‹ First sheet data (${data.values.length} rows):\n`); // Print first 20 rows for (let i = 0; i < Math.min(20, data.values.length); i++) { const row = data.values[i]; if (row && row.length > 0) { console.log(`Row ${i + 1}: ${row.join(" | ")}`); } } if (data.values.length > 20) { console.log(`\n... and ${data.values.length - 20} more rows`); } } else { console.log("āš ļø No data found in first sheet"); } } main().catch((err) => { console.error("āŒ Error:", err.message); process.exit(1); });