@ariadng/sheets 0.4.1 → 0.4.2

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/cli.cjs CHANGED
@@ -185,7 +185,7 @@ var OAuthAuth = class {
185
185
  var crypto = __toESM(require("crypto"), 1);
186
186
  var fs = __toESM(require("fs/promises"), 1);
187
187
  var TOKEN_URI = "https://oauth2.googleapis.com/token";
188
- var SCOPE = "https://www.googleapis.com/auth/spreadsheets.readonly";
188
+ var SCOPE = "https://www.googleapis.com/auth/spreadsheets";
189
189
  var TOKEN_LIFETIME_SECONDS = 3600;
190
190
  var ServiceAccountAuth = class {
191
191
  config;
package/dist/cli.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/types/index.ts","../src/http/index.ts","../src/auth/constants.ts","../src/auth/oauth.ts","../src/auth/service-account.ts","../src/auth/user-auth.ts","../src/auth/index.ts","../src/api/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * Google Sheets CLI\n * Command-line interface for Google Sheets operations\n */\n\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { createClient } from './api/index.js';\nimport { login, loadStoredTokens, deleteTokens } from './auth/index.js';\nimport type { OAuthClientCredentials } from './auth/index.js';\nimport { SheetsError } from './types/index.js';\nimport type { AuthConfig, SheetProperties, RawCellValue } from './types/index.js';\n\nconst VERSION = '0.3.4';\n\n// Claude Skill content embedded in the CLI\nconst CLAUDE_SKILL_CONTENT = `---\nname: sheets\ndescription: Read data from Google Sheets spreadsheets. Use this skill when the user wants to fetch, read, or analyze data from a Google Sheets URL or spreadsheet ID.\n---\n\n# Google Sheets CLI\n\nUse \\`npx -y @ariadng/sheets\\` to read data from Google Sheets.\n\n**Important**: Always use \\`npx -y\\` to skip the installation confirmation prompt.\n\n## Authentication\n\nBefore reading spreadsheets, check if the user is logged in:\n\n\\`\\`\\`bash\nnpx -y @ariadng/sheets whoami\n\\`\\`\\`\n\nIf not logged in (exit code 1), ask the user to run:\n\n\\`\\`\\`bash\nnpx -y @ariadng/sheets login\n\\`\\`\\`\n\n## Extract Spreadsheet ID\n\nFrom a Google Sheets URL like:\n\\`https://docs.google.com/spreadsheets/d/SPREADSHEET_ID/edit\\`\n\nThe spreadsheet ID is the string between \\`/d/\\` and \\`/edit\\`.\n\n## Commands\n\n### Get spreadsheet metadata\n\\`\\`\\`bash\nnpx -y @ariadng/sheets get SPREADSHEET_ID --format json\n\\`\\`\\`\n\n### List all sheets\n\\`\\`\\`bash\nnpx -y @ariadng/sheets list SPREADSHEET_ID --format json\n\\`\\`\\`\n\n### Read cell values\n\\`\\`\\`bash\nnpx -y @ariadng/sheets read SPREADSHEET_ID \"Sheet1!A1:D10\" --format json\n\\`\\`\\`\n\n### Read formulas\n\\`\\`\\`bash\nnpx -y @ariadng/sheets read SPREADSHEET_ID \"Sheet1!A1:D10\" --formula --format json\n\\`\\`\\`\n\n### Read by sheet index (for emoji/special character sheet names)\n\\`\\`\\`bash\nnpx -y @ariadng/sheets read SPREADSHEET_ID \"A1:D10\" -i 0 --format json\n\\`\\`\\`\n\n### Read by gid (sheet ID from URL)\n\\`\\`\\`bash\nnpx -y @ariadng/sheets read SPREADSHEET_ID \"A1:D10\" --gid 123456789 --format json\n\\`\\`\\`\n\n## Handling Emoji/Special Character Sheet Names\n\nShell argument parsing can corrupt emoji characters. Use \\`-i\\` (sheet index) or \\`--gid\\` instead:\n\n1. First, list sheets to find the index and gid:\n\\`\\`\\`bash\nnpx -y @ariadng/sheets list SPREADSHEET_ID --format json\n\\`\\`\\`\n\n2. Then read using index or gid:\n\\`\\`\\`bash\n# By index (0-based)\nnpx -y @ariadng/sheets read SPREADSHEET_ID \"A1:D10\" -i 3 --format json\n\n# By gid (from URL #gid=... or list output)\nnpx -y @ariadng/sheets read SPREADSHEET_ID \"A1:D10\" --gid 745108136 --format json\n\\`\\`\\`\n\n### Write values\n\\`\\`\\`bash\n# Single value\nnpx -y @ariadng/sheets write SPREADSHEET_ID \"Sheet1!A1\" \"Hello\"\n\n# Formula\nnpx -y @ariadng/sheets write SPREADSHEET_ID \"Sheet1!B10\" \"=SUM(B1:B9)\"\n\n# JSON array (starting cell, expands automatically)\nnpx -y @ariadng/sheets write SPREADSHEET_ID \"Sheet1!A1\" '[[\"Name\",\"Age\"],[\"Alice\",30]]' --format json\n\n# From file\nnpx -y @ariadng/sheets write SPREADSHEET_ID \"A1\" -i 0 --input data.json --format json\n\n# Store formula as text (not computed)\nnpx -y @ariadng/sheets write SPREADSHEET_ID \"A1\" \"=SUM(A:A)\" --raw\n\\`\\`\\`\n\n### Append rows\n\\`\\`\\`bash\n# Append to table\nnpx -y @ariadng/sheets append SPREADSHEET_ID \"Sheet1!A:D\" '[[\"New Item\",10,5,\"=B2*C2\"]]' --format json\n\n# Insert rows (push existing down)\nnpx -y @ariadng/sheets append SPREADSHEET_ID \"Sheet1!A:A\" --insert-rows '[[\"Inserted\"]]' --format json\n\\`\\`\\`\n\n### Clear cell values\n\\`\\`\\`bash\n# Clear single range\nnpx -y @ariadng/sheets clear SPREADSHEET_ID \"Sheet1!A1:D10\" --format json\n\n# Clear multiple ranges\nnpx -y @ariadng/sheets clear SPREADSHEET_ID \"Sheet1!A1:B5\" \"Sheet2!C1:D5\" --format json\n\n# Clear by sheet index\nnpx -y @ariadng/sheets clear SPREADSHEET_ID \"A1:D10\" -i 0 --format json\n\\`\\`\\`\n\n### Search for values\n\\`\\`\\`bash\n# Search all sheets (case-insensitive, contains)\nnpx -y @ariadng/sheets search SPREADSHEET_ID \"search term\" --format json\n\n# Search specific range\nnpx -y @ariadng/sheets search SPREADSHEET_ID \"term\" \"Sheet1!A1:D100\" --format json\n\n# Search by sheet index\nnpx -y @ariadng/sheets search SPREADSHEET_ID \"term\" -i 0 --format json\n\n# Exact match\nnpx -y @ariadng/sheets search SPREADSHEET_ID \"exact value\" --exact --format json\n\n# Regex search\nnpx -y @ariadng/sheets search SPREADSHEET_ID \"[0-9]{3}-[0-9]{4}\" --regex --format json\n\n# Case-sensitive with limit\nnpx -y @ariadng/sheets search SPREADSHEET_ID \"Term\" --case-sensitive --limit 10 --format json\n\\`\\`\\`\n\n## Range Format\n\n- \\`Sheet1!A1:D10\\` - Cells A1 to D10 on Sheet1\n- \\`Sheet1!A:A\\` - Entire column A\n- \\`Sheet1!1:1\\` - Entire row 1\n- \\`A1:D10\\` - Range on first sheet (or use with -i/--gid)\n\n## Tips\n\n- Always use \\`npx -y\\` to avoid interactive prompts\n- Always use \\`--format json\\` for structured, parseable output\n- Use \\`-i\\` or \\`--gid\\` for sheets with emoji or special characters\n- Check authentication status before making requests\n- Handle errors gracefully and inform the user\n`;\n\ninterface CliOptions {\n credentials?: string;\n token?: string;\n client?: string;\n format: 'json' | 'table';\n formula: boolean;\n sheetIndex?: number;\n gid?: number;\n // Options for write/append\n input?: string; // File path or '-' for stdin\n raw?: boolean; // --raw flag\n byColumns?: boolean; // --by-columns flag\n insertRows?: boolean; // --insert-rows flag (append only)\n // Search options\n caseSensitive?: boolean; // --case-sensitive\n exact?: boolean; // --exact\n regex?: boolean; // --regex\n limit?: number; // --limit <n>\n}\n\nfunction parseArgs(args: string[]): { command: string; positionals: string[]; options: CliOptions } {\n const options: CliOptions = { format: 'table', formula: false };\n const positionals: string[] = [];\n let command = '';\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '--credentials' && args[i + 1]) {\n options.credentials = args[++i];\n } else if (arg === '--token' && args[i + 1]) {\n options.token = args[++i];\n } else if (arg === '--client' && args[i + 1]) {\n options.client = args[++i];\n } else if (arg === '--format' && args[i + 1]) {\n options.format = args[++i] as 'json' | 'table';\n } else if (arg === '--formula') {\n options.formula = true;\n } else if ((arg === '--sheet-index' || arg === '-i') && args[i + 1]) {\n options.sheetIndex = parseInt(args[++i], 10);\n } else if (arg === '--gid' && args[i + 1]) {\n options.gid = parseInt(args[++i], 10);\n } else if (arg === '--input' && args[i + 1]) {\n options.input = args[++i];\n } else if (arg === '--raw') {\n options.raw = true;\n } else if (arg === '--by-columns') {\n options.byColumns = true;\n } else if (arg === '--insert-rows') {\n options.insertRows = true;\n } else if (arg === '--case-sensitive') {\n options.caseSensitive = true;\n } else if (arg === '--exact') {\n options.exact = true;\n } else if (arg === '--regex') {\n options.regex = true;\n } else if (arg === '--limit' && args[i + 1]) {\n options.limit = parseInt(args[++i], 10);\n } else if (arg === '--version' || arg === '--help') {\n command = arg;\n } else if (!arg.startsWith('-')) {\n if (!command) {\n command = arg;\n } else {\n positionals.push(arg);\n }\n }\n }\n\n return { command, positionals, options };\n}\n\nfunction printHelp(): void {\n console.log(`\nGoogle Sheets CLI v${VERSION}\n\nUsage:\n sheets <command> [options]\n\nCommands:\n login Login with Google account\n logout Logout and remove stored tokens\n whoami Show current logged-in user\n auth <credentials-file> Test service account authentication\n get <spreadsheet-id> Get spreadsheet metadata\n list <spreadsheet-id> List sheets in a spreadsheet\n read <spreadsheet-id> <range> Read cell values\n write <spreadsheet-id> <range> [values] Write values to cells\n append <spreadsheet-id> <range> [values] Append rows to table\n clear <spreadsheet-id> <range> Clear cell values (preserves formatting)\n search <id> <query> [range] Search for values in cells\n install-claude-skill Install Claude Code skill\n\nOptions:\n --client <file> OAuth client JSON file (for login)\n --credentials <file> Service account JSON file\n --token <token> OAuth access token\n --format <json|table> Output format (default: table)\n --formula Show formulas instead of values\n --sheet-index, -i <n> Sheet index (use 'list' to see indexes)\n --gid <id> Sheet ID (from URL #gid=...)\n --input <file> Read values from JSON file (- for stdin)\n --raw Store values exactly (formulas as text)\n --by-columns Write data column-by-column\n --insert-rows Insert rows, push existing data down (append)\n --case-sensitive Case-sensitive search (default: insensitive)\n --exact Exact match only (default: contains)\n --regex Treat query as regular expression\n --limit <n> Maximum number of results to return\n --version Show version number\n --help Show help\n\nExamples:\n sheets login\n sheets login --client client_secret.json\n sheets get 1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms\n sheets read 1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms Sheet1!A1:D10\n sheets install-claude-skill\n`);\n}\n\nfunction printVersion(): void {\n console.log(VERSION);\n}\n\nfunction getRangeErrorSuggestions(errorMessage: string, range?: string): string[] {\n const suggestions: string[] = [];\n\n // Check for \"Unable to parse range\" errors\n if (errorMessage.includes('Unable to parse range')) {\n // Detect backslash escaping (shell issue)\n if (range && range.includes('\\\\')) {\n suggestions.push('Detected backslash in range - this may be caused by shell escaping.');\n suggestions.push('Try using single quotes around the entire command or avoid piping.');\n }\n\n // Check for special characters that need quoting\n if (range && (range.includes('[') || range.includes(']') || range.includes(' '))) {\n suggestions.push('Sheet names with brackets or spaces need proper quoting.');\n suggestions.push('Example: sheets read ID \"[Sheet Name]!A1:B10\"');\n }\n\n // General suggestions\n suggestions.push('Verify the sheet name matches exactly (including trailing spaces).');\n suggestions.push('Use: sheets list <spreadsheet-id> to see all sheet names.');\n }\n\n return suggestions;\n}\n\nasync function getAuthConfig(options: CliOptions): Promise<AuthConfig> {\n // Priority: --token > --credentials > stored user tokens\n if (options.token) {\n return { type: 'oauth', accessToken: options.token };\n }\n\n if (options.credentials) {\n return { type: 'service-account', credentialsPath: options.credentials };\n }\n\n // Check for stored user tokens\n const storedTokens = await loadStoredTokens();\n if (storedTokens) {\n return { type: 'user' };\n }\n\n throw new Error('Not authenticated. Run \"sheets login\" or use --credentials');\n}\n\n// === Login Commands ===\n\nasync function loadClientCredentials(clientPath: string): Promise<OAuthClientCredentials> {\n const content = await fs.readFile(clientPath, 'utf-8');\n const data = JSON.parse(content);\n\n // Support Google's client_secret JSON format\n const installed = data.installed || data.web;\n if (installed) {\n return {\n clientId: installed.client_id,\n clientSecret: installed.client_secret,\n };\n }\n\n // Support simple {clientId, clientSecret} format\n if (data.clientId && data.clientSecret) {\n return data as OAuthClientCredentials;\n }\n\n throw new Error('Invalid client credentials file');\n}\n\nasync function cmdLogin(options: CliOptions): Promise<void> {\n try {\n let credentials: OAuthClientCredentials | undefined;\n\n if (options.client) {\n credentials = await loadClientCredentials(options.client);\n }\n\n const tokens = await login(credentials);\n console.log(`\\nLogin successful! Logged in as ${tokens.email}`);\n } catch (error) {\n const e = error as Error;\n console.error(`Login failed: ${e.message}`);\n process.exit(1);\n }\n}\n\nasync function cmdLogout(): Promise<void> {\n await deleteTokens();\n console.log('Logged out successfully.');\n}\n\nasync function cmdWhoami(): Promise<void> {\n const tokens = await loadStoredTokens();\n\n if (!tokens) {\n console.log('Not logged in. Run \"sheets login\" to authenticate.');\n process.exit(1);\n }\n\n console.log(`Logged in as: ${tokens.email || 'Unknown'}`);\n const expiresAt = new Date(tokens.expiresAt);\n const isExpired = Date.now() >= tokens.expiresAt;\n console.log(`Token expires: ${expiresAt.toLocaleString()}${isExpired ? ' (expired, will refresh)' : ''}`);\n}\n\n// === Service Account Auth ===\n\nasync function cmdAuth(credentialsPath: string): Promise<void> {\n try {\n await fs.access(credentialsPath);\n const content = await fs.readFile(credentialsPath, 'utf-8');\n const credentials = JSON.parse(content);\n\n if (credentials.type !== 'service_account') {\n throw new Error('Invalid credentials file: expected service_account type');\n }\n\n const client = createClient({\n auth: { type: 'service-account', credentialsPath },\n });\n\n console.log('Testing authentication...');\n console.log(` Project: ${credentials.project_id}`);\n console.log(` Client Email: ${credentials.client_email}`);\n\n try {\n await client.getSpreadsheet('test-auth-only');\n } catch (error) {\n const e = error as { code?: number };\n if (e.code === 404 || e.code === 403) {\n console.log('\\nAuthentication successful!');\n return;\n }\n throw error;\n }\n } catch (error) {\n const e = error as Error;\n console.error(`Authentication failed: ${e.message}`);\n process.exit(1);\n }\n}\n\n// === Claude Skill Installation ===\n\nasync function cmdInstallClaudeSkill(): Promise<void> {\n const homeDir = os.homedir();\n const skillDir = path.join(homeDir, '.claude', 'skills', 'sheets');\n const skillFile = path.join(skillDir, 'SKILL.md');\n\n try {\n // Create the skill directory\n await fs.mkdir(skillDir, { recursive: true });\n\n // Write the skill file\n await fs.writeFile(skillFile, CLAUDE_SKILL_CONTENT, 'utf-8');\n\n console.log('Claude skill installed successfully!');\n console.log(`Location: ${skillFile}`);\n console.log('');\n console.log('You can now use /sheets in Claude Code to read Google Sheets data.');\n } catch (error) {\n const e = error as Error;\n console.error(`Failed to install Claude skill: ${e.message}`);\n process.exit(1);\n }\n}\n\n// === Spreadsheet Commands ===\n\nasync function cmdGet(spreadsheetId: string, options: CliOptions): Promise<void> {\n const authConfig = await getAuthConfig(options);\n const client = createClient({ auth: authConfig });\n\n const spreadsheet = await client.getSpreadsheet(spreadsheetId);\n\n if (options.format === 'json') {\n console.log(JSON.stringify(spreadsheet, null, 2));\n } else {\n console.log(`Title: ${spreadsheet.properties.title}`);\n console.log(`ID: ${spreadsheet.spreadsheetId}`);\n console.log(`Locale: ${spreadsheet.properties.locale || 'N/A'}`);\n console.log(`Timezone: ${spreadsheet.properties.timeZone || 'N/A'}`);\n console.log(`Sheets: ${spreadsheet.sheets.length}`);\n if (spreadsheet.spreadsheetUrl) {\n console.log(`URL: ${spreadsheet.spreadsheetUrl}`);\n }\n }\n}\n\nasync function cmdList(spreadsheetId: string, options: CliOptions): Promise<void> {\n const authConfig = await getAuthConfig(options);\n const client = createClient({ auth: authConfig });\n\n const sheets = await client.getSheets(spreadsheetId);\n\n if (options.format === 'json') {\n console.log(JSON.stringify(sheets, null, 2));\n } else {\n console.log('Sheets:');\n sheets.forEach((sheet: SheetProperties) => {\n const grid = sheet.gridProperties;\n const size = grid ? ` (${grid.rowCount} x ${grid.columnCount})` : '';\n const hidden = sheet.hidden ? ' [hidden]' : '';\n console.log(` ${sheet.index}. ${sheet.title}${size}${hidden}`);\n console.log(` gid: ${sheet.sheetId}`);\n });\n }\n}\n\nasync function cmdRead(spreadsheetId: string, range: string, options: CliOptions): Promise<void> {\n const authConfig = await getAuthConfig(options);\n const client = createClient({ auth: authConfig });\n\n // Resolve sheet name from index or gid if provided\n let resolvedRange = range;\n if (options.sheetIndex !== undefined || options.gid !== undefined) {\n const sheets = await client.getSheets(spreadsheetId);\n let targetSheet: SheetProperties | undefined;\n\n if (options.sheetIndex !== undefined) {\n targetSheet = sheets.find(s => s.index === options.sheetIndex);\n if (!targetSheet) {\n throw new Error(`Sheet index ${options.sheetIndex} not found. Use 'sheets list' to see available sheets.`);\n }\n } else if (options.gid !== undefined) {\n targetSheet = sheets.find(s => s.sheetId === options.gid);\n if (!targetSheet) {\n throw new Error(`Sheet with gid ${options.gid} not found. Use 'sheets list' to see available sheets.`);\n }\n }\n\n if (targetSheet) {\n // Escape single quotes in sheet name and wrap in quotes\n const escapedTitle = targetSheet.title.replace(/'/g, \"''\");\n resolvedRange = `'${escapedTitle}'!${range}`;\n }\n }\n\n const valueRange = options.formula\n ? await client.getFormulas(spreadsheetId, resolvedRange)\n : await client.getValues(spreadsheetId, resolvedRange);\n\n if (options.format === 'json') {\n console.log(JSON.stringify(valueRange, null, 2));\n } else {\n console.log(`Range: ${valueRange.range}`);\n console.log('');\n\n if (valueRange.values.length === 0) {\n console.log('(empty)');\n return;\n }\n\n // Calculate column widths\n const colWidths: number[] = [];\n valueRange.values.forEach(row => {\n row.forEach((cell, i) => {\n const len = String(cell.value ?? '').length;\n colWidths[i] = Math.max(colWidths[i] || 0, len, 3);\n });\n });\n\n // Print table\n valueRange.values.forEach(row => {\n const cells = row.map((cell, i) => {\n const val = String(cell.value ?? '');\n return val.padEnd(colWidths[i]);\n });\n console.log(cells.join(' | '));\n });\n }\n}\n\nasync function cmdClear(spreadsheetId: string, ranges: string[], options: CliOptions): Promise<void> {\n const authConfig = await getAuthConfig(options);\n const client = createClient({ auth: authConfig });\n\n // Resolve sheet name from index or gid if provided\n let resolvedRanges = ranges;\n if (options.sheetIndex !== undefined || options.gid !== undefined) {\n const sheets = await client.getSheets(spreadsheetId);\n let targetSheet: SheetProperties | undefined;\n\n if (options.sheetIndex !== undefined) {\n targetSheet = sheets.find(s => s.index === options.sheetIndex);\n if (!targetSheet) {\n throw new Error(`Sheet index ${options.sheetIndex} not found. Use 'sheets list' to see available sheets.`);\n }\n } else if (options.gid !== undefined) {\n targetSheet = sheets.find(s => s.sheetId === options.gid);\n if (!targetSheet) {\n throw new Error(`Sheet with gid ${options.gid} not found. Use 'sheets list' to see available sheets.`);\n }\n }\n\n if (targetSheet) {\n // Escape single quotes in sheet name and wrap in quotes\n const escapedTitle = targetSheet.title.replace(/'/g, \"''\");\n resolvedRanges = ranges.map(range => `'${escapedTitle}'!${range}`);\n }\n }\n\n const result = await client.batchClearValues(spreadsheetId, resolvedRanges);\n\n if (options.format === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log('Cleared ranges:');\n result.clearedRanges.forEach(range => {\n console.log(` - ${range}`);\n });\n }\n}\n\nasync function parseWriteValues(\n valuesArg: string | undefined,\n inputPath: string | undefined\n): Promise<RawCellValue[][]> {\n let jsonStr: string;\n\n if (inputPath) {\n if (inputPath === '-') {\n // Read from stdin\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk);\n }\n jsonStr = Buffer.concat(chunks).toString('utf-8').trim();\n } else {\n jsonStr = await fs.readFile(inputPath, 'utf-8');\n }\n } else if (valuesArg) {\n jsonStr = valuesArg;\n } else {\n throw new Error('No values provided. Use inline JSON or --input <file>');\n }\n\n // Try to parse as JSON array\n try {\n const parsed = JSON.parse(jsonStr);\n\n // If it's a 2D array, return as-is\n if (Array.isArray(parsed) && (parsed.length === 0 || Array.isArray(parsed[0]))) {\n return parsed;\n }\n\n // If it's a 1D array, wrap it\n if (Array.isArray(parsed)) {\n return [parsed];\n }\n\n // Single value\n return [[parsed]];\n } catch {\n // Not JSON - treat as single string value\n return [[jsonStr]];\n }\n}\n\nasync function cmdWrite(\n spreadsheetId: string,\n range: string,\n valuesArg: string | undefined,\n options: CliOptions\n): Promise<void> {\n const authConfig = await getAuthConfig(options);\n const client = createClient({ auth: authConfig });\n\n // Resolve sheet name from index or gid if provided\n let resolvedRange = range;\n if (options.sheetIndex !== undefined || options.gid !== undefined) {\n const sheets = await client.getSheets(spreadsheetId);\n let targetSheet: SheetProperties | undefined;\n\n if (options.sheetIndex !== undefined) {\n targetSheet = sheets.find(s => s.index === options.sheetIndex);\n if (!targetSheet) {\n throw new Error(`Sheet index ${options.sheetIndex} not found.`);\n }\n } else if (options.gid !== undefined) {\n targetSheet = sheets.find(s => s.sheetId === options.gid);\n if (!targetSheet) {\n throw new Error(`Sheet with gid ${options.gid} not found.`);\n }\n }\n\n if (targetSheet) {\n const escapedTitle = targetSheet.title.replace(/'/g, \"''\");\n resolvedRange = `'${escapedTitle}'!${range}`;\n }\n }\n\n const values = await parseWriteValues(valuesArg, options.input);\n\n const result = await client.updateValues(spreadsheetId, resolvedRange, values, {\n valueInputOption: options.raw ? 'RAW' : 'USER_ENTERED',\n majorDimension: options.byColumns ? 'COLUMNS' : 'ROWS',\n });\n\n if (options.format === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(`Updated: ${result.updatedRange}`);\n console.log(` Rows: ${result.updatedRows}`);\n console.log(` Columns: ${result.updatedColumns}`);\n console.log(` Cells: ${result.updatedCells}`);\n }\n}\n\nasync function cmdAppend(\n spreadsheetId: string,\n range: string,\n valuesArg: string | undefined,\n options: CliOptions\n): Promise<void> {\n const authConfig = await getAuthConfig(options);\n const client = createClient({ auth: authConfig });\n\n // Resolve sheet name from index or gid\n let resolvedRange = range;\n if (options.sheetIndex !== undefined || options.gid !== undefined) {\n const sheets = await client.getSheets(spreadsheetId);\n let targetSheet: SheetProperties | undefined;\n\n if (options.sheetIndex !== undefined) {\n targetSheet = sheets.find(s => s.index === options.sheetIndex);\n if (!targetSheet) {\n throw new Error(`Sheet index ${options.sheetIndex} not found.`);\n }\n } else if (options.gid !== undefined) {\n targetSheet = sheets.find(s => s.sheetId === options.gid);\n if (!targetSheet) {\n throw new Error(`Sheet with gid ${options.gid} not found.`);\n }\n }\n\n if (targetSheet) {\n const escapedTitle = targetSheet.title.replace(/'/g, \"''\");\n resolvedRange = `'${escapedTitle}'!${range}`;\n }\n }\n\n const values = await parseWriteValues(valuesArg, options.input);\n\n const result = await client.appendValues(spreadsheetId, resolvedRange, values, {\n valueInputOption: options.raw ? 'RAW' : 'USER_ENTERED',\n majorDimension: options.byColumns ? 'COLUMNS' : 'ROWS',\n insertDataOption: options.insertRows ? 'INSERT_ROWS' : 'OVERWRITE',\n });\n\n if (options.format === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(`Appended to: ${result.updates.updatedRange}`);\n if (result.tableRange) {\n console.log(` Table range: ${result.tableRange}`);\n }\n console.log(` Rows: ${result.updates.updatedRows}`);\n console.log(` Columns: ${result.updates.updatedColumns}`);\n console.log(` Cells: ${result.updates.updatedCells}`);\n }\n}\n\nasync function cmdSearch(\n spreadsheetId: string,\n query: string,\n range: string | undefined,\n options: CliOptions\n): Promise<void> {\n const authConfig = await getAuthConfig(options);\n const client = createClient({ auth: authConfig });\n\n const result = await client.searchValues(spreadsheetId, query, {\n range,\n sheetIndex: options.sheetIndex,\n gid: options.gid,\n caseSensitive: options.caseSensitive,\n exactMatch: options.exact,\n regex: options.regex,\n limit: options.limit,\n });\n\n if (options.format === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (result.matches.length === 0) {\n console.log(`No matches found for \"${query}\"`);\n return;\n }\n\n console.log(`Found ${result.totalMatches} match${result.totalMatches === 1 ? '' : 'es'} for \"${query}\":`);\n console.log('');\n\n // Calculate column widths\n const headers = ['Sheet', 'Address', 'Row', 'Col', 'Value'];\n const colWidths = headers.map(h => h.length);\n\n result.matches.forEach(m => {\n colWidths[0] = Math.max(colWidths[0], m.sheet.length);\n colWidths[1] = Math.max(colWidths[1], m.address.length);\n colWidths[2] = Math.max(colWidths[2], String(m.row).length);\n colWidths[3] = Math.max(colWidths[3], String(m.column).length);\n const valueStr = String(m.value ?? '').substring(0, 50);\n colWidths[4] = Math.max(colWidths[4], valueStr.length);\n });\n\n // Print header\n console.log(headers.map((h, i) => h.padEnd(colWidths[i])).join(' | '));\n console.log(colWidths.map(w => '-'.repeat(w)).join('-+-'));\n\n // Print matches\n result.matches.forEach(m => {\n const valueStr = String(m.value ?? '').substring(0, 50);\n const row = [\n m.sheet.padEnd(colWidths[0]),\n m.address.padEnd(colWidths[1]),\n String(m.row).padEnd(colWidths[2]),\n String(m.column).padEnd(colWidths[3]),\n valueStr.padEnd(colWidths[4]),\n ];\n console.log(row.join(' | '));\n });\n }\n}\n\n// === Main ===\n\nasync function main(): Promise<void> {\n const { command, positionals, options } = parseArgs(process.argv.slice(2));\n\n if (!command || command === 'help' || command === '--help') {\n printHelp();\n return;\n }\n\n if (command === '--version') {\n printVersion();\n return;\n }\n\n try {\n switch (command) {\n case 'login':\n await cmdLogin(options);\n break;\n\n case 'logout':\n await cmdLogout();\n break;\n\n case 'whoami':\n await cmdWhoami();\n break;\n\n case 'auth': {\n const credentialsPath = positionals[0];\n if (!credentialsPath) {\n console.error('Usage: sheets auth <credentials-file>');\n process.exit(1);\n }\n await cmdAuth(credentialsPath);\n break;\n }\n\n case 'get': {\n const spreadsheetId = positionals[0];\n if (!spreadsheetId) {\n console.error('Usage: sheets get <spreadsheet-id>');\n process.exit(1);\n }\n await cmdGet(spreadsheetId, options);\n break;\n }\n\n case 'list': {\n const spreadsheetId = positionals[0];\n if (!spreadsheetId) {\n console.error('Usage: sheets list <spreadsheet-id>');\n process.exit(1);\n }\n await cmdList(spreadsheetId, options);\n break;\n }\n\n case 'read': {\n const spreadsheetId = positionals[0];\n const range = positionals[1];\n if (!spreadsheetId || !range) {\n console.error('Usage: sheets read <spreadsheet-id> <range>');\n process.exit(1);\n }\n await cmdRead(spreadsheetId, range, options);\n break;\n }\n\n case 'write': {\n const spreadsheetId = positionals[0];\n const range = positionals[1];\n const values = positionals[2];\n if (!spreadsheetId || !range) {\n console.error('Usage: sheets write <spreadsheet-id> <range> [values]');\n console.error(' sheets write <id> <range> --input <file>');\n process.exit(1);\n }\n await cmdWrite(spreadsheetId, range, values, options);\n break;\n }\n\n case 'append': {\n const spreadsheetId = positionals[0];\n const range = positionals[1];\n const values = positionals[2];\n if (!spreadsheetId || !range) {\n console.error('Usage: sheets append <spreadsheet-id> <range> [values]');\n console.error(' sheets append <id> <range> --input <file>');\n process.exit(1);\n }\n await cmdAppend(spreadsheetId, range, values, options);\n break;\n }\n\n case 'clear': {\n const spreadsheetId = positionals[0];\n const ranges = positionals.slice(1);\n if (!spreadsheetId || ranges.length === 0) {\n console.error('Usage: sheets clear <spreadsheet-id> <range> [range2] [range3] ...');\n process.exit(1);\n }\n await cmdClear(spreadsheetId, ranges, options);\n break;\n }\n\n case 'search': {\n const spreadsheetId = positionals[0];\n const query = positionals[1];\n const range = positionals[2];\n if (!spreadsheetId || !query) {\n console.error('Usage: sheets search <spreadsheet-id> <query> [range]');\n console.error(' sheets search <id> \"search term\" \"Sheet1!A1:D100\"');\n process.exit(1);\n }\n await cmdSearch(spreadsheetId, query, range, options);\n break;\n }\n\n case 'install-claude-skill':\n await cmdInstallClaudeSkill();\n break;\n\n default:\n console.error(`Unknown command: ${command}`);\n printHelp();\n process.exit(1);\n }\n } catch (error) {\n const e = error as Error;\n console.error(`Error: ${e.message}`);\n\n // Check if this is a SheetsError with additional context\n if (e.name === 'SheetsError') {\n const sheetsErr = e as SheetsError;\n if (sheetsErr.status) {\n console.error(`Status: ${sheetsErr.status}`);\n }\n }\n\n // Get the range from positionals if available\n const range = positionals[1];\n const suggestions = getRangeErrorSuggestions(e.message, range);\n\n if (suggestions.length > 0) {\n console.error('');\n console.error('Suggestions:');\n suggestions.forEach(s => console.error(` - ${s}`));\n }\n\n process.exit(1);\n }\n}\n\nmain();\n","/**\n * Google Sheets API Type Definitions\n */\n\n// === Grid Properties ===\n\nexport interface GridProperties {\n rowCount: number;\n columnCount: number;\n frozenRowCount?: number;\n frozenColumnCount?: number;\n hideGridlines?: boolean;\n}\n\n// === Sheet Properties ===\n\nexport interface SheetProperties {\n sheetId: number;\n title: string;\n index: number;\n sheetType?: 'GRID' | 'OBJECT' | 'DATA_SOURCE';\n gridProperties?: GridProperties;\n hidden?: boolean;\n rightToLeft?: boolean;\n}\n\n// === Spreadsheet ===\n\nexport interface SpreadsheetProperties {\n title: string;\n locale?: string;\n timeZone?: string;\n autoRecalc?: 'ON_CHANGE' | 'MINUTE' | 'HOUR';\n defaultFormat?: CellFormat;\n}\n\nexport interface Spreadsheet {\n spreadsheetId: string;\n properties: SpreadsheetProperties;\n sheets: { properties: SheetProperties }[];\n spreadsheetUrl?: string;\n}\n\n// === Cell Format ===\n\nexport interface CellFormat {\n numberFormat?: {\n type: string;\n pattern?: string;\n };\n backgroundColor?: Color;\n textFormat?: TextFormat;\n}\n\nexport interface Color {\n red?: number;\n green?: number;\n blue?: number;\n alpha?: number;\n}\n\nexport interface TextFormat {\n foregroundColor?: Color;\n fontFamily?: string;\n fontSize?: number;\n bold?: boolean;\n italic?: boolean;\n strikethrough?: boolean;\n underline?: boolean;\n}\n\n// === Cell Value ===\n\nexport interface CellValue {\n value: string | number | boolean | null;\n formula?: string;\n formattedValue?: string;\n}\n\n// === Value Range ===\n\nexport type ValueRenderOption = 'FORMATTED_VALUE' | 'UNFORMATTED_VALUE' | 'FORMULA';\nexport type DateTimeRenderOption = 'SERIAL_NUMBER' | 'FORMATTED_STRING';\nexport type MajorDimension = 'ROWS' | 'COLUMNS';\n\nexport interface ValueRange {\n range: string;\n majorDimension: MajorDimension;\n values: CellValue[][];\n}\n\nexport interface GetValuesOptions {\n valueRenderOption?: ValueRenderOption;\n dateTimeRenderOption?: DateTimeRenderOption;\n majorDimension?: MajorDimension;\n}\n\nexport interface BatchGetValuesResponse {\n spreadsheetId: string;\n valueRanges: ValueRange[];\n}\n\n// === Clear Values ===\n\nexport interface ClearValuesResponse {\n spreadsheetId: string;\n clearedRange: string;\n}\n\nexport interface BatchClearValuesResponse {\n spreadsheetId: string;\n clearedRanges: string[];\n}\n\n// === Write Values ===\n\nexport type ValueInputOption = 'RAW' | 'USER_ENTERED';\nexport type InsertDataOption = 'OVERWRITE' | 'INSERT_ROWS';\nexport type RawCellValue = string | number | boolean | null;\n\nexport interface UpdateValuesOptions {\n valueInputOption?: ValueInputOption;\n majorDimension?: MajorDimension;\n includeValuesInResponse?: boolean;\n responseValueRenderOption?: ValueRenderOption;\n responseDateTimeRenderOption?: DateTimeRenderOption;\n}\n\nexport interface AppendValuesOptions extends UpdateValuesOptions {\n insertDataOption?: InsertDataOption;\n}\n\nexport interface UpdateValuesResponse {\n spreadsheetId: string;\n updatedRange: string;\n updatedRows: number;\n updatedColumns: number;\n updatedCells: number;\n updatedData?: ValueRange;\n}\n\nexport interface BatchUpdateValuesResponse {\n spreadsheetId: string;\n totalUpdatedRows: number;\n totalUpdatedColumns: number;\n totalUpdatedCells: number;\n totalUpdatedSheets: number;\n responses: UpdateValuesResponse[];\n}\n\nexport interface AppendValuesResponse {\n spreadsheetId: string;\n tableRange?: string;\n updates: UpdateValuesResponse;\n}\n\n// === Search Values ===\n\nexport interface SearchMatch {\n sheet: string;\n sheetId: number;\n address: string;\n row: number;\n column: number;\n value: string | number | boolean | null;\n}\n\nexport interface SearchOptions {\n range?: string;\n sheetIndex?: number;\n gid?: number;\n caseSensitive?: boolean;\n exactMatch?: boolean;\n regex?: boolean;\n limit?: number;\n}\n\nexport interface SearchResult {\n query: string;\n matchType: 'contains' | 'exact' | 'regex';\n caseSensitive: boolean;\n totalMatches: number;\n matches: SearchMatch[];\n}\n\n// === Authentication ===\n\nexport interface OAuthConfig {\n type: 'oauth';\n accessToken: string;\n refreshToken?: string;\n clientId?: string;\n clientSecret?: string;\n expiresAt?: number; // Unix timestamp in ms when access token expires\n}\n\nexport interface ServiceAccountConfig {\n type: 'service-account';\n credentialsPath?: string;\n credentials?: ServiceAccountCredentials;\n}\n\nexport interface ServiceAccountCredentials {\n type: 'service_account';\n project_id: string;\n private_key_id: string;\n private_key: string;\n client_email: string;\n client_id: string;\n auth_uri: string;\n token_uri: string;\n}\n\nexport interface UserAuthConfig {\n type: 'user';\n}\n\nexport interface StoredTokens {\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n email?: string;\n}\n\nexport type AuthConfig = OAuthConfig | ServiceAccountConfig | UserAuthConfig;\n\nexport interface SheetsClientOptions {\n auth: AuthConfig;\n}\n\n// === Error Types ===\n\nexport interface SheetsApiErrorDetail {\n '@type'?: string;\n reason?: string;\n domain?: string;\n metadata?: Record<string, string>;\n}\n\nexport interface SheetsApiError {\n code: number;\n message: string;\n status: string;\n details?: SheetsApiErrorDetail[];\n}\n\nexport class SheetsError extends Error {\n code: number;\n status: string;\n details?: SheetsApiErrorDetail[];\n\n constructor(error: SheetsApiError) {\n super(error.message);\n this.name = 'SheetsError';\n this.code = error.code;\n this.status = error.status;\n this.details = error.details;\n }\n}\n","/**\n * HTTP Client for Google Sheets API\n * Uses native Node.js fetch (Node 18+)\n */\n\nimport { SheetsError } from '../types/index.js';\n\nconst BASE_URL = 'https://sheets.googleapis.com/v4';\nconst MAX_RETRIES = 3;\nconst INITIAL_BACKOFF_MS = 1000;\n\nexport interface HttpClientOptions {\n getAccessToken: () => Promise<string>;\n}\n\nexport interface RequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\n body?: unknown;\n params?: Record<string, string>;\n}\n\nexport class HttpClient {\n private getAccessToken: () => Promise<string>;\n\n constructor(options: HttpClientOptions) {\n this.getAccessToken = options.getAccessToken;\n }\n\n async request<T>(path: string, options: RequestOptions = {}): Promise<T> {\n const { method = 'GET', body, params } = options;\n\n let url = `${BASE_URL}${path}`;\n if (params) {\n const searchParams = new URLSearchParams(params);\n url += `?${searchParams.toString()}`;\n }\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n const accessToken = await this.getAccessToken();\n\n const response = await fetch(url, {\n method,\n headers: {\n 'Authorization': `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (response.status === 429) {\n const backoffMs = INITIAL_BACKOFF_MS * Math.pow(2, attempt);\n await this.sleep(backoffMs);\n continue;\n }\n\n const data = await response.json() as { error?: { code: number; message: string; status: string } };\n\n if (!response.ok) {\n if (data.error) {\n throw new SheetsError({\n code: data.error.code,\n message: data.error.message,\n status: data.error.status,\n });\n }\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return data as T;\n } catch (error) {\n lastError = error as Error;\n\n if (error instanceof SheetsError && error.code !== 429 && error.code !== 500 && error.code !== 503) {\n throw error;\n }\n\n if (attempt < MAX_RETRIES - 1) {\n const backoffMs = INITIAL_BACKOFF_MS * Math.pow(2, attempt);\n await this.sleep(backoffMs);\n }\n }\n }\n\n throw lastError || new Error('Request failed after retries');\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}\n","/**\n * OAuth Client Constants\n * Replace with your Google Cloud OAuth client credentials\n */\n\n// Built-in OAuth client (Desktop app type)\n// Project: ariadng-sheets\nexport const OAUTH_CLIENT_ID = '344941894490-jmdvo5ghomqi7vuisfrf80hfassk1ma5.apps.googleusercontent.com';\nexport const OAUTH_CLIENT_SECRET = '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';\n\n// Redirect URI for local callback server\nexport const OAUTH_REDIRECT_URI = 'http://localhost:8085/callback';\nexport const OAUTH_CALLBACK_PORT = 8085;\n\n// OAuth endpoints\nexport const OAUTH_AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth';\nexport const OAUTH_TOKEN_URL = 'https://oauth2.googleapis.com/token';\nexport const OAUTH_USERINFO_URL = 'https://www.googleapis.com/oauth2/v2/userinfo';\n\n// Scopes\nexport const OAUTH_SCOPES = [\n 'https://www.googleapis.com/auth/spreadsheets',\n 'https://www.googleapis.com/auth/userinfo.email',\n];\n","/**\n * OAuth 2.0 Authentication\n * Supports pre-obtained access tokens with optional auto-refresh\n *\n * For automation (e.g., n8n), provide:\n * - accessToken: Current access token\n * - refreshToken: For obtaining new tokens when expired\n * - clientId: OAuth client ID\n * - clientSecret: OAuth client secret\n * - expiresAt: When the access token expires (Unix timestamp in ms)\n */\n\nimport type { OAuthConfig } from '../types/index.js';\nimport { OAUTH_TOKEN_URL } from './constants.js';\n\ninterface TokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n token_type: string;\n}\n\nexport class OAuthAuth {\n private config: OAuthConfig;\n private cachedToken: string;\n private expiresAt: number;\n\n constructor(config: OAuthConfig) {\n this.config = config;\n this.cachedToken = config.accessToken;\n this.expiresAt = config.expiresAt || 0;\n }\n\n async getAccessToken(): Promise<string> {\n // If no expiration tracking or no refresh credentials, return cached token\n if (!this.canRefresh()) {\n return this.cachedToken;\n }\n\n // Check if token is expired (with 60 second buffer)\n if (this.isExpired()) {\n await this.refreshToken();\n }\n\n return this.cachedToken;\n }\n\n private canRefresh(): boolean {\n return !!(\n this.config.refreshToken &&\n this.config.clientId &&\n this.config.clientSecret &&\n this.expiresAt > 0\n );\n }\n\n private isExpired(): boolean {\n return Date.now() >= this.expiresAt - 60000;\n }\n\n private async refreshToken(): Promise<void> {\n if (!this.config.refreshToken || !this.config.clientId || !this.config.clientSecret) {\n throw new Error('Token expired and missing refresh credentials (refreshToken, clientId, clientSecret)');\n }\n\n const response = await fetch(OAUTH_TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n client_id: this.config.clientId,\n client_secret: this.config.clientSecret,\n refresh_token: this.config.refreshToken,\n grant_type: 'refresh_token',\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Token refresh failed: ${error}`);\n }\n\n const tokenResponse = await response.json() as TokenResponse;\n\n this.cachedToken = tokenResponse.access_token;\n this.expiresAt = Date.now() + (tokenResponse.expires_in * 1000);\n\n // Update config with new refresh token if provided\n if (tokenResponse.refresh_token) {\n this.config.refreshToken = tokenResponse.refresh_token;\n }\n }\n\n /**\n * Get current token state for persistence in automation tools\n * Returns updated tokens after any refresh operations\n */\n getTokenState(): { accessToken: string; refreshToken?: string; expiresAt: number } {\n return {\n accessToken: this.cachedToken,\n refreshToken: this.config.refreshToken,\n expiresAt: this.expiresAt,\n };\n }\n}\n","/**\n * Service Account JWT Authentication\n * Uses RS256 signing to exchange JWT for access token\n */\n\nimport * as crypto from 'crypto';\nimport * as fs from 'fs/promises';\nimport type { ServiceAccountConfig, ServiceAccountCredentials } from '../types/index.js';\n\nconst TOKEN_URI = 'https://oauth2.googleapis.com/token';\nconst SCOPE = 'https://www.googleapis.com/auth/spreadsheets.readonly';\nconst TOKEN_LIFETIME_SECONDS = 3600;\n\ninterface TokenResponse {\n access_token: string;\n expires_in: number;\n token_type: string;\n}\n\nexport class ServiceAccountAuth {\n private config: ServiceAccountConfig;\n private credentials: ServiceAccountCredentials | null = null;\n private cachedToken: string | null = null;\n private tokenExpiresAt: number = 0;\n\n constructor(config: ServiceAccountConfig) {\n this.config = config;\n }\n\n async getAccessToken(): Promise<string> {\n if (this.cachedToken && Date.now() < this.tokenExpiresAt - 60000) {\n return this.cachedToken;\n }\n\n await this.loadCredentials();\n const jwt = this.createJwt();\n const token = await this.exchangeJwtForToken(jwt);\n\n this.cachedToken = token.access_token;\n this.tokenExpiresAt = Date.now() + (token.expires_in * 1000);\n\n return this.cachedToken;\n }\n\n private async loadCredentials(): Promise<void> {\n if (this.credentials) return;\n\n if (this.config.credentials) {\n this.credentials = this.config.credentials;\n return;\n }\n\n if (!this.config.credentialsPath) {\n throw new Error('Service account requires credentialsPath or credentials');\n }\n\n const content = await fs.readFile(this.config.credentialsPath, 'utf-8');\n this.credentials = JSON.parse(content) as ServiceAccountCredentials;\n }\n\n private createJwt(): string {\n if (!this.credentials) {\n throw new Error('Credentials not loaded');\n }\n\n const now = Math.floor(Date.now() / 1000);\n\n const header = {\n alg: 'RS256',\n typ: 'JWT',\n };\n\n const payload = {\n iss: this.credentials.client_email,\n scope: SCOPE,\n aud: TOKEN_URI,\n iat: now,\n exp: now + TOKEN_LIFETIME_SECONDS,\n };\n\n const encodedHeader = this.base64UrlEncode(JSON.stringify(header));\n const encodedPayload = this.base64UrlEncode(JSON.stringify(payload));\n const signatureInput = `${encodedHeader}.${encodedPayload}`;\n\n const sign = crypto.createSign('RSA-SHA256');\n sign.update(signatureInput);\n const signature = sign.sign(this.credentials.private_key);\n const encodedSignature = this.base64UrlEncode(signature);\n\n return `${signatureInput}.${encodedSignature}`;\n }\n\n private base64UrlEncode(input: string | Buffer): string {\n const buffer = typeof input === 'string' ? Buffer.from(input) : input;\n return buffer.toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n }\n\n private async exchangeJwtForToken(jwt: string): Promise<TokenResponse> {\n const response = await fetch(TOKEN_URI, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',\n assertion: jwt,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Token exchange failed: ${error}`);\n }\n\n return await response.json() as TokenResponse;\n }\n}\n","/**\n * User OAuth Authentication\n * OAuth 2.0 Authorization Code flow with PKCE for personal Google accounts\n */\n\nimport * as crypto from 'crypto';\nimport * as fs from 'fs/promises';\nimport * as http from 'http';\nimport * as os from 'os';\nimport * as path from 'path';\nimport { exec } from 'child_process';\nimport type { StoredTokens } from '../types/index.js';\nimport {\n OAUTH_CLIENT_ID,\n OAUTH_CLIENT_SECRET,\n OAUTH_REDIRECT_URI,\n OAUTH_CALLBACK_PORT,\n OAUTH_AUTH_URL,\n OAUTH_TOKEN_URL,\n OAUTH_USERINFO_URL,\n OAUTH_SCOPES,\n} from './constants.js';\n\nexport interface OAuthClientCredentials {\n clientId: string;\n clientSecret: string;\n}\n\nconst CONFIG_DIR = path.join(os.homedir(), '.sheets');\nconst TOKENS_FILE = path.join(CONFIG_DIR, 'tokens.json');\n\n// === PKCE ===\n\ninterface PKCEPair {\n codeVerifier: string;\n codeChallenge: string;\n}\n\nexport function generatePKCE(): PKCEPair {\n const codeVerifier = crypto.randomBytes(32).toString('base64url');\n const codeChallenge = crypto\n .createHash('sha256')\n .update(codeVerifier)\n .digest('base64url');\n return { codeVerifier, codeChallenge };\n}\n\n// === Browser ===\n\nfunction openBrowser(url: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const platform = process.platform;\n let command: string;\n\n if (platform === 'darwin') {\n command = `open \"${url}\"`;\n } else if (platform === 'win32') {\n command = `start \"\" \"${url}\"`;\n } else {\n command = `xdg-open \"${url}\"`;\n }\n\n exec(command, (error) => {\n if (error) {\n reject(new Error(`Failed to open browser: ${error.message}`));\n } else {\n resolve();\n }\n });\n });\n}\n\n// === Callback Server ===\n\nfunction startCallbackServer(): Promise<string> {\n return new Promise((resolve, reject) => {\n let timeoutId: NodeJS.Timeout;\n\n const server = http.createServer((req, res) => {\n const url = new URL(req.url || '', `http://localhost:${OAUTH_CALLBACK_PORT}`);\n\n if (url.pathname === '/callback') {\n const code = url.searchParams.get('code');\n const error = url.searchParams.get('error');\n\n if (error) {\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end('<html><body><h1>Authorization Failed</h1><p>You can close this window.</p></body></html>');\n clearTimeout(timeoutId);\n server.close();\n reject(new Error(`Authorization error: ${error}`));\n return;\n }\n\n if (code) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('<html><body><h1>Authorization Successful</h1><p>You can close this window.</p></body></html>');\n clearTimeout(timeoutId);\n server.close();\n resolve(code);\n return;\n }\n\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end('<html><body><h1>Missing Code</h1></body></html>');\n } else {\n res.writeHead(404);\n res.end();\n }\n });\n\n server.on('error', (err) => {\n clearTimeout(timeoutId);\n reject(new Error(`Callback server error: ${err.message}`));\n });\n\n server.listen(OAUTH_CALLBACK_PORT, () => {\n // Server started, waiting for callback\n });\n\n // Timeout after 5 minutes\n timeoutId = setTimeout(() => {\n server.close();\n reject(new Error('Authorization timeout'));\n }, 5 * 60 * 1000);\n });\n}\n\n// === Authorization URL ===\n\nexport function getAuthorizationUrl(codeChallenge: string, clientId?: string): string {\n const params = new URLSearchParams({\n client_id: clientId || OAUTH_CLIENT_ID,\n redirect_uri: OAUTH_REDIRECT_URI,\n response_type: 'code',\n scope: OAUTH_SCOPES.join(' '),\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n access_type: 'offline',\n prompt: 'consent',\n });\n\n return `${OAUTH_AUTH_URL}?${params.toString()}`;\n}\n\n// === Token Exchange ===\n\ninterface TokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n token_type: string;\n}\n\nasync function exchangeCodeForTokens(code: string, codeVerifier: string, credentials?: OAuthClientCredentials): Promise<TokenResponse> {\n const response = await fetch(OAUTH_TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n client_id: credentials?.clientId || OAUTH_CLIENT_ID,\n client_secret: credentials?.clientSecret || OAUTH_CLIENT_SECRET,\n code,\n code_verifier: codeVerifier,\n grant_type: 'authorization_code',\n redirect_uri: OAUTH_REDIRECT_URI,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Token exchange failed: ${error}`);\n }\n\n return await response.json() as TokenResponse;\n}\n\nasync function refreshAccessToken(refreshToken: string): Promise<TokenResponse> {\n const response = await fetch(OAUTH_TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n client_id: OAUTH_CLIENT_ID,\n client_secret: OAUTH_CLIENT_SECRET,\n refresh_token: refreshToken,\n grant_type: 'refresh_token',\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Token refresh failed: ${error}`);\n }\n\n return await response.json() as TokenResponse;\n}\n\n// === User Info ===\n\ninterface UserInfo {\n email: string;\n id: string;\n}\n\nasync function getUserInfo(accessToken: string): Promise<UserInfo> {\n const response = await fetch(OAUTH_USERINFO_URL, {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n\n if (!response.ok) {\n throw new Error('Failed to get user info');\n }\n\n return await response.json() as UserInfo;\n}\n\n// === Token Storage ===\n\nasync function ensureConfigDir(): Promise<void> {\n try {\n await fs.mkdir(CONFIG_DIR, { recursive: true });\n } catch {\n // Directory already exists\n }\n}\n\nexport async function loadStoredTokens(): Promise<StoredTokens | null> {\n try {\n const content = await fs.readFile(TOKENS_FILE, 'utf-8');\n return JSON.parse(content) as StoredTokens;\n } catch {\n return null;\n }\n}\n\nasync function saveTokens(tokens: StoredTokens): Promise<void> {\n await ensureConfigDir();\n await fs.writeFile(TOKENS_FILE, JSON.stringify(tokens, null, 2));\n}\n\nexport async function deleteTokens(): Promise<void> {\n try {\n await fs.unlink(TOKENS_FILE);\n } catch {\n // File doesn't exist\n }\n}\n\n// === Login Flow ===\n\nexport async function login(credentials?: OAuthClientCredentials): Promise<StoredTokens> {\n const { codeVerifier, codeChallenge } = generatePKCE();\n const authUrl = getAuthorizationUrl(codeChallenge, credentials?.clientId);\n\n console.log('Opening browser for Google login...');\n\n // Start server first, then open browser\n const codePromise = startCallbackServer();\n await openBrowser(authUrl);\n\n console.log('Waiting for authorization...');\n const code = await codePromise;\n\n console.log('Exchanging code for tokens...');\n const tokenResponse = await exchangeCodeForTokens(code, codeVerifier, credentials);\n\n const userInfo = await getUserInfo(tokenResponse.access_token);\n\n const tokens: StoredTokens = {\n accessToken: tokenResponse.access_token,\n refreshToken: tokenResponse.refresh_token || '',\n expiresAt: Date.now() + (tokenResponse.expires_in * 1000),\n email: userInfo.email,\n };\n\n await saveTokens(tokens);\n return tokens;\n}\n\n// === Auth Provider ===\n\nexport class UserAuth {\n private tokens: StoredTokens | null = null;\n\n async getAccessToken(): Promise<string> {\n if (!this.tokens) {\n this.tokens = await loadStoredTokens();\n }\n\n if (!this.tokens) {\n throw new Error('Not logged in. Run \"sheets login\" first.');\n }\n\n // Refresh if expired (with 1 minute buffer)\n if (Date.now() >= this.tokens.expiresAt - 60000) {\n if (!this.tokens.refreshToken) {\n throw new Error('Token expired and no refresh token. Run \"sheets login\" again.');\n }\n\n const tokenResponse = await refreshAccessToken(this.tokens.refreshToken);\n this.tokens.accessToken = tokenResponse.access_token;\n this.tokens.expiresAt = Date.now() + (tokenResponse.expires_in * 1000);\n\n if (tokenResponse.refresh_token) {\n this.tokens.refreshToken = tokenResponse.refresh_token;\n }\n\n await saveTokens(this.tokens);\n }\n\n return this.tokens.accessToken;\n }\n}\n","/**\n * Authentication Module Exports\n */\n\nimport type { AuthConfig } from '../types/index.js';\nimport { OAuthAuth } from './oauth.js';\nimport { ServiceAccountAuth } from './service-account.js';\nimport { UserAuth } from './user-auth.js';\n\nexport { OAuthAuth } from './oauth.js';\nexport { ServiceAccountAuth } from './service-account.js';\nexport { UserAuth, login, loadStoredTokens, deleteTokens } from './user-auth.js';\nexport type { OAuthClientCredentials } from './user-auth.js';\n\nexport interface AuthProvider {\n getAccessToken(): Promise<string>;\n}\n\nexport function createAuthProvider(config: AuthConfig): AuthProvider {\n switch (config.type) {\n case 'oauth':\n return new OAuthAuth(config);\n case 'service-account':\n return new ServiceAccountAuth(config);\n case 'user':\n return new UserAuth();\n default:\n throw new Error(`Unknown auth type: ${(config as { type: string }).type}`);\n }\n}\n","/**\n * Google Sheets API Client\n */\n\nimport type {\n Spreadsheet,\n SheetProperties,\n ValueRange,\n GetValuesOptions,\n SheetsClientOptions,\n BatchGetValuesResponse,\n ClearValuesResponse,\n BatchClearValuesResponse,\n RawCellValue,\n UpdateValuesOptions,\n UpdateValuesResponse,\n BatchUpdateValuesResponse,\n AppendValuesOptions,\n AppendValuesResponse,\n SearchOptions,\n SearchResult,\n SearchMatch,\n} from '../types/index.js';\nimport { HttpClient } from '../http/index.js';\nimport { createAuthProvider } from '../auth/index.js';\n\ninterface RawValueRange {\n range: string;\n majorDimension?: 'ROWS' | 'COLUMNS';\n values?: (string | number | boolean | null)[][];\n}\n\ninterface RawBatchGetResponse {\n spreadsheetId: string;\n valueRanges?: RawValueRange[];\n}\n\n/**\n * Convert column letter(s) to 1-based column number\n * A=1, B=2, ..., Z=26, AA=27, AB=28, etc.\n */\nfunction columnLetterToNumber(letters: string): number {\n let result = 0;\n for (let i = 0; i < letters.length; i++) {\n result = result * 26 + (letters.charCodeAt(i) - 64);\n }\n return result;\n}\n\n/**\n * Convert 1-based column number to column letter(s)\n * 1=A, 2=B, ..., 26=Z, 27=AA, 28=AB, etc.\n */\nfunction columnNumberToLetter(num: number): string {\n let result = '';\n while (num > 0) {\n const remainder = (num - 1) % 26;\n result = String.fromCharCode(65 + remainder) + result;\n num = Math.floor((num - 1) / 26);\n }\n return result;\n}\n\n/**\n * Parse A1 notation to extract starting row and column\n * Returns { startRow, startCol } (1-based)\n */\nfunction parseA1Range(range: string): { startRow: number; startCol: number } {\n // Remove sheet name if present (e.g., \"Sheet1!A1:D10\" -> \"A1:D10\")\n const cellRef = range.includes('!') ? range.split('!')[1] : range;\n\n // Extract first cell (e.g., \"A1:D10\" -> \"A1\", \"A1\" -> \"A1\")\n const firstCell = cellRef.split(':')[0];\n\n // Parse column letters and row number\n const match = firstCell.match(/^([A-Z]+)(\\d+)$/i);\n if (!match) {\n return { startRow: 1, startCol: 1 };\n }\n\n return {\n startCol: columnLetterToNumber(match[1].toUpperCase()),\n startRow: parseInt(match[2], 10),\n };\n}\n\nexport class SheetsClient {\n private http: HttpClient;\n\n constructor(options: SheetsClientOptions) {\n const authProvider = createAuthProvider(options.auth);\n this.http = new HttpClient({\n getAccessToken: () => authProvider.getAccessToken(),\n });\n }\n\n /**\n * Get a spreadsheet by ID\n */\n async getSpreadsheet(spreadsheetId: string): Promise<Spreadsheet> {\n return this.http.request<Spreadsheet>(`/spreadsheets/${spreadsheetId}`);\n }\n\n /**\n * Get list of sheets in a spreadsheet\n */\n async getSheets(spreadsheetId: string): Promise<SheetProperties[]> {\n const spreadsheet = await this.getSpreadsheet(spreadsheetId);\n return spreadsheet.sheets.map(sheet => sheet.properties);\n }\n\n /**\n * Read cell values from a range\n */\n async getValues(spreadsheetId: string, range: string, options?: GetValuesOptions): Promise<ValueRange> {\n const params: Record<string, string> = {};\n\n if (options?.valueRenderOption) {\n params.valueRenderOption = options.valueRenderOption;\n }\n if (options?.dateTimeRenderOption) {\n params.dateTimeRenderOption = options.dateTimeRenderOption;\n }\n if (options?.majorDimension) {\n params.majorDimension = options.majorDimension;\n }\n\n const encodedRange = encodeURIComponent(range);\n const response = await this.http.request<RawValueRange>(\n `/spreadsheets/${spreadsheetId}/values/${encodedRange}`,\n { params }\n );\n\n return this.normalizeValueRange(response);\n }\n\n /**\n * Read cell formulas from a range\n */\n async getFormulas(spreadsheetId: string, range: string): Promise<ValueRange> {\n return this.getValues(spreadsheetId, range, { valueRenderOption: 'FORMULA' });\n }\n\n /**\n * Read multiple ranges at once\n */\n async batchGetValues(spreadsheetId: string, ranges: string[], options?: GetValuesOptions): Promise<BatchGetValuesResponse> {\n const params: Record<string, string> = {\n ranges: ranges.join(','),\n };\n\n if (options?.valueRenderOption) {\n params.valueRenderOption = options.valueRenderOption;\n }\n if (options?.dateTimeRenderOption) {\n params.dateTimeRenderOption = options.dateTimeRenderOption;\n }\n if (options?.majorDimension) {\n params.majorDimension = options.majorDimension;\n }\n\n const response = await this.http.request<RawBatchGetResponse>(\n `/spreadsheets/${spreadsheetId}/values:batchGet`,\n { params }\n );\n\n return {\n spreadsheetId: response.spreadsheetId,\n valueRanges: (response.valueRanges || []).map(vr => this.normalizeValueRange(vr)),\n };\n }\n\n /**\n * Clear values from a single range\n */\n async clearValues(spreadsheetId: string, range: string): Promise<ClearValuesResponse> {\n const encodedRange = encodeURIComponent(range);\n return this.http.request<ClearValuesResponse>(\n `/spreadsheets/${spreadsheetId}/values/${encodedRange}:clear`,\n { method: 'POST' }\n );\n }\n\n /**\n * Clear values from multiple ranges\n */\n async batchClearValues(spreadsheetId: string, ranges: string[]): Promise<BatchClearValuesResponse> {\n return this.http.request<BatchClearValuesResponse>(\n `/spreadsheets/${spreadsheetId}/values:batchClear`,\n { method: 'POST', body: { ranges } }\n );\n }\n\n /**\n * Write values to a range (or starting cell)\n * Range can be \"A1\" or \"A1:D10\" - data array determines actual extent\n */\n async updateValues(\n spreadsheetId: string,\n range: string,\n values: RawCellValue[][],\n options?: UpdateValuesOptions\n ): Promise<UpdateValuesResponse> {\n const params: Record<string, string> = {\n valueInputOption: options?.valueInputOption || 'USER_ENTERED',\n };\n\n if (options?.includeValuesInResponse) {\n params.includeValuesInResponse = 'true';\n }\n if (options?.responseValueRenderOption) {\n params.responseValueRenderOption = options.responseValueRenderOption;\n }\n if (options?.responseDateTimeRenderOption) {\n params.responseDateTimeRenderOption = options.responseDateTimeRenderOption;\n }\n\n const encodedRange = encodeURIComponent(range);\n return this.http.request<UpdateValuesResponse>(\n `/spreadsheets/${spreadsheetId}/values/${encodedRange}`,\n {\n method: 'PUT',\n params,\n body: {\n majorDimension: options?.majorDimension || 'ROWS',\n values,\n },\n }\n );\n }\n\n /**\n * Write to multiple ranges in one request\n */\n async batchUpdateValues(\n spreadsheetId: string,\n data: { range: string; values: RawCellValue[][] }[],\n options?: UpdateValuesOptions\n ): Promise<BatchUpdateValuesResponse> {\n return this.http.request<BatchUpdateValuesResponse>(\n `/spreadsheets/${spreadsheetId}/values:batchUpdate`,\n {\n method: 'POST',\n body: {\n valueInputOption: options?.valueInputOption || 'USER_ENTERED',\n data: data.map(d => ({\n range: d.range,\n majorDimension: options?.majorDimension || 'ROWS',\n values: d.values,\n })),\n includeValuesInResponse: options?.includeValuesInResponse || false,\n responseValueRenderOption: options?.responseValueRenderOption,\n responseDateTimeRenderOption: options?.responseDateTimeRenderOption,\n },\n }\n );\n }\n\n /**\n * Append rows after the last row of detected table\n */\n async appendValues(\n spreadsheetId: string,\n range: string,\n values: RawCellValue[][],\n options?: AppendValuesOptions\n ): Promise<AppendValuesResponse> {\n const params: Record<string, string> = {\n valueInputOption: options?.valueInputOption || 'USER_ENTERED',\n };\n\n if (options?.insertDataOption) {\n params.insertDataOption = options.insertDataOption;\n }\n if (options?.includeValuesInResponse) {\n params.includeValuesInResponse = 'true';\n }\n if (options?.responseValueRenderOption) {\n params.responseValueRenderOption = options.responseValueRenderOption;\n }\n if (options?.responseDateTimeRenderOption) {\n params.responseDateTimeRenderOption = options.responseDateTimeRenderOption;\n }\n\n const encodedRange = encodeURIComponent(range);\n return this.http.request<AppendValuesResponse>(\n `/spreadsheets/${spreadsheetId}/values/${encodedRange}:append`,\n {\n method: 'POST',\n params,\n body: {\n majorDimension: options?.majorDimension || 'ROWS',\n values,\n },\n }\n );\n }\n\n /**\n * Search for values matching a query across sheets\n */\n async searchValues(\n spreadsheetId: string,\n query: string,\n options?: SearchOptions\n ): Promise<SearchResult> {\n const caseSensitive = options?.caseSensitive ?? false;\n const exactMatch = options?.exactMatch ?? false;\n const useRegex = options?.regex ?? false;\n const limit = options?.limit;\n\n // Determine match type for response\n const matchType = useRegex ? 'regex' : (exactMatch ? 'exact' : 'contains');\n\n // Build the matcher function\n let matcher: (cellValue: string) => boolean;\n\n if (useRegex) {\n const flags = caseSensitive ? '' : 'i';\n const regex = new RegExp(query, flags);\n matcher = (cellValue) => regex.test(cellValue);\n } else if (exactMatch) {\n if (caseSensitive) {\n matcher = (cellValue) => cellValue === query;\n } else {\n const lowerQuery = query.toLowerCase();\n matcher = (cellValue) => cellValue.toLowerCase() === lowerQuery;\n }\n } else {\n // Contains match (default)\n if (caseSensitive) {\n matcher = (cellValue) => cellValue.includes(query);\n } else {\n const lowerQuery = query.toLowerCase();\n matcher = (cellValue) => cellValue.toLowerCase().includes(lowerQuery);\n }\n }\n\n const matches: SearchMatch[] = [];\n\n // Get sheets to search\n const allSheets = await this.getSheets(spreadsheetId);\n let sheetsToSearch: SheetProperties[];\n\n if (options?.sheetIndex !== undefined) {\n const sheet = allSheets.find(s => s.index === options.sheetIndex);\n if (!sheet) {\n throw new Error(`Sheet index ${options.sheetIndex} not found.`);\n }\n sheetsToSearch = [sheet];\n } else if (options?.gid !== undefined) {\n const sheet = allSheets.find(s => s.sheetId === options.gid);\n if (!sheet) {\n throw new Error(`Sheet with gid ${options.gid} not found.`);\n }\n sheetsToSearch = [sheet];\n } else if (options?.range && options.range.includes('!')) {\n // Range includes sheet name, use as-is\n sheetsToSearch = []; // Will handle specially below\n } else {\n // Search all sheets\n sheetsToSearch = allSheets.filter(s => !s.hidden);\n }\n\n // Search logic\n if (options?.range && options.range.includes('!')) {\n // Specific range with sheet name provided\n const valueRange = await this.getValues(spreadsheetId, options.range);\n const sheetName = options.range.split('!')[0].replace(/^'|'$/g, '').replace(/''/g, \"'\");\n const sheet = allSheets.find(s => s.title === sheetName);\n const { startRow, startCol } = parseA1Range(options.range);\n\n this.collectMatches(\n valueRange,\n sheetName,\n sheet?.sheetId ?? 0,\n startRow,\n startCol,\n matcher,\n matches,\n limit\n );\n } else {\n // Search across sheets\n for (const sheet of sheetsToSearch) {\n if (limit && matches.length >= limit) break;\n\n const escapedTitle = sheet.title.replace(/'/g, \"''\");\n const range = options?.range\n ? `'${escapedTitle}'!${options.range}`\n : `'${escapedTitle}'`; // Entire sheet\n\n try {\n const valueRange = await this.getValues(spreadsheetId, range);\n const { startRow, startCol } = parseA1Range(valueRange.range);\n\n this.collectMatches(\n valueRange,\n sheet.title,\n sheet.sheetId,\n startRow,\n startCol,\n matcher,\n matches,\n limit\n );\n } catch {\n // Skip sheets that fail (e.g., empty sheets)\n continue;\n }\n }\n }\n\n return {\n query,\n matchType,\n caseSensitive,\n totalMatches: matches.length,\n matches,\n };\n }\n\n private collectMatches(\n valueRange: ValueRange,\n sheetName: string,\n sheetId: number,\n startRow: number,\n startCol: number,\n matcher: (value: string) => boolean,\n matches: SearchMatch[],\n limit?: number\n ): void {\n for (let rowIndex = 0; rowIndex < valueRange.values.length; rowIndex++) {\n if (limit && matches.length >= limit) return;\n\n const row = valueRange.values[rowIndex];\n for (let colIndex = 0; colIndex < row.length; colIndex++) {\n if (limit && matches.length >= limit) return;\n\n const cell = row[colIndex];\n const cellValue = cell.value;\n\n // Skip null/undefined values\n if (cellValue == null) continue;\n\n // Convert to string for matching\n const stringValue = String(cellValue);\n\n if (matcher(stringValue)) {\n const actualRow = startRow + rowIndex;\n const actualCol = startCol + colIndex;\n\n matches.push({\n sheet: sheetName,\n sheetId,\n address: columnNumberToLetter(actualCol) + actualRow,\n row: actualRow,\n column: actualCol,\n value: cellValue,\n });\n }\n }\n }\n }\n\n private normalizeValueRange(raw: RawValueRange): ValueRange {\n const values = (raw.values || []).map(row =>\n row.map(cell => ({\n value: cell,\n }))\n );\n\n return {\n range: raw.range,\n majorDimension: raw.majorDimension || 'ROWS',\n values,\n };\n }\n}\n\nexport function createClient(options: SheetsClientOptions): SheetsClient {\n return new SheetsClient(options);\n}\n"],"mappings":"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","names":["fs","path","os","path","crypto","fs"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/types/index.ts","../src/http/index.ts","../src/auth/constants.ts","../src/auth/oauth.ts","../src/auth/service-account.ts","../src/auth/user-auth.ts","../src/auth/index.ts","../src/api/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * Google Sheets CLI\n * Command-line interface for Google Sheets operations\n */\n\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { createClient } from './api/index.js';\nimport { login, loadStoredTokens, deleteTokens } from './auth/index.js';\nimport type { OAuthClientCredentials } from './auth/index.js';\nimport { SheetsError } from './types/index.js';\nimport type { AuthConfig, SheetProperties, RawCellValue } from './types/index.js';\n\nconst VERSION = '0.3.4';\n\n// Claude Skill content embedded in the CLI\nconst CLAUDE_SKILL_CONTENT = `---\nname: sheets\ndescription: Read data from Google Sheets spreadsheets. Use this skill when the user wants to fetch, read, or analyze data from a Google Sheets URL or spreadsheet ID.\n---\n\n# Google Sheets CLI\n\nUse \\`npx -y @ariadng/sheets\\` to read data from Google Sheets.\n\n**Important**: Always use \\`npx -y\\` to skip the installation confirmation prompt.\n\n## Authentication\n\nBefore reading spreadsheets, check if the user is logged in:\n\n\\`\\`\\`bash\nnpx -y @ariadng/sheets whoami\n\\`\\`\\`\n\nIf not logged in (exit code 1), ask the user to run:\n\n\\`\\`\\`bash\nnpx -y @ariadng/sheets login\n\\`\\`\\`\n\n## Extract Spreadsheet ID\n\nFrom a Google Sheets URL like:\n\\`https://docs.google.com/spreadsheets/d/SPREADSHEET_ID/edit\\`\n\nThe spreadsheet ID is the string between \\`/d/\\` and \\`/edit\\`.\n\n## Commands\n\n### Get spreadsheet metadata\n\\`\\`\\`bash\nnpx -y @ariadng/sheets get SPREADSHEET_ID --format json\n\\`\\`\\`\n\n### List all sheets\n\\`\\`\\`bash\nnpx -y @ariadng/sheets list SPREADSHEET_ID --format json\n\\`\\`\\`\n\n### Read cell values\n\\`\\`\\`bash\nnpx -y @ariadng/sheets read SPREADSHEET_ID \"Sheet1!A1:D10\" --format json\n\\`\\`\\`\n\n### Read formulas\n\\`\\`\\`bash\nnpx -y @ariadng/sheets read SPREADSHEET_ID \"Sheet1!A1:D10\" --formula --format json\n\\`\\`\\`\n\n### Read by sheet index (for emoji/special character sheet names)\n\\`\\`\\`bash\nnpx -y @ariadng/sheets read SPREADSHEET_ID \"A1:D10\" -i 0 --format json\n\\`\\`\\`\n\n### Read by gid (sheet ID from URL)\n\\`\\`\\`bash\nnpx -y @ariadng/sheets read SPREADSHEET_ID \"A1:D10\" --gid 123456789 --format json\n\\`\\`\\`\n\n## Handling Emoji/Special Character Sheet Names\n\nShell argument parsing can corrupt emoji characters. Use \\`-i\\` (sheet index) or \\`--gid\\` instead:\n\n1. First, list sheets to find the index and gid:\n\\`\\`\\`bash\nnpx -y @ariadng/sheets list SPREADSHEET_ID --format json\n\\`\\`\\`\n\n2. Then read using index or gid:\n\\`\\`\\`bash\n# By index (0-based)\nnpx -y @ariadng/sheets read SPREADSHEET_ID \"A1:D10\" -i 3 --format json\n\n# By gid (from URL #gid=... or list output)\nnpx -y @ariadng/sheets read SPREADSHEET_ID \"A1:D10\" --gid 745108136 --format json\n\\`\\`\\`\n\n### Write values\n\\`\\`\\`bash\n# Single value\nnpx -y @ariadng/sheets write SPREADSHEET_ID \"Sheet1!A1\" \"Hello\"\n\n# Formula\nnpx -y @ariadng/sheets write SPREADSHEET_ID \"Sheet1!B10\" \"=SUM(B1:B9)\"\n\n# JSON array (starting cell, expands automatically)\nnpx -y @ariadng/sheets write SPREADSHEET_ID \"Sheet1!A1\" '[[\"Name\",\"Age\"],[\"Alice\",30]]' --format json\n\n# From file\nnpx -y @ariadng/sheets write SPREADSHEET_ID \"A1\" -i 0 --input data.json --format json\n\n# Store formula as text (not computed)\nnpx -y @ariadng/sheets write SPREADSHEET_ID \"A1\" \"=SUM(A:A)\" --raw\n\\`\\`\\`\n\n### Append rows\n\\`\\`\\`bash\n# Append to table\nnpx -y @ariadng/sheets append SPREADSHEET_ID \"Sheet1!A:D\" '[[\"New Item\",10,5,\"=B2*C2\"]]' --format json\n\n# Insert rows (push existing down)\nnpx -y @ariadng/sheets append SPREADSHEET_ID \"Sheet1!A:A\" --insert-rows '[[\"Inserted\"]]' --format json\n\\`\\`\\`\n\n### Clear cell values\n\\`\\`\\`bash\n# Clear single range\nnpx -y @ariadng/sheets clear SPREADSHEET_ID \"Sheet1!A1:D10\" --format json\n\n# Clear multiple ranges\nnpx -y @ariadng/sheets clear SPREADSHEET_ID \"Sheet1!A1:B5\" \"Sheet2!C1:D5\" --format json\n\n# Clear by sheet index\nnpx -y @ariadng/sheets clear SPREADSHEET_ID \"A1:D10\" -i 0 --format json\n\\`\\`\\`\n\n### Search for values\n\\`\\`\\`bash\n# Search all sheets (case-insensitive, contains)\nnpx -y @ariadng/sheets search SPREADSHEET_ID \"search term\" --format json\n\n# Search specific range\nnpx -y @ariadng/sheets search SPREADSHEET_ID \"term\" \"Sheet1!A1:D100\" --format json\n\n# Search by sheet index\nnpx -y @ariadng/sheets search SPREADSHEET_ID \"term\" -i 0 --format json\n\n# Exact match\nnpx -y @ariadng/sheets search SPREADSHEET_ID \"exact value\" --exact --format json\n\n# Regex search\nnpx -y @ariadng/sheets search SPREADSHEET_ID \"[0-9]{3}-[0-9]{4}\" --regex --format json\n\n# Case-sensitive with limit\nnpx -y @ariadng/sheets search SPREADSHEET_ID \"Term\" --case-sensitive --limit 10 --format json\n\\`\\`\\`\n\n## Range Format\n\n- \\`Sheet1!A1:D10\\` - Cells A1 to D10 on Sheet1\n- \\`Sheet1!A:A\\` - Entire column A\n- \\`Sheet1!1:1\\` - Entire row 1\n- \\`A1:D10\\` - Range on first sheet (or use with -i/--gid)\n\n## Tips\n\n- Always use \\`npx -y\\` to avoid interactive prompts\n- Always use \\`--format json\\` for structured, parseable output\n- Use \\`-i\\` or \\`--gid\\` for sheets with emoji or special characters\n- Check authentication status before making requests\n- Handle errors gracefully and inform the user\n`;\n\ninterface CliOptions {\n credentials?: string;\n token?: string;\n client?: string;\n format: 'json' | 'table';\n formula: boolean;\n sheetIndex?: number;\n gid?: number;\n // Options for write/append\n input?: string; // File path or '-' for stdin\n raw?: boolean; // --raw flag\n byColumns?: boolean; // --by-columns flag\n insertRows?: boolean; // --insert-rows flag (append only)\n // Search options\n caseSensitive?: boolean; // --case-sensitive\n exact?: boolean; // --exact\n regex?: boolean; // --regex\n limit?: number; // --limit <n>\n}\n\nfunction parseArgs(args: string[]): { command: string; positionals: string[]; options: CliOptions } {\n const options: CliOptions = { format: 'table', formula: false };\n const positionals: string[] = [];\n let command = '';\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '--credentials' && args[i + 1]) {\n options.credentials = args[++i];\n } else if (arg === '--token' && args[i + 1]) {\n options.token = args[++i];\n } else if (arg === '--client' && args[i + 1]) {\n options.client = args[++i];\n } else if (arg === '--format' && args[i + 1]) {\n options.format = args[++i] as 'json' | 'table';\n } else if (arg === '--formula') {\n options.formula = true;\n } else if ((arg === '--sheet-index' || arg === '-i') && args[i + 1]) {\n options.sheetIndex = parseInt(args[++i], 10);\n } else if (arg === '--gid' && args[i + 1]) {\n options.gid = parseInt(args[++i], 10);\n } else if (arg === '--input' && args[i + 1]) {\n options.input = args[++i];\n } else if (arg === '--raw') {\n options.raw = true;\n } else if (arg === '--by-columns') {\n options.byColumns = true;\n } else if (arg === '--insert-rows') {\n options.insertRows = true;\n } else if (arg === '--case-sensitive') {\n options.caseSensitive = true;\n } else if (arg === '--exact') {\n options.exact = true;\n } else if (arg === '--regex') {\n options.regex = true;\n } else if (arg === '--limit' && args[i + 1]) {\n options.limit = parseInt(args[++i], 10);\n } else if (arg === '--version' || arg === '--help') {\n command = arg;\n } else if (!arg.startsWith('-')) {\n if (!command) {\n command = arg;\n } else {\n positionals.push(arg);\n }\n }\n }\n\n return { command, positionals, options };\n}\n\nfunction printHelp(): void {\n console.log(`\nGoogle Sheets CLI v${VERSION}\n\nUsage:\n sheets <command> [options]\n\nCommands:\n login Login with Google account\n logout Logout and remove stored tokens\n whoami Show current logged-in user\n auth <credentials-file> Test service account authentication\n get <spreadsheet-id> Get spreadsheet metadata\n list <spreadsheet-id> List sheets in a spreadsheet\n read <spreadsheet-id> <range> Read cell values\n write <spreadsheet-id> <range> [values] Write values to cells\n append <spreadsheet-id> <range> [values] Append rows to table\n clear <spreadsheet-id> <range> Clear cell values (preserves formatting)\n search <id> <query> [range] Search for values in cells\n install-claude-skill Install Claude Code skill\n\nOptions:\n --client <file> OAuth client JSON file (for login)\n --credentials <file> Service account JSON file\n --token <token> OAuth access token\n --format <json|table> Output format (default: table)\n --formula Show formulas instead of values\n --sheet-index, -i <n> Sheet index (use 'list' to see indexes)\n --gid <id> Sheet ID (from URL #gid=...)\n --input <file> Read values from JSON file (- for stdin)\n --raw Store values exactly (formulas as text)\n --by-columns Write data column-by-column\n --insert-rows Insert rows, push existing data down (append)\n --case-sensitive Case-sensitive search (default: insensitive)\n --exact Exact match only (default: contains)\n --regex Treat query as regular expression\n --limit <n> Maximum number of results to return\n --version Show version number\n --help Show help\n\nExamples:\n sheets login\n sheets login --client client_secret.json\n sheets get 1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms\n sheets read 1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms Sheet1!A1:D10\n sheets install-claude-skill\n`);\n}\n\nfunction printVersion(): void {\n console.log(VERSION);\n}\n\nfunction getRangeErrorSuggestions(errorMessage: string, range?: string): string[] {\n const suggestions: string[] = [];\n\n // Check for \"Unable to parse range\" errors\n if (errorMessage.includes('Unable to parse range')) {\n // Detect backslash escaping (shell issue)\n if (range && range.includes('\\\\')) {\n suggestions.push('Detected backslash in range - this may be caused by shell escaping.');\n suggestions.push('Try using single quotes around the entire command or avoid piping.');\n }\n\n // Check for special characters that need quoting\n if (range && (range.includes('[') || range.includes(']') || range.includes(' '))) {\n suggestions.push('Sheet names with brackets or spaces need proper quoting.');\n suggestions.push('Example: sheets read ID \"[Sheet Name]!A1:B10\"');\n }\n\n // General suggestions\n suggestions.push('Verify the sheet name matches exactly (including trailing spaces).');\n suggestions.push('Use: sheets list <spreadsheet-id> to see all sheet names.');\n }\n\n return suggestions;\n}\n\nasync function getAuthConfig(options: CliOptions): Promise<AuthConfig> {\n // Priority: --token > --credentials > stored user tokens\n if (options.token) {\n return { type: 'oauth', accessToken: options.token };\n }\n\n if (options.credentials) {\n return { type: 'service-account', credentialsPath: options.credentials };\n }\n\n // Check for stored user tokens\n const storedTokens = await loadStoredTokens();\n if (storedTokens) {\n return { type: 'user' };\n }\n\n throw new Error('Not authenticated. Run \"sheets login\" or use --credentials');\n}\n\n// === Login Commands ===\n\nasync function loadClientCredentials(clientPath: string): Promise<OAuthClientCredentials> {\n const content = await fs.readFile(clientPath, 'utf-8');\n const data = JSON.parse(content);\n\n // Support Google's client_secret JSON format\n const installed = data.installed || data.web;\n if (installed) {\n return {\n clientId: installed.client_id,\n clientSecret: installed.client_secret,\n };\n }\n\n // Support simple {clientId, clientSecret} format\n if (data.clientId && data.clientSecret) {\n return data as OAuthClientCredentials;\n }\n\n throw new Error('Invalid client credentials file');\n}\n\nasync function cmdLogin(options: CliOptions): Promise<void> {\n try {\n let credentials: OAuthClientCredentials | undefined;\n\n if (options.client) {\n credentials = await loadClientCredentials(options.client);\n }\n\n const tokens = await login(credentials);\n console.log(`\\nLogin successful! Logged in as ${tokens.email}`);\n } catch (error) {\n const e = error as Error;\n console.error(`Login failed: ${e.message}`);\n process.exit(1);\n }\n}\n\nasync function cmdLogout(): Promise<void> {\n await deleteTokens();\n console.log('Logged out successfully.');\n}\n\nasync function cmdWhoami(): Promise<void> {\n const tokens = await loadStoredTokens();\n\n if (!tokens) {\n console.log('Not logged in. Run \"sheets login\" to authenticate.');\n process.exit(1);\n }\n\n console.log(`Logged in as: ${tokens.email || 'Unknown'}`);\n const expiresAt = new Date(tokens.expiresAt);\n const isExpired = Date.now() >= tokens.expiresAt;\n console.log(`Token expires: ${expiresAt.toLocaleString()}${isExpired ? ' (expired, will refresh)' : ''}`);\n}\n\n// === Service Account Auth ===\n\nasync function cmdAuth(credentialsPath: string): Promise<void> {\n try {\n await fs.access(credentialsPath);\n const content = await fs.readFile(credentialsPath, 'utf-8');\n const credentials = JSON.parse(content);\n\n if (credentials.type !== 'service_account') {\n throw new Error('Invalid credentials file: expected service_account type');\n }\n\n const client = createClient({\n auth: { type: 'service-account', credentialsPath },\n });\n\n console.log('Testing authentication...');\n console.log(` Project: ${credentials.project_id}`);\n console.log(` Client Email: ${credentials.client_email}`);\n\n try {\n await client.getSpreadsheet('test-auth-only');\n } catch (error) {\n const e = error as { code?: number };\n if (e.code === 404 || e.code === 403) {\n console.log('\\nAuthentication successful!');\n return;\n }\n throw error;\n }\n } catch (error) {\n const e = error as Error;\n console.error(`Authentication failed: ${e.message}`);\n process.exit(1);\n }\n}\n\n// === Claude Skill Installation ===\n\nasync function cmdInstallClaudeSkill(): Promise<void> {\n const homeDir = os.homedir();\n const skillDir = path.join(homeDir, '.claude', 'skills', 'sheets');\n const skillFile = path.join(skillDir, 'SKILL.md');\n\n try {\n // Create the skill directory\n await fs.mkdir(skillDir, { recursive: true });\n\n // Write the skill file\n await fs.writeFile(skillFile, CLAUDE_SKILL_CONTENT, 'utf-8');\n\n console.log('Claude skill installed successfully!');\n console.log(`Location: ${skillFile}`);\n console.log('');\n console.log('You can now use /sheets in Claude Code to read Google Sheets data.');\n } catch (error) {\n const e = error as Error;\n console.error(`Failed to install Claude skill: ${e.message}`);\n process.exit(1);\n }\n}\n\n// === Spreadsheet Commands ===\n\nasync function cmdGet(spreadsheetId: string, options: CliOptions): Promise<void> {\n const authConfig = await getAuthConfig(options);\n const client = createClient({ auth: authConfig });\n\n const spreadsheet = await client.getSpreadsheet(spreadsheetId);\n\n if (options.format === 'json') {\n console.log(JSON.stringify(spreadsheet, null, 2));\n } else {\n console.log(`Title: ${spreadsheet.properties.title}`);\n console.log(`ID: ${spreadsheet.spreadsheetId}`);\n console.log(`Locale: ${spreadsheet.properties.locale || 'N/A'}`);\n console.log(`Timezone: ${spreadsheet.properties.timeZone || 'N/A'}`);\n console.log(`Sheets: ${spreadsheet.sheets.length}`);\n if (spreadsheet.spreadsheetUrl) {\n console.log(`URL: ${spreadsheet.spreadsheetUrl}`);\n }\n }\n}\n\nasync function cmdList(spreadsheetId: string, options: CliOptions): Promise<void> {\n const authConfig = await getAuthConfig(options);\n const client = createClient({ auth: authConfig });\n\n const sheets = await client.getSheets(spreadsheetId);\n\n if (options.format === 'json') {\n console.log(JSON.stringify(sheets, null, 2));\n } else {\n console.log('Sheets:');\n sheets.forEach((sheet: SheetProperties) => {\n const grid = sheet.gridProperties;\n const size = grid ? ` (${grid.rowCount} x ${grid.columnCount})` : '';\n const hidden = sheet.hidden ? ' [hidden]' : '';\n console.log(` ${sheet.index}. ${sheet.title}${size}${hidden}`);\n console.log(` gid: ${sheet.sheetId}`);\n });\n }\n}\n\nasync function cmdRead(spreadsheetId: string, range: string, options: CliOptions): Promise<void> {\n const authConfig = await getAuthConfig(options);\n const client = createClient({ auth: authConfig });\n\n // Resolve sheet name from index or gid if provided\n let resolvedRange = range;\n if (options.sheetIndex !== undefined || options.gid !== undefined) {\n const sheets = await client.getSheets(spreadsheetId);\n let targetSheet: SheetProperties | undefined;\n\n if (options.sheetIndex !== undefined) {\n targetSheet = sheets.find(s => s.index === options.sheetIndex);\n if (!targetSheet) {\n throw new Error(`Sheet index ${options.sheetIndex} not found. Use 'sheets list' to see available sheets.`);\n }\n } else if (options.gid !== undefined) {\n targetSheet = sheets.find(s => s.sheetId === options.gid);\n if (!targetSheet) {\n throw new Error(`Sheet with gid ${options.gid} not found. Use 'sheets list' to see available sheets.`);\n }\n }\n\n if (targetSheet) {\n // Escape single quotes in sheet name and wrap in quotes\n const escapedTitle = targetSheet.title.replace(/'/g, \"''\");\n resolvedRange = `'${escapedTitle}'!${range}`;\n }\n }\n\n const valueRange = options.formula\n ? await client.getFormulas(spreadsheetId, resolvedRange)\n : await client.getValues(spreadsheetId, resolvedRange);\n\n if (options.format === 'json') {\n console.log(JSON.stringify(valueRange, null, 2));\n } else {\n console.log(`Range: ${valueRange.range}`);\n console.log('');\n\n if (valueRange.values.length === 0) {\n console.log('(empty)');\n return;\n }\n\n // Calculate column widths\n const colWidths: number[] = [];\n valueRange.values.forEach(row => {\n row.forEach((cell, i) => {\n const len = String(cell.value ?? '').length;\n colWidths[i] = Math.max(colWidths[i] || 0, len, 3);\n });\n });\n\n // Print table\n valueRange.values.forEach(row => {\n const cells = row.map((cell, i) => {\n const val = String(cell.value ?? '');\n return val.padEnd(colWidths[i]);\n });\n console.log(cells.join(' | '));\n });\n }\n}\n\nasync function cmdClear(spreadsheetId: string, ranges: string[], options: CliOptions): Promise<void> {\n const authConfig = await getAuthConfig(options);\n const client = createClient({ auth: authConfig });\n\n // Resolve sheet name from index or gid if provided\n let resolvedRanges = ranges;\n if (options.sheetIndex !== undefined || options.gid !== undefined) {\n const sheets = await client.getSheets(spreadsheetId);\n let targetSheet: SheetProperties | undefined;\n\n if (options.sheetIndex !== undefined) {\n targetSheet = sheets.find(s => s.index === options.sheetIndex);\n if (!targetSheet) {\n throw new Error(`Sheet index ${options.sheetIndex} not found. Use 'sheets list' to see available sheets.`);\n }\n } else if (options.gid !== undefined) {\n targetSheet = sheets.find(s => s.sheetId === options.gid);\n if (!targetSheet) {\n throw new Error(`Sheet with gid ${options.gid} not found. Use 'sheets list' to see available sheets.`);\n }\n }\n\n if (targetSheet) {\n // Escape single quotes in sheet name and wrap in quotes\n const escapedTitle = targetSheet.title.replace(/'/g, \"''\");\n resolvedRanges = ranges.map(range => `'${escapedTitle}'!${range}`);\n }\n }\n\n const result = await client.batchClearValues(spreadsheetId, resolvedRanges);\n\n if (options.format === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log('Cleared ranges:');\n result.clearedRanges.forEach(range => {\n console.log(` - ${range}`);\n });\n }\n}\n\nasync function parseWriteValues(\n valuesArg: string | undefined,\n inputPath: string | undefined\n): Promise<RawCellValue[][]> {\n let jsonStr: string;\n\n if (inputPath) {\n if (inputPath === '-') {\n // Read from stdin\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk);\n }\n jsonStr = Buffer.concat(chunks).toString('utf-8').trim();\n } else {\n jsonStr = await fs.readFile(inputPath, 'utf-8');\n }\n } else if (valuesArg) {\n jsonStr = valuesArg;\n } else {\n throw new Error('No values provided. Use inline JSON or --input <file>');\n }\n\n // Try to parse as JSON array\n try {\n const parsed = JSON.parse(jsonStr);\n\n // If it's a 2D array, return as-is\n if (Array.isArray(parsed) && (parsed.length === 0 || Array.isArray(parsed[0]))) {\n return parsed;\n }\n\n // If it's a 1D array, wrap it\n if (Array.isArray(parsed)) {\n return [parsed];\n }\n\n // Single value\n return [[parsed]];\n } catch {\n // Not JSON - treat as single string value\n return [[jsonStr]];\n }\n}\n\nasync function cmdWrite(\n spreadsheetId: string,\n range: string,\n valuesArg: string | undefined,\n options: CliOptions\n): Promise<void> {\n const authConfig = await getAuthConfig(options);\n const client = createClient({ auth: authConfig });\n\n // Resolve sheet name from index or gid if provided\n let resolvedRange = range;\n if (options.sheetIndex !== undefined || options.gid !== undefined) {\n const sheets = await client.getSheets(spreadsheetId);\n let targetSheet: SheetProperties | undefined;\n\n if (options.sheetIndex !== undefined) {\n targetSheet = sheets.find(s => s.index === options.sheetIndex);\n if (!targetSheet) {\n throw new Error(`Sheet index ${options.sheetIndex} not found.`);\n }\n } else if (options.gid !== undefined) {\n targetSheet = sheets.find(s => s.sheetId === options.gid);\n if (!targetSheet) {\n throw new Error(`Sheet with gid ${options.gid} not found.`);\n }\n }\n\n if (targetSheet) {\n const escapedTitle = targetSheet.title.replace(/'/g, \"''\");\n resolvedRange = `'${escapedTitle}'!${range}`;\n }\n }\n\n const values = await parseWriteValues(valuesArg, options.input);\n\n const result = await client.updateValues(spreadsheetId, resolvedRange, values, {\n valueInputOption: options.raw ? 'RAW' : 'USER_ENTERED',\n majorDimension: options.byColumns ? 'COLUMNS' : 'ROWS',\n });\n\n if (options.format === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(`Updated: ${result.updatedRange}`);\n console.log(` Rows: ${result.updatedRows}`);\n console.log(` Columns: ${result.updatedColumns}`);\n console.log(` Cells: ${result.updatedCells}`);\n }\n}\n\nasync function cmdAppend(\n spreadsheetId: string,\n range: string,\n valuesArg: string | undefined,\n options: CliOptions\n): Promise<void> {\n const authConfig = await getAuthConfig(options);\n const client = createClient({ auth: authConfig });\n\n // Resolve sheet name from index or gid\n let resolvedRange = range;\n if (options.sheetIndex !== undefined || options.gid !== undefined) {\n const sheets = await client.getSheets(spreadsheetId);\n let targetSheet: SheetProperties | undefined;\n\n if (options.sheetIndex !== undefined) {\n targetSheet = sheets.find(s => s.index === options.sheetIndex);\n if (!targetSheet) {\n throw new Error(`Sheet index ${options.sheetIndex} not found.`);\n }\n } else if (options.gid !== undefined) {\n targetSheet = sheets.find(s => s.sheetId === options.gid);\n if (!targetSheet) {\n throw new Error(`Sheet with gid ${options.gid} not found.`);\n }\n }\n\n if (targetSheet) {\n const escapedTitle = targetSheet.title.replace(/'/g, \"''\");\n resolvedRange = `'${escapedTitle}'!${range}`;\n }\n }\n\n const values = await parseWriteValues(valuesArg, options.input);\n\n const result = await client.appendValues(spreadsheetId, resolvedRange, values, {\n valueInputOption: options.raw ? 'RAW' : 'USER_ENTERED',\n majorDimension: options.byColumns ? 'COLUMNS' : 'ROWS',\n insertDataOption: options.insertRows ? 'INSERT_ROWS' : 'OVERWRITE',\n });\n\n if (options.format === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(`Appended to: ${result.updates.updatedRange}`);\n if (result.tableRange) {\n console.log(` Table range: ${result.tableRange}`);\n }\n console.log(` Rows: ${result.updates.updatedRows}`);\n console.log(` Columns: ${result.updates.updatedColumns}`);\n console.log(` Cells: ${result.updates.updatedCells}`);\n }\n}\n\nasync function cmdSearch(\n spreadsheetId: string,\n query: string,\n range: string | undefined,\n options: CliOptions\n): Promise<void> {\n const authConfig = await getAuthConfig(options);\n const client = createClient({ auth: authConfig });\n\n const result = await client.searchValues(spreadsheetId, query, {\n range,\n sheetIndex: options.sheetIndex,\n gid: options.gid,\n caseSensitive: options.caseSensitive,\n exactMatch: options.exact,\n regex: options.regex,\n limit: options.limit,\n });\n\n if (options.format === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (result.matches.length === 0) {\n console.log(`No matches found for \"${query}\"`);\n return;\n }\n\n console.log(`Found ${result.totalMatches} match${result.totalMatches === 1 ? '' : 'es'} for \"${query}\":`);\n console.log('');\n\n // Calculate column widths\n const headers = ['Sheet', 'Address', 'Row', 'Col', 'Value'];\n const colWidths = headers.map(h => h.length);\n\n result.matches.forEach(m => {\n colWidths[0] = Math.max(colWidths[0], m.sheet.length);\n colWidths[1] = Math.max(colWidths[1], m.address.length);\n colWidths[2] = Math.max(colWidths[2], String(m.row).length);\n colWidths[3] = Math.max(colWidths[3], String(m.column).length);\n const valueStr = String(m.value ?? '').substring(0, 50);\n colWidths[4] = Math.max(colWidths[4], valueStr.length);\n });\n\n // Print header\n console.log(headers.map((h, i) => h.padEnd(colWidths[i])).join(' | '));\n console.log(colWidths.map(w => '-'.repeat(w)).join('-+-'));\n\n // Print matches\n result.matches.forEach(m => {\n const valueStr = String(m.value ?? '').substring(0, 50);\n const row = [\n m.sheet.padEnd(colWidths[0]),\n m.address.padEnd(colWidths[1]),\n String(m.row).padEnd(colWidths[2]),\n String(m.column).padEnd(colWidths[3]),\n valueStr.padEnd(colWidths[4]),\n ];\n console.log(row.join(' | '));\n });\n }\n}\n\n// === Main ===\n\nasync function main(): Promise<void> {\n const { command, positionals, options } = parseArgs(process.argv.slice(2));\n\n if (!command || command === 'help' || command === '--help') {\n printHelp();\n return;\n }\n\n if (command === '--version') {\n printVersion();\n return;\n }\n\n try {\n switch (command) {\n case 'login':\n await cmdLogin(options);\n break;\n\n case 'logout':\n await cmdLogout();\n break;\n\n case 'whoami':\n await cmdWhoami();\n break;\n\n case 'auth': {\n const credentialsPath = positionals[0];\n if (!credentialsPath) {\n console.error('Usage: sheets auth <credentials-file>');\n process.exit(1);\n }\n await cmdAuth(credentialsPath);\n break;\n }\n\n case 'get': {\n const spreadsheetId = positionals[0];\n if (!spreadsheetId) {\n console.error('Usage: sheets get <spreadsheet-id>');\n process.exit(1);\n }\n await cmdGet(spreadsheetId, options);\n break;\n }\n\n case 'list': {\n const spreadsheetId = positionals[0];\n if (!spreadsheetId) {\n console.error('Usage: sheets list <spreadsheet-id>');\n process.exit(1);\n }\n await cmdList(spreadsheetId, options);\n break;\n }\n\n case 'read': {\n const spreadsheetId = positionals[0];\n const range = positionals[1];\n if (!spreadsheetId || !range) {\n console.error('Usage: sheets read <spreadsheet-id> <range>');\n process.exit(1);\n }\n await cmdRead(spreadsheetId, range, options);\n break;\n }\n\n case 'write': {\n const spreadsheetId = positionals[0];\n const range = positionals[1];\n const values = positionals[2];\n if (!spreadsheetId || !range) {\n console.error('Usage: sheets write <spreadsheet-id> <range> [values]');\n console.error(' sheets write <id> <range> --input <file>');\n process.exit(1);\n }\n await cmdWrite(spreadsheetId, range, values, options);\n break;\n }\n\n case 'append': {\n const spreadsheetId = positionals[0];\n const range = positionals[1];\n const values = positionals[2];\n if (!spreadsheetId || !range) {\n console.error('Usage: sheets append <spreadsheet-id> <range> [values]');\n console.error(' sheets append <id> <range> --input <file>');\n process.exit(1);\n }\n await cmdAppend(spreadsheetId, range, values, options);\n break;\n }\n\n case 'clear': {\n const spreadsheetId = positionals[0];\n const ranges = positionals.slice(1);\n if (!spreadsheetId || ranges.length === 0) {\n console.error('Usage: sheets clear <spreadsheet-id> <range> [range2] [range3] ...');\n process.exit(1);\n }\n await cmdClear(spreadsheetId, ranges, options);\n break;\n }\n\n case 'search': {\n const spreadsheetId = positionals[0];\n const query = positionals[1];\n const range = positionals[2];\n if (!spreadsheetId || !query) {\n console.error('Usage: sheets search <spreadsheet-id> <query> [range]');\n console.error(' sheets search <id> \"search term\" \"Sheet1!A1:D100\"');\n process.exit(1);\n }\n await cmdSearch(spreadsheetId, query, range, options);\n break;\n }\n\n case 'install-claude-skill':\n await cmdInstallClaudeSkill();\n break;\n\n default:\n console.error(`Unknown command: ${command}`);\n printHelp();\n process.exit(1);\n }\n } catch (error) {\n const e = error as Error;\n console.error(`Error: ${e.message}`);\n\n // Check if this is a SheetsError with additional context\n if (e.name === 'SheetsError') {\n const sheetsErr = e as SheetsError;\n if (sheetsErr.status) {\n console.error(`Status: ${sheetsErr.status}`);\n }\n }\n\n // Get the range from positionals if available\n const range = positionals[1];\n const suggestions = getRangeErrorSuggestions(e.message, range);\n\n if (suggestions.length > 0) {\n console.error('');\n console.error('Suggestions:');\n suggestions.forEach(s => console.error(` - ${s}`));\n }\n\n process.exit(1);\n }\n}\n\nmain();\n","/**\n * Google Sheets API Type Definitions\n */\n\n// === Grid Properties ===\n\nexport interface GridProperties {\n rowCount: number;\n columnCount: number;\n frozenRowCount?: number;\n frozenColumnCount?: number;\n hideGridlines?: boolean;\n}\n\n// === Sheet Properties ===\n\nexport interface SheetProperties {\n sheetId: number;\n title: string;\n index: number;\n sheetType?: 'GRID' | 'OBJECT' | 'DATA_SOURCE';\n gridProperties?: GridProperties;\n hidden?: boolean;\n rightToLeft?: boolean;\n}\n\n// === Spreadsheet ===\n\nexport interface SpreadsheetProperties {\n title: string;\n locale?: string;\n timeZone?: string;\n autoRecalc?: 'ON_CHANGE' | 'MINUTE' | 'HOUR';\n defaultFormat?: CellFormat;\n}\n\nexport interface Spreadsheet {\n spreadsheetId: string;\n properties: SpreadsheetProperties;\n sheets: { properties: SheetProperties }[];\n spreadsheetUrl?: string;\n}\n\n// === Cell Format ===\n\nexport interface CellFormat {\n numberFormat?: {\n type: string;\n pattern?: string;\n };\n backgroundColor?: Color;\n textFormat?: TextFormat;\n}\n\nexport interface Color {\n red?: number;\n green?: number;\n blue?: number;\n alpha?: number;\n}\n\nexport interface TextFormat {\n foregroundColor?: Color;\n fontFamily?: string;\n fontSize?: number;\n bold?: boolean;\n italic?: boolean;\n strikethrough?: boolean;\n underline?: boolean;\n}\n\n// === Cell Value ===\n\nexport interface CellValue {\n value: string | number | boolean | null;\n formula?: string;\n formattedValue?: string;\n}\n\n// === Value Range ===\n\nexport type ValueRenderOption = 'FORMATTED_VALUE' | 'UNFORMATTED_VALUE' | 'FORMULA';\nexport type DateTimeRenderOption = 'SERIAL_NUMBER' | 'FORMATTED_STRING';\nexport type MajorDimension = 'ROWS' | 'COLUMNS';\n\nexport interface ValueRange {\n range: string;\n majorDimension: MajorDimension;\n values: CellValue[][];\n}\n\nexport interface GetValuesOptions {\n valueRenderOption?: ValueRenderOption;\n dateTimeRenderOption?: DateTimeRenderOption;\n majorDimension?: MajorDimension;\n}\n\nexport interface BatchGetValuesResponse {\n spreadsheetId: string;\n valueRanges: ValueRange[];\n}\n\n// === Clear Values ===\n\nexport interface ClearValuesResponse {\n spreadsheetId: string;\n clearedRange: string;\n}\n\nexport interface BatchClearValuesResponse {\n spreadsheetId: string;\n clearedRanges: string[];\n}\n\n// === Write Values ===\n\nexport type ValueInputOption = 'RAW' | 'USER_ENTERED';\nexport type InsertDataOption = 'OVERWRITE' | 'INSERT_ROWS';\nexport type RawCellValue = string | number | boolean | null;\n\nexport interface UpdateValuesOptions {\n valueInputOption?: ValueInputOption;\n majorDimension?: MajorDimension;\n includeValuesInResponse?: boolean;\n responseValueRenderOption?: ValueRenderOption;\n responseDateTimeRenderOption?: DateTimeRenderOption;\n}\n\nexport interface AppendValuesOptions extends UpdateValuesOptions {\n insertDataOption?: InsertDataOption;\n}\n\nexport interface UpdateValuesResponse {\n spreadsheetId: string;\n updatedRange: string;\n updatedRows: number;\n updatedColumns: number;\n updatedCells: number;\n updatedData?: ValueRange;\n}\n\nexport interface BatchUpdateValuesResponse {\n spreadsheetId: string;\n totalUpdatedRows: number;\n totalUpdatedColumns: number;\n totalUpdatedCells: number;\n totalUpdatedSheets: number;\n responses: UpdateValuesResponse[];\n}\n\nexport interface AppendValuesResponse {\n spreadsheetId: string;\n tableRange?: string;\n updates: UpdateValuesResponse;\n}\n\n// === Search Values ===\n\nexport interface SearchMatch {\n sheet: string;\n sheetId: number;\n address: string;\n row: number;\n column: number;\n value: string | number | boolean | null;\n}\n\nexport interface SearchOptions {\n range?: string;\n sheetIndex?: number;\n gid?: number;\n caseSensitive?: boolean;\n exactMatch?: boolean;\n regex?: boolean;\n limit?: number;\n}\n\nexport interface SearchResult {\n query: string;\n matchType: 'contains' | 'exact' | 'regex';\n caseSensitive: boolean;\n totalMatches: number;\n matches: SearchMatch[];\n}\n\n// === Authentication ===\n\nexport interface OAuthConfig {\n type: 'oauth';\n accessToken: string;\n refreshToken?: string;\n clientId?: string;\n clientSecret?: string;\n expiresAt?: number; // Unix timestamp in ms when access token expires\n}\n\nexport interface ServiceAccountConfig {\n type: 'service-account';\n credentialsPath?: string;\n credentials?: ServiceAccountCredentials;\n}\n\nexport interface ServiceAccountCredentials {\n type: 'service_account';\n project_id: string;\n private_key_id: string;\n private_key: string;\n client_email: string;\n client_id: string;\n auth_uri: string;\n token_uri: string;\n}\n\nexport interface UserAuthConfig {\n type: 'user';\n}\n\nexport interface StoredTokens {\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n email?: string;\n}\n\nexport type AuthConfig = OAuthConfig | ServiceAccountConfig | UserAuthConfig;\n\nexport interface SheetsClientOptions {\n auth: AuthConfig;\n}\n\n// === Error Types ===\n\nexport interface SheetsApiErrorDetail {\n '@type'?: string;\n reason?: string;\n domain?: string;\n metadata?: Record<string, string>;\n}\n\nexport interface SheetsApiError {\n code: number;\n message: string;\n status: string;\n details?: SheetsApiErrorDetail[];\n}\n\nexport class SheetsError extends Error {\n code: number;\n status: string;\n details?: SheetsApiErrorDetail[];\n\n constructor(error: SheetsApiError) {\n super(error.message);\n this.name = 'SheetsError';\n this.code = error.code;\n this.status = error.status;\n this.details = error.details;\n }\n}\n","/**\n * HTTP Client for Google Sheets API\n * Uses native Node.js fetch (Node 18+)\n */\n\nimport { SheetsError } from '../types/index.js';\n\nconst BASE_URL = 'https://sheets.googleapis.com/v4';\nconst MAX_RETRIES = 3;\nconst INITIAL_BACKOFF_MS = 1000;\n\nexport interface HttpClientOptions {\n getAccessToken: () => Promise<string>;\n}\n\nexport interface RequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\n body?: unknown;\n params?: Record<string, string>;\n}\n\nexport class HttpClient {\n private getAccessToken: () => Promise<string>;\n\n constructor(options: HttpClientOptions) {\n this.getAccessToken = options.getAccessToken;\n }\n\n async request<T>(path: string, options: RequestOptions = {}): Promise<T> {\n const { method = 'GET', body, params } = options;\n\n let url = `${BASE_URL}${path}`;\n if (params) {\n const searchParams = new URLSearchParams(params);\n url += `?${searchParams.toString()}`;\n }\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n const accessToken = await this.getAccessToken();\n\n const response = await fetch(url, {\n method,\n headers: {\n 'Authorization': `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (response.status === 429) {\n const backoffMs = INITIAL_BACKOFF_MS * Math.pow(2, attempt);\n await this.sleep(backoffMs);\n continue;\n }\n\n const data = await response.json() as { error?: { code: number; message: string; status: string } };\n\n if (!response.ok) {\n if (data.error) {\n throw new SheetsError({\n code: data.error.code,\n message: data.error.message,\n status: data.error.status,\n });\n }\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return data as T;\n } catch (error) {\n lastError = error as Error;\n\n if (error instanceof SheetsError && error.code !== 429 && error.code !== 500 && error.code !== 503) {\n throw error;\n }\n\n if (attempt < MAX_RETRIES - 1) {\n const backoffMs = INITIAL_BACKOFF_MS * Math.pow(2, attempt);\n await this.sleep(backoffMs);\n }\n }\n }\n\n throw lastError || new Error('Request failed after retries');\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}\n","/**\n * OAuth Client Constants\n * Replace with your Google Cloud OAuth client credentials\n */\n\n// Built-in OAuth client (Desktop app type)\n// Project: ariadng-sheets\nexport const OAUTH_CLIENT_ID = '344941894490-jmdvo5ghomqi7vuisfrf80hfassk1ma5.apps.googleusercontent.com';\nexport const OAUTH_CLIENT_SECRET = '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';\n\n// Redirect URI for local callback server\nexport const OAUTH_REDIRECT_URI = 'http://localhost:8085/callback';\nexport const OAUTH_CALLBACK_PORT = 8085;\n\n// OAuth endpoints\nexport const OAUTH_AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth';\nexport const OAUTH_TOKEN_URL = 'https://oauth2.googleapis.com/token';\nexport const OAUTH_USERINFO_URL = 'https://www.googleapis.com/oauth2/v2/userinfo';\n\n// Scopes\nexport const OAUTH_SCOPES = [\n 'https://www.googleapis.com/auth/spreadsheets',\n 'https://www.googleapis.com/auth/userinfo.email',\n];\n","/**\n * OAuth 2.0 Authentication\n * Supports pre-obtained access tokens with optional auto-refresh\n *\n * For automation (e.g., n8n), provide:\n * - accessToken: Current access token\n * - refreshToken: For obtaining new tokens when expired\n * - clientId: OAuth client ID\n * - clientSecret: OAuth client secret\n * - expiresAt: When the access token expires (Unix timestamp in ms)\n */\n\nimport type { OAuthConfig } from '../types/index.js';\nimport { OAUTH_TOKEN_URL } from './constants.js';\n\ninterface TokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n token_type: string;\n}\n\nexport class OAuthAuth {\n private config: OAuthConfig;\n private cachedToken: string;\n private expiresAt: number;\n\n constructor(config: OAuthConfig) {\n this.config = config;\n this.cachedToken = config.accessToken;\n this.expiresAt = config.expiresAt || 0;\n }\n\n async getAccessToken(): Promise<string> {\n // If no expiration tracking or no refresh credentials, return cached token\n if (!this.canRefresh()) {\n return this.cachedToken;\n }\n\n // Check if token is expired (with 60 second buffer)\n if (this.isExpired()) {\n await this.refreshToken();\n }\n\n return this.cachedToken;\n }\n\n private canRefresh(): boolean {\n return !!(\n this.config.refreshToken &&\n this.config.clientId &&\n this.config.clientSecret &&\n this.expiresAt > 0\n );\n }\n\n private isExpired(): boolean {\n return Date.now() >= this.expiresAt - 60000;\n }\n\n private async refreshToken(): Promise<void> {\n if (!this.config.refreshToken || !this.config.clientId || !this.config.clientSecret) {\n throw new Error('Token expired and missing refresh credentials (refreshToken, clientId, clientSecret)');\n }\n\n const response = await fetch(OAUTH_TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n client_id: this.config.clientId,\n client_secret: this.config.clientSecret,\n refresh_token: this.config.refreshToken,\n grant_type: 'refresh_token',\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Token refresh failed: ${error}`);\n }\n\n const tokenResponse = await response.json() as TokenResponse;\n\n this.cachedToken = tokenResponse.access_token;\n this.expiresAt = Date.now() + (tokenResponse.expires_in * 1000);\n\n // Update config with new refresh token if provided\n if (tokenResponse.refresh_token) {\n this.config.refreshToken = tokenResponse.refresh_token;\n }\n }\n\n /**\n * Get current token state for persistence in automation tools\n * Returns updated tokens after any refresh operations\n */\n getTokenState(): { accessToken: string; refreshToken?: string; expiresAt: number } {\n return {\n accessToken: this.cachedToken,\n refreshToken: this.config.refreshToken,\n expiresAt: this.expiresAt,\n };\n }\n}\n","/**\n * Service Account JWT Authentication\n * Uses RS256 signing to exchange JWT for access token\n */\n\nimport * as crypto from 'crypto';\nimport * as fs from 'fs/promises';\nimport type { ServiceAccountConfig, ServiceAccountCredentials } from '../types/index.js';\n\nconst TOKEN_URI = 'https://oauth2.googleapis.com/token';\nconst SCOPE = 'https://www.googleapis.com/auth/spreadsheets';\nconst TOKEN_LIFETIME_SECONDS = 3600;\n\ninterface TokenResponse {\n access_token: string;\n expires_in: number;\n token_type: string;\n}\n\nexport class ServiceAccountAuth {\n private config: ServiceAccountConfig;\n private credentials: ServiceAccountCredentials | null = null;\n private cachedToken: string | null = null;\n private tokenExpiresAt: number = 0;\n\n constructor(config: ServiceAccountConfig) {\n this.config = config;\n }\n\n async getAccessToken(): Promise<string> {\n if (this.cachedToken && Date.now() < this.tokenExpiresAt - 60000) {\n return this.cachedToken;\n }\n\n await this.loadCredentials();\n const jwt = this.createJwt();\n const token = await this.exchangeJwtForToken(jwt);\n\n this.cachedToken = token.access_token;\n this.tokenExpiresAt = Date.now() + (token.expires_in * 1000);\n\n return this.cachedToken;\n }\n\n private async loadCredentials(): Promise<void> {\n if (this.credentials) return;\n\n if (this.config.credentials) {\n this.credentials = this.config.credentials;\n return;\n }\n\n if (!this.config.credentialsPath) {\n throw new Error('Service account requires credentialsPath or credentials');\n }\n\n const content = await fs.readFile(this.config.credentialsPath, 'utf-8');\n this.credentials = JSON.parse(content) as ServiceAccountCredentials;\n }\n\n private createJwt(): string {\n if (!this.credentials) {\n throw new Error('Credentials not loaded');\n }\n\n const now = Math.floor(Date.now() / 1000);\n\n const header = {\n alg: 'RS256',\n typ: 'JWT',\n };\n\n const payload = {\n iss: this.credentials.client_email,\n scope: SCOPE,\n aud: TOKEN_URI,\n iat: now,\n exp: now + TOKEN_LIFETIME_SECONDS,\n };\n\n const encodedHeader = this.base64UrlEncode(JSON.stringify(header));\n const encodedPayload = this.base64UrlEncode(JSON.stringify(payload));\n const signatureInput = `${encodedHeader}.${encodedPayload}`;\n\n const sign = crypto.createSign('RSA-SHA256');\n sign.update(signatureInput);\n const signature = sign.sign(this.credentials.private_key);\n const encodedSignature = this.base64UrlEncode(signature);\n\n return `${signatureInput}.${encodedSignature}`;\n }\n\n private base64UrlEncode(input: string | Buffer): string {\n const buffer = typeof input === 'string' ? Buffer.from(input) : input;\n return buffer.toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n }\n\n private async exchangeJwtForToken(jwt: string): Promise<TokenResponse> {\n const response = await fetch(TOKEN_URI, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',\n assertion: jwt,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Token exchange failed: ${error}`);\n }\n\n return await response.json() as TokenResponse;\n }\n}\n","/**\n * User OAuth Authentication\n * OAuth 2.0 Authorization Code flow with PKCE for personal Google accounts\n */\n\nimport * as crypto from 'crypto';\nimport * as fs from 'fs/promises';\nimport * as http from 'http';\nimport * as os from 'os';\nimport * as path from 'path';\nimport { exec } from 'child_process';\nimport type { StoredTokens } from '../types/index.js';\nimport {\n OAUTH_CLIENT_ID,\n OAUTH_CLIENT_SECRET,\n OAUTH_REDIRECT_URI,\n OAUTH_CALLBACK_PORT,\n OAUTH_AUTH_URL,\n OAUTH_TOKEN_URL,\n OAUTH_USERINFO_URL,\n OAUTH_SCOPES,\n} from './constants.js';\n\nexport interface OAuthClientCredentials {\n clientId: string;\n clientSecret: string;\n}\n\nconst CONFIG_DIR = path.join(os.homedir(), '.sheets');\nconst TOKENS_FILE = path.join(CONFIG_DIR, 'tokens.json');\n\n// === PKCE ===\n\ninterface PKCEPair {\n codeVerifier: string;\n codeChallenge: string;\n}\n\nexport function generatePKCE(): PKCEPair {\n const codeVerifier = crypto.randomBytes(32).toString('base64url');\n const codeChallenge = crypto\n .createHash('sha256')\n .update(codeVerifier)\n .digest('base64url');\n return { codeVerifier, codeChallenge };\n}\n\n// === Browser ===\n\nfunction openBrowser(url: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const platform = process.platform;\n let command: string;\n\n if (platform === 'darwin') {\n command = `open \"${url}\"`;\n } else if (platform === 'win32') {\n command = `start \"\" \"${url}\"`;\n } else {\n command = `xdg-open \"${url}\"`;\n }\n\n exec(command, (error) => {\n if (error) {\n reject(new Error(`Failed to open browser: ${error.message}`));\n } else {\n resolve();\n }\n });\n });\n}\n\n// === Callback Server ===\n\nfunction startCallbackServer(): Promise<string> {\n return new Promise((resolve, reject) => {\n let timeoutId: NodeJS.Timeout;\n\n const server = http.createServer((req, res) => {\n const url = new URL(req.url || '', `http://localhost:${OAUTH_CALLBACK_PORT}`);\n\n if (url.pathname === '/callback') {\n const code = url.searchParams.get('code');\n const error = url.searchParams.get('error');\n\n if (error) {\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end('<html><body><h1>Authorization Failed</h1><p>You can close this window.</p></body></html>');\n clearTimeout(timeoutId);\n server.close();\n reject(new Error(`Authorization error: ${error}`));\n return;\n }\n\n if (code) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end('<html><body><h1>Authorization Successful</h1><p>You can close this window.</p></body></html>');\n clearTimeout(timeoutId);\n server.close();\n resolve(code);\n return;\n }\n\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end('<html><body><h1>Missing Code</h1></body></html>');\n } else {\n res.writeHead(404);\n res.end();\n }\n });\n\n server.on('error', (err) => {\n clearTimeout(timeoutId);\n reject(new Error(`Callback server error: ${err.message}`));\n });\n\n server.listen(OAUTH_CALLBACK_PORT, () => {\n // Server started, waiting for callback\n });\n\n // Timeout after 5 minutes\n timeoutId = setTimeout(() => {\n server.close();\n reject(new Error('Authorization timeout'));\n }, 5 * 60 * 1000);\n });\n}\n\n// === Authorization URL ===\n\nexport function getAuthorizationUrl(codeChallenge: string, clientId?: string): string {\n const params = new URLSearchParams({\n client_id: clientId || OAUTH_CLIENT_ID,\n redirect_uri: OAUTH_REDIRECT_URI,\n response_type: 'code',\n scope: OAUTH_SCOPES.join(' '),\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n access_type: 'offline',\n prompt: 'consent',\n });\n\n return `${OAUTH_AUTH_URL}?${params.toString()}`;\n}\n\n// === Token Exchange ===\n\ninterface TokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n token_type: string;\n}\n\nasync function exchangeCodeForTokens(code: string, codeVerifier: string, credentials?: OAuthClientCredentials): Promise<TokenResponse> {\n const response = await fetch(OAUTH_TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n client_id: credentials?.clientId || OAUTH_CLIENT_ID,\n client_secret: credentials?.clientSecret || OAUTH_CLIENT_SECRET,\n code,\n code_verifier: codeVerifier,\n grant_type: 'authorization_code',\n redirect_uri: OAUTH_REDIRECT_URI,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Token exchange failed: ${error}`);\n }\n\n return await response.json() as TokenResponse;\n}\n\nasync function refreshAccessToken(refreshToken: string): Promise<TokenResponse> {\n const response = await fetch(OAUTH_TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n client_id: OAUTH_CLIENT_ID,\n client_secret: OAUTH_CLIENT_SECRET,\n refresh_token: refreshToken,\n grant_type: 'refresh_token',\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Token refresh failed: ${error}`);\n }\n\n return await response.json() as TokenResponse;\n}\n\n// === User Info ===\n\ninterface UserInfo {\n email: string;\n id: string;\n}\n\nasync function getUserInfo(accessToken: string): Promise<UserInfo> {\n const response = await fetch(OAUTH_USERINFO_URL, {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n\n if (!response.ok) {\n throw new Error('Failed to get user info');\n }\n\n return await response.json() as UserInfo;\n}\n\n// === Token Storage ===\n\nasync function ensureConfigDir(): Promise<void> {\n try {\n await fs.mkdir(CONFIG_DIR, { recursive: true });\n } catch {\n // Directory already exists\n }\n}\n\nexport async function loadStoredTokens(): Promise<StoredTokens | null> {\n try {\n const content = await fs.readFile(TOKENS_FILE, 'utf-8');\n return JSON.parse(content) as StoredTokens;\n } catch {\n return null;\n }\n}\n\nasync function saveTokens(tokens: StoredTokens): Promise<void> {\n await ensureConfigDir();\n await fs.writeFile(TOKENS_FILE, JSON.stringify(tokens, null, 2));\n}\n\nexport async function deleteTokens(): Promise<void> {\n try {\n await fs.unlink(TOKENS_FILE);\n } catch {\n // File doesn't exist\n }\n}\n\n// === Login Flow ===\n\nexport async function login(credentials?: OAuthClientCredentials): Promise<StoredTokens> {\n const { codeVerifier, codeChallenge } = generatePKCE();\n const authUrl = getAuthorizationUrl(codeChallenge, credentials?.clientId);\n\n console.log('Opening browser for Google login...');\n\n // Start server first, then open browser\n const codePromise = startCallbackServer();\n await openBrowser(authUrl);\n\n console.log('Waiting for authorization...');\n const code = await codePromise;\n\n console.log('Exchanging code for tokens...');\n const tokenResponse = await exchangeCodeForTokens(code, codeVerifier, credentials);\n\n const userInfo = await getUserInfo(tokenResponse.access_token);\n\n const tokens: StoredTokens = {\n accessToken: tokenResponse.access_token,\n refreshToken: tokenResponse.refresh_token || '',\n expiresAt: Date.now() + (tokenResponse.expires_in * 1000),\n email: userInfo.email,\n };\n\n await saveTokens(tokens);\n return tokens;\n}\n\n// === Auth Provider ===\n\nexport class UserAuth {\n private tokens: StoredTokens | null = null;\n\n async getAccessToken(): Promise<string> {\n if (!this.tokens) {\n this.tokens = await loadStoredTokens();\n }\n\n if (!this.tokens) {\n throw new Error('Not logged in. Run \"sheets login\" first.');\n }\n\n // Refresh if expired (with 1 minute buffer)\n if (Date.now() >= this.tokens.expiresAt - 60000) {\n if (!this.tokens.refreshToken) {\n throw new Error('Token expired and no refresh token. Run \"sheets login\" again.');\n }\n\n const tokenResponse = await refreshAccessToken(this.tokens.refreshToken);\n this.tokens.accessToken = tokenResponse.access_token;\n this.tokens.expiresAt = Date.now() + (tokenResponse.expires_in * 1000);\n\n if (tokenResponse.refresh_token) {\n this.tokens.refreshToken = tokenResponse.refresh_token;\n }\n\n await saveTokens(this.tokens);\n }\n\n return this.tokens.accessToken;\n }\n}\n","/**\n * Authentication Module Exports\n */\n\nimport type { AuthConfig } from '../types/index.js';\nimport { OAuthAuth } from './oauth.js';\nimport { ServiceAccountAuth } from './service-account.js';\nimport { UserAuth } from './user-auth.js';\n\nexport { OAuthAuth } from './oauth.js';\nexport { ServiceAccountAuth } from './service-account.js';\nexport { UserAuth, login, loadStoredTokens, deleteTokens } from './user-auth.js';\nexport type { OAuthClientCredentials } from './user-auth.js';\n\nexport interface AuthProvider {\n getAccessToken(): Promise<string>;\n}\n\nexport function createAuthProvider(config: AuthConfig): AuthProvider {\n switch (config.type) {\n case 'oauth':\n return new OAuthAuth(config);\n case 'service-account':\n return new ServiceAccountAuth(config);\n case 'user':\n return new UserAuth();\n default:\n throw new Error(`Unknown auth type: ${(config as { type: string }).type}`);\n }\n}\n","/**\n * Google Sheets API Client\n */\n\nimport type {\n Spreadsheet,\n SheetProperties,\n ValueRange,\n GetValuesOptions,\n SheetsClientOptions,\n BatchGetValuesResponse,\n ClearValuesResponse,\n BatchClearValuesResponse,\n RawCellValue,\n UpdateValuesOptions,\n UpdateValuesResponse,\n BatchUpdateValuesResponse,\n AppendValuesOptions,\n AppendValuesResponse,\n SearchOptions,\n SearchResult,\n SearchMatch,\n} from '../types/index.js';\nimport { HttpClient } from '../http/index.js';\nimport { createAuthProvider } from '../auth/index.js';\n\ninterface RawValueRange {\n range: string;\n majorDimension?: 'ROWS' | 'COLUMNS';\n values?: (string | number | boolean | null)[][];\n}\n\ninterface RawBatchGetResponse {\n spreadsheetId: string;\n valueRanges?: RawValueRange[];\n}\n\n/**\n * Convert column letter(s) to 1-based column number\n * A=1, B=2, ..., Z=26, AA=27, AB=28, etc.\n */\nfunction columnLetterToNumber(letters: string): number {\n let result = 0;\n for (let i = 0; i < letters.length; i++) {\n result = result * 26 + (letters.charCodeAt(i) - 64);\n }\n return result;\n}\n\n/**\n * Convert 1-based column number to column letter(s)\n * 1=A, 2=B, ..., 26=Z, 27=AA, 28=AB, etc.\n */\nfunction columnNumberToLetter(num: number): string {\n let result = '';\n while (num > 0) {\n const remainder = (num - 1) % 26;\n result = String.fromCharCode(65 + remainder) + result;\n num = Math.floor((num - 1) / 26);\n }\n return result;\n}\n\n/**\n * Parse A1 notation to extract starting row and column\n * Returns { startRow, startCol } (1-based)\n */\nfunction parseA1Range(range: string): { startRow: number; startCol: number } {\n // Remove sheet name if present (e.g., \"Sheet1!A1:D10\" -> \"A1:D10\")\n const cellRef = range.includes('!') ? range.split('!')[1] : range;\n\n // Extract first cell (e.g., \"A1:D10\" -> \"A1\", \"A1\" -> \"A1\")\n const firstCell = cellRef.split(':')[0];\n\n // Parse column letters and row number\n const match = firstCell.match(/^([A-Z]+)(\\d+)$/i);\n if (!match) {\n return { startRow: 1, startCol: 1 };\n }\n\n return {\n startCol: columnLetterToNumber(match[1].toUpperCase()),\n startRow: parseInt(match[2], 10),\n };\n}\n\nexport class SheetsClient {\n private http: HttpClient;\n\n constructor(options: SheetsClientOptions) {\n const authProvider = createAuthProvider(options.auth);\n this.http = new HttpClient({\n getAccessToken: () => authProvider.getAccessToken(),\n });\n }\n\n /**\n * Get a spreadsheet by ID\n */\n async getSpreadsheet(spreadsheetId: string): Promise<Spreadsheet> {\n return this.http.request<Spreadsheet>(`/spreadsheets/${spreadsheetId}`);\n }\n\n /**\n * Get list of sheets in a spreadsheet\n */\n async getSheets(spreadsheetId: string): Promise<SheetProperties[]> {\n const spreadsheet = await this.getSpreadsheet(spreadsheetId);\n return spreadsheet.sheets.map(sheet => sheet.properties);\n }\n\n /**\n * Read cell values from a range\n */\n async getValues(spreadsheetId: string, range: string, options?: GetValuesOptions): Promise<ValueRange> {\n const params: Record<string, string> = {};\n\n if (options?.valueRenderOption) {\n params.valueRenderOption = options.valueRenderOption;\n }\n if (options?.dateTimeRenderOption) {\n params.dateTimeRenderOption = options.dateTimeRenderOption;\n }\n if (options?.majorDimension) {\n params.majorDimension = options.majorDimension;\n }\n\n const encodedRange = encodeURIComponent(range);\n const response = await this.http.request<RawValueRange>(\n `/spreadsheets/${spreadsheetId}/values/${encodedRange}`,\n { params }\n );\n\n return this.normalizeValueRange(response);\n }\n\n /**\n * Read cell formulas from a range\n */\n async getFormulas(spreadsheetId: string, range: string): Promise<ValueRange> {\n return this.getValues(spreadsheetId, range, { valueRenderOption: 'FORMULA' });\n }\n\n /**\n * Read multiple ranges at once\n */\n async batchGetValues(spreadsheetId: string, ranges: string[], options?: GetValuesOptions): Promise<BatchGetValuesResponse> {\n const params: Record<string, string> = {\n ranges: ranges.join(','),\n };\n\n if (options?.valueRenderOption) {\n params.valueRenderOption = options.valueRenderOption;\n }\n if (options?.dateTimeRenderOption) {\n params.dateTimeRenderOption = options.dateTimeRenderOption;\n }\n if (options?.majorDimension) {\n params.majorDimension = options.majorDimension;\n }\n\n const response = await this.http.request<RawBatchGetResponse>(\n `/spreadsheets/${spreadsheetId}/values:batchGet`,\n { params }\n );\n\n return {\n spreadsheetId: response.spreadsheetId,\n valueRanges: (response.valueRanges || []).map(vr => this.normalizeValueRange(vr)),\n };\n }\n\n /**\n * Clear values from a single range\n */\n async clearValues(spreadsheetId: string, range: string): Promise<ClearValuesResponse> {\n const encodedRange = encodeURIComponent(range);\n return this.http.request<ClearValuesResponse>(\n `/spreadsheets/${spreadsheetId}/values/${encodedRange}:clear`,\n { method: 'POST' }\n );\n }\n\n /**\n * Clear values from multiple ranges\n */\n async batchClearValues(spreadsheetId: string, ranges: string[]): Promise<BatchClearValuesResponse> {\n return this.http.request<BatchClearValuesResponse>(\n `/spreadsheets/${spreadsheetId}/values:batchClear`,\n { method: 'POST', body: { ranges } }\n );\n }\n\n /**\n * Write values to a range (or starting cell)\n * Range can be \"A1\" or \"A1:D10\" - data array determines actual extent\n */\n async updateValues(\n spreadsheetId: string,\n range: string,\n values: RawCellValue[][],\n options?: UpdateValuesOptions\n ): Promise<UpdateValuesResponse> {\n const params: Record<string, string> = {\n valueInputOption: options?.valueInputOption || 'USER_ENTERED',\n };\n\n if (options?.includeValuesInResponse) {\n params.includeValuesInResponse = 'true';\n }\n if (options?.responseValueRenderOption) {\n params.responseValueRenderOption = options.responseValueRenderOption;\n }\n if (options?.responseDateTimeRenderOption) {\n params.responseDateTimeRenderOption = options.responseDateTimeRenderOption;\n }\n\n const encodedRange = encodeURIComponent(range);\n return this.http.request<UpdateValuesResponse>(\n `/spreadsheets/${spreadsheetId}/values/${encodedRange}`,\n {\n method: 'PUT',\n params,\n body: {\n majorDimension: options?.majorDimension || 'ROWS',\n values,\n },\n }\n );\n }\n\n /**\n * Write to multiple ranges in one request\n */\n async batchUpdateValues(\n spreadsheetId: string,\n data: { range: string; values: RawCellValue[][] }[],\n options?: UpdateValuesOptions\n ): Promise<BatchUpdateValuesResponse> {\n return this.http.request<BatchUpdateValuesResponse>(\n `/spreadsheets/${spreadsheetId}/values:batchUpdate`,\n {\n method: 'POST',\n body: {\n valueInputOption: options?.valueInputOption || 'USER_ENTERED',\n data: data.map(d => ({\n range: d.range,\n majorDimension: options?.majorDimension || 'ROWS',\n values: d.values,\n })),\n includeValuesInResponse: options?.includeValuesInResponse || false,\n responseValueRenderOption: options?.responseValueRenderOption,\n responseDateTimeRenderOption: options?.responseDateTimeRenderOption,\n },\n }\n );\n }\n\n /**\n * Append rows after the last row of detected table\n */\n async appendValues(\n spreadsheetId: string,\n range: string,\n values: RawCellValue[][],\n options?: AppendValuesOptions\n ): Promise<AppendValuesResponse> {\n const params: Record<string, string> = {\n valueInputOption: options?.valueInputOption || 'USER_ENTERED',\n };\n\n if (options?.insertDataOption) {\n params.insertDataOption = options.insertDataOption;\n }\n if (options?.includeValuesInResponse) {\n params.includeValuesInResponse = 'true';\n }\n if (options?.responseValueRenderOption) {\n params.responseValueRenderOption = options.responseValueRenderOption;\n }\n if (options?.responseDateTimeRenderOption) {\n params.responseDateTimeRenderOption = options.responseDateTimeRenderOption;\n }\n\n const encodedRange = encodeURIComponent(range);\n return this.http.request<AppendValuesResponse>(\n `/spreadsheets/${spreadsheetId}/values/${encodedRange}:append`,\n {\n method: 'POST',\n params,\n body: {\n majorDimension: options?.majorDimension || 'ROWS',\n values,\n },\n }\n );\n }\n\n /**\n * Search for values matching a query across sheets\n */\n async searchValues(\n spreadsheetId: string,\n query: string,\n options?: SearchOptions\n ): Promise<SearchResult> {\n const caseSensitive = options?.caseSensitive ?? false;\n const exactMatch = options?.exactMatch ?? false;\n const useRegex = options?.regex ?? false;\n const limit = options?.limit;\n\n // Determine match type for response\n const matchType = useRegex ? 'regex' : (exactMatch ? 'exact' : 'contains');\n\n // Build the matcher function\n let matcher: (cellValue: string) => boolean;\n\n if (useRegex) {\n const flags = caseSensitive ? '' : 'i';\n const regex = new RegExp(query, flags);\n matcher = (cellValue) => regex.test(cellValue);\n } else if (exactMatch) {\n if (caseSensitive) {\n matcher = (cellValue) => cellValue === query;\n } else {\n const lowerQuery = query.toLowerCase();\n matcher = (cellValue) => cellValue.toLowerCase() === lowerQuery;\n }\n } else {\n // Contains match (default)\n if (caseSensitive) {\n matcher = (cellValue) => cellValue.includes(query);\n } else {\n const lowerQuery = query.toLowerCase();\n matcher = (cellValue) => cellValue.toLowerCase().includes(lowerQuery);\n }\n }\n\n const matches: SearchMatch[] = [];\n\n // Get sheets to search\n const allSheets = await this.getSheets(spreadsheetId);\n let sheetsToSearch: SheetProperties[];\n\n if (options?.sheetIndex !== undefined) {\n const sheet = allSheets.find(s => s.index === options.sheetIndex);\n if (!sheet) {\n throw new Error(`Sheet index ${options.sheetIndex} not found.`);\n }\n sheetsToSearch = [sheet];\n } else if (options?.gid !== undefined) {\n const sheet = allSheets.find(s => s.sheetId === options.gid);\n if (!sheet) {\n throw new Error(`Sheet with gid ${options.gid} not found.`);\n }\n sheetsToSearch = [sheet];\n } else if (options?.range && options.range.includes('!')) {\n // Range includes sheet name, use as-is\n sheetsToSearch = []; // Will handle specially below\n } else {\n // Search all sheets\n sheetsToSearch = allSheets.filter(s => !s.hidden);\n }\n\n // Search logic\n if (options?.range && options.range.includes('!')) {\n // Specific range with sheet name provided\n const valueRange = await this.getValues(spreadsheetId, options.range);\n const sheetName = options.range.split('!')[0].replace(/^'|'$/g, '').replace(/''/g, \"'\");\n const sheet = allSheets.find(s => s.title === sheetName);\n const { startRow, startCol } = parseA1Range(options.range);\n\n this.collectMatches(\n valueRange,\n sheetName,\n sheet?.sheetId ?? 0,\n startRow,\n startCol,\n matcher,\n matches,\n limit\n );\n } else {\n // Search across sheets\n for (const sheet of sheetsToSearch) {\n if (limit && matches.length >= limit) break;\n\n const escapedTitle = sheet.title.replace(/'/g, \"''\");\n const range = options?.range\n ? `'${escapedTitle}'!${options.range}`\n : `'${escapedTitle}'`; // Entire sheet\n\n try {\n const valueRange = await this.getValues(spreadsheetId, range);\n const { startRow, startCol } = parseA1Range(valueRange.range);\n\n this.collectMatches(\n valueRange,\n sheet.title,\n sheet.sheetId,\n startRow,\n startCol,\n matcher,\n matches,\n limit\n );\n } catch {\n // Skip sheets that fail (e.g., empty sheets)\n continue;\n }\n }\n }\n\n return {\n query,\n matchType,\n caseSensitive,\n totalMatches: matches.length,\n matches,\n };\n }\n\n private collectMatches(\n valueRange: ValueRange,\n sheetName: string,\n sheetId: number,\n startRow: number,\n startCol: number,\n matcher: (value: string) => boolean,\n matches: SearchMatch[],\n limit?: number\n ): void {\n for (let rowIndex = 0; rowIndex < valueRange.values.length; rowIndex++) {\n if (limit && matches.length >= limit) return;\n\n const row = valueRange.values[rowIndex];\n for (let colIndex = 0; colIndex < row.length; colIndex++) {\n if (limit && matches.length >= limit) return;\n\n const cell = row[colIndex];\n const cellValue = cell.value;\n\n // Skip null/undefined values\n if (cellValue == null) continue;\n\n // Convert to string for matching\n const stringValue = String(cellValue);\n\n if (matcher(stringValue)) {\n const actualRow = startRow + rowIndex;\n const actualCol = startCol + colIndex;\n\n matches.push({\n sheet: sheetName,\n sheetId,\n address: columnNumberToLetter(actualCol) + actualRow,\n row: actualRow,\n column: actualCol,\n value: cellValue,\n });\n }\n }\n }\n }\n\n private normalizeValueRange(raw: RawValueRange): ValueRange {\n const values = (raw.values || []).map(row =>\n row.map(cell => ({\n value: cell,\n }))\n );\n\n return {\n range: raw.range,\n majorDimension: raw.majorDimension || 'ROWS',\n values,\n };\n }\n}\n\nexport function createClient(options: SheetsClientOptions): SheetsClient {\n return new SheetsClient(options);\n}\n"],"mappings":"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","names":["fs","path","os","path","crypto","fs"]}
package/dist/cli.js CHANGED
@@ -162,7 +162,7 @@ var OAuthAuth = class {
162
162
  import * as crypto from "crypto";
163
163
  import * as fs from "fs/promises";
164
164
  var TOKEN_URI = "https://oauth2.googleapis.com/token";
165
- var SCOPE = "https://www.googleapis.com/auth/spreadsheets.readonly";
165
+ var SCOPE = "https://www.googleapis.com/auth/spreadsheets";
166
166
  var TOKEN_LIFETIME_SECONDS = 3600;
167
167
  var ServiceAccountAuth = class {
168
168
  config;