UNPKG

quallaa-cli

Version:

Sets up core infrastructure services for AI-assisted development

266 lines • 9.83 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.defaultSchemas = void 0; exports.setupTypesense = setupTypesense; exports.createTypesenseCollection = createTypesenseCollection; const chalk_1 = __importDefault(require("chalk")); const inquirer_1 = __importDefault(require("inquirer")); const axios_1 = __importDefault(require("axios")); const credentials_1 = require("../storage/credentials"); async function setupTypesense() { try { console.log(chalk_1.default.gray('\nTypesense provides fast, typo-tolerant search.')); console.log(chalk_1.default.gray('This is optional but recommended for content-heavy applications.\n')); const existing = await (0, credentials_1.getCredentials)('typesense'); if (existing) { const { useExisting } = await inquirer_1.default.prompt([ { type: 'confirm', name: 'useExisting', message: 'Existing Typesense credentials found. Use them?', default: true, }, ]); if (useExisting) { return { success: true, service: 'typesense', message: 'Using existing credentials' }; } } const { setupChoice } = await inquirer_1.default.prompt([ { type: 'list', name: 'setupChoice', message: 'How would you like to set up Typesense?', choices: [ { name: 'Typesense Cloud (recommended)', value: 'cloud' }, { name: 'Self-hosted instance', value: 'self-hosted' }, { name: 'Skip Typesense setup', value: 'skip' }, ], }, ]); if (setupChoice === 'skip') { return { success: true, service: 'typesense', message: 'Skipped Typesense setup', }; } let credentials; if (setupChoice === 'cloud') { credentials = await setupTypesenseCloud(); } else { credentials = await setupSelfHosted(); } await (0, credentials_1.saveCredentials)('typesense', credentials); await addToEnvFile(credentials); return { success: true, service: 'typesense', credentials: { typesense: credentials }, }; } catch (error) { return { success: false, service: 'typesense', message: error instanceof Error ? error.message : 'Setup failed', error: error, }; } } async function setupTypesenseCloud() { console.log(chalk_1.default.yellow('\nā˜ļø Typesense Cloud Setup')); console.log(chalk_1.default.gray('Note: Typesense Cloud requires manual setup through their website.')); console.log(chalk_1.default.gray('1. Go to: https://cloud.typesense.org/')); console.log(chalk_1.default.gray('2. Create a cluster')); console.log(chalk_1.default.gray('3. Get your connection details\n')); const { host, port, protocol, apiKey } = await inquirer_1.default.prompt([ { type: 'input', name: 'host', message: 'Cluster hostname (e.g., xxx-1.a1.typesense.net):', validate: (input) => input.length > 0 || 'Hostname is required', }, { type: 'input', name: 'port', message: 'Port:', default: '443', }, { type: 'list', name: 'protocol', message: 'Protocol:', choices: ['https', 'http'], default: 'https', }, { type: 'password', name: 'apiKey', message: 'Admin API Key:', validate: (input) => input.length > 0 || 'API key is required', }, ]); await testConnection({ host, port, protocol, apiKey }); return { host, port, protocol, apiKey }; } async function setupSelfHosted() { console.log(chalk_1.default.yellow('\nšŸ  Self-hosted Typesense Setup')); const { host, port, protocol, apiKey } = await inquirer_1.default.prompt([ { type: 'input', name: 'host', message: 'Typesense host:', default: 'localhost', }, { type: 'input', name: 'port', message: 'Port:', default: '8108', }, { type: 'list', name: 'protocol', message: 'Protocol:', choices: ['http', 'https'], default: 'http', }, { type: 'input', name: 'apiKey', message: 'Admin API Key (from your Typesense config):', validate: (input) => input.length > 0 || 'API key is required', }, ]); await testConnection({ host, port, protocol, apiKey }); return { host, port, protocol, apiKey }; } async function testConnection(config) { try { console.log(chalk_1.default.gray('Testing connection...')); const response = await axios_1.default.get(`${config.protocol}://${config.host}:${config.port}/health`, { headers: { 'X-TYPESENSE-API-KEY': config.apiKey, }, timeout: 10000, }); if (response.data.ok === true) { console.log(chalk_1.default.green('āœ“ Connection successful')); } else { throw new Error('Health check failed'); } } catch (error) { console.error(chalk_1.default.red('āœ— Connection failed')); throw new Error('Could not connect to Typesense. Please check your settings.'); } } async function addToEnvFile(credentials) { const envContent = ` # Typesense TYPESENSE_HOST=${credentials.host} TYPESENSE_PORT=${credentials.port} TYPESENSE_PROTOCOL=${credentials.protocol} TYPESENSE_API_KEY=${credentials.apiKey} `; const fs = await Promise.resolve().then(() => __importStar(require('fs/promises'))); try { await fs.access('.env.local'); await fs.appendFile('.env.local', envContent); } catch { await fs.writeFile('.env.local', envContent); } console.log(chalk_1.default.green('āœ“ Environment variables added to .env.local')); } async function createTypesenseCollection(collectionName, schema) { const credentials = await (0, credentials_1.getCredentials)('typesense'); if (!credentials) { throw new Error('Typesense not configured. Run "quallaa setup typesense" first.'); } const url = `${credentials.protocol}://${credentials.host}:${credentials.port}/collections`; const response = await axios_1.default.post(url, { name: collectionName, ...schema, }, { headers: { 'X-TYPESENSE-API-KEY': credentials.apiKey, 'Content-Type': 'application/json', }, }); if (response.status === 201) { console.log(chalk_1.default.green(`āœ“ Collection '${collectionName}' created`)); } } exports.defaultSchemas = { contacts: { fields: [ { name: 'name', type: 'string' }, { name: 'email', type: 'string' }, { name: 'company', type: 'string', optional: true }, { name: 'role', type: 'string', optional: true }, { name: 'created_at', type: 'int64' }, ], default_sorting_field: 'created_at', }, posts: { fields: [ { name: 'title', type: 'string' }, { name: 'content', type: 'string' }, { name: 'author', type: 'string' }, { name: 'tags', type: 'string[]', optional: true }, { name: 'published_at', type: 'int64' }, ], default_sorting_field: 'published_at', }, products: { fields: [ { name: 'name', type: 'string' }, { name: 'description', type: 'string' }, { name: 'price', type: 'float' }, { name: 'category', type: 'string' }, { name: 'tags', type: 'string[]', optional: true }, { name: 'created_at', type: 'int64' }, ], default_sorting_field: 'created_at', }, }; //# sourceMappingURL=typesense.js.map