longcelot-sheet-db
Version:
Google Sheets-backed staging database adapter for Node.js with schema-first design
114 lines • 4.96 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadCLIConfig = loadCLIConfig;
exports.buildAdminAdapter = buildAdminAdapter;
exports.resolveSheetTargets = resolveSheetTargets;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const chalk_1 = __importDefault(require("chalk"));
const sheetAdapter_1 = require("../../adapter/sheetAdapter");
const oauth_1 = require("../../auth/oauth");
const cliFiles_1 = require("../../utils/cliFiles");
const actorConfig_1 = require("../../utils/actorConfig");
const oauthFlow_1 = require("./oauthFlow");
function loadCLIConfig() {
try {
return require((0, cliFiles_1.resolveConfigPath)()).default;
}
catch {
console.error(chalk_1.default.red('❌ lsdb.config.ts not found. Run: lsdb init'));
process.exit(1);
}
}
/**
* Sets up a fully-wired SheetAdapter (env checks, OAuth, admin context) with the given schemas
* registered — shared by drop-table/drop-column/rename-column, which each also need direct
* SheetClient access (via adapter.getClient()) alongside normal table() CRUD for reading the
* admin `users` table on --all-users.
*/
async function buildAdminAdapter(params) {
require('dotenv').config();
const requiredEnvVars = ['GOOGLE_CLIENT_ID', 'GOOGLE_CLIENT_SECRET', 'GOOGLE_REDIRECT_URI'];
for (const envVar of requiredEnvVars) {
if (!process.env[envVar]) {
console.error(chalk_1.default.red(`❌ Missing environment variable: ${envVar}`));
process.exit(1);
}
}
const adminActor = params.config.actors.find((a) => (0, actorConfig_1.resolveActorName)(a) === 'admin');
const adminSheetId = adminActor ? process.env[adminActor.sheetIdEnv] : process.env.ADMIN_SHEET_ID;
if (!adminSheetId) {
console.error(chalk_1.default.red(`❌ Admin sheet ID not set. Add ${adminActor?.sheetIdEnv ?? 'ADMIN_SHEET_ID'} to your .env`));
process.exit(1);
}
const oauth = (0, oauth_1.createOAuthManager)({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
redirectUri: process.env.GOOGLE_REDIRECT_URI,
});
let tokens;
try {
if (params.tokenFile) {
const tokenFilePath = path_1.default.resolve(process.cwd(), params.tokenFile);
if (!fs_1.default.existsSync(tokenFilePath)) {
console.error(chalk_1.default.red(`❌ Token file not found: ${tokenFilePath}`));
process.exit(1);
}
tokens = JSON.parse(fs_1.default.readFileSync(tokenFilePath, 'utf-8'));
console.log(chalk_1.default.green(`✅ Loaded tokens from ${params.tokenFile}\n`));
}
else {
tokens = await (0, oauthFlow_1.resolveTokens)(oauth);
}
}
catch (err) {
console.error(chalk_1.default.red(`❌ Authentication failed: ${err}`));
process.exit(1);
}
const adapter = (0, sheetAdapter_1.createSheetAdapter)({
adminSheetId,
credentials: {
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
redirectUri: process.env.GOOGLE_REDIRECT_URI,
},
tokens,
});
adapter.registerSchemas(params.schemas);
const adminCtx = adapter.withContext({ userId: 'schema-cli', actor: 'admin', actorSheetId: adminSheetId });
return { adapter, adminCtx, adminSheetId };
}
/**
* Resolves which live Google Sheets a change to an actor's table should apply to: the admin
* sheet for actor:'admin', or the actor's configured dev/shared sheet plus (with --all-users)
* every registered user's personal actor sheet, read from the admin `users` table exactly like
* sync.ts's --all-users flow does.
*/
async function resolveSheetTargets(adminCtx, actor, adminSheetId, actorCfg, allUsers) {
if (actor === 'admin') {
return [{ sheetId: adminSheetId, label: 'admin' }];
}
const targets = [];
const configuredSheetId = actorCfg ? process.env[actorCfg.sheetIdEnv] : undefined;
if (configuredSheetId) {
targets.push({ sheetId: configuredSheetId, label: `${actor} (dev/shared)` });
}
if (allUsers) {
try {
const users = await adminCtx.table('users').findMany({});
for (const user of users) {
if (user.role === actor && user.actor_sheet_id) {
targets.push({ sheetId: user.actor_sheet_id, label: `${actor}:${user.user_id}` });
}
}
}
catch (err) {
console.log(chalk_1.default.yellow(` ⚠ Could not fetch registered users for --all-users: ${err}`));
}
}
return targets;
}
//# sourceMappingURL=adminAdapter.js.map