@juspay/neurolink
Version:
The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002
461 lines • 20.8 kB
JavaScript
/**
* Auth Command Factory for NeuroLink
*
* Creates the unified authentication command with subcommands for AI providers.
* Subcommands:
* - login, logout, status, refresh: Anthropic OAuth (API key + OAuth)
* - providers, validate, health: Multi-provider auth management
*/
/** Providers with first-class credential flows in `neurolink auth`. */
const AUTH_LOGIN_PROVIDERS = ["anthropic", "codex"];
/**
* Auth Command Factory
*
* Creates the main auth command with subcommands:
* - login: Authenticate with a provider (Anthropic OAuth)
* - logout: Clear stored credentials
* - status: Show authentication status
* - refresh: Manually refresh OAuth tokens
* - providers: List available auth providers
* - validate: Validate a token against a provider
* - health: Check auth provider health
*/
export class AuthCommandFactory {
/**
* Create the main auth command with subcommands
*/
static createAuthCommands() {
return {
command: "auth <subcommand>",
describe: "Manage authentication with AI providers (API key or OAuth)",
builder: (yargs) => {
return yargs
.command("login <provider>", "Authenticate with an AI provider", (yargs) => this.buildLoginOptions(yargs), async (argv) => {
const { handleLogin } = await import("../commands/auth.js");
await handleLogin(argv);
})
.command("logout <provider>", "Clear stored credentials for a provider", (yargs) => this.buildLogoutOptions(yargs), async (argv) => {
const { handleLogout } = await import("../commands/auth.js");
await handleLogout(argv);
})
.command("status [provider]", "Show authentication status for provider(s)", (yargs) => this.buildStatusOptions(yargs), async (argv) => {
const { handleStatus } = await import("../commands/auth.js");
await handleStatus(argv);
})
.command("refresh <provider>", "Manually refresh OAuth tokens for a provider", (yargs) => this.buildRefreshOptions(yargs), async (argv) => {
const { handleRefresh } = await import("../commands/auth.js");
await handleRefresh(argv);
})
.command("list", "List all authenticated accounts", (yargs) => this.buildListOptions(yargs), async (argv) => {
const { handleList } = await import("../commands/auth.js");
await handleList(argv);
})
.command("remove <provider>", "Remove an authenticated account", (yargs) => this.buildRemoveOptions(yargs), async (argv) => {
const { handleRemove } = await import("../commands/auth.js");
await handleRemove(argv);
})
.command("cleanup", "Remove expired and disabled accounts from token store", (yargs) => this.buildCleanupOptions(yargs), async (argv) => {
const { handleCleanup } = await import("../commands/auth.js");
await handleCleanup(argv);
})
.command("enable <account>", "Re-enable a previously disabled account", (yargs) => this.buildEnableOptions(yargs), async (argv) => {
const { handleEnable } = await import("../commands/auth.js");
await handleEnable(argv);
})
.command("disable <account>", "Take an account out of the proxy pool until re-enabled", (yargs) => this.buildDisableOptions(yargs), async (argv) => {
const { handleDisable } = await import("../commands/auth.js");
await handleDisable(argv);
})
.command("cooldown <action> [account]", "Inspect or clear per-account rate-limit cooldowns", (yargs) => this.buildCooldownClearOptions(yargs.positional("action", {
type: "string",
choices: ["list", "clear"],
description: "list cooldowns, or clear one/all",
demandOption: true,
})), async (argv) => {
const { handleCooldown } = await import("../commands/auth.js");
await handleCooldown(argv);
})
.command("overage [action]", "Show or set whether the pool may spend paid extra usage", (yargs) => yargs
.positional("action", {
type: "string",
choices: ["status", "auto", "always", "never"],
default: "status",
description: "Policy to apply, or 'status' to show it",
})
.option("config", {
type: "string",
description: "Path to the proxy config YAML",
}), async (argv) => {
const { handleOverage } = await import("../commands/auth.js");
await handleOverage(argv);
})
.command("set-primary <email>", "Set the proxy's primary (home) Anthropic account", (yargs) => this.buildSetPrimaryOptions(yargs), async (argv) => {
const { handleSetPrimary } = await import("../commands/auth.js");
await handleSetPrimary(argv);
})
.command("get-primary", "Show the proxy's currently configured primary account", (yargs) => this.buildPrimaryConfigOption(yargs), async (argv) => {
const { handleGetPrimary } = await import("../commands/auth.js");
await handleGetPrimary(argv);
})
.command("clear-primary", "Clear the proxy's configured primary account", (yargs) => this.buildPrimaryConfigOption(yargs), async (argv) => {
const { handleClearPrimary } = await import("../commands/auth.js");
await handleClearPrimary(argv);
})
.command("providers", "List available authentication providers", (yargs) => yargs.option("format", {
type: "string",
choices: ["text", "json", "table"],
default: "text",
description: "Output format",
alias: "f",
}), async (argv) => {
const { handleProvidersCommand } = await import("../commands/authProviders.js");
await handleProvidersCommand(argv);
})
.command("validate <token>", "Validate an authentication token", (yargs) => this.buildValidateOptions(yargs), async (argv) => {
const { handleValidateCommand } = await import("../commands/authProviders.js");
await handleValidateCommand(argv);
})
.command("health", "Check authentication provider health", (yargs) => this.buildHealthOptions(yargs), async (argv) => {
const { handleHealthCommand } = await import("../commands/authProviders.js");
await handleHealthCommand(argv);
})
.option("format", {
choices: ["text", "json"],
default: "text",
description: "Output format",
})
.option("quiet", {
type: "boolean",
alias: "q",
default: false,
description: "Suppress non-essential output",
})
.option("debug", {
type: "boolean",
default: false,
description: "Enable debug output",
})
.demandCommand(1, "Please specify an auth subcommand")
.example("$0 auth login anthropic", "Authenticate with Anthropic")
.example("$0 auth login anthropic --method create-api-key", "Create API key via OAuth (Claude Pro/Max - Recommended)")
.example("$0 auth login anthropic --add --label alice", "Add additional account with label")
.example("$0 auth list", "List all authenticated accounts")
.example("$0 auth status", "Show authentication status for all providers")
.example("$0 auth logout anthropic", "Clear Anthropic stored credentials")
.example("$0 auth remove anthropic --label alice", "Remove a specific account")
.example("$0 auth refresh anthropic", "Refresh Anthropic OAuth tokens")
.example("$0 auth cleanup", "Remove expired and disabled accounts")
.example("$0 auth cleanup --force", "Remove stale accounts without confirmation")
.example("$0 auth enable anthropic:1-VjRIq", "Re-enable a disabled account")
.example("$0 auth set-primary alice@example.com", "Make alice@example.com the proxy's primary (home) account")
.example("$0 auth get-primary", "Show the proxy's currently configured primary account")
.example("$0 auth clear-primary", "Remove the configured primary account (use insertion-order fallback)")
.help();
},
handler: () => {
// No-op handler as subcommands handle everything
},
};
}
/**
* Build options for login subcommand
*/
static buildLoginOptions(yargs) {
return yargs
.positional("provider", {
type: "string",
description: "AI provider to authenticate with",
choices: AUTH_LOGIN_PROVIDERS,
demandOption: true,
})
.option("method", {
type: "string",
alias: "m",
description: "Authentication method",
choices: ["api-key", "oauth", "create-api-key"],
})
.option("non-interactive", {
type: "boolean",
description: "Skip interactive prompts (requires environment variables)",
default: false,
})
.option("add", {
type: "boolean",
default: false,
description: "Add as additional account to the pool (instead of replacing)",
})
.option("label", {
type: "string",
description: "Human-readable label for this account (used with --add)",
})
.example("$0 auth login anthropic", "Interactive authentication (choose method)")
.example("$0 auth login anthropic --method api-key", "API key authentication")
.example("$0 auth login anthropic --method create-api-key", "Create API key via OAuth (Claude Pro/Max)")
.example("$0 auth login anthropic --method oauth", "Direct OAuth (experimental)")
.example("$0 auth login anthropic --add --label alice", "Add as additional account with label");
}
/**
* Build options for logout subcommand
*/
static buildLogoutOptions(yargs) {
return yargs
.positional("provider", {
type: "string",
description: "AI provider to log out from",
choices: AUTH_LOGIN_PROVIDERS,
demandOption: true,
})
.example("$0 auth logout anthropic", "Clear all Anthropic credentials");
}
/**
* Build options for status subcommand
*/
static buildStatusOptions(yargs) {
return yargs
.positional("provider", {
type: "string",
description: "AI provider to check (optional, shows all if not specified)",
choices: AUTH_LOGIN_PROVIDERS,
})
.example("$0 auth status", "Show status for all configured providers")
.example("$0 auth status anthropic", "Show Anthropic authentication status")
.example("$0 auth status --format json", "Show status in JSON format");
}
/**
* Build options for refresh subcommand
*/
static buildRefreshOptions(yargs) {
return yargs
.positional("provider", {
type: "string",
description: "AI provider to refresh tokens for",
choices: AUTH_LOGIN_PROVIDERS,
demandOption: true,
})
.example("$0 auth refresh anthropic", "Refresh Anthropic OAuth tokens");
}
/**
* Build options for list subcommand
*/
static buildListOptions(yargs) {
return yargs
.option("refresh", {
type: "boolean",
default: false,
description: "Refresh available provider limits for authenticated accounts; show unsupported providers explicitly",
})
.example("$0 auth list", "List all authenticated accounts")
.example("$0 auth list --format json", "List accounts in JSON format")
.example("$0 auth list --refresh", "Fetch fresh session/weekly/model-scoped limits before listing");
}
/**
* Build options for remove subcommand
*/
static buildRemoveOptions(yargs) {
return yargs
.positional("provider", {
type: "string",
description: "Provider namespace to remove an account from",
demandOption: true,
})
.option("label", {
type: "string",
description: "Label of the account to remove (e.g., alice)",
})
.option("account", {
type: "string",
description: "Full compound key of the account to remove (e.g., anthropic:alice)",
})
.conflicts("label", "account")
.check((argv) => {
if (argv.account &&
!String(argv.account).startsWith(`${String(argv.provider)}:`)) {
throw new Error("--account must belong to the selected provider");
}
return true;
})
.example("$0 auth remove anthropic --label alice", "Remove account with label alice")
.example("$0 auth remove anthropic --account anthropic:alice", "Remove account by compound key");
}
/**
* Build options for cleanup subcommand
*/
static buildCleanupOptions(yargs) {
return yargs
.option("force", {
type: "boolean",
default: false,
description: "Skip confirmation when removing disabled accounts",
})
.example("$0 auth cleanup", "Remove expired and disabled accounts")
.example("$0 auth cleanup --force", "Remove stale accounts without confirmation");
}
/**
* Build options for enable subcommand
*/
static buildEnableOptions(yargs) {
return yargs
.positional("account", {
type: "string",
description: "Account key to re-enable (e.g., anthropic:1-VjRIq)",
demandOption: true,
})
.example("$0 auth enable anthropic:1-VjRIq", "Re-enable a disabled account");
}
/**
* Build options for disable subcommand
*/
static buildDisableOptions(yargs) {
return yargs
.positional("account", {
type: "string",
description: "Account key to disable (e.g., anthropic:1-VjRIq)",
demandOption: true,
})
.option("reason", {
type: "string",
description: "Why the account is being disabled (shown in auth list)",
})
.example("$0 auth disable anthropic:1-VjRIq", "Take an account out of the proxy pool");
}
/**
* Build options for the cooldown subcommands
*/
static buildCooldownClearOptions(yargs) {
return (yargs
.positional("account", {
type: "string",
description: "Account key whose cooldown should be cleared",
})
.option("all", {
type: "boolean",
default: false,
description: "Clear cooldowns for every account",
})
.example("$0 auth cooldown clear anthropic:1-VjRIq", "Return a parked account to the pool immediately")
// Reject a scope the handler cannot honour rather than silently picking
// one. `--all` beats a named account there, so `clear <account> --all`
// would wipe every cooldown while reading as a single-account command.
.check((argv) => {
const action = String(argv.action ?? "");
const account = argv.account ? String(argv.account) : undefined;
if (action === "clear" && account && argv.all === true) {
throw new Error("Pass an account or --all, not both: --all clears every cooldown.");
}
if (action === "list" && (account || argv.all === true)) {
throw new Error("`auth cooldown list` takes no account and no --all; it lists every cooling account.");
}
return true;
}));
}
/**
* Build options for set-primary subcommand
*/
static buildSetPrimaryOptions(yargs) {
return yargs
.positional("email", {
type: "string",
description: "Email/label of the Anthropic account to make primary (home)",
demandOption: true,
})
.option("config", {
type: "string",
description: "Path to the proxy config YAML (default: ~/.neurolink/proxy-config.yaml)",
})
.example("$0 auth set-primary alice@example.com", "Write routing.primary-account to the default proxy config")
.example("$0 auth set-primary alice@example.com --config ./proxy.yaml", "Use a non-default config path");
}
/**
* Build options for get-primary / clear-primary subcommands.
*/
static buildPrimaryConfigOption(yargs) {
return yargs.option("config", {
type: "string",
description: "Path to the proxy config YAML (default: ~/.neurolink/proxy-config.yaml)",
});
}
/**
* Auth provider choices for multi-provider commands
*/
static AUTH_PROVIDER_CHOICES = [
"auth0",
"clerk",
"supabase",
"firebase",
"workos",
"better-auth",
"jwt",
"oauth2",
"cognito",
"keycloak",
];
/**
* Build common provider options for validate/health commands
*/
static buildProviderOptions(yargs) {
return yargs
.option("provider", {
type: "string",
choices: this.AUTH_PROVIDER_CHOICES,
default: "auth0",
description: "Authentication provider type",
alias: "p",
})
.option("domain", {
type: "string",
description: "Auth0 domain (for auth0 provider)",
})
.option("clientId", {
type: "string",
description: "Client ID (for auth0 provider)",
alias: "client-id",
})
.option("secretKey", {
type: "string",
description: "Secret key (for clerk provider)",
alias: "secret-key",
})
.option("url", {
type: "string",
description: "Provider URL (for supabase, better-auth)",
})
.option("anonKey", {
type: "string",
description: "Anon key (for supabase provider)",
alias: "anon-key",
})
.option("apiKey", {
type: "string",
description: "API key (for workos provider)",
alias: "api-key",
})
.option("secret", {
type: "string",
description: "Secret (for better-auth, jwt providers). Can also be set via BETTER_AUTH_SECRET or JWT_SECRET env vars.",
})
.option("format", {
type: "string",
choices: ["text", "json"],
default: "text",
description: "Output format",
alias: "f",
});
}
/**
* Build options for validate subcommand
*/
static buildValidateOptions(yargs) {
return this.buildProviderOptions(yargs.positional("token", {
type: "string",
description: "The token to validate (JWT or session token)",
demandOption: true,
}));
}
/**
* Build options for health subcommand
*/
static buildHealthOptions(yargs) {
return this.buildProviderOptions(yargs);
}
}
//# sourceMappingURL=authCommandFactory.js.map