UNPKG

longcelot-sheet-db

Version:

Google Sheets-backed staging database adapter for Node.js with schema-first design

77 lines 3.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.readTokens = readTokens; exports.saveTokens = saveTokens; exports.resolveTokens = resolveTokens; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const chalk_1 = __importDefault(require("chalk")); const inquirer_1 = __importDefault(require("inquirer")); const cliFiles_1 = require("../../utils/cliFiles"); function readTokens() { const tokenPath = (0, cliFiles_1.resolveTokensPath)(); if (!fs_1.default.existsSync(tokenPath)) return null; try { return JSON.parse(fs_1.default.readFileSync(tokenPath, 'utf-8')); } catch { return null; } } function saveTokens(tokens) { const tokenPath = path_1.default.join(process.cwd(), cliFiles_1.TOKENS_FILENAME); // mode: 0o600 — owner read/write only. This file holds a Google OAuth refresh_token, which is a // long-lived bearer credential for the admin's Sheets/Drive access; default file permissions // (typically 0o644, world/group-readable) would leave it exposed to any other local user or // process on a shared machine or CI runner. fs_1.default.writeFileSync(tokenPath, JSON.stringify(tokens, null, 2), { encoding: 'utf-8', mode: 0o600 }); try { fs_1.default.chmodSync(tokenPath, 0o600); } catch { // Best-effort — e.g. unsupported on some Windows filesystems. writeFileSync's own `mode` // above already covers the common case (file didn't previously exist with looser permissions). } } /** * Refreshes stored tokens if present, otherwise walks the user through the interactive * browser OAuth flow. Shared by every CLI command that needs to talk to the Sheets API * (sync, drop-table, drop-column, rename-column). */ async function resolveTokens(oauth) { const stored = readTokens(); if (stored?.refresh_token) { try { console.log(chalk_1.default.cyan('🔄 Refreshing OAuth tokens...\n')); const refreshed = await oauth.refreshTokens(stored.refresh_token); const merged = { ...stored, ...refreshed }; saveTokens(merged); return merged; } catch { console.log(chalk_1.default.yellow('⚠️ Token refresh failed. Re-authorizing...\n')); } } const authUrl = oauth.getAuthUrl(); console.log(chalk_1.default.cyan('🔐 Authorization required.\n')); console.log(chalk_1.default.white('Open the following URL in your browser:\n')); console.log(chalk_1.default.bold.underline(authUrl)); console.log(); const { code } = await inquirer_1.default.prompt([ { type: 'input', name: 'code', message: 'Paste the authorization code from the redirect URL:', validate: (v) => (v.trim().length > 0 ? true : 'Code cannot be empty'), }, ]); const tokens = await oauth.getTokens(code.trim()); saveTokens(tokens); console.log(chalk_1.default.green(`✅ Tokens saved to ${cliFiles_1.TOKENS_FILENAME}\n`)); return tokens; } //# sourceMappingURL=oauthFlow.js.map