longcelot-sheet-db
Version:
Google Sheets-backed staging database adapter for Node.js with schema-first design
175 lines (171 loc) • 7.6 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.initCommand = initCommand;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const inquirer_1 = __importDefault(require("inquirer"));
const chalk_1 = __importDefault(require("chalk"));
function printBanner() {
const c = chalk_1.default.hex('#05b5fb').bold;
const lines = [
'█ ██ █ █ ██ ███ ████ █ ██ ████ ███ █ █ ████ ████ ████ ███ ███ ',
'█ █ █ ██ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █',
'█ █ █ █ ██ █ ██ █ ███ █ █ █ █ ██ ████ ███ ███ █ █ █ ███',
'█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █',
'████ ██ █ █ ███ ███ ████ ████ ██ █ ███ █ █ ████ ████ █ ███ ███',
];
console.log();
lines.forEach((line) => console.log(' ' + c(line)));
console.log();
console.log(' ' + chalk_1.default.hex('#05b5fb')('Google Sheets-backed Staging Database Adapter'));
console.log();
}
async function initCommand(options) {
printBanner();
if (options.integrate) {
console.log(chalk_1.default.blue('Integrating into an existing project...\n'));
}
const defaultProjectName = path_1.default.basename(process.cwd());
const answers = await inquirer_1.default.prompt([
{
type: 'input',
name: 'projectName',
message: 'Project name:',
default: defaultProjectName,
when: !options.integrate,
},
{
type: 'input',
name: 'superAdminEmail',
message: 'Super admin email:',
validate: (input) => input.includes('@') || 'Please enter a valid email',
},
{
type: 'input',
name: 'actors',
message: 'Actors (comma-separated):',
default: 'admin,user',
filter: (input) => input.split(',').map((s) => s.trim()),
},
]);
const projectName = options.integrate ? defaultProjectName : answers.projectName;
const actorConfigs = answers.actors.map((role) => ({
name: role,
sheetIdEnv: role === 'admin' ? 'ADMIN_SHEET_ID' : `DEV_${role.toUpperCase()}_SHEET_ID`,
}));
const configContent = `export default {
projectName: "${projectName}",
superAdminEmail: "${answers.superAdminEmail}",
actors: ${JSON.stringify(actorConfigs, null, 2)},
// Schema mismatch behaviour: 'warn' | 'error' | 'auto-sync'
onSchemaMismatch: 'warn',
};
`;
const nonAdminActors = answers.actors.filter((a) => a !== 'admin');
const devSheetVars = nonAdminActors
.map((role) => `DEV_${role.toUpperCase()}_SHEET_ID=`)
.join('\n');
const envContent = `# Google OAuth credentials
# Get these at: https://console.cloud.google.com/apis/credentials
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_REDIRECT_URI=http://localhost:3000/auth/callback
# Your central admin Google Sheet ID
# Create a blank Google Sheet and paste the ID from its URL here
ADMIN_SHEET_ID=
${nonAdminActors.length > 0 ? `\n# Development actor sheet IDs (one per actor type)\n${devSheetVars}\n` : ''}
# Super admin email (new user sheets will be shared with this account)
SUPER_ADMIN_EMAIL=${answers.superAdminEmail}
`;
const hasExistingConfig = fs_1.default.existsSync('lsdb.config.ts') || fs_1.default.existsSync('sheet-db.config.ts');
if (!hasExistingConfig || !options.integrate) {
fs_1.default.writeFileSync('lsdb.config.ts', configContent);
}
else {
console.log(chalk_1.default.yellow('ℹ A config file already exists (lsdb.config.ts or sheet-db.config.ts), skipping creation.'));
}
if (!fs_1.default.existsSync('.env') || !options.integrate) {
fs_1.default.writeFileSync('.env', envContent);
}
else {
console.log(chalk_1.default.yellow('ℹ .env already exists, please merge Google OAuth vars manually.'));
// Optionally append to .env
const currentEnv = fs_1.default.readFileSync('.env', 'utf-8');
if (!currentEnv.includes('GOOGLE_CLIENT_ID')) {
fs_1.default.appendFileSync('.env', '\n' + envContent);
console.log(chalk_1.default.green('✅ Appended Google Sheet DB variables to .env'));
}
}
if (!fs_1.default.existsSync('schemas')) {
fs_1.default.mkdirSync('schemas');
}
const adminSchemas = {
users: `import { defineTable, string } from 'longcelot-sheet-db';
export default defineTable({
name: 'users',
actor: 'admin',
timestamps: true,
columns: {
user_id: string().required().unique(),
role: string().required(),
email: string().required().unique(),
actor_sheet_id: string(),
status: string().enum(['active', 'inactive']).default('active'),
},
});
`,
credentials: `import { defineTable, string } from 'longcelot-sheet-db';
export default defineTable({
name: 'credentials',
actor: 'admin',
columns: {
user_id: string().required(),
password_hash: string(),
provider: string().enum(['oauth', 'local']).required(),
},
});
`,
schema_versions: `import { defineTable, string, number } from 'longcelot-sheet-db';
export default defineTable({
name: 'schema_versions',
actor: 'admin',
columns: {
schema_version_id: string().primary(),
actor_sheet_id: string().required(),
table_name: string().required(),
schema_hash: string().required(),
synced_at: string().required(),
column_count: number().required(),
},
});
`,
};
for (const role of answers.actors) {
const actorDir = path_1.default.join('schemas', role);
if (!fs_1.default.existsSync(actorDir)) {
fs_1.default.mkdirSync(actorDir, { recursive: true });
}
if (role === 'admin') {
for (const [name, content] of Object.entries(adminSchemas)) {
fs_1.default.writeFileSync(path_1.default.join(actorDir, `${name}.ts`), content);
}
}
}
console.log(chalk_1.default.green('\n✅ Project initialized!\n'));
console.log(chalk_1.default.yellow('Created:'));
console.log(' ' + chalk_1.default.white('lsdb.config.ts'));
console.log(' ' + chalk_1.default.white('.env'));
console.log(' ' + chalk_1.default.white('schemas/'));
console.log(chalk_1.default.cyan('\nNext steps:'));
console.log(' 1. ' + chalk_1.default.white('Fill in your .env file:'));
console.log(' ' + chalk_1.default.gray('GOOGLE_CLIENT_ID=<your-client-id>'));
console.log(' ' + chalk_1.default.gray('GOOGLE_CLIENT_SECRET=<your-client-secret>'));
console.log(' ' + chalk_1.default.gray('ADMIN_SHEET_ID=<your-sheet-id>'));
console.log(' ' + chalk_1.default.dim('→ https://console.cloud.google.com/apis/credentials'));
console.log(' 2. ' + chalk_1.default.white('Generate tables: lsdb generate <table-name>'));
console.log(' 3. ' + chalk_1.default.white('Sync to sheets: lsdb sync\n'));
}
//# sourceMappingURL=init.js.map