@vigilbase/cli
Version:
Vigilbase CLI — security scanners, agent tools, and Vigilbase One from the terminal.
187 lines (186 loc) • 8.49 kB
JavaScript
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]');
};