UNPKG

@vigilbase/cli

Version:

Vigilbase CLI — security scanners, agent tools, and Vigilbase One from the terminal.

187 lines (186 loc) • 8.49 kB
import { invitationSchema, validateArguments } from './legacy-validation.js'; import { asArray, asRecord, ok, outputJson, outputLines, requireOneClient, withSpinner, } from './helpers.js'; import { handleBilling } from './billing.js'; export const handleAccount = async (ctx) => { if ((ctx.rest[0] ?? '').toLowerCase() === 'billing') { return handleBilling({ ...ctx, command: 'billing', rest: ctx.rest.slice(1), }); } const subcommand = (ctx.rest[0] ?? 'show').toLowerCase(); let invitation; if (subcommand === 'invites' || subcommand === 'invitations') { const action = (ctx.rest[1] ?? 'list').toLowerCase(); if (action === 'list' || action === 'ls') validateArguments(ctx, ctx.rest[1] === undefined ? 1 : 2); else if (action === 'create' || action === 'add') { if (ctx.values.email !== undefined && ctx.rest[2] !== undefined) throw new Error('Specify the invite email either positionally or with --email, not both.'); validateArguments(ctx, ctx.values.email === undefined ? 3 : 2, ['email', 'role', 'isConfirm'], 'vigilbase account invites create <email> --confirm'); invitation = invitationSchema.parse({ email: ctx.values.email ?? ctx.rest[2], role: ctx.values.role }); if (!ctx.values.isConfirm) throw new Error('Sending an organization invitation requires --confirm.'); } else throw new Error('Usage: vigilbase account invites [list|create]'); } else { if (!['show', 'me', 'overview', 'services', 'service', 'org', 'organization', 'members', 'endpoints', 'endpoint', 'sessions', 'session'].includes(subcommand)) { throw new Error('Usage: vigilbase account [services|org|endpoints|sessions|invites|billing]'); } validateArguments(ctx, ctx.rest[0] === undefined ? 0 : 1); } const one = await requireOneClient(ctx); if (subcommand === 'show' || subcommand === 'me' || subcommand === 'overview') { const account = await withSpinner(ctx, 'Loading account', () => one.getAccount()); if (ctx.mode === 'json') { outputJson(ctx, account); return ok(); } const user = asRecord(account.user); const organization = asRecord(account.organization); const customer = asRecord(account.customer); outputLines(ctx, [ `user ${String(user?.email ?? user?.id ?? '(unknown)')}`, organization ? `org ${String(organization.name ?? organization.id)}${organization.role ? ` (${String(organization.role)})` : ''}` : 'org (none)', customer ? `customer ${String(customer.name ?? customer.id)}${customer.domain ? ` ${String(customer.domain)}` : ''}` : account.isInternal ? 'customer (internal — no customer record)' : 'customer (none)', ]); return ok(); } if (subcommand === 'services' || subcommand === 'service') { const services = await withSpinner(ctx, 'Loading services', () => one.getAccountServices()); if (ctx.mode === 'json') { outputJson(ctx, services); return ok(); } const rows = asArray(services.services); if (!rows.length) { ctx.writer.stdout('No active services.'); } else { for (const raw of rows) { const service = asRecord(raw); if (!service) continue; ctx.writer.stdout(`${String(service.tool).padEnd(16)} ${String(service.status)}${service.domain ? ` ${String(service.domain)}` : ''}`); } } if (typeof services.endpointCount === 'number') { ctx.writer.stdout(`endpoints ${services.endpointCount}`); } return ok(); } if (subcommand === 'org' || subcommand === 'organization' || subcommand === 'members') { const org = await withSpinner(ctx, 'Loading organization', () => one.getAccountOrganization()); if (ctx.mode === 'json') { outputJson(ctx, org); return ok(); } const organization = asRecord(org.organization); if (organization) { ctx.writer.stdout(`org ${String(organization.displayName || organization.name)}${organization.role ? ` (${String(organization.role)})` : ''}`); } else { ctx.writer.stdout('org (none)'); } const members = asArray(org.members); if (!members.length) { ctx.writer.stdout('members (none)'); } else { for (const raw of members) { const member = asRecord(raw); if (!member) continue; ctx.writer.stdout(`member ${String(member.email || member.name)} (${String(member.role)})`); } } return ok(); } if (subcommand === 'endpoints' || subcommand === 'endpoint') { const payload = await withSpinner(ctx, 'Loading endpoints', () => one.getAccountEndpoints()); if (ctx.mode === 'json') { outputJson(ctx, payload); return ok(); } const endpoints = asArray(payload.endpoints); if (!endpoints.length) { ctx.writer.stdout('No endpoints.'); return ok(); } for (const raw of endpoints) { const endpoint = asRecord(raw); if (!endpoint) continue; const name = String(endpoint.displayName || endpoint.systemName || endpoint.id); const state = endpoint.isOffline ? 'offline' : 'online'; ctx.writer.stdout(`${name.padEnd(28)} ${state}${endpoint.integration ? ` ${String(endpoint.integration)}` : ''}`); } return ok(); } if (subcommand === 'sessions' || subcommand === 'session') { const payload = await withSpinner(ctx, 'Loading sessions', () => one.getAccountSessions()); if (ctx.mode === 'json') { outputJson(ctx, payload); return ok(); } const sessions = asArray(payload.sessions); if (!sessions.length) { ctx.writer.stdout('No sessions.'); return ok(); } for (const raw of sessions) { const session = asRecord(raw); if (!session) continue; ctx.writer.stdout(`${String(session.id).slice(0, 12)}… ${String(session.ipAddress || '-')} ${String(session.createdAt || '')}`); } return ok(); } if (subcommand === 'invites' || subcommand === 'invitations') { const action = (ctx.rest[1] ?? 'list').toLowerCase(); if (action === 'list' || action === 'ls') { const payload = await withSpinner(ctx, 'Loading invitations', () => one.getAccountInvitations()); if (ctx.mode === 'json') { outputJson(ctx, payload); return ok(); } const invitations = asArray(payload.invitations); if (!invitations.length) { ctx.writer.stdout('No pending invitations.'); return ok(); } for (const raw of invitations) { const invite = asRecord(raw); if (!invite) continue; const email = String(invite.inviteeEmail || invite.email || '-'); ctx.writer.stdout(`${email} ${String(invite.role || 'member')} ${String(invite.status || 'pending')}`); } return ok(); } if (action === 'create' || action === 'add') { const { email, role } = invitation; const payload = await withSpinner(ctx, `Inviting ${email}`, () => one.createAccountInvitation({ email, role })); if (ctx.mode === 'json') { outputJson(ctx, payload); } else { ctx.writer.stdout(`invited ${email} (${role})`); } return ok(); } throw new Error('Usage: vigilbase account invites [list|create] [--email …] [--role …] [--confirm]'); } throw new Error('Usage: vigilbase account [services|org|endpoints|sessions|invites|billing] [--json]'); };