@spacelr/cli 0.1.7 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  ));
25
25
 
26
26
  // libs/cli/src/index.ts
27
- var import_commander14 = require("commander");
27
+ var import_commander15 = require("commander");
28
28
 
29
29
  // libs/cli/src/lib/output.ts
30
30
  var import_ora = __toESM(require("ora"));
@@ -1233,7 +1233,7 @@ function sleep(ms) {
1233
1233
  }
1234
1234
 
1235
1235
  // libs/cli/src/commands/db/index.ts
1236
- var import_commander12 = require("commander");
1236
+ var import_commander13 = require("commander");
1237
1237
 
1238
1238
  // libs/cli/src/commands/db/indexes-deploy.ts
1239
1239
  var import_commander8 = require("commander");
@@ -1448,25 +1448,162 @@ function createRulesPullCommand() {
1448
1448
  });
1449
1449
  }
1450
1450
 
1451
+ // libs/cli/src/commands/db/collection-set.ts
1452
+ var import_commander12 = require("commander");
1453
+ var RESERVED_FILTER_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
1454
+ function parsePositiveInt(value, flag) {
1455
+ if (!/^\d+$/.test(value)) {
1456
+ throw new Error(`${flag} must be a positive integer (got "${value}")`);
1457
+ }
1458
+ const n = Number(value);
1459
+ if (!Number.isInteger(n) || n <= 0) {
1460
+ throw new Error(`${flag} must be a positive integer (got "${value}")`);
1461
+ }
1462
+ return n;
1463
+ }
1464
+ function parseBool(value, flag) {
1465
+ const lower = value.toLowerCase();
1466
+ if (lower === "true" || lower === "1") return true;
1467
+ if (lower === "false" || lower === "0") return false;
1468
+ throw new Error(`${flag} must be true|false (got "${value}")`);
1469
+ }
1470
+ function parseCsv(value) {
1471
+ return value.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
1472
+ }
1473
+ function createCollectionSetCommand() {
1474
+ return new import_commander12.Command("set").description("Update collection metadata (realtimeMode, retention, throttle, search filter)").argument("<name>", "Collection name").option("--project <id>", "Project ID").option("--config <path>", "Config file path").option(
1475
+ "--realtime-mode <mode>",
1476
+ "Switch realtime delivery mode: pubsub (default, fire-and-forget) or stream (durable, replayable)"
1477
+ ).option(
1478
+ "--retention-max-len <n>",
1479
+ "Approximate max retained events on the Redis stream (mutually exclusive with --retention-max-age-ms)"
1480
+ ).option(
1481
+ "--retention-max-age-ms <ms>",
1482
+ "Retention age in ms for stream entries (mutually exclusive with --retention-max-len)"
1483
+ ).option(
1484
+ "--throttle-enabled <bool>",
1485
+ "true|false \u2014 toggle the per-collection write throttle. Use false for high-volume system collections (e.g. audit logs)."
1486
+ ).option("--throttle-limit <n>", "Max writes per window (1..10000)").option("--throttle-window-ms <ms>", "Throttle window in ms (1000..3_600_000)").option(
1487
+ "--require-filter <fields>",
1488
+ 'Comma-separated top-level filter keys required on every search() call (alphanumeric + underscore, max 10 keys). Pass an empty string ("") to clear an existing requirement.'
1489
+ ).option("--yes", "Skip confirmation").action(async (name, opts, cmd) => {
1490
+ const globalOpts = cmd.optsWithGlobals();
1491
+ const config = loadConfig(opts.config);
1492
+ const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);
1493
+ try {
1494
+ const token = await requireAuth(globalOpts.token);
1495
+ const projectId = resolveProjectId(opts.project, config);
1496
+ const body = {};
1497
+ if (opts.realtimeMode !== void 0) {
1498
+ if (opts.realtimeMode !== "pubsub" && opts.realtimeMode !== "stream") {
1499
+ throw new Error(`--realtime-mode must be 'pubsub' or 'stream' (got "${opts.realtimeMode}")`);
1500
+ }
1501
+ body.realtimeMode = opts.realtimeMode;
1502
+ }
1503
+ if (opts.retentionMaxLen !== void 0 || opts.retentionMaxAgeMs !== void 0) {
1504
+ if (opts.retentionMaxLen !== void 0 && opts.retentionMaxAgeMs !== void 0) {
1505
+ throw new Error("Set at most one of --retention-max-len or --retention-max-age-ms");
1506
+ }
1507
+ body.streamRetention = {};
1508
+ if (opts.retentionMaxLen !== void 0) {
1509
+ body.streamRetention.maxLen = parsePositiveInt(opts.retentionMaxLen, "--retention-max-len");
1510
+ }
1511
+ if (opts.retentionMaxAgeMs !== void 0) {
1512
+ const ms = parsePositiveInt(opts.retentionMaxAgeMs, "--retention-max-age-ms");
1513
+ if (ms < 1e3) throw new Error("--retention-max-age-ms must be >= 1000 (1 second)");
1514
+ body.streamRetention.maxAgeMs = ms;
1515
+ }
1516
+ }
1517
+ if (opts.throttleEnabled !== void 0 || opts.throttleLimit !== void 0 || opts.throttleWindowMs !== void 0) {
1518
+ body.writeThrottle = {};
1519
+ if (opts.throttleEnabled !== void 0) {
1520
+ body.writeThrottle.enabled = parseBool(opts.throttleEnabled, "--throttle-enabled");
1521
+ }
1522
+ if (opts.throttleLimit !== void 0) {
1523
+ const n = parsePositiveInt(opts.throttleLimit, "--throttle-limit");
1524
+ if (n > 1e4) throw new Error("--throttle-limit must be <= 10000");
1525
+ body.writeThrottle.limit = n;
1526
+ }
1527
+ if (opts.throttleWindowMs !== void 0) {
1528
+ const ms = parsePositiveInt(opts.throttleWindowMs, "--throttle-window-ms");
1529
+ if (ms < 1e3 || ms > 36e5) {
1530
+ throw new Error("--throttle-window-ms must be between 1000 and 3_600_000");
1531
+ }
1532
+ body.writeThrottle.windowMs = ms;
1533
+ }
1534
+ }
1535
+ if (opts.requireFilter !== void 0) {
1536
+ const fields = parseCsv(opts.requireFilter);
1537
+ if (fields.length === 0) {
1538
+ body.searchConfig = {};
1539
+ } else {
1540
+ if (fields.length > 10) throw new Error("--require-filter accepts at most 10 keys");
1541
+ for (const f of fields) {
1542
+ if (!/^[a-zA-Z0-9_]+$/.test(f) || f.length > 64) {
1543
+ throw new Error(`Invalid filter key "${f}" \u2014 must be alphanumeric/underscore, max 64 chars`);
1544
+ }
1545
+ if (RESERVED_FILTER_KEYS.has(f)) {
1546
+ throw new Error(`Reserved filter key "${f}" \u2014 __proto__/constructor/prototype are not allowed`);
1547
+ }
1548
+ }
1549
+ body.searchConfig = { requireFilter: Array.from(new Set(fields)) };
1550
+ }
1551
+ }
1552
+ if (Object.keys(body).length === 0) {
1553
+ throw new Error(
1554
+ "No metadata fields provided. Pass at least one of --realtime-mode, --retention-*, --throttle-*, --require-filter."
1555
+ );
1556
+ }
1557
+ if (!opts.yes && !isJsonMode()) {
1558
+ info(`Updating collection "${name}" (project ${projectId}) with:`);
1559
+ info(JSON.stringify(body, null, 2));
1560
+ const confirmed = await promptConfirm("Proceed?");
1561
+ if (!confirmed) {
1562
+ info("Aborted");
1563
+ return;
1564
+ }
1565
+ }
1566
+ const spin = spinner("Updating collection metadata...");
1567
+ const client = new ApiClient({ apiUrl, token, projectId });
1568
+ const result = await client.patch(
1569
+ `/databases/${encodeURIComponent(projectId)}/collections/${encodeURIComponent(name)}`,
1570
+ body
1571
+ );
1572
+ spin.succeed("Collection metadata updated");
1573
+ if (isJsonMode()) {
1574
+ json(result);
1575
+ } else {
1576
+ success(`Updated "${name}"`);
1577
+ }
1578
+ } catch (err) {
1579
+ error(err instanceof Error ? err.message : "Failed to update collection metadata");
1580
+ process.exitCode = 1;
1581
+ }
1582
+ });
1583
+ }
1584
+
1451
1585
  // libs/cli/src/commands/db/index.ts
1452
1586
  function createDbCommand() {
1453
- const indexes = new import_commander12.Command("indexes").description("Manage database indexes");
1587
+ const indexes = new import_commander13.Command("indexes").description("Manage database indexes");
1454
1588
  indexes.addCommand(createIndexesDeployCommand());
1455
1589
  indexes.addCommand(createIndexesPullCommand());
1456
- const rules = new import_commander12.Command("rules").description("Manage database rules");
1590
+ const rules = new import_commander13.Command("rules").description("Manage database rules");
1457
1591
  rules.addCommand(createRulesDeployCommand());
1458
1592
  rules.addCommand(createRulesPullCommand());
1459
- const db = new import_commander12.Command("db").description("Database management commands");
1593
+ const collection = new import_commander13.Command("collection").description("Manage collection-level settings (realtime mode, retention, throttle, search filter)");
1594
+ collection.addCommand(createCollectionSetCommand());
1595
+ const db = new import_commander13.Command("db").description("Database management commands");
1460
1596
  db.addCommand(indexes);
1461
1597
  db.addCommand(rules);
1598
+ db.addCommand(collection);
1462
1599
  return db;
1463
1600
  }
1464
1601
 
1465
1602
  // libs/cli/src/commands/functions.ts
1466
1603
  var path6 = __toESM(require("path"));
1467
- var import_commander13 = require("commander");
1604
+ var import_commander14 = require("commander");
1468
1605
  function createFunctionsCommand() {
1469
- const functions = new import_commander13.Command("functions").description("Manage serverless functions");
1606
+ const functions = new import_commander14.Command("functions").description("Manage serverless functions");
1470
1607
  functions.command("deploy [directory]").description("Deploy a function").requiredOption("--name <name>", "Function name").option("--entry <file>", "Entry point (default: index.js)").option("--cron <expression>", "Cron schedule expression").option("--timezone <tz>", "Timezone for cron (default: UTC)").option("--timeout <ms>", "Execution timeout in ms").option("--memory <mb>", "Memory limit in MB").option("--env <KEY=VALUE...>", "Environment variables", collectEnvVars, {}).option("--project <id>", "Project ID").action(async (directory, opts, cmd) => {
1471
1608
  const globalOpts = cmd.optsWithGlobals();
1472
1609
  const config = loadConfig();
@@ -1721,7 +1858,7 @@ function collectEnvVars(value, previous) {
1721
1858
  }
1722
1859
 
1723
1860
  // libs/cli/src/index.ts
1724
- var program = new import_commander14.Command();
1861
+ var program = new import_commander15.Command();
1725
1862
  program.name("spacelr").description("CLI tool for the Spacelr platform").version("0.1.0").option("--api-url <url>", "Override API URL").option("--token <token>", "Explicit auth token (CI mode)").option("--json", "Output as JSON").option("--verbose", "Verbose logging").hook("preAction", (thisCommand) => {
1726
1863
  const opts = thisCommand.optsWithGlobals();
1727
1864
  setOutputMode({
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../libs/cli/src/index.ts","../../../../libs/cli/src/lib/output.ts","../../../../libs/cli/src/commands/login.ts","../../../../libs/cli/src/lib/auth.ts","../../../../libs/cli/src/lib/config.ts","../../../../libs/cli/src/commands/logout.ts","../../../../libs/cli/src/commands/whoami.ts","../../../../libs/cli/src/lib/api-client.ts","../../../../libs/cli/src/commands/projects.ts","../../../../libs/cli/src/commands/use.ts","../../../../libs/cli/src/lib/prompt.ts","../../../../libs/cli/src/commands/init.ts","../../../../libs/cli/src/commands/deploy.ts","../../../../libs/cli/src/lib/zip.ts","../../../../libs/cli/src/commands/db/index.ts","../../../../libs/cli/src/commands/db/indexes-deploy.ts","../../../../libs/cli/src/commands/db/indexes-pull.ts","../../../../libs/cli/src/commands/db/rules-deploy.ts","../../../../libs/cli/src/commands/db/rules-pull.ts","../../../../libs/cli/src/commands/functions.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { setOutputMode } from './lib/output';\nimport { createLoginCommand } from './commands/login';\nimport { createLogoutCommand } from './commands/logout';\nimport { createWhoamiCommand } from './commands/whoami';\nimport { createProjectsCommand } from './commands/projects';\nimport { createUseCommand } from './commands/use';\nimport { createInitCommand } from './commands/init';\nimport { createDeployCommand } from './commands/deploy';\nimport { createDbCommand } from './commands/db';\nimport { createFunctionsCommand } from './commands/functions';\n\nconst program = new Command();\n\nprogram\n .name('spacelr')\n .description('CLI tool for the Spacelr platform')\n .version('0.1.0')\n .option('--api-url <url>', 'Override API URL')\n .option('--token <token>', 'Explicit auth token (CI mode)')\n .option('--json', 'Output as JSON')\n .option('--verbose', 'Verbose logging')\n .hook('preAction', (thisCommand) => {\n const opts = thisCommand.optsWithGlobals();\n setOutputMode({\n json: opts['json'] as boolean | undefined,\n verbose: opts['verbose'] as boolean | undefined,\n });\n });\n\nprogram.addCommand(createLoginCommand());\nprogram.addCommand(createLogoutCommand());\nprogram.addCommand(createWhoamiCommand());\nprogram.addCommand(createProjectsCommand());\nprogram.addCommand(createUseCommand());\nprogram.addCommand(createInitCommand());\nprogram.addCommand(createDeployCommand());\nprogram.addCommand(createDbCommand());\nprogram.addCommand(createFunctionsCommand());\n\nprogram.parse();\n","import ora, { type Ora } from 'ora';\nimport pc from 'picocolors';\n\nlet jsonMode = false;\nlet verboseMode = false;\n\nexport function setOutputMode(options: {\n json?: boolean;\n verbose?: boolean;\n}): void {\n jsonMode = options.json ?? false;\n verboseMode = options.verbose ?? false;\n}\n\nexport function isJsonMode(): boolean {\n return jsonMode;\n}\n\nexport function success(message: string): void {\n if (!jsonMode) {\n console.log(pc.green(`\\u2713 ${message}`));\n }\n}\n\nexport function error(message: string): void {\n if (!jsonMode) {\n console.error(pc.red(`\\u2717 ${message}`));\n }\n}\n\nexport function warn(message: string): void {\n if (!jsonMode) {\n console.warn(pc.yellow(`! ${message}`));\n }\n}\n\nexport function info(message: string): void {\n if (!jsonMode) {\n console.log(pc.cyan(`\\u2139 ${message}`));\n }\n}\n\nexport function verbose(message: string): void {\n if (verboseMode && !jsonMode) {\n console.log(pc.dim(` ${message}`));\n }\n}\n\nexport function json(data: unknown): void {\n console.log(JSON.stringify(data, null, 2));\n}\n\nexport function table(\n headers: string[],\n rows: string[][],\n): void {\n if (jsonMode) return;\n\n const colWidths = headers.map((h, i) => {\n const maxRow = rows.reduce(\n (max, row) => Math.max(max, (row[i] ?? '').length),\n 0,\n );\n return Math.max(h.length, maxRow);\n });\n\n const headerLine = headers\n .map((h, i) => pc.bold(h.padEnd(colWidths[i] ?? 0)))\n .join(' ');\n const separator = colWidths.map((w) => '-'.repeat(w)).join(' ');\n\n console.log(headerLine);\n console.log(separator);\n for (const row of rows) {\n console.log(\n row.map((cell, i) => cell.padEnd(colWidths[i] ?? 0)).join(' '),\n );\n }\n}\n\nexport function spinner(text: string): Ora {\n if (jsonMode) {\n return ora({ text, isSilent: true });\n }\n return ora(text).start();\n}\n\nexport function formatBytes(bytes: number): string {\n if (bytes === 0) return '0 B';\n const units = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(1024));\n const value = bytes / Math.pow(1024, i);\n return `${value.toFixed(i === 0 ? 0 : 1)} ${units[i]}`;\n}\n","import * as http from 'node:http';\nimport * as crypto from 'node:crypto';\nimport { Command } from 'commander';\nimport open from 'open';\nimport { generatePKCE, storeCredentials } from '../lib/auth';\nimport { resolveApiUrl, loadConfig } from '../lib/config';\nimport { success, error, info, spinner, json, isJsonMode } from '../lib/output';\nimport type { GlobalOptions, TokenResponse, StoredCredentials } from '../lib/types';\n\nconst CLI_CLIENT_ID = 'spacelr-cli';\n\nexport function createLoginCommand(): Command {\n return new Command('login')\n .description('Authenticate with Spacelr via browser')\n .option('--auth-url <url>', 'OAuth server URL (defaults to --api-url)')\n .option(\n '--global',\n 'Store credentials globally (~/.spacelr/credentials.json) instead of in the current project',\n )\n .action(async (opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n const authUrl = (opts.authUrl as string | undefined) ?? apiUrl;\n const forceGlobal = opts.global === true;\n\n try {\n const credentials = await performLogin(authUrl, apiUrl);\n const location = storeCredentials(credentials, forceGlobal);\n\n if (isJsonMode()) {\n json({\n success: true,\n expiresAt: credentials.expiresAt,\n credentialsPath: location.path,\n scope: location.scope,\n });\n } else {\n success('Logged in successfully');\n if (location.scope === 'project') {\n info(`Credentials stored in ${location.path} (project-local)`);\n } else {\n info(`Credentials stored in ${location.path} (global)`);\n }\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Login failed');\n process.exitCode = 1;\n }\n });\n}\n\nasync function performLogin(authUrl: string, apiUrl: string): Promise<StoredCredentials> {\n const { codeVerifier, codeChallenge } = generatePKCE();\n const state = crypto.randomBytes(16).toString('base64url');\n\n // Start local HTTP server on a random port\n const { port, waitForCode, close } = await startCallbackServer(state);\n\n const authorizeUrl = buildAuthorizeUrl(authUrl, port, codeChallenge, state);\n\n info(`Opening browser for authentication...`);\n info(`If the browser doesn't open, visit: ${authorizeUrl}`);\n\n await open(authorizeUrl);\n\n const spin = spinner('Waiting for authentication...');\n\n try {\n const code = await waitForCode;\n spin.text = 'Exchanging authorization code...';\n\n const tokenResponse = await exchangeCode(\n authUrl,\n code,\n codeVerifier,\n port,\n );\n\n spin.succeed('Authentication complete');\n\n // Validate expires_in: must be a positive finite number. A bogus 0/-1\n // would put expiresAt in the past and trigger a refresh on every CLI\n // command. Same guard as in refreshStoredToken.\n const expiresInRaw: unknown = tokenResponse.expires_in;\n const expiresIn =\n typeof expiresInRaw === 'number' &&\n Number.isFinite(expiresInRaw) &&\n expiresInRaw > 0\n ? expiresInRaw\n : 3600;\n\n return {\n accessToken: tokenResponse.access_token,\n refreshToken: tokenResponse.refresh_token,\n expiresAt: Date.now() + expiresIn * 1000,\n apiUrl,\n };\n } catch (err) {\n spin.fail('Authentication failed');\n throw err;\n } finally {\n close();\n }\n}\n\nfunction buildAuthorizeUrl(\n apiUrl: string,\n port: number,\n codeChallenge: string,\n state: string,\n): string {\n const params = new URLSearchParams({\n client_id: CLI_CLIENT_ID,\n redirect_uri: `http://127.0.0.1:${port}/callback`,\n response_type: 'code',\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n scope: 'openid profile email',\n state,\n });\n return `${apiUrl}/auth/authorize?${params.toString()}`;\n}\n\nasync function startCallbackServer(expectedState: string): Promise<{\n port: number;\n waitForCode: Promise<string>;\n close: () => void;\n}> {\n return new Promise((resolveServer) => {\n let resolveCode: (code: string) => void;\n let rejectCode: (err: Error) => void;\n\n const waitForCode = new Promise<string>((resolve, reject) => {\n resolveCode = resolve;\n rejectCode = reject;\n });\n\n const server = http.createServer((req, res) => {\n const url = new URL(req.url ?? '/', `http://127.0.0.1`);\n\n if (url.pathname === '/callback') {\n const code = url.searchParams.get('code');\n const errorParam = url.searchParams.get('error');\n const returnedState = url.searchParams.get('state');\n\n if (errorParam) {\n const description =\n url.searchParams.get('error_description') ?? errorParam;\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(errorPage(description));\n rejectCode(new Error(`OAuth error: ${description}`));\n return;\n }\n\n // CSRF protection: verify state matches\n if (returnedState !== expectedState) {\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end(errorPage('Invalid state parameter (possible CSRF attack)'));\n rejectCode(new Error('OAuth state mismatch'));\n return;\n }\n\n if (!code) {\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end(errorPage('No authorization code received'));\n rejectCode(new Error('No authorization code received'));\n return;\n }\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(successPage());\n resolveCode(code);\n } else {\n res.writeHead(404);\n res.end();\n }\n });\n\n // Timeout after 5 minutes\n const timeout = setTimeout(() => {\n rejectCode(new Error('Login timed out after 5 minutes'));\n server.close();\n }, 5 * 60 * 1000);\n\n server.listen(0, '127.0.0.1', () => {\n const address = server.address();\n const port =\n typeof address === 'object' && address ? address.port : 0;\n\n resolveServer({\n port,\n waitForCode,\n close: () => {\n clearTimeout(timeout);\n server.close();\n },\n });\n });\n });\n}\n\nasync function exchangeCode(\n apiUrl: string,\n code: string,\n codeVerifier: string,\n port: number,\n): Promise<TokenResponse> {\n const response = await fetch(`${apiUrl}/auth/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n code_verifier: codeVerifier,\n client_id: CLI_CLIENT_ID,\n redirect_uri: `http://127.0.0.1:${port}/callback`,\n }),\n });\n\n if (!response.ok) {\n let message: string;\n try {\n const body = (await response.json()) as { message?: string; error?: string };\n message = body.message ?? body.error ?? response.statusText;\n } catch {\n message = response.statusText;\n }\n throw new Error(`Token exchange failed: ${message}`);\n }\n\n const parsed = (await response.json()) as TokenResponse;\n // Validate the server returned a usable access token. A malformed\n // response would otherwise produce { accessToken: undefined } on disk\n // and a confusing \"login succeeded then auth failed\" experience.\n if (typeof parsed.access_token !== 'string' || parsed.access_token.length === 0) {\n throw new Error('Token exchange returned no access_token');\n }\n return parsed;\n}\n\nfunction successPage(): string {\n return `<!DOCTYPE html>\n<html><head><title>Spacelr CLI</title>\n<style>body{font-family:system-ui,sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#f8f9fa;}\n.box{text-align:center;padding:2rem;}.check{font-size:3rem;color:#22c55e;}</style></head>\n<body><div class=\"box\"><div class=\"check\">&#10003;</div><h1>Authenticated</h1><p>You can close this window and return to the terminal.</p></div></body></html>`;\n}\n\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\nfunction errorPage(message: string): string {\n return `<!DOCTYPE html>\n<html><head><title>Spacelr CLI</title>\n<style>body{font-family:system-ui,sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#f8f9fa;}\n.box{text-align:center;padding:2rem;}.x{font-size:3rem;color:#ef4444;}</style></head>\n<body><div class=\"box\"><div class=\"x\">&#10007;</div><h1>Authentication Failed</h1><p>${escapeHtml(message)}</p></div></body></html>`;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport * as crypto from 'node:crypto';\nimport type { StoredCredentials, PKCEChallenge, TokenResponse } from './types';\nimport { findConfigPath } from './config';\nimport { verbose, info, warn } from './output';\n\nexport type CredentialsScope = 'project' | 'global';\n\nexport interface CredentialsLocation {\n path: string;\n scope: CredentialsScope;\n projectDir?: string;\n}\n\nfunction getGlobalCredentialsDir(): string {\n return path.join(\n process.env['HOME'] ?? process.env['USERPROFILE'] ?? os.homedir(),\n '.spacelr',\n );\n}\n\nfunction getGlobalCredentialsFile(): string {\n return path.join(getGlobalCredentialsDir(), 'credentials.json');\n}\n\n/**\n * Resolve where credentials should be read from / written to.\n *\n * Lookup order:\n * 1. If `forceGlobal` is true → always use ~/.spacelr/credentials.json\n * 2. Walk up from cwd looking for `spacelr.json` — if found, credentials\n * live at `<projectDir>/.spacelr/credentials.json` (project scope)\n * 3. Otherwise → fall back to ~/.spacelr/credentials.json (global scope)\n *\n * Note: this function chooses the *primary* location. A read fallback from\n * project → global happens in `getStoredCredentials` so users with only\n * legacy global credentials can still authenticate from inside a project.\n */\nexport function resolveCredentialsFile(forceGlobal = false): CredentialsLocation {\n if (forceGlobal) {\n return { path: getGlobalCredentialsFile(), scope: 'global' };\n }\n const configPath = findConfigPath();\n if (configPath) {\n const projectDir = path.dirname(configPath);\n return {\n path: path.join(projectDir, '.spacelr', 'credentials.json'),\n scope: 'project',\n projectDir,\n };\n }\n return { path: getGlobalCredentialsFile(), scope: 'global' };\n}\n\n/**\n * Ensure the project's `.gitignore` excludes `.spacelr/` so credentials never\n * reach git. Runs before every project-scoped credential write (login and\n * refresh), so a user who deletes the entry gets it restored automatically.\n *\n * Matches these patterns as \"already ignored\": `.spacelr/`, `.spacelr`,\n * `.spacelr/*`, `.spacelr/credentials.json`.\n *\n * shared-with: libs/mcp-server/src/config.ts (intentional duplication —\n * the two packages publish independently and must not depend on each other)\n */\nexport function ensureGitignored(projectDir: string): { safe: boolean } {\n const gitignorePath = path.join(projectDir, '.gitignore');\n const entry = '.spacelr/';\n\n const matchesExisting = (line: string): boolean => {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) return false;\n return (\n trimmed === '.spacelr' ||\n trimmed === '.spacelr/' ||\n trimmed === '.spacelr/*' ||\n trimmed === '.spacelr/**' ||\n trimmed === '.spacelr/credentials.json' ||\n // Leading-slash forms anchor the pattern to the repo root\n trimmed === '/.spacelr' ||\n trimmed === '/.spacelr/' ||\n trimmed === '/.spacelr/*' ||\n trimmed === '/.spacelr/**' ||\n trimmed === '/.spacelr/credentials.json'\n );\n };\n\n // Heuristic: any line starting with `!` that mentions `.spacelr` could\n // un-ignore credentials. We deliberately use a permissive prefix check\n // (instead of exact-string matching) because gitignore supports many\n // pattern variants — `!.spacelr*`, `!.spacelr/**/*.json`, `!/.spacelr/**`,\n // etc. — and an exhaustive list would inevitably miss something. False\n // positives here just refuse the write (safe default); false negatives\n // would silently leave credentials trackable.\n const hasNegation = (line: string): boolean => {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) return false;\n return trimmed.startsWith('!') && trimmed.includes('.spacelr');\n };\n\n let content = '';\n let existed = false;\n try {\n content = fs.readFileSync(gitignorePath, 'utf-8');\n existed = true;\n } catch (err) {\n // ENOENT is expected (no .gitignore yet). Any other error (e.g. EACCES)\n // means we cannot verify safety — return safe:true (best-effort: a\n // user with a read-only .gitignore presumably knows what they're doing\n // and we don't want to block their login).\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') return { safe: true };\n }\n\n const lines = content.split(/\\r?\\n/);\n // Check for negation FIRST. A negation anywhere in the file un-ignores\n // credentials regardless of whether a positive match exists earlier:\n // git evaluates rules in order and the LAST matching rule wins, so\n // `.spacelr/` followed by `!.spacelr/credentials.json` still tracks\n // credentials. Returning early on a positive match would miss this.\n if (lines.some(hasNegation)) {\n const alreadyHasMatch = lines.some(matchesExisting);\n warn(\n alreadyHasMatch\n ? '.gitignore already contains .spacelr/ but ALSO contains a ' +\n 'negation pattern that un-ignores credentials. Remove the ' +\n 'negation or store credentials globally with ' +\n '`spacelr login --global`.'\n : '.gitignore contains a negation pattern for .spacelr/ — ' +\n 'refusing to write credentials safety entry. Remove the ' +\n 'negation or store credentials globally with ' +\n '`spacelr login --global`.',\n );\n return { safe: false };\n }\n if (lines.some(matchesExisting)) return { safe: true };\n\n const needsLeadingNewline = existed && content.length > 0 && !content.endsWith('\\n');\n const newContent =\n (existed ? content : '') +\n (needsLeadingNewline ? '\\n' : '') +\n entry +\n '\\n';\n\n try {\n // Atomic write so a crash mid-write cannot truncate .gitignore and\n // silently drop the .spacelr/ entry.\n writeFileAtomic(gitignorePath, newContent, 0o644);\n info(`Added ${entry} to .gitignore (credentials must never be committed)`);\n return { safe: true };\n } catch {\n // Best-effort — do not fail login if .gitignore is read-only.\n // Return safe:true so the caller still writes credentials (a read-only\n // .gitignore is the user's choice; we can't fix it for them).\n return { safe: true };\n }\n}\n\n/**\n * Read credentials from the resolved location, with a legacy fallback:\n * if project-scoped lookup finds nothing, also try the global file. This\n * keeps existing users with only `~/.spacelr/credentials.json` working.\n */\nexport function getStoredCredentials(\n forceGlobal = false,\n): StoredCredentials | null {\n return getStoredCredentialsWithLocation(forceGlobal)?.credentials ?? null;\n}\n\n/**\n * Same as `getStoredCredentials` but also returns the *actual* location the\n * credentials were read from. This is critical for refresh: when the project\n * scope has no file, the fallback returns global credentials, and the\n * subsequent refresh write MUST go back to global (not to the project) —\n * otherwise the global file is left with a revoked refresh token.\n */\nexport function getStoredCredentialsWithLocation(\n forceGlobal = false,\n): { credentials: StoredCredentials; location: CredentialsLocation } | null {\n const primary = resolveCredentialsFile(forceGlobal);\n const fromPrimary = readCredentialsFromDisk(primary.path);\n if (fromPrimary) return { credentials: fromPrimary, location: primary };\n\n // Fallback: project scope with no local file → try global for legacy users\n if (!forceGlobal && primary.scope === 'project') {\n const globalPath = getGlobalCredentialsFile();\n const fromGlobal = readCredentialsFromDisk(globalPath);\n if (fromGlobal) {\n return {\n credentials: fromGlobal,\n location: { path: globalPath, scope: 'global' },\n };\n }\n }\n return null;\n}\n\nfunction readCredentialsFromDisk(filePath: string): StoredCredentials | null {\n try {\n // No existsSync guard — would race with concurrent unlink. The catch\n // below covers ENOENT, JSON parse errors, and read failures uniformly.\n const content = fs.readFileSync(filePath, 'utf-8');\n const parsed: unknown = JSON.parse(content);\n if (typeof parsed !== 'object' || parsed === null) return null;\n const obj = parsed as Record<string, unknown>;\n if (\n typeof obj['accessToken'] !== 'string' ||\n obj['accessToken'].length === 0 ||\n !Number.isFinite(obj['expiresAt']) ||\n typeof obj['apiUrl'] !== 'string' ||\n obj['apiUrl'].length === 0\n ) {\n return null;\n }\n // refreshToken is optional, but if present must be a string —\n // otherwise we'd serialize a non-string into the refresh request body.\n if ('refreshToken' in obj && typeof obj['refreshToken'] !== 'string') {\n return null;\n }\n return parsed as StoredCredentials;\n } catch {\n return null;\n }\n}\n\n/**\n * Atomic write: write to `<path>.tmp` then rename. Rename is atomic on POSIX\n * and Windows so concurrent readers never see a partial file.\n *\n * shared-with: libs/mcp-server/src/config.ts\n */\nfunction writeFileAtomic(filePath: string, data: string, mode: number): void {\n const tmpPath = `${filePath}.tmp.${process.pid}.${crypto.randomBytes(6).toString('hex')}`;\n try {\n fs.writeFileSync(tmpPath, data, { mode });\n fs.renameSync(tmpPath, filePath);\n } catch (err) {\n // Best-effort cleanup of temp file on failure\n try {\n fs.unlinkSync(tmpPath);\n } catch {\n /* ignore */\n }\n throw err;\n }\n}\n\n/**\n * Persist credentials to disk and return the location they were written to.\n *\n * The second argument has two valid forms:\n * - `boolean` (default `false`): treated as `forceGlobal` — `true` writes\n * to `~/.spacelr/credentials.json`, `false` walks up to find a project.\n * Used by `login` where the caller only knows whether the user passed\n * `--global`.\n * - `CredentialsLocation`: an explicit target. Used by refresh to write\n * back to the exact file the credentials were read from, preventing\n * scope mismatch when legacy global creds are used inside a project.\n */\nexport function storeCredentials(\n credentials: StoredCredentials,\n target: boolean | CredentialsLocation = false,\n): CredentialsLocation {\n const location =\n typeof target === 'boolean' ? resolveCredentialsFile(target) : target;\n\n // Safety: ensure .spacelr/ is gitignored before we write to a project.\n // If a negation pattern is detected, ensureGitignored returns safe:false\n // and we refuse to write credentials to that project — the user must use\n // `--global` instead. Without this guard the credential file would land\n // in a .gitignore-trackable location.\n if (location.scope === 'project' && location.projectDir) {\n const { safe } = ensureGitignored(location.projectDir);\n if (!safe) {\n throw new Error(\n 'Refusing to write project-local credentials: .gitignore contains ' +\n 'a negation pattern that would un-ignore .spacelr/. Run ' +\n '`spacelr login --global` to store credentials in ~/.spacelr/.',\n );\n }\n }\n\n // mkdirSync with recursive:true is idempotent and does not throw if the\n // directory already exists, so no existsSync guard needed.\n const dir = path.dirname(location.path);\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n // mode: on mkdirSync only applies when the directory is created. If the\n // user pre-created .spacelr/ with wider permissions (e.g. 0o755), enforce\n // 0o700 here so other local users cannot enumerate credential filenames.\n // Best-effort — chmod can fail on Windows / non-owned dirs, in which case\n // we leave the existing mode rather than failing the credential write.\n try {\n fs.chmodSync(dir, 0o700);\n } catch {\n /* ignore */\n }\n\n writeFileAtomic(location.path, JSON.stringify(credentials, null, 2), 0o600);\n return location;\n}\n\n/**\n * Clear credentials at the resolved location. If `scope` is 'all', clear\n * both project-local and global files.\n */\nexport function clearCredentials(scope: 'auto' | 'global' | 'all' = 'auto'): {\n cleared: CredentialsLocation[];\n} {\n const cleared: CredentialsLocation[] = [];\n\n // No existsSync guard — race-prone and inconsistent with the rest of\n // the file. Just unlink and swallow ENOENT (file already gone is success).\n // Surface other errors (EACCES etc.) so the user knows the file is still\n // there, instead of seeing a misleading \"No credentials found\" message.\n const tryDelete = (loc: CredentialsLocation): void => {\n try {\n fs.unlinkSync(loc.path);\n cleared.push(loc);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== 'ENOENT') {\n // Use warn (not verbose) so the user always sees this — otherwise\n // a permission failure looks like a successful logout.\n warn(\n `Failed to remove ${loc.path} (${code ?? 'unknown error'}) — file may still be on disk`,\n );\n }\n }\n };\n\n if (scope === 'all') {\n // Delete the current project file (if cwd is inside a project) AND\n // the global file. Two limitations of \"all\":\n // 1. Other projects on disk cannot be enumerated and are left alone.\n // 2. If a project's spacelr.json was deleted but\n // `.spacelr/credentials.json` still exists, the walk-up lookup\n // now resolves to global scope and the orphaned project file\n // is NOT cleaned up. The user must remove it manually.\n const primary = resolveCredentialsFile(false);\n if (primary.scope === 'project') tryDelete(primary);\n // Reuse the resolved global path when primary is already global —\n // avoids a redundant walk-up FS scan.\n tryDelete(\n primary.scope === 'global' ? primary : resolveCredentialsFile(true),\n );\n } else {\n tryDelete(resolveCredentialsFile(scope === 'global'));\n }\n\n return { cleared };\n}\n\nexport function isTokenExpired(credentials: StoredCredentials): boolean {\n // Add 60 second buffer\n return Date.now() >= credentials.expiresAt - 60_000;\n}\n\nexport async function resolveToken(flagToken?: string): Promise<string | null> {\n if (flagToken) return flagToken;\n if (process.env['SPACELR_TOKEN']) return process.env['SPACELR_TOKEN'];\n const loaded = getStoredCredentialsWithLocation();\n if (!loaded) return null;\n const { credentials, location } = loaded;\n if (!isTokenExpired(credentials)) return credentials.accessToken;\n // Token expired — only refresh if we have a refresh token\n // (apiUrl is already validated by readCredentialsFromDisk)\n if (credentials.refreshToken) {\n const newToken = await refreshStoredToken(credentials, location);\n if (newToken) return newToken;\n }\n return null;\n}\n\nconst REFRESH_TIMEOUT_MS = 10_000;\n\n/**\n * Refreshes the access token using the stored refresh token.\n * Always uses credentials.apiUrl (issuer-bound) to prevent\n * sending refresh tokens to untrusted URLs.\n *\n * The `sourceLocation` parameter is REQUIRED — it ensures the refreshed\n * credentials are written back to the exact file they were read from,\n * which is critical when falling back from project scope to global scope\n * (otherwise the global file is left with a revoked refresh token).\n *\n * On 401 (token already revoked — likely by a concurrent process),\n * re-reads the *same* file once. If another process has already\n * stored a newer token, returns that instead of failing.\n */\nexport async function refreshStoredToken(\n credentials: StoredCredentials,\n sourceLocation: CredentialsLocation,\n): Promise<string | null> {\n // Short-circuit: nothing to refresh against. Without this guard a future\n // caller could POST `{ refreshToken: '' }` to the auth server.\n if (!credentials.refreshToken) return null;\n\n // Validate scheme — a credentials file with apiUrl: \"file:///etc/passwd\"\n // (manually edited or written by a compromised process) would otherwise\n // produce an opaque fetch error. Only http(s) is accepted.\n try {\n const parsed = new URL(credentials.apiUrl);\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n verbose(`Refusing to refresh against non-http(s) URL: ${parsed.protocol}`);\n return null;\n }\n } catch {\n verbose('Refusing to refresh: stored apiUrl is not a valid URL');\n return null;\n }\n\n const apiUrl = credentials.apiUrl.replace(/\\/+$/, '');\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), REFRESH_TIMEOUT_MS);\n\n try {\n verbose('Refreshing access token...');\n const response = await fetch(`${apiUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: credentials.refreshToken }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n verbose(`Token refresh failed (HTTP ${response.status})`);\n // Concurrent-refresh fallback: another process may have already rotated\n // the token. Re-read the SAME file (sourceLocation) — not via cwd —\n // so we don't accidentally pick up a different scope's credentials.\n if (response.status === 401) {\n const fresh = readCredentialsFromDisk(sourceLocation.path);\n if (\n fresh &&\n (fresh.accessToken !== credentials.accessToken ||\n fresh.refreshToken !== credentials.refreshToken) &&\n !isTokenExpired(fresh)\n ) {\n verbose('Using credentials refreshed by concurrent process');\n return fresh.accessToken;\n }\n }\n return null;\n }\n\n const data = (await response.json()) as TokenResponse;\n if (typeof data.access_token !== 'string') {\n verbose('Token refresh returned unexpected response shape');\n return null;\n }\n // Validate expires_in: must be a positive finite number. A bogus value\n // (0, negative, NaN from a string, etc.) would either trigger an\n // immediate refresh loop or set expiresAt to NaN.\n const expiresInRaw = data.expires_in;\n const expiresIn =\n typeof expiresInRaw === 'number' &&\n Number.isFinite(expiresInRaw) &&\n expiresInRaw > 0\n ? expiresInRaw\n : 3600;\n const newCredentials: StoredCredentials = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token ?? credentials.refreshToken,\n expiresAt: Date.now() + expiresIn * 1000,\n apiUrl: credentials.apiUrl,\n };\n // Write back to the EXACT location we read from, not wherever the\n // current cwd would resolve to. This prevents scope mismatch where\n // a legacy global login inside a project would leak into a project file.\n storeCredentials(newCredentials, sourceLocation);\n verbose('Token refreshed successfully');\n return data.access_token;\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n verbose('Token refresh timed out');\n } else {\n verbose('Token refresh error');\n }\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport class AuthRequiredError extends Error {\n constructor() {\n super('Not logged in. Run \"spacelr login\" to authenticate.');\n this.name = 'AuthRequiredError';\n }\n}\n\n/**\n * Resolves a token or throws AuthRequiredError.\n * Use in commands that require authentication.\n */\nexport async function requireAuth(flagToken?: string): Promise<string> {\n const token = await resolveToken(flagToken);\n if (!token) {\n throw new AuthRequiredError();\n }\n return token;\n}\n\nexport function generatePKCE(): PKCEChallenge {\n const codeVerifier = crypto.randomBytes(32).toString('base64url');\n const codeChallenge = crypto\n .createHash('sha256')\n .update(codeVerifier)\n .digest('base64url');\n return { codeVerifier, codeChallenge };\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { SpacelrConfig, DatabaseRules, DatabaseIndexes } from './types';\n\nconst CONFIG_FILENAME = 'spacelr.json';\nexport const RULES_FILENAME = 'spacelr.rules.json';\nexport const INDEXES_FILENAME = 'spacelr.indexes.json';\n\nfunction readJsonFile<T>(filePath: string, label: string): T {\n const content = fs.readFileSync(filePath, 'utf-8');\n try {\n return JSON.parse(content) as T;\n } catch (err) {\n const detail = err instanceof Error ? `: ${err.message}` : '';\n throw new Error(\n `Invalid JSON in ${label}: ${filePath}${detail}\\nPlease check the file for syntax errors.`,\n );\n }\n}\n\nfunction writeJsonFile(filePath: string, data: unknown): void {\n fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\\n', 'utf-8');\n}\n\nfunction resolveSiblingPath(filename: string, configPath?: string): string {\n const resolved = configPath ?? findConfigPath();\n const dir = resolved ? path.dirname(resolved) : process.cwd();\n return path.join(dir, filename);\n}\n\nexport function findConfigPath(startDir?: string): string | null {\n let dir = startDir ?? process.cwd();\n\n while (true) {\n const candidate = path.join(dir, CONFIG_FILENAME);\n if (fs.existsSync(candidate)) {\n return candidate;\n }\n const parent = path.dirname(dir);\n if (parent === dir) {\n return null;\n }\n dir = parent;\n }\n}\n\nexport function loadConfig(configPath?: string): SpacelrConfig | null {\n const resolved = configPath ?? findConfigPath();\n if (!resolved || !fs.existsSync(resolved)) return null;\n return readJsonFile<SpacelrConfig>(resolved, 'config file');\n}\n\nexport function saveConfig(\n config: SpacelrConfig,\n configPath?: string,\n): void {\n const resolved = configPath ?? findConfigPath() ?? path.join(process.cwd(), CONFIG_FILENAME);\n writeJsonFile(resolved, config);\n}\n\nexport function resolveProjectId(\n flagValue?: string,\n config?: SpacelrConfig | null,\n): string {\n const projectId = flagValue ?? config?.projectId;\n if (!projectId) {\n throw new Error(\n 'Project ID is required. Provide --project <id> or set \"projectId\" in spacelr.json',\n );\n }\n return projectId;\n}\n\nexport function resolveApiUrl(\n flagValue?: string,\n config?: SpacelrConfig | null,\n): string {\n return (\n flagValue ??\n config?.apiUrl ??\n process.env['SPACELR_API_URL'] ??\n 'https://api.spacelr.com/api/v1'\n );\n}\n\nexport function loadRules(configPath?: string): DatabaseRules | null {\n const filePath = resolveSiblingPath(RULES_FILENAME, configPath);\n if (!fs.existsSync(filePath)) return null;\n return readJsonFile<DatabaseRules>(filePath, 'rules file');\n}\n\nexport function saveRules(rules: DatabaseRules, configPath?: string): void {\n writeJsonFile(resolveSiblingPath(RULES_FILENAME, configPath), rules);\n}\n\nexport function loadIndexes(configPath?: string): DatabaseIndexes | null {\n const filePath = resolveSiblingPath(INDEXES_FILENAME, configPath);\n if (!fs.existsSync(filePath)) return null;\n return readJsonFile<DatabaseIndexes>(filePath, 'indexes file');\n}\n\nexport function saveIndexes(indexes: DatabaseIndexes, configPath?: string): void {\n writeJsonFile(resolveSiblingPath(INDEXES_FILENAME, configPath), indexes);\n}\n","import { Command } from 'commander';\nimport { clearCredentials } from '../lib/auth';\nimport { success, warn, info, json, isJsonMode } from '../lib/output';\n\nexport function createLogoutCommand(): Command {\n return new Command('logout')\n .description('Clear stored credentials')\n .option('--global', 'Clear only the global credentials file')\n .option(\n '--all',\n 'Clear the current project credentials file (if any) and the global ' +\n 'credentials file (other projects are not touched — they cannot be ' +\n 'enumerated)',\n )\n .action(async (opts) => {\n // --global and --all are mutually exclusive: --all already includes\n // global, so combining them is ambiguous. Reject explicitly instead\n // of silently treating them as --all.\n if (opts.global === true && opts.all === true) {\n warn('--global and --all cannot be combined; --all already removes the global file');\n process.exitCode = 1;\n return;\n }\n\n const scope: 'auto' | 'global' | 'all' =\n opts.all === true ? 'all' : opts.global === true ? 'global' : 'auto';\n\n const { cleared } = clearCredentials(scope);\n\n if (isJsonMode()) {\n json({\n success: true,\n cleared: cleared.map((c) => ({ path: c.path, scope: c.scope })),\n });\n } else if (cleared.length === 0) {\n warn('No credentials found');\n } else {\n success('Logged out successfully');\n for (const loc of cleared) {\n info(`Removed ${loc.path} (${loc.scope})`);\n }\n }\n });\n}\n","import { Command } from 'commander';\nimport { ApiClient } from '../lib/api-client';\nimport { resolveApiUrl, loadConfig } from '../lib/config';\nimport { requireAuth } from '../lib/auth';\nimport { success, error, info, json, isJsonMode } from '../lib/output';\nimport type { GlobalOptions, UserInfo } from '../lib/types';\n\nexport function createWhoamiCommand(): Command {\n return new Command('whoami')\n .description('Show current authenticated user')\n .action(async (_opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const client = new ApiClient({ apiUrl, token });\n const response = await client.get<{ user: UserInfo }>('/auth/me');\n const user = response.user;\n\n if (isJsonMode()) {\n json(user);\n } else {\n success(`Logged in as ${user.email ?? user.username ?? user.id}`);\n if (user.displayName) info(`Name: ${user.displayName}`);\n if (user.roles?.length) info(`Roles: ${user.roles.join(', ')}`);\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to get user info');\n process.exitCode = 1;\n }\n });\n}\n","import {\n getStoredCredentialsWithLocation,\n isTokenExpired,\n refreshStoredToken,\n type CredentialsLocation,\n} from './auth';\nimport { verbose } from './output';\nimport type { StoredCredentials } from './types';\n\ninterface ApiClientOptions {\n apiUrl: string;\n token?: string;\n clientId?: string;\n projectId?: string;\n}\n\ninterface RequestOptions {\n method?: string;\n body?: BodyInit | Record<string, unknown>;\n headers?: Record<string, string>;\n timeout?: number;\n}\n\nexport class ApiClient {\n private readonly apiUrl: string;\n private readonly clientId: string;\n private readonly projectId?: string;\n private explicitToken?: string;\n private refreshing: Promise<string | null> | null = null;\n\n constructor(options: ApiClientOptions) {\n this.apiUrl = options.apiUrl.replace(/\\/+$/, '');\n this.explicitToken = options.token;\n this.clientId = options.clientId ?? 'spacelr-cli';\n this.projectId = options.projectId;\n }\n\n private async getToken(): Promise<string | null> {\n if (this.explicitToken) return this.explicitToken;\n\n const envToken = process.env['SPACELR_TOKEN'];\n if (envToken) return envToken;\n\n const loaded = getStoredCredentialsWithLocation();\n if (!loaded) return null;\n const { credentials, location } = loaded;\n\n if (!isTokenExpired(credentials)) {\n return credentials.accessToken;\n }\n\n // Token expired, try refreshing — pass location so refresh writes back\n // to the exact file we read from (scope-safe)\n if (credentials.refreshToken) {\n return this.refreshAccessToken(credentials, location);\n }\n\n return null;\n }\n\n private async refreshAccessToken(\n credentials: StoredCredentials,\n location: CredentialsLocation,\n ): Promise<string | null> {\n // Deduplicate concurrent refreshes\n if (this.refreshing) return this.refreshing;\n\n this.refreshing = refreshStoredToken(credentials, location).finally(() => {\n this.refreshing = null;\n });\n\n return this.refreshing;\n }\n\n private serializeBody(\n body: RequestOptions['body'],\n contentType: string | undefined,\n ): BodyInit | undefined {\n if (!body) return undefined;\n if (contentType === 'application/json') {\n return JSON.stringify(body);\n }\n // Buffer, string, URLSearchParams, etc. are already valid BodyInit\n return body as BodyInit;\n }\n\n private async request<T>(\n path: string,\n options: RequestOptions = {},\n ): Promise<T> {\n const { method = 'GET', body, headers = {}, timeout = 30_000 } = options;\n const url = `${this.apiUrl}${path}`;\n\n const token = await this.getToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n if (body && !headers['Content-Type']) {\n headers['Content-Type'] = 'application/json';\n }\n\n headers['x-client-id'] = this.clientId;\n if (this.projectId) {\n headers['x-project-id'] = this.projectId;\n }\n\n const serializedBody = this.serializeBody(body, headers['Content-Type']);\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n\n verbose(`${method} ${url}`);\n\n try {\n const response = await fetch(url, {\n method,\n headers,\n body: serializedBody,\n signal: controller.signal,\n });\n\n if (response.status === 401 && !this.explicitToken) {\n // Try refresh once\n const loaded = getStoredCredentialsWithLocation();\n if (loaded) {\n // If another process already rotated the token between getToken()\n // and now, the on-disk token is fresh — use it directly instead\n // of refreshing again (avoids burning a single-use refresh token).\n let newToken: string | null = null;\n if (!isTokenExpired(loaded.credentials)) {\n newToken = loaded.credentials.accessToken;\n } else if (loaded.credentials.refreshToken) {\n newToken = await this.refreshAccessToken(\n loaded.credentials,\n loaded.location,\n );\n }\n if (newToken) {\n headers['Authorization'] = `Bearer ${newToken}`;\n const retryController = new AbortController();\n const retryTimer = setTimeout(() => retryController.abort(), timeout);\n const retryResponse = await fetch(url, {\n method,\n headers,\n body: serializedBody,\n signal: retryController.signal,\n });\n clearTimeout(retryTimer);\n if (!retryResponse.ok) {\n // If retry still 401, surface the actionable login message\n // instead of a generic \"API error (401): Unauthorized\".\n if (retryResponse.status === 401) {\n throw new Error(\n 'Authentication required. Run \"spacelr login\" to authenticate.',\n );\n }\n await this.throwApiError(retryResponse);\n }\n return (await retryResponse.json()) as T;\n }\n }\n throw new Error(\n 'Authentication required. Run \"spacelr login\" to authenticate.',\n );\n }\n\n if (!response.ok) {\n await this.throwApiError(response);\n }\n\n const contentType = response.headers.get('content-type');\n if (contentType?.includes('application/json')) {\n return (await response.json()) as T;\n }\n return (await response.text()) as unknown as T;\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error(`Request timed out: ${method} ${path}`);\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n }\n\n private async throwApiError(response: Response): Promise<never> {\n let message: string;\n try {\n const body = (await response.json()) as { message?: string; error?: string };\n message = body.message ?? body.error ?? response.statusText;\n } catch {\n message = response.statusText;\n }\n throw new Error(`API error (${response.status}): ${message}`);\n }\n\n async get<T>(path: string, timeout?: number): Promise<T> {\n return this.request<T>(path, { timeout });\n }\n\n async post<T>(path: string, body?: Record<string, unknown> | BodyInit, timeout?: number): Promise<T> {\n return this.request<T>(path, { method: 'POST', body, timeout });\n }\n\n async put<T>(path: string, body?: Record<string, unknown> | BodyInit, timeout?: number): Promise<T> {\n return this.request<T>(path, { method: 'PUT', body, timeout });\n }\n\n async patch<T>(path: string, body?: Record<string, unknown> | BodyInit, timeout?: number): Promise<T> {\n return this.request<T>(path, { method: 'PATCH', body, timeout });\n }\n\n async delete<T>(path: string, timeout?: number): Promise<T> {\n return this.request<T>(path, { method: 'DELETE', timeout });\n }\n\n async uploadFile(\n path: string,\n fileBuffer: Buffer,\n filename: string,\n ): Promise<DeploymentUploadResponse> {\n const boundary = `----spacelr${Date.now()}`;\n const parts: Buffer[] = [];\n\n // Sanitize filename for embedding in the Content-Disposition header.\n // Strip CR/LF (header injection) and quote characters (would break the\n // quoted string and allow injecting additional MIME headers).\n const safeFilename = filename.replace(/[\\r\\n\"]/g, '_');\n\n // Build multipart body manually (no form-data dependency needed)\n const header = Buffer.from(\n `--${boundary}\\r\\n` +\n `Content-Disposition: form-data; name=\"file\"; filename=\"${safeFilename}\"\\r\\n` +\n `Content-Type: application/zip\\r\\n\\r\\n`,\n );\n const footer = Buffer.from(`\\r\\n--${boundary}--\\r\\n`);\n parts.push(header, fileBuffer, footer);\n const body = Buffer.concat(parts);\n\n return this.request<DeploymentUploadResponse>(path, {\n method: 'POST',\n body,\n headers: {\n 'Content-Type': `multipart/form-data; boundary=${boundary}`,\n },\n timeout: 300_000, // 5 minutes for uploads\n });\n }\n}\n\ninterface DeploymentUploadResponse {\n deploymentId: string;\n status: string;\n fileCount: number;\n totalSizeBytes: number;\n}\n","import { Command } from 'commander';\nimport { ApiClient } from '../lib/api-client';\nimport { resolveApiUrl, loadConfig } from '../lib/config';\nimport { requireAuth } from '../lib/auth';\nimport { error, spinner, json, isJsonMode, table, info } from '../lib/output';\nimport type { GlobalOptions, ProjectInfo } from '../lib/types';\n\nexport function createProjectsCommand(): Command {\n return new Command('projects')\n .description('List your projects')\n .action(async (_opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const client = new ApiClient({ apiUrl, token });\n const spin = spinner('Fetching projects...');\n const result = await client.get<{ projects: ProjectInfo[] }>('/projects');\n spin.stop();\n\n const projects = result.projects;\n\n if (projects.length === 0) {\n info('No projects found');\n return;\n }\n\n const activeProjectId = config?.projectId;\n\n if (isJsonMode()) {\n json(projects);\n } else {\n table(\n ['', 'ID', 'Name', 'Slug'],\n projects.map((p) => [\n p.id === activeProjectId ? '*' : ' ',\n p.id,\n p.name,\n p.slug,\n ]),\n );\n if (activeProjectId) {\n info(`\\n* = active project (from spacelr.json)`);\n }\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to list projects');\n process.exitCode = 1;\n }\n });\n}\n\nexport async function fetchProjects(\n client: ApiClient,\n): Promise<ProjectInfo[]> {\n const result = await client.get<{ projects: ProjectInfo[] }>('/projects');\n return result.projects;\n}\n","import { Command } from 'commander';\nimport { ApiClient } from '../lib/api-client';\nimport { resolveApiUrl, loadConfig, saveConfig } from '../lib/config';\nimport { requireAuth } from '../lib/auth';\nimport { success, error, spinner, json, isJsonMode, info } from '../lib/output';\nimport { promptChoice } from '../lib/prompt';\nimport { fetchProjects } from './projects';\nimport type { GlobalOptions, ProjectInfo } from '../lib/types';\n\nexport function createUseCommand(): Command {\n return new Command('use')\n .description('Set the active project')\n .argument('[project]', 'Project ID or slug')\n .action(async (project: string | undefined, _opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const client = new ApiClient({ apiUrl, token });\n const spin = spinner('Fetching projects...');\n const projects = await fetchProjects(client);\n spin.stop();\n\n if (projects.length === 0) {\n error('No projects found. Create a project first.');\n process.exitCode = 1;\n return;\n }\n\n let selected: ProjectInfo;\n\n if (project) {\n // Find by ID or slug\n const match = projects.find(\n (p) => p.id === project || p.slug === project,\n );\n if (!match) {\n error(`Project \"${project}\" not found`);\n info('Available projects:');\n for (const p of projects) {\n info(` ${p.slug} (${p.id})`);\n }\n process.exitCode = 1;\n return;\n }\n selected = match;\n } else {\n // Interactive selection\n selected = await promptChoice(\n 'Select a project:',\n projects.map((p) => ({\n ...p,\n label: `${p.name} (${p.slug})`,\n })),\n );\n }\n\n // Update config\n const updatedConfig = { ...config, projectId: selected.id };\n saveConfig(updatedConfig);\n\n if (isJsonMode()) {\n json({ projectId: selected.id, name: selected.name, slug: selected.slug });\n } else {\n success(`Now using project \"${selected.name}\" (${selected.slug})`);\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to select project');\n process.exitCode = 1;\n }\n });\n}\n","import * as readline from 'node:readline';\n\nexport async function promptChoice<T extends { label: string }>(\n message: string,\n choices: T[],\n): Promise<T> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n\n console.error(`\\n${message}\\n`);\n choices.forEach((choice, i) => {\n console.error(` ${i + 1}) ${choice.label}`);\n });\n console.error();\n\n return new Promise((resolve, reject) => {\n rl.question(' Enter number: ', (answer) => {\n rl.close();\n const index = parseInt(answer, 10) - 1;\n if (isNaN(index) || index < 0 || index >= choices.length) {\n reject(new Error('Invalid selection'));\n return;\n }\n resolve(choices[index]);\n });\n });\n}\n\nexport async function promptConfirm(message: string): Promise<boolean> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n\n return new Promise((resolve) => {\n rl.question(`${message} (y/N) `, (answer) => {\n rl.close();\n resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');\n });\n });\n}\n\nexport async function promptInput(message: string, defaultValue?: string): Promise<string> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n\n const suffix = defaultValue ? ` (${defaultValue})` : '';\n\n return new Promise((resolve) => {\n rl.question(`${message}${suffix}: `, (answer) => {\n rl.close();\n resolve(answer.trim() || defaultValue || '');\n });\n });\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { Command } from 'commander';\nimport { ApiClient } from '../lib/api-client';\nimport { resolveApiUrl, loadConfig, saveConfig } from '../lib/config';\nimport { requireAuth } from '../lib/auth';\nimport { success, error, warn, spinner, json, isJsonMode, info } from '../lib/output';\nimport { promptChoice, promptInput } from '../lib/prompt';\nimport { fetchProjects } from './projects';\nimport type { GlobalOptions, SpacelrConfig } from '../lib/types';\n\nexport function createInitCommand(): Command {\n return new Command('init')\n .description('Initialize a spacelr.json config in the current directory')\n .action(async (_opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const existingConfig = loadConfig();\n\n const configPath = path.join(process.cwd(), 'spacelr.json');\n if (fs.existsSync(configPath)) {\n warn(`spacelr.json already exists in ${process.cwd()}`);\n info('Use \"spacelr use\" to change the active project');\n return;\n }\n\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, existingConfig);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const client = new ApiClient({ apiUrl, token });\n const spin = spinner('Fetching projects...');\n const projects = await fetchProjects(client);\n spin.stop();\n\n if (projects.length === 0) {\n error('No projects found. Create a project in the admin panel first.');\n process.exitCode = 1;\n return;\n }\n\n // Select project\n const selected = await promptChoice(\n 'Select a project:',\n projects.map((p) => ({\n ...p,\n label: `${p.name} (${p.slug})`,\n })),\n );\n\n // Ask for hosting directory\n const hostingDir = await promptInput(\n 'Hosting directory',\n './dist',\n );\n\n const config: SpacelrConfig = {\n projectId: selected.id,\n apiUrl: apiUrl !== 'https://api.spacelr.com/api/v1' ? apiUrl : undefined,\n hosting: {\n directory: hostingDir,\n },\n };\n\n saveConfig(config, configPath);\n\n if (isJsonMode()) {\n json(config);\n } else {\n success(`Created spacelr.json for \"${selected.name}\"`);\n info(`Project: ${selected.slug} (${selected.id})`);\n info(`Hosting directory: ${hostingDir}`);\n info('');\n info('Next steps:');\n info(' spacelr deploy Deploy your site');\n info(' spacelr db indexes pull Pull database indexes');\n info(' spacelr db rules pull Pull database rules');\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Initialization failed');\n process.exitCode = 1;\n }\n });\n}\n","import * as path from 'node:path';\nimport { Command } from 'commander';\nimport { ApiClient } from '../lib/api-client';\nimport {\n resolveApiUrl,\n resolveProjectId,\n loadConfig,\n} from '../lib/config';\nimport { requireAuth } from '../lib/auth';\nimport { createZipBuffer, countFiles } from '../lib/zip';\nimport {\n error,\n info,\n spinner,\n json,\n isJsonMode,\n formatBytes,\n verbose,\n} from '../lib/output';\nimport type {\n GlobalOptions,\n DeploymentResponse,\n} from '../lib/types';\n\nexport function createDeployCommand(): Command {\n return new Command('deploy')\n .description('Deploy a directory to Spacelr hosting')\n .argument('[directory]', 'Directory to deploy')\n .option('--project <id>', 'Project ID')\n .option('--description <text>', 'Deployment description')\n .option('--no-wait', 'Do not wait for processing to complete')\n .option('--dry-run', 'Show what would be deployed without uploading')\n .action(async (directory: string | undefined, opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const deployDir = directory ?? config?.hosting?.directory ?? '.';\n const absDir = path.resolve(deployDir);\n\n const client = new ApiClient({ apiUrl, token, projectId });\n await deploy(client, projectId, absDir, {\n description: opts.description,\n wait: opts.wait !== false,\n dryRun: opts.dryRun === true,\n });\n } catch (err) {\n error(err instanceof Error ? err.message : 'Deployment failed');\n process.exitCode = 1;\n }\n });\n}\n\ninterface DeployOptions {\n description?: string;\n wait: boolean;\n dryRun: boolean;\n}\n\nasync function deploy(\n client: ApiClient,\n projectId: string,\n directory: string,\n options: DeployOptions,\n): Promise<void> {\n // Step 1: Count files and create ZIP\n const spin = spinner('Preparing deployment...');\n\n const fileCount = countFiles(directory);\n verbose(`Found ${fileCount} files in ${directory}`);\n\n spin.text = 'Creating archive...';\n const zipBuffer = await createZipBuffer(directory);\n verbose(`Archive size: ${formatBytes(zipBuffer.length)}`);\n\n if (options.dryRun) {\n spin.succeed('Dry run complete');\n if (isJsonMode()) {\n json({ dryRun: true, fileCount, archiveSize: zipBuffer.length, directory });\n } else {\n info(`Directory: ${directory}`);\n info(`Files: ${fileCount}`);\n info(`Archive size: ${formatBytes(zipBuffer.length)}`);\n }\n return;\n }\n\n // Step 2: Create deployment\n spin.text = 'Creating deployment...';\n const deployment = await client.post<DeploymentResponse>(\n `/hosting/${projectId}/deployments`,\n {\n description: options.description,\n },\n );\n verbose(`Deployment ID: ${deployment.deploymentId}`);\n\n // Step 3: Upload ZIP\n spin.text = `Uploading ${formatBytes(zipBuffer.length)}...`;\n await client.uploadFile(\n `/hosting/${projectId}/deployments/${deployment.deploymentId}/upload`,\n zipBuffer,\n 'deployment.zip',\n );\n\n if (!options.wait) {\n spin.succeed('Upload complete');\n info(`Deployment ${deployment.deploymentId} is processing`);\n if (isJsonMode()) {\n json({ deploymentId: deployment.deploymentId, status: 'processing' });\n }\n return;\n }\n\n // Step 4: Poll for status\n spin.text = 'Processing deployment...';\n const result = await pollDeploymentStatus(\n client,\n projectId,\n deployment.deploymentId,\n spin,\n );\n\n if (result.status === 'active') {\n spin.succeed('Deployment active');\n if (isJsonMode()) {\n json(result);\n } else {\n info(`Deployment ID: ${result.deploymentId}`);\n info(`Files: ${result.fileCount}`);\n info(`Size: ${formatBytes(result.totalSizeBytes)}`);\n }\n } else if (result.status === 'failed') {\n spin.fail('Deployment failed');\n error(result.errorMessage ?? 'Unknown error');\n process.exitCode = 1;\n } else {\n spin.warn(`Deployment status: ${result.status}`);\n if (isJsonMode()) {\n json(result);\n }\n }\n}\n\nasync function pollDeploymentStatus(\n client: ApiClient,\n projectId: string,\n deploymentId: string,\n spin: { text: string },\n): Promise<DeploymentResponse> {\n const maxAttempts = 120; // 10 minutes (5s intervals)\n for (let i = 0; i < maxAttempts; i++) {\n await sleep(5000);\n const status = await client.get<DeploymentResponse>(\n `/hosting/${projectId}/deployments/${deploymentId}/status`,\n );\n\n verbose(`Poll ${i + 1}: status=${status.status}`);\n spin.text = `Processing deployment... (${status.status})`;\n\n if (\n status.status === 'active' ||\n status.status === 'failed'\n ) {\n return status;\n }\n }\n\n throw new Error('Deployment timed out after 10 minutes');\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport archiver from 'archiver';\n\nexport async function createZipBuffer(directory: string): Promise<Buffer> {\n const absDir = path.resolve(directory);\n if (!fs.existsSync(absDir)) {\n throw new Error(`Directory not found: ${absDir}`);\n }\n if (!fs.statSync(absDir).isDirectory()) {\n throw new Error(`Not a directory: ${absDir}`);\n }\n\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n const archive = archiver('zip', { zlib: { level: 9 } });\n\n archive.on('data', (chunk: Buffer) => chunks.push(chunk));\n archive.on('end', () => resolve(Buffer.concat(chunks)));\n archive.on('error', reject);\n\n archive.directory(absDir, false);\n archive.finalize();\n });\n}\n\nexport function countFiles(directory: string): number {\n const absDir = path.resolve(directory);\n let count = 0;\n\n function walk(dir: string): void {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isFile()) {\n count++;\n } else if (entry.isDirectory()) {\n walk(path.join(dir, entry.name));\n }\n }\n }\n\n walk(absDir);\n return count;\n}\n","import { Command } from 'commander';\nimport { createIndexesDeployCommand } from './indexes-deploy';\nimport { createIndexesPullCommand } from './indexes-pull';\nimport { createRulesDeployCommand } from './rules-deploy';\nimport { createRulesPullCommand } from './rules-pull';\n\nexport function createDbCommand(): Command {\n const indexes = new Command('indexes')\n .description('Manage database indexes');\n\n indexes.addCommand(createIndexesDeployCommand());\n indexes.addCommand(createIndexesPullCommand());\n\n const rules = new Command('rules')\n .description('Manage database rules');\n\n rules.addCommand(createRulesDeployCommand());\n rules.addCommand(createRulesPullCommand());\n\n const db = new Command('db')\n .description('Database management commands');\n\n db.addCommand(indexes);\n db.addCommand(rules);\n\n return db;\n}\n","import { Command } from 'commander';\nimport { ApiClient } from '../../lib/api-client';\nimport {\n resolveApiUrl,\n resolveProjectId,\n loadConfig,\n loadIndexes,\n} from '../../lib/config';\nimport { requireAuth } from '../../lib/auth';\nimport { success, error, info, spinner, json, isJsonMode, warn } from '../../lib/output';\nimport { promptConfirm } from '../../lib/prompt';\nimport type { GlobalOptions, IndexRuleEntry, RemoteIndexEntry } from '../../lib/types';\n\nexport function createIndexesDeployCommand(): Command {\n return new Command('deploy')\n .description('Deploy indexes from spacelr.indexes.json to remote')\n .option('--project <id>', 'Project ID')\n .option('--config <path>', 'Config file path')\n .option('--yes', 'Skip confirmation')\n .action(async (opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig(opts.config);\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const indexes = loadIndexes(opts.config);\n\n if (!indexes || Object.keys(indexes).length === 0) {\n warn('No indexes found in spacelr.indexes.json');\n return;\n }\n\n // Convert index format: config uses 1/-1, API expects asc/desc\n const indexRules = convertIndexFormat(indexes);\n\n const collectionCount = Object.keys(indexRules).length;\n const totalIndexes = Object.values(indexRules).reduce(\n (sum, arr) => sum + arr.length,\n 0,\n );\n\n if (!opts.yes) {\n info(\n `Will deploy ${totalIndexes} index(es) across ${collectionCount} collection(s)`,\n );\n const confirmed = await promptConfirm('Proceed with deployment?');\n if (!confirmed) {\n info('Aborted');\n return;\n }\n }\n\n const spin = spinner('Deploying indexes...');\n const client = new ApiClient({ apiUrl, token, projectId });\n const result = await client.put<{ message: string }>(\n `/databases/${projectId}/index-rules`,\n { indexRules },\n );\n\n spin.succeed('Indexes deployed');\n\n if (isJsonMode()) {\n json(result);\n } else {\n success(result.message ?? 'Indexes synced successfully');\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to deploy indexes');\n process.exitCode = 1;\n }\n });\n}\n\nfunction convertIndexFormat(\n indexes: Record<string, IndexRuleEntry[]>,\n): Record<string, RemoteIndexEntry[]> {\n const result: Record<string, RemoteIndexEntry[]> = {};\n\n for (const [collection, entries] of Object.entries(indexes)) {\n result[collection] = entries.map((entry) => {\n const fields: Record<string, 'asc' | 'desc'> = {};\n for (const [field, direction] of Object.entries(entry.fields)) {\n fields[field] = direction === 1 ? 'asc' : 'desc';\n }\n return {\n fields,\n ...(entry.unique !== undefined && { unique: entry.unique }),\n ...(entry.sparse !== undefined && { sparse: entry.sparse }),\n ...(entry.ttlSeconds !== undefined && { ttlSeconds: entry.ttlSeconds }),\n };\n });\n }\n\n return result;\n}\n","import { Command } from 'commander';\nimport { ApiClient } from '../../lib/api-client';\nimport {\n resolveApiUrl,\n resolveProjectId,\n loadConfig,\n saveConfig,\n saveIndexes,\n} from '../../lib/config';\nimport { requireAuth } from '../../lib/auth';\nimport { success, error, spinner, json, isJsonMode, info } from '../../lib/output';\nimport type { GlobalOptions, IndexRuleEntry, RemoteIndexEntry } from '../../lib/types';\n\nexport function createIndexesPullCommand(): Command {\n return new Command('pull')\n .description('Pull current indexes from remote to spacelr.indexes.json')\n .option('--project <id>', 'Project ID')\n .option('--config <path>', 'Config file path')\n .action(async (opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig(opts.config);\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n\n const spin = spinner('Pulling indexes...');\n const client = new ApiClient({ apiUrl, token, projectId });\n const response = await client.get<Record<string, unknown>>(\n `/databases/${projectId}/index-rules`,\n );\n\n // The API may return the indexes directly or wrapped in { indexRules }\n const remoteIndexes: Record<string, RemoteIndexEntry[]> =\n response && 'indexRules' in response\n ? (response['indexRules'] as Record<string, RemoteIndexEntry[]>)\n : (response as Record<string, RemoteIndexEntry[]>) ?? {};\n\n // Convert from API format (asc/desc) to config format (1/-1)\n const indexes = convertFromRemoteFormat(remoteIndexes);\n\n saveIndexes(indexes, opts.config);\n\n if (opts.project && opts.project !== config?.projectId) {\n saveConfig({ ...config, projectId: opts.project }, opts.config);\n }\n\n spin.succeed('Indexes pulled');\n\n const collectionCount = Object.keys(indexes).length;\n const totalIndexes = Object.values(indexes).reduce(\n (sum, arr) => sum + arr.length,\n 0,\n );\n\n if (isJsonMode()) {\n json(indexes);\n } else {\n success(\n `Pulled ${totalIndexes} index(es) from ${collectionCount} collection(s)`,\n );\n info('Indexes file updated');\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to pull indexes');\n process.exitCode = 1;\n }\n });\n}\n\nfunction convertFromRemoteFormat(\n remoteIndexes: Record<string, RemoteIndexEntry[]>,\n): Record<string, IndexRuleEntry[]> {\n const result: Record<string, IndexRuleEntry[]> = {};\n\n for (const [collection, entries] of Object.entries(remoteIndexes)) {\n result[collection] = entries.map((entry) => {\n const fields: Record<string, 1 | -1> = {};\n for (const [field, direction] of Object.entries(entry.fields)) {\n fields[field] = direction === 'asc' ? 1 : -1;\n }\n return {\n fields,\n ...(entry.unique !== undefined && { unique: entry.unique }),\n ...(entry.sparse !== undefined && { sparse: entry.sparse }),\n ...(entry.ttlSeconds !== undefined && {\n ttlSeconds: entry.ttlSeconds,\n }),\n };\n });\n }\n\n return result;\n}\n","import { Command } from 'commander';\nimport { ApiClient } from '../../lib/api-client';\nimport {\n resolveApiUrl,\n resolveProjectId,\n loadConfig,\n loadRules,\n} from '../../lib/config';\nimport { requireAuth } from '../../lib/auth';\nimport { success, error, info, spinner, json, isJsonMode, warn } from '../../lib/output';\nimport { promptConfirm } from '../../lib/prompt';\nimport type { GlobalOptions } from '../../lib/types';\n\nexport function createRulesDeployCommand(): Command {\n return new Command('deploy')\n .description('Deploy rules from spacelr.rules.json to remote')\n .option('--project <id>', 'Project ID')\n .option('--config <path>', 'Config file path')\n .option('--yes', 'Skip confirmation')\n .action(async (opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig(opts.config);\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const rules = loadRules(opts.config);\n\n if (!rules || Object.keys(rules).length === 0) {\n warn('No rules found in spacelr.rules.json');\n return;\n }\n\n const ruleCount = Object.keys(rules).length;\n\n if (!opts.yes) {\n info(`Will deploy rules for ${ruleCount} collection(s)`);\n const confirmed = await promptConfirm('Proceed with deployment?');\n if (!confirmed) {\n info('Aborted');\n return;\n }\n }\n\n // Validate first\n const spin = spinner('Validating rules...');\n const client = new ApiClient({ apiUrl, token, projectId });\n\n await client.post<{ valid: boolean }>(\n `/databases/${projectId}/rules/validate`,\n { rules },\n );\n\n // Deploy\n spin.text = 'Deploying rules...';\n const result = await client.put<{ message: string }>(\n `/databases/${projectId}/rules`,\n { rules },\n );\n\n spin.succeed('Rules deployed');\n\n if (isJsonMode()) {\n json(result);\n } else {\n success(result.message ?? 'Rules deployed successfully');\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to deploy rules');\n process.exitCode = 1;\n }\n });\n}\n","import { Command } from 'commander';\nimport { ApiClient } from '../../lib/api-client';\nimport {\n resolveApiUrl,\n resolveProjectId,\n loadConfig,\n saveConfig,\n saveRules,\n} from '../../lib/config';\nimport { requireAuth } from '../../lib/auth';\nimport { success, error, spinner, json, isJsonMode, info } from '../../lib/output';\nimport type { GlobalOptions } from '../../lib/types';\n\nexport function createRulesPullCommand(): Command {\n return new Command('pull')\n .description('Pull current rules from remote to spacelr.rules.json')\n .option('--project <id>', 'Project ID')\n .option('--config <path>', 'Config file path')\n .action(async (opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig(opts.config);\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n\n const spin = spinner('Pulling rules...');\n const client = new ApiClient({ apiUrl, token, projectId });\n const result = await client.get<{ rules: Record<string, unknown> }>(\n `/databases/${projectId}/rules`,\n );\n\n const rules = result.rules;\n\n saveRules(rules, opts.config);\n\n if (opts.project && opts.project !== config?.projectId) {\n saveConfig({ ...config, projectId: opts.project }, opts.config);\n }\n\n spin.succeed('Rules pulled');\n\n const ruleCount = Object.keys(rules).length;\n\n if (isJsonMode()) {\n json(rules);\n } else {\n success(`Pulled rules for ${ruleCount} collection(s)`);\n info('Rules file updated');\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to pull rules');\n process.exitCode = 1;\n }\n });\n}\n","import * as path from 'node:path';\nimport { Command } from 'commander';\nimport { ApiClient } from '../lib/api-client';\nimport {\n resolveApiUrl,\n resolveProjectId,\n loadConfig,\n} from '../lib/config';\nimport { requireAuth } from '../lib/auth';\nimport { createZipBuffer, countFiles } from '../lib/zip';\nimport {\n error,\n info,\n spinner,\n json,\n isJsonMode,\n formatBytes,\n verbose,\n} from '../lib/output';\nimport type { GlobalOptions } from '../lib/types';\n\ninterface FunctionEntry {\n id: string;\n name: string;\n enabled: boolean;\n cronExpression?: string;\n environmentVariables?: Record<string, string>;\n}\n\ninterface FunctionListResponse {\n data?: FunctionEntry[];\n}\n\ninterface FunctionCreateResponse {\n id?: string;\n data?: { id: string };\n}\n\ninterface ExecutionLogEntry {\n timestamp: string;\n level: string;\n message: string;\n}\n\ninterface ExecutionEntry {\n status: string;\n startedAt: string;\n duration?: number;\n triggeredBy: string;\n error?: string;\n logs?: ExecutionLogEntry[];\n}\n\ninterface ExecutionsResponse {\n items?: ExecutionEntry[];\n data?: { items?: ExecutionEntry[] };\n}\n\nexport function createFunctionsCommand(): Command {\n const functions = new Command('functions')\n .description('Manage serverless functions');\n\n functions\n .command('deploy [directory]')\n .description('Deploy a function')\n .requiredOption('--name <name>', 'Function name')\n .option('--entry <file>', 'Entry point (default: index.js)')\n .option('--cron <expression>', 'Cron schedule expression')\n .option('--timezone <tz>', 'Timezone for cron (default: UTC)')\n .option('--timeout <ms>', 'Execution timeout in ms')\n .option('--memory <mb>', 'Memory limit in MB')\n .option('--env <KEY=VALUE...>', 'Environment variables', collectEnvVars, {})\n .option('--project <id>', 'Project ID')\n .action(async (directory: string | undefined, opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const deployDir = directory ?? '.';\n const absDir = path.resolve(deployDir);\n\n const client = new ApiClient({ apiUrl, token, projectId });\n\n // Create zip\n const spin = spinner('Preparing deployment...');\n const fileCount = countFiles(absDir);\n verbose(`Found ${fileCount} files in ${absDir}`);\n\n spin.text = 'Creating archive...';\n const zipBuffer = await createZipBuffer(absDir);\n verbose(`Archive size: ${formatBytes(zipBuffer.length)}`);\n\n // Check if function already exists\n spin.text = 'Checking for existing function...';\n const envVars = opts.env as Record<string, string>;\n const existingFns = await client.get<\n FunctionEntry[] | FunctionListResponse\n >(`/projects/${projectId}/functions`);\n const fnList: FunctionEntry[] = Array.isArray(existingFns)\n ? existingFns\n : (existingFns as FunctionListResponse).data || [];\n const existing = fnList.find(\n (f: FunctionEntry) => f.name === opts.name,\n );\n\n let functionId: string;\n const functionBody = {\n entryPoint: opts.entry,\n cronExpression: opts.cron,\n cronTimezone: opts.timezone,\n timeout: opts.timeout ? parseInt(opts.timeout, 10) : undefined,\n memoryLimitMb: opts.memory ? parseInt(opts.memory, 10) : undefined,\n environmentVariables:\n Object.keys(envVars).length > 0 ? envVars : undefined,\n };\n\n if (existing) {\n // Update existing function\n spin.text = 'Updating function...';\n await client.patch(\n `/projects/${projectId}/functions/${existing.id}`,\n functionBody,\n );\n functionId = existing.id;\n } else {\n // Create new function\n spin.text = 'Creating function...';\n const createResult = await client.post<FunctionCreateResponse>(\n `/projects/${projectId}/functions`,\n { name: opts.name, ...functionBody },\n );\n const createdId = createResult.id || createResult.data?.id;\n if (!createdId) {\n throw new Error('Failed to create function');\n }\n functionId = createdId;\n }\n\n // Upload code\n spin.text = 'Uploading code...';\n await client.uploadFile(\n `/projects/${projectId}/functions/${functionId}/deploy`,\n zipBuffer,\n 'code.zip',\n );\n\n spin.succeed(\n `Function \"${opts.name}\" deployed (${formatBytes(zipBuffer.length)}, ${fileCount} files)`,\n );\n\n if (opts.cron) {\n info(`Cron schedule: ${opts.cron}`);\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Deploy failed');\n process.exitCode = 1;\n }\n });\n\n functions\n .command('list')\n .description('List functions')\n .option('--project <id>', 'Project ID')\n .action(async (opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const client = new ApiClient({ apiUrl, token, projectId });\n\n const result = await client.get<FunctionEntry[] | FunctionListResponse>(\n `/projects/${projectId}/functions`,\n );\n\n const fns: FunctionEntry[] = Array.isArray(result)\n ? result\n : (result as FunctionListResponse).data || [];\n\n if (isJsonMode()) {\n json(fns);\n return;\n }\n\n if (fns.length === 0) {\n info('No functions found');\n return;\n }\n\n for (const fn of fns) {\n const status = fn.enabled ? 'enabled' : 'disabled';\n const cron = fn.cronExpression ? ` [${fn.cronExpression}]` : '';\n info(`${fn.name} (${fn.id}) - ${status}${cron}`);\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to list functions');\n process.exitCode = 1;\n }\n });\n\n functions\n .command('delete <name>')\n .description('Delete a function')\n .option('--project <id>', 'Project ID')\n .action(async (name: string, opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const client = new ApiClient({ apiUrl, token, projectId });\n\n const fn = await findFunctionByName(client, projectId, name);\n\n await client.delete(\n `/projects/${projectId}/functions/${fn.id}`,\n );\n\n info(`Function \"${name}\" deleted`);\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to delete function');\n process.exitCode = 1;\n }\n });\n\n functions\n .command('trigger <name>')\n .description('Trigger a function execution')\n .option('--project <id>', 'Project ID')\n .action(async (name: string, opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const client = new ApiClient({ apiUrl, token, projectId });\n\n const fn = await findFunctionByName(client, projectId, name);\n\n const spin = spinner('Triggering function...');\n await client.post(\n `/projects/${projectId}/functions/${fn.id}/trigger`,\n );\n spin.succeed(`Function \"${name}\" triggered`);\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to trigger function');\n process.exitCode = 1;\n }\n });\n\n functions\n .command('logs <name>')\n .description('View function execution logs')\n .option('--limit <n>', 'Number of executions to show', '10')\n .option('--project <id>', 'Project ID')\n .action(async (name: string, opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const client = new ApiClient({ apiUrl, token, projectId });\n\n const fn = await findFunctionByName(client, projectId, name);\n\n const limit = parseInt(opts.limit, 10);\n const result = await client.get<ExecutionsResponse>(\n `/projects/${projectId}/functions/${fn.id}/executions?limit=${limit}`,\n );\n\n const executions = result.items || result.data?.items || [];\n\n if (isJsonMode()) {\n json(executions);\n return;\n }\n\n if (executions.length === 0) {\n info('No executions found');\n return;\n }\n\n for (const exec of executions) {\n const date = new Date(exec.startedAt).toLocaleString();\n const duration = exec.duration ? `${exec.duration}ms` : '-';\n info(\n `[${exec.status}] ${date} (${duration}) - ${exec.triggeredBy}${exec.error ? ` - ${exec.error}` : ''}`,\n );\n\n if (exec.logs && exec.logs.length > 0) {\n for (const log of exec.logs) {\n const logTime = new Date(log.timestamp).toLocaleTimeString();\n info(` ${logTime} [${log.level}] ${log.message}`);\n }\n }\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to get logs');\n process.exitCode = 1;\n }\n });\n\n const envCmd = functions\n .command('env')\n .description('Manage function environment variables');\n\n envCmd\n .command('set <name> <keyValue>')\n .description('Set an environment variable (KEY=VALUE)')\n .option('--project <id>', 'Project ID')\n .action(async (name: string, keyValue: string, opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const client = new ApiClient({ apiUrl, token, projectId });\n\n const eqIndex = keyValue.indexOf('=');\n if (eqIndex === -1) {\n throw new Error('Format must be KEY=VALUE');\n }\n const key = keyValue.substring(0, eqIndex);\n const value = keyValue.substring(eqIndex + 1);\n\n const fn = await findFunctionByName(client, projectId, name);\n\n // Merge with current env vars\n const currentVars = fn.environmentVariables || {};\n const updatedVars = { ...currentVars, [key]: value };\n\n await client.patch(\n `/projects/${projectId}/functions/${fn.id}`,\n { environmentVariables: updatedVars },\n );\n\n info(`Set ${key} for function \"${name}\"`);\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to set env var');\n process.exitCode = 1;\n }\n });\n\n envCmd\n .command('list <name>')\n .description('List environment variables for a function')\n .option('--project <id>', 'Project ID')\n .action(async (name: string, opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const client = new ApiClient({ apiUrl, token, projectId });\n\n const fn = await findFunctionByName(client, projectId, name);\n\n const vars = fn.environmentVariables || {};\n const keys = Object.keys(vars);\n\n if (isJsonMode()) {\n json(vars);\n return;\n }\n\n if (keys.length === 0) {\n info('No environment variables set');\n return;\n }\n\n for (const key of keys) {\n info(`${key}=${vars[key]}`);\n }\n } catch (err) {\n error(\n err instanceof Error ? err.message : 'Failed to list env vars',\n );\n process.exitCode = 1;\n }\n });\n\n return functions;\n}\n\n/** Look up a function by name from the list endpoint. */\nasync function findFunctionByName(\n client: ApiClient,\n projectId: string,\n name: string,\n): Promise<FunctionEntry> {\n const result = await client.get<FunctionEntry[] | FunctionListResponse>(\n `/projects/${projectId}/functions`,\n );\n\n const fnList: FunctionEntry[] = Array.isArray(result)\n ? result\n : (result as FunctionListResponse).data || [];\n\n const fn = fnList.find((f) => f.name === name);\n if (!fn) {\n throw new Error(`Function \"${name}\" not found`);\n }\n return fn;\n}\n\nfunction collectEnvVars(\n value: string,\n previous: Record<string, string>,\n): Record<string, string> {\n const eqIndex = value.indexOf('=');\n if (eqIndex === -1) return previous;\n const key = value.substring(0, eqIndex);\n const val = value.substring(eqIndex + 1);\n return { ...previous, [key]: val };\n}\n"],"mappings":"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","names":["import_commander","pc","ora","crypto","fs","path","open","resolve","import_commander","import_commander","path","import_commander","import_commander","resolve","fs","path","import_commander","path","import_commander","fs","path","resolve","archiver","resolve","import_commander","import_commander","import_commander","import_commander","import_commander","path","import_commander"]}
1
+ {"version":3,"sources":["../../../../libs/cli/src/index.ts","../../../../libs/cli/src/lib/output.ts","../../../../libs/cli/src/commands/login.ts","../../../../libs/cli/src/lib/auth.ts","../../../../libs/cli/src/lib/config.ts","../../../../libs/cli/src/commands/logout.ts","../../../../libs/cli/src/commands/whoami.ts","../../../../libs/cli/src/lib/api-client.ts","../../../../libs/cli/src/commands/projects.ts","../../../../libs/cli/src/commands/use.ts","../../../../libs/cli/src/lib/prompt.ts","../../../../libs/cli/src/commands/init.ts","../../../../libs/cli/src/commands/deploy.ts","../../../../libs/cli/src/lib/zip.ts","../../../../libs/cli/src/commands/db/index.ts","../../../../libs/cli/src/commands/db/indexes-deploy.ts","../../../../libs/cli/src/commands/db/indexes-pull.ts","../../../../libs/cli/src/commands/db/rules-deploy.ts","../../../../libs/cli/src/commands/db/rules-pull.ts","../../../../libs/cli/src/commands/db/collection-set.ts","../../../../libs/cli/src/commands/functions.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { setOutputMode } from './lib/output';\nimport { createLoginCommand } from './commands/login';\nimport { createLogoutCommand } from './commands/logout';\nimport { createWhoamiCommand } from './commands/whoami';\nimport { createProjectsCommand } from './commands/projects';\nimport { createUseCommand } from './commands/use';\nimport { createInitCommand } from './commands/init';\nimport { createDeployCommand } from './commands/deploy';\nimport { createDbCommand } from './commands/db';\nimport { createFunctionsCommand } from './commands/functions';\n\nconst program = new Command();\n\nprogram\n .name('spacelr')\n .description('CLI tool for the Spacelr platform')\n .version('0.1.0')\n .option('--api-url <url>', 'Override API URL')\n .option('--token <token>', 'Explicit auth token (CI mode)')\n .option('--json', 'Output as JSON')\n .option('--verbose', 'Verbose logging')\n .hook('preAction', (thisCommand) => {\n const opts = thisCommand.optsWithGlobals();\n setOutputMode({\n json: opts['json'] as boolean | undefined,\n verbose: opts['verbose'] as boolean | undefined,\n });\n });\n\nprogram.addCommand(createLoginCommand());\nprogram.addCommand(createLogoutCommand());\nprogram.addCommand(createWhoamiCommand());\nprogram.addCommand(createProjectsCommand());\nprogram.addCommand(createUseCommand());\nprogram.addCommand(createInitCommand());\nprogram.addCommand(createDeployCommand());\nprogram.addCommand(createDbCommand());\nprogram.addCommand(createFunctionsCommand());\n\nprogram.parse();\n","import ora, { type Ora } from 'ora';\nimport pc from 'picocolors';\n\nlet jsonMode = false;\nlet verboseMode = false;\n\nexport function setOutputMode(options: {\n json?: boolean;\n verbose?: boolean;\n}): void {\n jsonMode = options.json ?? false;\n verboseMode = options.verbose ?? false;\n}\n\nexport function isJsonMode(): boolean {\n return jsonMode;\n}\n\nexport function success(message: string): void {\n if (!jsonMode) {\n console.log(pc.green(`\\u2713 ${message}`));\n }\n}\n\nexport function error(message: string): void {\n if (!jsonMode) {\n console.error(pc.red(`\\u2717 ${message}`));\n }\n}\n\nexport function warn(message: string): void {\n if (!jsonMode) {\n console.warn(pc.yellow(`! ${message}`));\n }\n}\n\nexport function info(message: string): void {\n if (!jsonMode) {\n console.log(pc.cyan(`\\u2139 ${message}`));\n }\n}\n\nexport function verbose(message: string): void {\n if (verboseMode && !jsonMode) {\n console.log(pc.dim(` ${message}`));\n }\n}\n\nexport function json(data: unknown): void {\n console.log(JSON.stringify(data, null, 2));\n}\n\nexport function table(\n headers: string[],\n rows: string[][],\n): void {\n if (jsonMode) return;\n\n const colWidths = headers.map((h, i) => {\n const maxRow = rows.reduce(\n (max, row) => Math.max(max, (row[i] ?? '').length),\n 0,\n );\n return Math.max(h.length, maxRow);\n });\n\n const headerLine = headers\n .map((h, i) => pc.bold(h.padEnd(colWidths[i] ?? 0)))\n .join(' ');\n const separator = colWidths.map((w) => '-'.repeat(w)).join(' ');\n\n console.log(headerLine);\n console.log(separator);\n for (const row of rows) {\n console.log(\n row.map((cell, i) => cell.padEnd(colWidths[i] ?? 0)).join(' '),\n );\n }\n}\n\nexport function spinner(text: string): Ora {\n if (jsonMode) {\n return ora({ text, isSilent: true });\n }\n return ora(text).start();\n}\n\nexport function formatBytes(bytes: number): string {\n if (bytes === 0) return '0 B';\n const units = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(1024));\n const value = bytes / Math.pow(1024, i);\n return `${value.toFixed(i === 0 ? 0 : 1)} ${units[i]}`;\n}\n","import * as http from 'node:http';\nimport * as crypto from 'node:crypto';\nimport { Command } from 'commander';\nimport open from 'open';\nimport { generatePKCE, storeCredentials } from '../lib/auth';\nimport { resolveApiUrl, loadConfig } from '../lib/config';\nimport { success, error, info, spinner, json, isJsonMode } from '../lib/output';\nimport type { GlobalOptions, TokenResponse, StoredCredentials } from '../lib/types';\n\nconst CLI_CLIENT_ID = 'spacelr-cli';\n\nexport function createLoginCommand(): Command {\n return new Command('login')\n .description('Authenticate with Spacelr via browser')\n .option('--auth-url <url>', 'OAuth server URL (defaults to --api-url)')\n .option(\n '--global',\n 'Store credentials globally (~/.spacelr/credentials.json) instead of in the current project',\n )\n .action(async (opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n const authUrl = (opts.authUrl as string | undefined) ?? apiUrl;\n const forceGlobal = opts.global === true;\n\n try {\n const credentials = await performLogin(authUrl, apiUrl);\n const location = storeCredentials(credentials, forceGlobal);\n\n if (isJsonMode()) {\n json({\n success: true,\n expiresAt: credentials.expiresAt,\n credentialsPath: location.path,\n scope: location.scope,\n });\n } else {\n success('Logged in successfully');\n if (location.scope === 'project') {\n info(`Credentials stored in ${location.path} (project-local)`);\n } else {\n info(`Credentials stored in ${location.path} (global)`);\n }\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Login failed');\n process.exitCode = 1;\n }\n });\n}\n\nasync function performLogin(authUrl: string, apiUrl: string): Promise<StoredCredentials> {\n const { codeVerifier, codeChallenge } = generatePKCE();\n const state = crypto.randomBytes(16).toString('base64url');\n\n // Start local HTTP server on a random port\n const { port, waitForCode, close } = await startCallbackServer(state);\n\n const authorizeUrl = buildAuthorizeUrl(authUrl, port, codeChallenge, state);\n\n info(`Opening browser for authentication...`);\n info(`If the browser doesn't open, visit: ${authorizeUrl}`);\n\n await open(authorizeUrl);\n\n const spin = spinner('Waiting for authentication...');\n\n try {\n const code = await waitForCode;\n spin.text = 'Exchanging authorization code...';\n\n const tokenResponse = await exchangeCode(\n authUrl,\n code,\n codeVerifier,\n port,\n );\n\n spin.succeed('Authentication complete');\n\n // Validate expires_in: must be a positive finite number. A bogus 0/-1\n // would put expiresAt in the past and trigger a refresh on every CLI\n // command. Same guard as in refreshStoredToken.\n const expiresInRaw: unknown = tokenResponse.expires_in;\n const expiresIn =\n typeof expiresInRaw === 'number' &&\n Number.isFinite(expiresInRaw) &&\n expiresInRaw > 0\n ? expiresInRaw\n : 3600;\n\n return {\n accessToken: tokenResponse.access_token,\n refreshToken: tokenResponse.refresh_token,\n expiresAt: Date.now() + expiresIn * 1000,\n apiUrl,\n };\n } catch (err) {\n spin.fail('Authentication failed');\n throw err;\n } finally {\n close();\n }\n}\n\nfunction buildAuthorizeUrl(\n apiUrl: string,\n port: number,\n codeChallenge: string,\n state: string,\n): string {\n const params = new URLSearchParams({\n client_id: CLI_CLIENT_ID,\n redirect_uri: `http://127.0.0.1:${port}/callback`,\n response_type: 'code',\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n scope: 'openid profile email',\n state,\n });\n return `${apiUrl}/auth/authorize?${params.toString()}`;\n}\n\nasync function startCallbackServer(expectedState: string): Promise<{\n port: number;\n waitForCode: Promise<string>;\n close: () => void;\n}> {\n return new Promise((resolveServer) => {\n let resolveCode: (code: string) => void;\n let rejectCode: (err: Error) => void;\n\n const waitForCode = new Promise<string>((resolve, reject) => {\n resolveCode = resolve;\n rejectCode = reject;\n });\n\n const server = http.createServer((req, res) => {\n const url = new URL(req.url ?? '/', `http://127.0.0.1`);\n\n if (url.pathname === '/callback') {\n const code = url.searchParams.get('code');\n const errorParam = url.searchParams.get('error');\n const returnedState = url.searchParams.get('state');\n\n if (errorParam) {\n const description =\n url.searchParams.get('error_description') ?? errorParam;\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(errorPage(description));\n rejectCode(new Error(`OAuth error: ${description}`));\n return;\n }\n\n // CSRF protection: verify state matches\n if (returnedState !== expectedState) {\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end(errorPage('Invalid state parameter (possible CSRF attack)'));\n rejectCode(new Error('OAuth state mismatch'));\n return;\n }\n\n if (!code) {\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end(errorPage('No authorization code received'));\n rejectCode(new Error('No authorization code received'));\n return;\n }\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(successPage());\n resolveCode(code);\n } else {\n res.writeHead(404);\n res.end();\n }\n });\n\n // Timeout after 5 minutes\n const timeout = setTimeout(() => {\n rejectCode(new Error('Login timed out after 5 minutes'));\n server.close();\n }, 5 * 60 * 1000);\n\n server.listen(0, '127.0.0.1', () => {\n const address = server.address();\n const port =\n typeof address === 'object' && address ? address.port : 0;\n\n resolveServer({\n port,\n waitForCode,\n close: () => {\n clearTimeout(timeout);\n server.close();\n },\n });\n });\n });\n}\n\nasync function exchangeCode(\n apiUrl: string,\n code: string,\n codeVerifier: string,\n port: number,\n): Promise<TokenResponse> {\n const response = await fetch(`${apiUrl}/auth/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n code_verifier: codeVerifier,\n client_id: CLI_CLIENT_ID,\n redirect_uri: `http://127.0.0.1:${port}/callback`,\n }),\n });\n\n if (!response.ok) {\n let message: string;\n try {\n const body = (await response.json()) as { message?: string; error?: string };\n message = body.message ?? body.error ?? response.statusText;\n } catch {\n message = response.statusText;\n }\n throw new Error(`Token exchange failed: ${message}`);\n }\n\n const parsed = (await response.json()) as TokenResponse;\n // Validate the server returned a usable access token. A malformed\n // response would otherwise produce { accessToken: undefined } on disk\n // and a confusing \"login succeeded then auth failed\" experience.\n if (typeof parsed.access_token !== 'string' || parsed.access_token.length === 0) {\n throw new Error('Token exchange returned no access_token');\n }\n return parsed;\n}\n\nfunction successPage(): string {\n return `<!DOCTYPE html>\n<html><head><title>Spacelr CLI</title>\n<style>body{font-family:system-ui,sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#f8f9fa;}\n.box{text-align:center;padding:2rem;}.check{font-size:3rem;color:#22c55e;}</style></head>\n<body><div class=\"box\"><div class=\"check\">&#10003;</div><h1>Authenticated</h1><p>You can close this window and return to the terminal.</p></div></body></html>`;\n}\n\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\nfunction errorPage(message: string): string {\n return `<!DOCTYPE html>\n<html><head><title>Spacelr CLI</title>\n<style>body{font-family:system-ui,sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#f8f9fa;}\n.box{text-align:center;padding:2rem;}.x{font-size:3rem;color:#ef4444;}</style></head>\n<body><div class=\"box\"><div class=\"x\">&#10007;</div><h1>Authentication Failed</h1><p>${escapeHtml(message)}</p></div></body></html>`;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport * as crypto from 'node:crypto';\nimport type { StoredCredentials, PKCEChallenge, TokenResponse } from './types';\nimport { findConfigPath } from './config';\nimport { verbose, info, warn } from './output';\n\nexport type CredentialsScope = 'project' | 'global';\n\nexport interface CredentialsLocation {\n path: string;\n scope: CredentialsScope;\n projectDir?: string;\n}\n\nfunction getGlobalCredentialsDir(): string {\n return path.join(\n process.env['HOME'] ?? process.env['USERPROFILE'] ?? os.homedir(),\n '.spacelr',\n );\n}\n\nfunction getGlobalCredentialsFile(): string {\n return path.join(getGlobalCredentialsDir(), 'credentials.json');\n}\n\n/**\n * Resolve where credentials should be read from / written to.\n *\n * Lookup order:\n * 1. If `forceGlobal` is true → always use ~/.spacelr/credentials.json\n * 2. Walk up from cwd looking for `spacelr.json` — if found, credentials\n * live at `<projectDir>/.spacelr/credentials.json` (project scope)\n * 3. Otherwise → fall back to ~/.spacelr/credentials.json (global scope)\n *\n * Note: this function chooses the *primary* location. A read fallback from\n * project → global happens in `getStoredCredentials` so users with only\n * legacy global credentials can still authenticate from inside a project.\n */\nexport function resolveCredentialsFile(forceGlobal = false): CredentialsLocation {\n if (forceGlobal) {\n return { path: getGlobalCredentialsFile(), scope: 'global' };\n }\n const configPath = findConfigPath();\n if (configPath) {\n const projectDir = path.dirname(configPath);\n return {\n path: path.join(projectDir, '.spacelr', 'credentials.json'),\n scope: 'project',\n projectDir,\n };\n }\n return { path: getGlobalCredentialsFile(), scope: 'global' };\n}\n\n/**\n * Ensure the project's `.gitignore` excludes `.spacelr/` so credentials never\n * reach git. Runs before every project-scoped credential write (login and\n * refresh), so a user who deletes the entry gets it restored automatically.\n *\n * Matches these patterns as \"already ignored\": `.spacelr/`, `.spacelr`,\n * `.spacelr/*`, `.spacelr/credentials.json`.\n *\n * shared-with: libs/mcp-server/src/config.ts (intentional duplication —\n * the two packages publish independently and must not depend on each other)\n */\nexport function ensureGitignored(projectDir: string): { safe: boolean } {\n const gitignorePath = path.join(projectDir, '.gitignore');\n const entry = '.spacelr/';\n\n const matchesExisting = (line: string): boolean => {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) return false;\n return (\n trimmed === '.spacelr' ||\n trimmed === '.spacelr/' ||\n trimmed === '.spacelr/*' ||\n trimmed === '.spacelr/**' ||\n trimmed === '.spacelr/credentials.json' ||\n // Leading-slash forms anchor the pattern to the repo root\n trimmed === '/.spacelr' ||\n trimmed === '/.spacelr/' ||\n trimmed === '/.spacelr/*' ||\n trimmed === '/.spacelr/**' ||\n trimmed === '/.spacelr/credentials.json'\n );\n };\n\n // Heuristic: any line starting with `!` that mentions `.spacelr` could\n // un-ignore credentials. We deliberately use a permissive prefix check\n // (instead of exact-string matching) because gitignore supports many\n // pattern variants — `!.spacelr*`, `!.spacelr/**/*.json`, `!/.spacelr/**`,\n // etc. — and an exhaustive list would inevitably miss something. False\n // positives here just refuse the write (safe default); false negatives\n // would silently leave credentials trackable.\n const hasNegation = (line: string): boolean => {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) return false;\n return trimmed.startsWith('!') && trimmed.includes('.spacelr');\n };\n\n let content = '';\n let existed = false;\n try {\n content = fs.readFileSync(gitignorePath, 'utf-8');\n existed = true;\n } catch (err) {\n // ENOENT is expected (no .gitignore yet). Any other error (e.g. EACCES)\n // means we cannot verify safety — return safe:true (best-effort: a\n // user with a read-only .gitignore presumably knows what they're doing\n // and we don't want to block their login).\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') return { safe: true };\n }\n\n const lines = content.split(/\\r?\\n/);\n // Check for negation FIRST. A negation anywhere in the file un-ignores\n // credentials regardless of whether a positive match exists earlier:\n // git evaluates rules in order and the LAST matching rule wins, so\n // `.spacelr/` followed by `!.spacelr/credentials.json` still tracks\n // credentials. Returning early on a positive match would miss this.\n if (lines.some(hasNegation)) {\n const alreadyHasMatch = lines.some(matchesExisting);\n warn(\n alreadyHasMatch\n ? '.gitignore already contains .spacelr/ but ALSO contains a ' +\n 'negation pattern that un-ignores credentials. Remove the ' +\n 'negation or store credentials globally with ' +\n '`spacelr login --global`.'\n : '.gitignore contains a negation pattern for .spacelr/ — ' +\n 'refusing to write credentials safety entry. Remove the ' +\n 'negation or store credentials globally with ' +\n '`spacelr login --global`.',\n );\n return { safe: false };\n }\n if (lines.some(matchesExisting)) return { safe: true };\n\n const needsLeadingNewline = existed && content.length > 0 && !content.endsWith('\\n');\n const newContent =\n (existed ? content : '') +\n (needsLeadingNewline ? '\\n' : '') +\n entry +\n '\\n';\n\n try {\n // Atomic write so a crash mid-write cannot truncate .gitignore and\n // silently drop the .spacelr/ entry.\n writeFileAtomic(gitignorePath, newContent, 0o644);\n info(`Added ${entry} to .gitignore (credentials must never be committed)`);\n return { safe: true };\n } catch {\n // Best-effort — do not fail login if .gitignore is read-only.\n // Return safe:true so the caller still writes credentials (a read-only\n // .gitignore is the user's choice; we can't fix it for them).\n return { safe: true };\n }\n}\n\n/**\n * Read credentials from the resolved location, with a legacy fallback:\n * if project-scoped lookup finds nothing, also try the global file. This\n * keeps existing users with only `~/.spacelr/credentials.json` working.\n */\nexport function getStoredCredentials(\n forceGlobal = false,\n): StoredCredentials | null {\n return getStoredCredentialsWithLocation(forceGlobal)?.credentials ?? null;\n}\n\n/**\n * Same as `getStoredCredentials` but also returns the *actual* location the\n * credentials were read from. This is critical for refresh: when the project\n * scope has no file, the fallback returns global credentials, and the\n * subsequent refresh write MUST go back to global (not to the project) —\n * otherwise the global file is left with a revoked refresh token.\n */\nexport function getStoredCredentialsWithLocation(\n forceGlobal = false,\n): { credentials: StoredCredentials; location: CredentialsLocation } | null {\n const primary = resolveCredentialsFile(forceGlobal);\n const fromPrimary = readCredentialsFromDisk(primary.path);\n if (fromPrimary) return { credentials: fromPrimary, location: primary };\n\n // Fallback: project scope with no local file → try global for legacy users\n if (!forceGlobal && primary.scope === 'project') {\n const globalPath = getGlobalCredentialsFile();\n const fromGlobal = readCredentialsFromDisk(globalPath);\n if (fromGlobal) {\n return {\n credentials: fromGlobal,\n location: { path: globalPath, scope: 'global' },\n };\n }\n }\n return null;\n}\n\nfunction readCredentialsFromDisk(filePath: string): StoredCredentials | null {\n try {\n // No existsSync guard — would race with concurrent unlink. The catch\n // below covers ENOENT, JSON parse errors, and read failures uniformly.\n const content = fs.readFileSync(filePath, 'utf-8');\n const parsed: unknown = JSON.parse(content);\n if (typeof parsed !== 'object' || parsed === null) return null;\n const obj = parsed as Record<string, unknown>;\n if (\n typeof obj['accessToken'] !== 'string' ||\n obj['accessToken'].length === 0 ||\n !Number.isFinite(obj['expiresAt']) ||\n typeof obj['apiUrl'] !== 'string' ||\n obj['apiUrl'].length === 0\n ) {\n return null;\n }\n // refreshToken is optional, but if present must be a string —\n // otherwise we'd serialize a non-string into the refresh request body.\n if ('refreshToken' in obj && typeof obj['refreshToken'] !== 'string') {\n return null;\n }\n return parsed as StoredCredentials;\n } catch {\n return null;\n }\n}\n\n/**\n * Atomic write: write to `<path>.tmp` then rename. Rename is atomic on POSIX\n * and Windows so concurrent readers never see a partial file.\n *\n * shared-with: libs/mcp-server/src/config.ts\n */\nfunction writeFileAtomic(filePath: string, data: string, mode: number): void {\n const tmpPath = `${filePath}.tmp.${process.pid}.${crypto.randomBytes(6).toString('hex')}`;\n try {\n fs.writeFileSync(tmpPath, data, { mode });\n fs.renameSync(tmpPath, filePath);\n } catch (err) {\n // Best-effort cleanup of temp file on failure\n try {\n fs.unlinkSync(tmpPath);\n } catch {\n /* ignore */\n }\n throw err;\n }\n}\n\n/**\n * Persist credentials to disk and return the location they were written to.\n *\n * The second argument has two valid forms:\n * - `boolean` (default `false`): treated as `forceGlobal` — `true` writes\n * to `~/.spacelr/credentials.json`, `false` walks up to find a project.\n * Used by `login` where the caller only knows whether the user passed\n * `--global`.\n * - `CredentialsLocation`: an explicit target. Used by refresh to write\n * back to the exact file the credentials were read from, preventing\n * scope mismatch when legacy global creds are used inside a project.\n */\nexport function storeCredentials(\n credentials: StoredCredentials,\n target: boolean | CredentialsLocation = false,\n): CredentialsLocation {\n const location =\n typeof target === 'boolean' ? resolveCredentialsFile(target) : target;\n\n // Safety: ensure .spacelr/ is gitignored before we write to a project.\n // If a negation pattern is detected, ensureGitignored returns safe:false\n // and we refuse to write credentials to that project — the user must use\n // `--global` instead. Without this guard the credential file would land\n // in a .gitignore-trackable location.\n if (location.scope === 'project' && location.projectDir) {\n const { safe } = ensureGitignored(location.projectDir);\n if (!safe) {\n throw new Error(\n 'Refusing to write project-local credentials: .gitignore contains ' +\n 'a negation pattern that would un-ignore .spacelr/. Run ' +\n '`spacelr login --global` to store credentials in ~/.spacelr/.',\n );\n }\n }\n\n // mkdirSync with recursive:true is idempotent and does not throw if the\n // directory already exists, so no existsSync guard needed.\n const dir = path.dirname(location.path);\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n // mode: on mkdirSync only applies when the directory is created. If the\n // user pre-created .spacelr/ with wider permissions (e.g. 0o755), enforce\n // 0o700 here so other local users cannot enumerate credential filenames.\n // Best-effort — chmod can fail on Windows / non-owned dirs, in which case\n // we leave the existing mode rather than failing the credential write.\n try {\n fs.chmodSync(dir, 0o700);\n } catch {\n /* ignore */\n }\n\n writeFileAtomic(location.path, JSON.stringify(credentials, null, 2), 0o600);\n return location;\n}\n\n/**\n * Clear credentials at the resolved location. If `scope` is 'all', clear\n * both project-local and global files.\n */\nexport function clearCredentials(scope: 'auto' | 'global' | 'all' = 'auto'): {\n cleared: CredentialsLocation[];\n} {\n const cleared: CredentialsLocation[] = [];\n\n // No existsSync guard — race-prone and inconsistent with the rest of\n // the file. Just unlink and swallow ENOENT (file already gone is success).\n // Surface other errors (EACCES etc.) so the user knows the file is still\n // there, instead of seeing a misleading \"No credentials found\" message.\n const tryDelete = (loc: CredentialsLocation): void => {\n try {\n fs.unlinkSync(loc.path);\n cleared.push(loc);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== 'ENOENT') {\n // Use warn (not verbose) so the user always sees this — otherwise\n // a permission failure looks like a successful logout.\n warn(\n `Failed to remove ${loc.path} (${code ?? 'unknown error'}) — file may still be on disk`,\n );\n }\n }\n };\n\n if (scope === 'all') {\n // Delete the current project file (if cwd is inside a project) AND\n // the global file. Two limitations of \"all\":\n // 1. Other projects on disk cannot be enumerated and are left alone.\n // 2. If a project's spacelr.json was deleted but\n // `.spacelr/credentials.json` still exists, the walk-up lookup\n // now resolves to global scope and the orphaned project file\n // is NOT cleaned up. The user must remove it manually.\n const primary = resolveCredentialsFile(false);\n if (primary.scope === 'project') tryDelete(primary);\n // Reuse the resolved global path when primary is already global —\n // avoids a redundant walk-up FS scan.\n tryDelete(\n primary.scope === 'global' ? primary : resolveCredentialsFile(true),\n );\n } else {\n tryDelete(resolveCredentialsFile(scope === 'global'));\n }\n\n return { cleared };\n}\n\nexport function isTokenExpired(credentials: StoredCredentials): boolean {\n // Add 60 second buffer\n return Date.now() >= credentials.expiresAt - 60_000;\n}\n\nexport async function resolveToken(flagToken?: string): Promise<string | null> {\n if (flagToken) return flagToken;\n if (process.env['SPACELR_TOKEN']) return process.env['SPACELR_TOKEN'];\n const loaded = getStoredCredentialsWithLocation();\n if (!loaded) return null;\n const { credentials, location } = loaded;\n if (!isTokenExpired(credentials)) return credentials.accessToken;\n // Token expired — only refresh if we have a refresh token\n // (apiUrl is already validated by readCredentialsFromDisk)\n if (credentials.refreshToken) {\n const newToken = await refreshStoredToken(credentials, location);\n if (newToken) return newToken;\n }\n return null;\n}\n\nconst REFRESH_TIMEOUT_MS = 10_000;\n\n/**\n * Refreshes the access token using the stored refresh token.\n * Always uses credentials.apiUrl (issuer-bound) to prevent\n * sending refresh tokens to untrusted URLs.\n *\n * The `sourceLocation` parameter is REQUIRED — it ensures the refreshed\n * credentials are written back to the exact file they were read from,\n * which is critical when falling back from project scope to global scope\n * (otherwise the global file is left with a revoked refresh token).\n *\n * On 401 (token already revoked — likely by a concurrent process),\n * re-reads the *same* file once. If another process has already\n * stored a newer token, returns that instead of failing.\n */\nexport async function refreshStoredToken(\n credentials: StoredCredentials,\n sourceLocation: CredentialsLocation,\n): Promise<string | null> {\n // Short-circuit: nothing to refresh against. Without this guard a future\n // caller could POST `{ refreshToken: '' }` to the auth server.\n if (!credentials.refreshToken) return null;\n\n // Validate scheme — a credentials file with apiUrl: \"file:///etc/passwd\"\n // (manually edited or written by a compromised process) would otherwise\n // produce an opaque fetch error. Only http(s) is accepted.\n try {\n const parsed = new URL(credentials.apiUrl);\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n verbose(`Refusing to refresh against non-http(s) URL: ${parsed.protocol}`);\n return null;\n }\n } catch {\n verbose('Refusing to refresh: stored apiUrl is not a valid URL');\n return null;\n }\n\n const apiUrl = credentials.apiUrl.replace(/\\/+$/, '');\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), REFRESH_TIMEOUT_MS);\n\n try {\n verbose('Refreshing access token...');\n const response = await fetch(`${apiUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: credentials.refreshToken }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n verbose(`Token refresh failed (HTTP ${response.status})`);\n // Concurrent-refresh fallback: another process may have already rotated\n // the token. Re-read the SAME file (sourceLocation) — not via cwd —\n // so we don't accidentally pick up a different scope's credentials.\n if (response.status === 401) {\n const fresh = readCredentialsFromDisk(sourceLocation.path);\n if (\n fresh &&\n (fresh.accessToken !== credentials.accessToken ||\n fresh.refreshToken !== credentials.refreshToken) &&\n !isTokenExpired(fresh)\n ) {\n verbose('Using credentials refreshed by concurrent process');\n return fresh.accessToken;\n }\n }\n return null;\n }\n\n const data = (await response.json()) as TokenResponse;\n if (typeof data.access_token !== 'string') {\n verbose('Token refresh returned unexpected response shape');\n return null;\n }\n // Validate expires_in: must be a positive finite number. A bogus value\n // (0, negative, NaN from a string, etc.) would either trigger an\n // immediate refresh loop or set expiresAt to NaN.\n const expiresInRaw = data.expires_in;\n const expiresIn =\n typeof expiresInRaw === 'number' &&\n Number.isFinite(expiresInRaw) &&\n expiresInRaw > 0\n ? expiresInRaw\n : 3600;\n const newCredentials: StoredCredentials = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token ?? credentials.refreshToken,\n expiresAt: Date.now() + expiresIn * 1000,\n apiUrl: credentials.apiUrl,\n };\n // Write back to the EXACT location we read from, not wherever the\n // current cwd would resolve to. This prevents scope mismatch where\n // a legacy global login inside a project would leak into a project file.\n storeCredentials(newCredentials, sourceLocation);\n verbose('Token refreshed successfully');\n return data.access_token;\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n verbose('Token refresh timed out');\n } else {\n verbose('Token refresh error');\n }\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport class AuthRequiredError extends Error {\n constructor() {\n super('Not logged in. Run \"spacelr login\" to authenticate.');\n this.name = 'AuthRequiredError';\n }\n}\n\n/**\n * Resolves a token or throws AuthRequiredError.\n * Use in commands that require authentication.\n */\nexport async function requireAuth(flagToken?: string): Promise<string> {\n const token = await resolveToken(flagToken);\n if (!token) {\n throw new AuthRequiredError();\n }\n return token;\n}\n\nexport function generatePKCE(): PKCEChallenge {\n const codeVerifier = crypto.randomBytes(32).toString('base64url');\n const codeChallenge = crypto\n .createHash('sha256')\n .update(codeVerifier)\n .digest('base64url');\n return { codeVerifier, codeChallenge };\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { SpacelrConfig, DatabaseRules, DatabaseIndexes } from './types';\n\nconst CONFIG_FILENAME = 'spacelr.json';\nexport const RULES_FILENAME = 'spacelr.rules.json';\nexport const INDEXES_FILENAME = 'spacelr.indexes.json';\n\nfunction readJsonFile<T>(filePath: string, label: string): T {\n const content = fs.readFileSync(filePath, 'utf-8');\n try {\n return JSON.parse(content) as T;\n } catch (err) {\n const detail = err instanceof Error ? `: ${err.message}` : '';\n throw new Error(\n `Invalid JSON in ${label}: ${filePath}${detail}\\nPlease check the file for syntax errors.`,\n );\n }\n}\n\nfunction writeJsonFile(filePath: string, data: unknown): void {\n fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\\n', 'utf-8');\n}\n\nfunction resolveSiblingPath(filename: string, configPath?: string): string {\n const resolved = configPath ?? findConfigPath();\n const dir = resolved ? path.dirname(resolved) : process.cwd();\n return path.join(dir, filename);\n}\n\nexport function findConfigPath(startDir?: string): string | null {\n let dir = startDir ?? process.cwd();\n\n while (true) {\n const candidate = path.join(dir, CONFIG_FILENAME);\n if (fs.existsSync(candidate)) {\n return candidate;\n }\n const parent = path.dirname(dir);\n if (parent === dir) {\n return null;\n }\n dir = parent;\n }\n}\n\nexport function loadConfig(configPath?: string): SpacelrConfig | null {\n const resolved = configPath ?? findConfigPath();\n if (!resolved || !fs.existsSync(resolved)) return null;\n return readJsonFile<SpacelrConfig>(resolved, 'config file');\n}\n\nexport function saveConfig(\n config: SpacelrConfig,\n configPath?: string,\n): void {\n const resolved = configPath ?? findConfigPath() ?? path.join(process.cwd(), CONFIG_FILENAME);\n writeJsonFile(resolved, config);\n}\n\nexport function resolveProjectId(\n flagValue?: string,\n config?: SpacelrConfig | null,\n): string {\n const projectId = flagValue ?? config?.projectId;\n if (!projectId) {\n throw new Error(\n 'Project ID is required. Provide --project <id> or set \"projectId\" in spacelr.json',\n );\n }\n return projectId;\n}\n\nexport function resolveApiUrl(\n flagValue?: string,\n config?: SpacelrConfig | null,\n): string {\n return (\n flagValue ??\n config?.apiUrl ??\n process.env['SPACELR_API_URL'] ??\n 'https://api.spacelr.com/api/v1'\n );\n}\n\nexport function loadRules(configPath?: string): DatabaseRules | null {\n const filePath = resolveSiblingPath(RULES_FILENAME, configPath);\n if (!fs.existsSync(filePath)) return null;\n return readJsonFile<DatabaseRules>(filePath, 'rules file');\n}\n\nexport function saveRules(rules: DatabaseRules, configPath?: string): void {\n writeJsonFile(resolveSiblingPath(RULES_FILENAME, configPath), rules);\n}\n\nexport function loadIndexes(configPath?: string): DatabaseIndexes | null {\n const filePath = resolveSiblingPath(INDEXES_FILENAME, configPath);\n if (!fs.existsSync(filePath)) return null;\n return readJsonFile<DatabaseIndexes>(filePath, 'indexes file');\n}\n\nexport function saveIndexes(indexes: DatabaseIndexes, configPath?: string): void {\n writeJsonFile(resolveSiblingPath(INDEXES_FILENAME, configPath), indexes);\n}\n","import { Command } from 'commander';\nimport { clearCredentials } from '../lib/auth';\nimport { success, warn, info, json, isJsonMode } from '../lib/output';\n\nexport function createLogoutCommand(): Command {\n return new Command('logout')\n .description('Clear stored credentials')\n .option('--global', 'Clear only the global credentials file')\n .option(\n '--all',\n 'Clear the current project credentials file (if any) and the global ' +\n 'credentials file (other projects are not touched — they cannot be ' +\n 'enumerated)',\n )\n .action(async (opts) => {\n // --global and --all are mutually exclusive: --all already includes\n // global, so combining them is ambiguous. Reject explicitly instead\n // of silently treating them as --all.\n if (opts.global === true && opts.all === true) {\n warn('--global and --all cannot be combined; --all already removes the global file');\n process.exitCode = 1;\n return;\n }\n\n const scope: 'auto' | 'global' | 'all' =\n opts.all === true ? 'all' : opts.global === true ? 'global' : 'auto';\n\n const { cleared } = clearCredentials(scope);\n\n if (isJsonMode()) {\n json({\n success: true,\n cleared: cleared.map((c) => ({ path: c.path, scope: c.scope })),\n });\n } else if (cleared.length === 0) {\n warn('No credentials found');\n } else {\n success('Logged out successfully');\n for (const loc of cleared) {\n info(`Removed ${loc.path} (${loc.scope})`);\n }\n }\n });\n}\n","import { Command } from 'commander';\nimport { ApiClient } from '../lib/api-client';\nimport { resolveApiUrl, loadConfig } from '../lib/config';\nimport { requireAuth } from '../lib/auth';\nimport { success, error, info, json, isJsonMode } from '../lib/output';\nimport type { GlobalOptions, UserInfo } from '../lib/types';\n\nexport function createWhoamiCommand(): Command {\n return new Command('whoami')\n .description('Show current authenticated user')\n .action(async (_opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const client = new ApiClient({ apiUrl, token });\n const response = await client.get<{ user: UserInfo }>('/auth/me');\n const user = response.user;\n\n if (isJsonMode()) {\n json(user);\n } else {\n success(`Logged in as ${user.email ?? user.username ?? user.id}`);\n if (user.displayName) info(`Name: ${user.displayName}`);\n if (user.roles?.length) info(`Roles: ${user.roles.join(', ')}`);\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to get user info');\n process.exitCode = 1;\n }\n });\n}\n","import {\n getStoredCredentialsWithLocation,\n isTokenExpired,\n refreshStoredToken,\n type CredentialsLocation,\n} from './auth';\nimport { verbose } from './output';\nimport type { StoredCredentials } from './types';\n\ninterface ApiClientOptions {\n apiUrl: string;\n token?: string;\n clientId?: string;\n projectId?: string;\n}\n\ninterface RequestOptions {\n method?: string;\n body?: BodyInit | Record<string, unknown>;\n headers?: Record<string, string>;\n timeout?: number;\n}\n\nexport class ApiClient {\n private readonly apiUrl: string;\n private readonly clientId: string;\n private readonly projectId?: string;\n private explicitToken?: string;\n private refreshing: Promise<string | null> | null = null;\n\n constructor(options: ApiClientOptions) {\n this.apiUrl = options.apiUrl.replace(/\\/+$/, '');\n this.explicitToken = options.token;\n this.clientId = options.clientId ?? 'spacelr-cli';\n this.projectId = options.projectId;\n }\n\n private async getToken(): Promise<string | null> {\n if (this.explicitToken) return this.explicitToken;\n\n const envToken = process.env['SPACELR_TOKEN'];\n if (envToken) return envToken;\n\n const loaded = getStoredCredentialsWithLocation();\n if (!loaded) return null;\n const { credentials, location } = loaded;\n\n if (!isTokenExpired(credentials)) {\n return credentials.accessToken;\n }\n\n // Token expired, try refreshing — pass location so refresh writes back\n // to the exact file we read from (scope-safe)\n if (credentials.refreshToken) {\n return this.refreshAccessToken(credentials, location);\n }\n\n return null;\n }\n\n private async refreshAccessToken(\n credentials: StoredCredentials,\n location: CredentialsLocation,\n ): Promise<string | null> {\n // Deduplicate concurrent refreshes\n if (this.refreshing) return this.refreshing;\n\n this.refreshing = refreshStoredToken(credentials, location).finally(() => {\n this.refreshing = null;\n });\n\n return this.refreshing;\n }\n\n private serializeBody(\n body: RequestOptions['body'],\n contentType: string | undefined,\n ): BodyInit | undefined {\n if (!body) return undefined;\n if (contentType === 'application/json') {\n return JSON.stringify(body);\n }\n // Buffer, string, URLSearchParams, etc. are already valid BodyInit\n return body as BodyInit;\n }\n\n private async request<T>(\n path: string,\n options: RequestOptions = {},\n ): Promise<T> {\n const { method = 'GET', body, headers = {}, timeout = 30_000 } = options;\n const url = `${this.apiUrl}${path}`;\n\n const token = await this.getToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n if (body && !headers['Content-Type']) {\n headers['Content-Type'] = 'application/json';\n }\n\n headers['x-client-id'] = this.clientId;\n if (this.projectId) {\n headers['x-project-id'] = this.projectId;\n }\n\n const serializedBody = this.serializeBody(body, headers['Content-Type']);\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n\n verbose(`${method} ${url}`);\n\n try {\n const response = await fetch(url, {\n method,\n headers,\n body: serializedBody,\n signal: controller.signal,\n });\n\n if (response.status === 401 && !this.explicitToken) {\n // Try refresh once\n const loaded = getStoredCredentialsWithLocation();\n if (loaded) {\n // If another process already rotated the token between getToken()\n // and now, the on-disk token is fresh — use it directly instead\n // of refreshing again (avoids burning a single-use refresh token).\n let newToken: string | null = null;\n if (!isTokenExpired(loaded.credentials)) {\n newToken = loaded.credentials.accessToken;\n } else if (loaded.credentials.refreshToken) {\n newToken = await this.refreshAccessToken(\n loaded.credentials,\n loaded.location,\n );\n }\n if (newToken) {\n headers['Authorization'] = `Bearer ${newToken}`;\n const retryController = new AbortController();\n const retryTimer = setTimeout(() => retryController.abort(), timeout);\n const retryResponse = await fetch(url, {\n method,\n headers,\n body: serializedBody,\n signal: retryController.signal,\n });\n clearTimeout(retryTimer);\n if (!retryResponse.ok) {\n // If retry still 401, surface the actionable login message\n // instead of a generic \"API error (401): Unauthorized\".\n if (retryResponse.status === 401) {\n throw new Error(\n 'Authentication required. Run \"spacelr login\" to authenticate.',\n );\n }\n await this.throwApiError(retryResponse);\n }\n return (await retryResponse.json()) as T;\n }\n }\n throw new Error(\n 'Authentication required. Run \"spacelr login\" to authenticate.',\n );\n }\n\n if (!response.ok) {\n await this.throwApiError(response);\n }\n\n const contentType = response.headers.get('content-type');\n if (contentType?.includes('application/json')) {\n return (await response.json()) as T;\n }\n return (await response.text()) as unknown as T;\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error(`Request timed out: ${method} ${path}`);\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n }\n\n private async throwApiError(response: Response): Promise<never> {\n let message: string;\n try {\n const body = (await response.json()) as { message?: string; error?: string };\n message = body.message ?? body.error ?? response.statusText;\n } catch {\n message = response.statusText;\n }\n throw new Error(`API error (${response.status}): ${message}`);\n }\n\n async get<T>(path: string, timeout?: number): Promise<T> {\n return this.request<T>(path, { timeout });\n }\n\n async post<T>(path: string, body?: Record<string, unknown> | BodyInit, timeout?: number): Promise<T> {\n return this.request<T>(path, { method: 'POST', body, timeout });\n }\n\n async put<T>(path: string, body?: Record<string, unknown> | BodyInit, timeout?: number): Promise<T> {\n return this.request<T>(path, { method: 'PUT', body, timeout });\n }\n\n async patch<T>(path: string, body?: Record<string, unknown> | BodyInit, timeout?: number): Promise<T> {\n return this.request<T>(path, { method: 'PATCH', body, timeout });\n }\n\n async delete<T>(path: string, timeout?: number): Promise<T> {\n return this.request<T>(path, { method: 'DELETE', timeout });\n }\n\n async uploadFile(\n path: string,\n fileBuffer: Buffer,\n filename: string,\n ): Promise<DeploymentUploadResponse> {\n const boundary = `----spacelr${Date.now()}`;\n const parts: Buffer[] = [];\n\n // Sanitize filename for embedding in the Content-Disposition header.\n // Strip CR/LF (header injection) and quote characters (would break the\n // quoted string and allow injecting additional MIME headers).\n const safeFilename = filename.replace(/[\\r\\n\"]/g, '_');\n\n // Build multipart body manually (no form-data dependency needed)\n const header = Buffer.from(\n `--${boundary}\\r\\n` +\n `Content-Disposition: form-data; name=\"file\"; filename=\"${safeFilename}\"\\r\\n` +\n `Content-Type: application/zip\\r\\n\\r\\n`,\n );\n const footer = Buffer.from(`\\r\\n--${boundary}--\\r\\n`);\n parts.push(header, fileBuffer, footer);\n const body = Buffer.concat(parts);\n\n return this.request<DeploymentUploadResponse>(path, {\n method: 'POST',\n body,\n headers: {\n 'Content-Type': `multipart/form-data; boundary=${boundary}`,\n },\n timeout: 300_000, // 5 minutes for uploads\n });\n }\n}\n\ninterface DeploymentUploadResponse {\n deploymentId: string;\n status: string;\n fileCount: number;\n totalSizeBytes: number;\n}\n","import { Command } from 'commander';\nimport { ApiClient } from '../lib/api-client';\nimport { resolveApiUrl, loadConfig } from '../lib/config';\nimport { requireAuth } from '../lib/auth';\nimport { error, spinner, json, isJsonMode, table, info } from '../lib/output';\nimport type { GlobalOptions, ProjectInfo } from '../lib/types';\n\nexport function createProjectsCommand(): Command {\n return new Command('projects')\n .description('List your projects')\n .action(async (_opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const client = new ApiClient({ apiUrl, token });\n const spin = spinner('Fetching projects...');\n const result = await client.get<{ projects: ProjectInfo[] }>('/projects');\n spin.stop();\n\n const projects = result.projects;\n\n if (projects.length === 0) {\n info('No projects found');\n return;\n }\n\n const activeProjectId = config?.projectId;\n\n if (isJsonMode()) {\n json(projects);\n } else {\n table(\n ['', 'ID', 'Name', 'Slug'],\n projects.map((p) => [\n p.id === activeProjectId ? '*' : ' ',\n p.id,\n p.name,\n p.slug,\n ]),\n );\n if (activeProjectId) {\n info(`\\n* = active project (from spacelr.json)`);\n }\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to list projects');\n process.exitCode = 1;\n }\n });\n}\n\nexport async function fetchProjects(\n client: ApiClient,\n): Promise<ProjectInfo[]> {\n const result = await client.get<{ projects: ProjectInfo[] }>('/projects');\n return result.projects;\n}\n","import { Command } from 'commander';\nimport { ApiClient } from '../lib/api-client';\nimport { resolveApiUrl, loadConfig, saveConfig } from '../lib/config';\nimport { requireAuth } from '../lib/auth';\nimport { success, error, spinner, json, isJsonMode, info } from '../lib/output';\nimport { promptChoice } from '../lib/prompt';\nimport { fetchProjects } from './projects';\nimport type { GlobalOptions, ProjectInfo } from '../lib/types';\n\nexport function createUseCommand(): Command {\n return new Command('use')\n .description('Set the active project')\n .argument('[project]', 'Project ID or slug')\n .action(async (project: string | undefined, _opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const client = new ApiClient({ apiUrl, token });\n const spin = spinner('Fetching projects...');\n const projects = await fetchProjects(client);\n spin.stop();\n\n if (projects.length === 0) {\n error('No projects found. Create a project first.');\n process.exitCode = 1;\n return;\n }\n\n let selected: ProjectInfo;\n\n if (project) {\n // Find by ID or slug\n const match = projects.find(\n (p) => p.id === project || p.slug === project,\n );\n if (!match) {\n error(`Project \"${project}\" not found`);\n info('Available projects:');\n for (const p of projects) {\n info(` ${p.slug} (${p.id})`);\n }\n process.exitCode = 1;\n return;\n }\n selected = match;\n } else {\n // Interactive selection\n selected = await promptChoice(\n 'Select a project:',\n projects.map((p) => ({\n ...p,\n label: `${p.name} (${p.slug})`,\n })),\n );\n }\n\n // Update config\n const updatedConfig = { ...config, projectId: selected.id };\n saveConfig(updatedConfig);\n\n if (isJsonMode()) {\n json({ projectId: selected.id, name: selected.name, slug: selected.slug });\n } else {\n success(`Now using project \"${selected.name}\" (${selected.slug})`);\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to select project');\n process.exitCode = 1;\n }\n });\n}\n","import * as readline from 'node:readline';\n\nexport async function promptChoice<T extends { label: string }>(\n message: string,\n choices: T[],\n): Promise<T> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n\n console.error(`\\n${message}\\n`);\n choices.forEach((choice, i) => {\n console.error(` ${i + 1}) ${choice.label}`);\n });\n console.error();\n\n return new Promise((resolve, reject) => {\n rl.question(' Enter number: ', (answer) => {\n rl.close();\n const index = parseInt(answer, 10) - 1;\n if (isNaN(index) || index < 0 || index >= choices.length) {\n reject(new Error('Invalid selection'));\n return;\n }\n resolve(choices[index]);\n });\n });\n}\n\nexport async function promptConfirm(message: string): Promise<boolean> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n\n return new Promise((resolve) => {\n rl.question(`${message} (y/N) `, (answer) => {\n rl.close();\n resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');\n });\n });\n}\n\nexport async function promptInput(message: string, defaultValue?: string): Promise<string> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n\n const suffix = defaultValue ? ` (${defaultValue})` : '';\n\n return new Promise((resolve) => {\n rl.question(`${message}${suffix}: `, (answer) => {\n rl.close();\n resolve(answer.trim() || defaultValue || '');\n });\n });\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { Command } from 'commander';\nimport { ApiClient } from '../lib/api-client';\nimport { resolveApiUrl, loadConfig, saveConfig } from '../lib/config';\nimport { requireAuth } from '../lib/auth';\nimport { success, error, warn, spinner, json, isJsonMode, info } from '../lib/output';\nimport { promptChoice, promptInput } from '../lib/prompt';\nimport { fetchProjects } from './projects';\nimport type { GlobalOptions, SpacelrConfig } from '../lib/types';\n\nexport function createInitCommand(): Command {\n return new Command('init')\n .description('Initialize a spacelr.json config in the current directory')\n .action(async (_opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const existingConfig = loadConfig();\n\n const configPath = path.join(process.cwd(), 'spacelr.json');\n if (fs.existsSync(configPath)) {\n warn(`spacelr.json already exists in ${process.cwd()}`);\n info('Use \"spacelr use\" to change the active project');\n return;\n }\n\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, existingConfig);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const client = new ApiClient({ apiUrl, token });\n const spin = spinner('Fetching projects...');\n const projects = await fetchProjects(client);\n spin.stop();\n\n if (projects.length === 0) {\n error('No projects found. Create a project in the admin panel first.');\n process.exitCode = 1;\n return;\n }\n\n // Select project\n const selected = await promptChoice(\n 'Select a project:',\n projects.map((p) => ({\n ...p,\n label: `${p.name} (${p.slug})`,\n })),\n );\n\n // Ask for hosting directory\n const hostingDir = await promptInput(\n 'Hosting directory',\n './dist',\n );\n\n const config: SpacelrConfig = {\n projectId: selected.id,\n apiUrl: apiUrl !== 'https://api.spacelr.com/api/v1' ? apiUrl : undefined,\n hosting: {\n directory: hostingDir,\n },\n };\n\n saveConfig(config, configPath);\n\n if (isJsonMode()) {\n json(config);\n } else {\n success(`Created spacelr.json for \"${selected.name}\"`);\n info(`Project: ${selected.slug} (${selected.id})`);\n info(`Hosting directory: ${hostingDir}`);\n info('');\n info('Next steps:');\n info(' spacelr deploy Deploy your site');\n info(' spacelr db indexes pull Pull database indexes');\n info(' spacelr db rules pull Pull database rules');\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Initialization failed');\n process.exitCode = 1;\n }\n });\n}\n","import * as path from 'node:path';\nimport { Command } from 'commander';\nimport { ApiClient } from '../lib/api-client';\nimport {\n resolveApiUrl,\n resolveProjectId,\n loadConfig,\n} from '../lib/config';\nimport { requireAuth } from '../lib/auth';\nimport { createZipBuffer, countFiles } from '../lib/zip';\nimport {\n error,\n info,\n spinner,\n json,\n isJsonMode,\n formatBytes,\n verbose,\n} from '../lib/output';\nimport type {\n GlobalOptions,\n DeploymentResponse,\n} from '../lib/types';\n\nexport function createDeployCommand(): Command {\n return new Command('deploy')\n .description('Deploy a directory to Spacelr hosting')\n .argument('[directory]', 'Directory to deploy')\n .option('--project <id>', 'Project ID')\n .option('--description <text>', 'Deployment description')\n .option('--no-wait', 'Do not wait for processing to complete')\n .option('--dry-run', 'Show what would be deployed without uploading')\n .action(async (directory: string | undefined, opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const deployDir = directory ?? config?.hosting?.directory ?? '.';\n const absDir = path.resolve(deployDir);\n\n const client = new ApiClient({ apiUrl, token, projectId });\n await deploy(client, projectId, absDir, {\n description: opts.description,\n wait: opts.wait !== false,\n dryRun: opts.dryRun === true,\n });\n } catch (err) {\n error(err instanceof Error ? err.message : 'Deployment failed');\n process.exitCode = 1;\n }\n });\n}\n\ninterface DeployOptions {\n description?: string;\n wait: boolean;\n dryRun: boolean;\n}\n\nasync function deploy(\n client: ApiClient,\n projectId: string,\n directory: string,\n options: DeployOptions,\n): Promise<void> {\n // Step 1: Count files and create ZIP\n const spin = spinner('Preparing deployment...');\n\n const fileCount = countFiles(directory);\n verbose(`Found ${fileCount} files in ${directory}`);\n\n spin.text = 'Creating archive...';\n const zipBuffer = await createZipBuffer(directory);\n verbose(`Archive size: ${formatBytes(zipBuffer.length)}`);\n\n if (options.dryRun) {\n spin.succeed('Dry run complete');\n if (isJsonMode()) {\n json({ dryRun: true, fileCount, archiveSize: zipBuffer.length, directory });\n } else {\n info(`Directory: ${directory}`);\n info(`Files: ${fileCount}`);\n info(`Archive size: ${formatBytes(zipBuffer.length)}`);\n }\n return;\n }\n\n // Step 2: Create deployment\n spin.text = 'Creating deployment...';\n const deployment = await client.post<DeploymentResponse>(\n `/hosting/${projectId}/deployments`,\n {\n description: options.description,\n },\n );\n verbose(`Deployment ID: ${deployment.deploymentId}`);\n\n // Step 3: Upload ZIP\n spin.text = `Uploading ${formatBytes(zipBuffer.length)}...`;\n await client.uploadFile(\n `/hosting/${projectId}/deployments/${deployment.deploymentId}/upload`,\n zipBuffer,\n 'deployment.zip',\n );\n\n if (!options.wait) {\n spin.succeed('Upload complete');\n info(`Deployment ${deployment.deploymentId} is processing`);\n if (isJsonMode()) {\n json({ deploymentId: deployment.deploymentId, status: 'processing' });\n }\n return;\n }\n\n // Step 4: Poll for status\n spin.text = 'Processing deployment...';\n const result = await pollDeploymentStatus(\n client,\n projectId,\n deployment.deploymentId,\n spin,\n );\n\n if (result.status === 'active') {\n spin.succeed('Deployment active');\n if (isJsonMode()) {\n json(result);\n } else {\n info(`Deployment ID: ${result.deploymentId}`);\n info(`Files: ${result.fileCount}`);\n info(`Size: ${formatBytes(result.totalSizeBytes)}`);\n }\n } else if (result.status === 'failed') {\n spin.fail('Deployment failed');\n error(result.errorMessage ?? 'Unknown error');\n process.exitCode = 1;\n } else {\n spin.warn(`Deployment status: ${result.status}`);\n if (isJsonMode()) {\n json(result);\n }\n }\n}\n\nasync function pollDeploymentStatus(\n client: ApiClient,\n projectId: string,\n deploymentId: string,\n spin: { text: string },\n): Promise<DeploymentResponse> {\n const maxAttempts = 120; // 10 minutes (5s intervals)\n for (let i = 0; i < maxAttempts; i++) {\n await sleep(5000);\n const status = await client.get<DeploymentResponse>(\n `/hosting/${projectId}/deployments/${deploymentId}/status`,\n );\n\n verbose(`Poll ${i + 1}: status=${status.status}`);\n spin.text = `Processing deployment... (${status.status})`;\n\n if (\n status.status === 'active' ||\n status.status === 'failed'\n ) {\n return status;\n }\n }\n\n throw new Error('Deployment timed out after 10 minutes');\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport archiver from 'archiver';\n\nexport async function createZipBuffer(directory: string): Promise<Buffer> {\n const absDir = path.resolve(directory);\n if (!fs.existsSync(absDir)) {\n throw new Error(`Directory not found: ${absDir}`);\n }\n if (!fs.statSync(absDir).isDirectory()) {\n throw new Error(`Not a directory: ${absDir}`);\n }\n\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n const archive = archiver('zip', { zlib: { level: 9 } });\n\n archive.on('data', (chunk: Buffer) => chunks.push(chunk));\n archive.on('end', () => resolve(Buffer.concat(chunks)));\n archive.on('error', reject);\n\n archive.directory(absDir, false);\n archive.finalize();\n });\n}\n\nexport function countFiles(directory: string): number {\n const absDir = path.resolve(directory);\n let count = 0;\n\n function walk(dir: string): void {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isFile()) {\n count++;\n } else if (entry.isDirectory()) {\n walk(path.join(dir, entry.name));\n }\n }\n }\n\n walk(absDir);\n return count;\n}\n","import { Command } from 'commander';\nimport { createIndexesDeployCommand } from './indexes-deploy';\nimport { createIndexesPullCommand } from './indexes-pull';\nimport { createRulesDeployCommand } from './rules-deploy';\nimport { createRulesPullCommand } from './rules-pull';\nimport { createCollectionSetCommand } from './collection-set';\n\nexport function createDbCommand(): Command {\n const indexes = new Command('indexes')\n .description('Manage database indexes');\n\n indexes.addCommand(createIndexesDeployCommand());\n indexes.addCommand(createIndexesPullCommand());\n\n const rules = new Command('rules')\n .description('Manage database rules');\n\n rules.addCommand(createRulesDeployCommand());\n rules.addCommand(createRulesPullCommand());\n\n const collection = new Command('collection')\n .description('Manage collection-level settings (realtime mode, retention, throttle, search filter)');\n\n collection.addCommand(createCollectionSetCommand());\n\n const db = new Command('db')\n .description('Database management commands');\n\n db.addCommand(indexes);\n db.addCommand(rules);\n db.addCommand(collection);\n\n return db;\n}\n","import { Command } from 'commander';\nimport { ApiClient } from '../../lib/api-client';\nimport {\n resolveApiUrl,\n resolveProjectId,\n loadConfig,\n loadIndexes,\n} from '../../lib/config';\nimport { requireAuth } from '../../lib/auth';\nimport { success, error, info, spinner, json, isJsonMode, warn } from '../../lib/output';\nimport { promptConfirm } from '../../lib/prompt';\nimport type { GlobalOptions, IndexRuleEntry, RemoteIndexEntry } from '../../lib/types';\n\nexport function createIndexesDeployCommand(): Command {\n return new Command('deploy')\n .description('Deploy indexes from spacelr.indexes.json to remote')\n .option('--project <id>', 'Project ID')\n .option('--config <path>', 'Config file path')\n .option('--yes', 'Skip confirmation')\n .action(async (opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig(opts.config);\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const indexes = loadIndexes(opts.config);\n\n if (!indexes || Object.keys(indexes).length === 0) {\n warn('No indexes found in spacelr.indexes.json');\n return;\n }\n\n // Convert index format: config uses 1/-1, API expects asc/desc\n const indexRules = convertIndexFormat(indexes);\n\n const collectionCount = Object.keys(indexRules).length;\n const totalIndexes = Object.values(indexRules).reduce(\n (sum, arr) => sum + arr.length,\n 0,\n );\n\n if (!opts.yes) {\n info(\n `Will deploy ${totalIndexes} index(es) across ${collectionCount} collection(s)`,\n );\n const confirmed = await promptConfirm('Proceed with deployment?');\n if (!confirmed) {\n info('Aborted');\n return;\n }\n }\n\n const spin = spinner('Deploying indexes...');\n const client = new ApiClient({ apiUrl, token, projectId });\n const result = await client.put<{ message: string }>(\n `/databases/${projectId}/index-rules`,\n { indexRules },\n );\n\n spin.succeed('Indexes deployed');\n\n if (isJsonMode()) {\n json(result);\n } else {\n success(result.message ?? 'Indexes synced successfully');\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to deploy indexes');\n process.exitCode = 1;\n }\n });\n}\n\nfunction convertIndexFormat(\n indexes: Record<string, IndexRuleEntry[]>,\n): Record<string, RemoteIndexEntry[]> {\n const result: Record<string, RemoteIndexEntry[]> = {};\n\n for (const [collection, entries] of Object.entries(indexes)) {\n result[collection] = entries.map((entry) => {\n const fields: Record<string, 'asc' | 'desc'> = {};\n for (const [field, direction] of Object.entries(entry.fields)) {\n fields[field] = direction === 1 ? 'asc' : 'desc';\n }\n return {\n fields,\n ...(entry.unique !== undefined && { unique: entry.unique }),\n ...(entry.sparse !== undefined && { sparse: entry.sparse }),\n ...(entry.ttlSeconds !== undefined && { ttlSeconds: entry.ttlSeconds }),\n };\n });\n }\n\n return result;\n}\n","import { Command } from 'commander';\nimport { ApiClient } from '../../lib/api-client';\nimport {\n resolveApiUrl,\n resolveProjectId,\n loadConfig,\n saveConfig,\n saveIndexes,\n} from '../../lib/config';\nimport { requireAuth } from '../../lib/auth';\nimport { success, error, spinner, json, isJsonMode, info } from '../../lib/output';\nimport type { GlobalOptions, IndexRuleEntry, RemoteIndexEntry } from '../../lib/types';\n\nexport function createIndexesPullCommand(): Command {\n return new Command('pull')\n .description('Pull current indexes from remote to spacelr.indexes.json')\n .option('--project <id>', 'Project ID')\n .option('--config <path>', 'Config file path')\n .action(async (opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig(opts.config);\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n\n const spin = spinner('Pulling indexes...');\n const client = new ApiClient({ apiUrl, token, projectId });\n const response = await client.get<Record<string, unknown>>(\n `/databases/${projectId}/index-rules`,\n );\n\n // The API may return the indexes directly or wrapped in { indexRules }\n const remoteIndexes: Record<string, RemoteIndexEntry[]> =\n response && 'indexRules' in response\n ? (response['indexRules'] as Record<string, RemoteIndexEntry[]>)\n : (response as Record<string, RemoteIndexEntry[]>) ?? {};\n\n // Convert from API format (asc/desc) to config format (1/-1)\n const indexes = convertFromRemoteFormat(remoteIndexes);\n\n saveIndexes(indexes, opts.config);\n\n if (opts.project && opts.project !== config?.projectId) {\n saveConfig({ ...config, projectId: opts.project }, opts.config);\n }\n\n spin.succeed('Indexes pulled');\n\n const collectionCount = Object.keys(indexes).length;\n const totalIndexes = Object.values(indexes).reduce(\n (sum, arr) => sum + arr.length,\n 0,\n );\n\n if (isJsonMode()) {\n json(indexes);\n } else {\n success(\n `Pulled ${totalIndexes} index(es) from ${collectionCount} collection(s)`,\n );\n info('Indexes file updated');\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to pull indexes');\n process.exitCode = 1;\n }\n });\n}\n\nfunction convertFromRemoteFormat(\n remoteIndexes: Record<string, RemoteIndexEntry[]>,\n): Record<string, IndexRuleEntry[]> {\n const result: Record<string, IndexRuleEntry[]> = {};\n\n for (const [collection, entries] of Object.entries(remoteIndexes)) {\n result[collection] = entries.map((entry) => {\n const fields: Record<string, 1 | -1> = {};\n for (const [field, direction] of Object.entries(entry.fields)) {\n fields[field] = direction === 'asc' ? 1 : -1;\n }\n return {\n fields,\n ...(entry.unique !== undefined && { unique: entry.unique }),\n ...(entry.sparse !== undefined && { sparse: entry.sparse }),\n ...(entry.ttlSeconds !== undefined && {\n ttlSeconds: entry.ttlSeconds,\n }),\n };\n });\n }\n\n return result;\n}\n","import { Command } from 'commander';\nimport { ApiClient } from '../../lib/api-client';\nimport {\n resolveApiUrl,\n resolveProjectId,\n loadConfig,\n loadRules,\n} from '../../lib/config';\nimport { requireAuth } from '../../lib/auth';\nimport { success, error, info, spinner, json, isJsonMode, warn } from '../../lib/output';\nimport { promptConfirm } from '../../lib/prompt';\nimport type { GlobalOptions } from '../../lib/types';\n\nexport function createRulesDeployCommand(): Command {\n return new Command('deploy')\n .description('Deploy rules from spacelr.rules.json to remote')\n .option('--project <id>', 'Project ID')\n .option('--config <path>', 'Config file path')\n .option('--yes', 'Skip confirmation')\n .action(async (opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig(opts.config);\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const rules = loadRules(opts.config);\n\n if (!rules || Object.keys(rules).length === 0) {\n warn('No rules found in spacelr.rules.json');\n return;\n }\n\n const ruleCount = Object.keys(rules).length;\n\n if (!opts.yes) {\n info(`Will deploy rules for ${ruleCount} collection(s)`);\n const confirmed = await promptConfirm('Proceed with deployment?');\n if (!confirmed) {\n info('Aborted');\n return;\n }\n }\n\n // Validate first\n const spin = spinner('Validating rules...');\n const client = new ApiClient({ apiUrl, token, projectId });\n\n await client.post<{ valid: boolean }>(\n `/databases/${projectId}/rules/validate`,\n { rules },\n );\n\n // Deploy\n spin.text = 'Deploying rules...';\n const result = await client.put<{ message: string }>(\n `/databases/${projectId}/rules`,\n { rules },\n );\n\n spin.succeed('Rules deployed');\n\n if (isJsonMode()) {\n json(result);\n } else {\n success(result.message ?? 'Rules deployed successfully');\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to deploy rules');\n process.exitCode = 1;\n }\n });\n}\n","import { Command } from 'commander';\nimport { ApiClient } from '../../lib/api-client';\nimport {\n resolveApiUrl,\n resolveProjectId,\n loadConfig,\n saveConfig,\n saveRules,\n} from '../../lib/config';\nimport { requireAuth } from '../../lib/auth';\nimport { success, error, spinner, json, isJsonMode, info } from '../../lib/output';\nimport type { GlobalOptions } from '../../lib/types';\n\nexport function createRulesPullCommand(): Command {\n return new Command('pull')\n .description('Pull current rules from remote to spacelr.rules.json')\n .option('--project <id>', 'Project ID')\n .option('--config <path>', 'Config file path')\n .action(async (opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig(opts.config);\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n\n const spin = spinner('Pulling rules...');\n const client = new ApiClient({ apiUrl, token, projectId });\n const result = await client.get<{ rules: Record<string, unknown> }>(\n `/databases/${projectId}/rules`,\n );\n\n const rules = result.rules;\n\n saveRules(rules, opts.config);\n\n if (opts.project && opts.project !== config?.projectId) {\n saveConfig({ ...config, projectId: opts.project }, opts.config);\n }\n\n spin.succeed('Rules pulled');\n\n const ruleCount = Object.keys(rules).length;\n\n if (isJsonMode()) {\n json(rules);\n } else {\n success(`Pulled rules for ${ruleCount} collection(s)`);\n info('Rules file updated');\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to pull rules');\n process.exitCode = 1;\n }\n });\n}\n","import { Command } from 'commander';\nimport { ApiClient } from '../../lib/api-client';\nimport { resolveApiUrl, resolveProjectId, loadConfig } from '../../lib/config';\nimport { requireAuth } from '../../lib/auth';\nimport { success, error, info, spinner, json, isJsonMode } from '../../lib/output';\nimport { promptConfirm } from '../../lib/prompt';\nimport type { GlobalOptions } from '../../lib/types';\n\ninterface UpdateBody extends Record<string, unknown> {\n realtimeMode?: 'pubsub' | 'stream';\n streamRetention?: { maxLen?: number; maxAgeMs?: number };\n writeThrottle?: { enabled?: boolean; limit?: number; windowMs?: number };\n searchConfig?: { requireFilter?: string[] };\n}\n\nconst RESERVED_FILTER_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\nfunction parsePositiveInt(value: string, flag: string): number {\n // Restrict to plain digit input — `Number()` otherwise accepts scientific\n // notation (\"1e10\" → 10_000_000_000) and bypasses any sane upper bound.\n if (!/^\\d+$/.test(value)) {\n throw new Error(`${flag} must be a positive integer (got \"${value}\")`);\n }\n const n = Number(value);\n if (!Number.isInteger(n) || n <= 0) {\n throw new Error(`${flag} must be a positive integer (got \"${value}\")`);\n }\n return n;\n}\n\nfunction parseBool(value: string, flag: string): boolean {\n const lower = value.toLowerCase();\n if (lower === 'true' || lower === '1') return true;\n if (lower === 'false' || lower === '0') return false;\n throw new Error(`${flag} must be true|false (got \"${value}\")`);\n}\n\nfunction parseCsv(value: string): string[] {\n return value\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n}\n\nexport function createCollectionSetCommand(): Command {\n return new Command('set')\n .description('Update collection metadata (realtimeMode, retention, throttle, search filter)')\n .argument('<name>', 'Collection name')\n .option('--project <id>', 'Project ID')\n .option('--config <path>', 'Config file path')\n .option(\n '--realtime-mode <mode>',\n 'Switch realtime delivery mode: pubsub (default, fire-and-forget) or stream (durable, replayable)',\n )\n .option(\n '--retention-max-len <n>',\n 'Approximate max retained events on the Redis stream (mutually exclusive with --retention-max-age-ms)',\n )\n .option(\n '--retention-max-age-ms <ms>',\n 'Retention age in ms for stream entries (mutually exclusive with --retention-max-len)',\n )\n .option(\n '--throttle-enabled <bool>',\n 'true|false — toggle the per-collection write throttle. Use false for high-volume system collections (e.g. audit logs).',\n )\n .option('--throttle-limit <n>', 'Max writes per window (1..10000)')\n .option('--throttle-window-ms <ms>', 'Throttle window in ms (1000..3_600_000)')\n .option(\n '--require-filter <fields>',\n 'Comma-separated top-level filter keys required on every search() call (alphanumeric + underscore, max 10 keys). Pass an empty string (\"\") to clear an existing requirement.',\n )\n .option('--yes', 'Skip confirmation')\n .action(async (name: string, opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig(opts.config);\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n\n const body: UpdateBody = {};\n\n if (opts.realtimeMode !== undefined) {\n if (opts.realtimeMode !== 'pubsub' && opts.realtimeMode !== 'stream') {\n throw new Error(`--realtime-mode must be 'pubsub' or 'stream' (got \"${opts.realtimeMode}\")`);\n }\n body.realtimeMode = opts.realtimeMode;\n }\n\n if (opts.retentionMaxLen !== undefined || opts.retentionMaxAgeMs !== undefined) {\n if (opts.retentionMaxLen !== undefined && opts.retentionMaxAgeMs !== undefined) {\n throw new Error('Set at most one of --retention-max-len or --retention-max-age-ms');\n }\n body.streamRetention = {};\n if (opts.retentionMaxLen !== undefined) {\n body.streamRetention.maxLen = parsePositiveInt(opts.retentionMaxLen, '--retention-max-len');\n }\n if (opts.retentionMaxAgeMs !== undefined) {\n const ms = parsePositiveInt(opts.retentionMaxAgeMs, '--retention-max-age-ms');\n if (ms < 1000) throw new Error('--retention-max-age-ms must be >= 1000 (1 second)');\n body.streamRetention.maxAgeMs = ms;\n }\n }\n\n if (\n opts.throttleEnabled !== undefined ||\n opts.throttleLimit !== undefined ||\n opts.throttleWindowMs !== undefined\n ) {\n body.writeThrottle = {};\n if (opts.throttleEnabled !== undefined) {\n body.writeThrottle.enabled = parseBool(opts.throttleEnabled, '--throttle-enabled');\n }\n if (opts.throttleLimit !== undefined) {\n const n = parsePositiveInt(opts.throttleLimit, '--throttle-limit');\n if (n > 10000) throw new Error('--throttle-limit must be <= 10000');\n body.writeThrottle.limit = n;\n }\n if (opts.throttleWindowMs !== undefined) {\n const ms = parsePositiveInt(opts.throttleWindowMs, '--throttle-window-ms');\n if (ms < 1000 || ms > 3_600_000) {\n throw new Error('--throttle-window-ms must be between 1000 and 3_600_000');\n }\n body.writeThrottle.windowMs = ms;\n }\n }\n\n if (opts.requireFilter !== undefined) {\n const fields = parseCsv(opts.requireFilter);\n if (fields.length === 0) {\n // `{}` clears the override per the service contract at\n // collection.service.ts:429-462 — empty searchConfig triggers\n // a $unset on the document. Omitting the field entirely would\n // be \"no change\".\n body.searchConfig = {};\n } else {\n if (fields.length > 10) throw new Error('--require-filter accepts at most 10 keys');\n for (const f of fields) {\n if (!/^[a-zA-Z0-9_]+$/.test(f) || f.length > 64) {\n throw new Error(`Invalid filter key \"${f}\" — must be alphanumeric/underscore, max 64 chars`);\n }\n if (RESERVED_FILTER_KEYS.has(f)) {\n throw new Error(`Reserved filter key \"${f}\" — __proto__/constructor/prototype are not allowed`);\n }\n }\n body.searchConfig = { requireFilter: Array.from(new Set(fields)) };\n }\n }\n\n if (Object.keys(body).length === 0) {\n throw new Error(\n 'No metadata fields provided. Pass at least one of --realtime-mode, --retention-*, --throttle-*, --require-filter.',\n );\n }\n\n // `--json` implies non-interactive — automation can't answer prompts,\n // and a JSON consumer expects a single JSON document, not a confirmation\n // banner. Skip the prompt; trust the caller passed --yes-equivalent intent.\n if (!opts.yes && !isJsonMode()) {\n info(`Updating collection \"${name}\" (project ${projectId}) with:`);\n info(JSON.stringify(body, null, 2));\n const confirmed = await promptConfirm('Proceed?');\n if (!confirmed) {\n info('Aborted');\n return;\n }\n }\n\n const spin = spinner('Updating collection metadata...');\n const client = new ApiClient({ apiUrl, token, projectId });\n const result = await client.patch<unknown>(\n `/databases/${encodeURIComponent(projectId)}/collections/${encodeURIComponent(name)}`,\n body,\n );\n spin.succeed('Collection metadata updated');\n\n if (isJsonMode()) {\n json(result);\n } else {\n success(`Updated \"${name}\"`);\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to update collection metadata');\n process.exitCode = 1;\n }\n });\n}\n","import * as path from 'node:path';\nimport { Command } from 'commander';\nimport { ApiClient } from '../lib/api-client';\nimport {\n resolveApiUrl,\n resolveProjectId,\n loadConfig,\n} from '../lib/config';\nimport { requireAuth } from '../lib/auth';\nimport { createZipBuffer, countFiles } from '../lib/zip';\nimport {\n error,\n info,\n spinner,\n json,\n isJsonMode,\n formatBytes,\n verbose,\n} from '../lib/output';\nimport type { GlobalOptions } from '../lib/types';\n\ninterface FunctionEntry {\n id: string;\n name: string;\n enabled: boolean;\n cronExpression?: string;\n environmentVariables?: Record<string, string>;\n}\n\ninterface FunctionListResponse {\n data?: FunctionEntry[];\n}\n\ninterface FunctionCreateResponse {\n id?: string;\n data?: { id: string };\n}\n\ninterface ExecutionLogEntry {\n timestamp: string;\n level: string;\n message: string;\n}\n\ninterface ExecutionEntry {\n status: string;\n startedAt: string;\n duration?: number;\n triggeredBy: string;\n error?: string;\n logs?: ExecutionLogEntry[];\n}\n\ninterface ExecutionsResponse {\n items?: ExecutionEntry[];\n data?: { items?: ExecutionEntry[] };\n}\n\nexport function createFunctionsCommand(): Command {\n const functions = new Command('functions')\n .description('Manage serverless functions');\n\n functions\n .command('deploy [directory]')\n .description('Deploy a function')\n .requiredOption('--name <name>', 'Function name')\n .option('--entry <file>', 'Entry point (default: index.js)')\n .option('--cron <expression>', 'Cron schedule expression')\n .option('--timezone <tz>', 'Timezone for cron (default: UTC)')\n .option('--timeout <ms>', 'Execution timeout in ms')\n .option('--memory <mb>', 'Memory limit in MB')\n .option('--env <KEY=VALUE...>', 'Environment variables', collectEnvVars, {})\n .option('--project <id>', 'Project ID')\n .action(async (directory: string | undefined, opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const deployDir = directory ?? '.';\n const absDir = path.resolve(deployDir);\n\n const client = new ApiClient({ apiUrl, token, projectId });\n\n // Create zip\n const spin = spinner('Preparing deployment...');\n const fileCount = countFiles(absDir);\n verbose(`Found ${fileCount} files in ${absDir}`);\n\n spin.text = 'Creating archive...';\n const zipBuffer = await createZipBuffer(absDir);\n verbose(`Archive size: ${formatBytes(zipBuffer.length)}`);\n\n // Check if function already exists\n spin.text = 'Checking for existing function...';\n const envVars = opts.env as Record<string, string>;\n const existingFns = await client.get<\n FunctionEntry[] | FunctionListResponse\n >(`/projects/${projectId}/functions`);\n const fnList: FunctionEntry[] = Array.isArray(existingFns)\n ? existingFns\n : (existingFns as FunctionListResponse).data || [];\n const existing = fnList.find(\n (f: FunctionEntry) => f.name === opts.name,\n );\n\n let functionId: string;\n const functionBody = {\n entryPoint: opts.entry,\n cronExpression: opts.cron,\n cronTimezone: opts.timezone,\n timeout: opts.timeout ? parseInt(opts.timeout, 10) : undefined,\n memoryLimitMb: opts.memory ? parseInt(opts.memory, 10) : undefined,\n environmentVariables:\n Object.keys(envVars).length > 0 ? envVars : undefined,\n };\n\n if (existing) {\n // Update existing function\n spin.text = 'Updating function...';\n await client.patch(\n `/projects/${projectId}/functions/${existing.id}`,\n functionBody,\n );\n functionId = existing.id;\n } else {\n // Create new function\n spin.text = 'Creating function...';\n const createResult = await client.post<FunctionCreateResponse>(\n `/projects/${projectId}/functions`,\n { name: opts.name, ...functionBody },\n );\n const createdId = createResult.id || createResult.data?.id;\n if (!createdId) {\n throw new Error('Failed to create function');\n }\n functionId = createdId;\n }\n\n // Upload code\n spin.text = 'Uploading code...';\n await client.uploadFile(\n `/projects/${projectId}/functions/${functionId}/deploy`,\n zipBuffer,\n 'code.zip',\n );\n\n spin.succeed(\n `Function \"${opts.name}\" deployed (${formatBytes(zipBuffer.length)}, ${fileCount} files)`,\n );\n\n if (opts.cron) {\n info(`Cron schedule: ${opts.cron}`);\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Deploy failed');\n process.exitCode = 1;\n }\n });\n\n functions\n .command('list')\n .description('List functions')\n .option('--project <id>', 'Project ID')\n .action(async (opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const client = new ApiClient({ apiUrl, token, projectId });\n\n const result = await client.get<FunctionEntry[] | FunctionListResponse>(\n `/projects/${projectId}/functions`,\n );\n\n const fns: FunctionEntry[] = Array.isArray(result)\n ? result\n : (result as FunctionListResponse).data || [];\n\n if (isJsonMode()) {\n json(fns);\n return;\n }\n\n if (fns.length === 0) {\n info('No functions found');\n return;\n }\n\n for (const fn of fns) {\n const status = fn.enabled ? 'enabled' : 'disabled';\n const cron = fn.cronExpression ? ` [${fn.cronExpression}]` : '';\n info(`${fn.name} (${fn.id}) - ${status}${cron}`);\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to list functions');\n process.exitCode = 1;\n }\n });\n\n functions\n .command('delete <name>')\n .description('Delete a function')\n .option('--project <id>', 'Project ID')\n .action(async (name: string, opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const client = new ApiClient({ apiUrl, token, projectId });\n\n const fn = await findFunctionByName(client, projectId, name);\n\n await client.delete(\n `/projects/${projectId}/functions/${fn.id}`,\n );\n\n info(`Function \"${name}\" deleted`);\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to delete function');\n process.exitCode = 1;\n }\n });\n\n functions\n .command('trigger <name>')\n .description('Trigger a function execution')\n .option('--project <id>', 'Project ID')\n .action(async (name: string, opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const client = new ApiClient({ apiUrl, token, projectId });\n\n const fn = await findFunctionByName(client, projectId, name);\n\n const spin = spinner('Triggering function...');\n await client.post(\n `/projects/${projectId}/functions/${fn.id}/trigger`,\n );\n spin.succeed(`Function \"${name}\" triggered`);\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to trigger function');\n process.exitCode = 1;\n }\n });\n\n functions\n .command('logs <name>')\n .description('View function execution logs')\n .option('--limit <n>', 'Number of executions to show', '10')\n .option('--project <id>', 'Project ID')\n .action(async (name: string, opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const client = new ApiClient({ apiUrl, token, projectId });\n\n const fn = await findFunctionByName(client, projectId, name);\n\n const limit = parseInt(opts.limit, 10);\n const result = await client.get<ExecutionsResponse>(\n `/projects/${projectId}/functions/${fn.id}/executions?limit=${limit}`,\n );\n\n const executions = result.items || result.data?.items || [];\n\n if (isJsonMode()) {\n json(executions);\n return;\n }\n\n if (executions.length === 0) {\n info('No executions found');\n return;\n }\n\n for (const exec of executions) {\n const date = new Date(exec.startedAt).toLocaleString();\n const duration = exec.duration ? `${exec.duration}ms` : '-';\n info(\n `[${exec.status}] ${date} (${duration}) - ${exec.triggeredBy}${exec.error ? ` - ${exec.error}` : ''}`,\n );\n\n if (exec.logs && exec.logs.length > 0) {\n for (const log of exec.logs) {\n const logTime = new Date(log.timestamp).toLocaleTimeString();\n info(` ${logTime} [${log.level}] ${log.message}`);\n }\n }\n }\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to get logs');\n process.exitCode = 1;\n }\n });\n\n const envCmd = functions\n .command('env')\n .description('Manage function environment variables');\n\n envCmd\n .command('set <name> <keyValue>')\n .description('Set an environment variable (KEY=VALUE)')\n .option('--project <id>', 'Project ID')\n .action(async (name: string, keyValue: string, opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const client = new ApiClient({ apiUrl, token, projectId });\n\n const eqIndex = keyValue.indexOf('=');\n if (eqIndex === -1) {\n throw new Error('Format must be KEY=VALUE');\n }\n const key = keyValue.substring(0, eqIndex);\n const value = keyValue.substring(eqIndex + 1);\n\n const fn = await findFunctionByName(client, projectId, name);\n\n // Merge with current env vars\n const currentVars = fn.environmentVariables || {};\n const updatedVars = { ...currentVars, [key]: value };\n\n await client.patch(\n `/projects/${projectId}/functions/${fn.id}`,\n { environmentVariables: updatedVars },\n );\n\n info(`Set ${key} for function \"${name}\"`);\n } catch (err) {\n error(err instanceof Error ? err.message : 'Failed to set env var');\n process.exitCode = 1;\n }\n });\n\n envCmd\n .command('list <name>')\n .description('List environment variables for a function')\n .option('--project <id>', 'Project ID')\n .action(async (name: string, opts, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals<GlobalOptions>();\n const config = loadConfig();\n const apiUrl = resolveApiUrl(globalOpts.apiUrl, config);\n\n try {\n const token = await requireAuth(globalOpts.token);\n const projectId = resolveProjectId(opts.project, config);\n const client = new ApiClient({ apiUrl, token, projectId });\n\n const fn = await findFunctionByName(client, projectId, name);\n\n const vars = fn.environmentVariables || {};\n const keys = Object.keys(vars);\n\n if (isJsonMode()) {\n json(vars);\n return;\n }\n\n if (keys.length === 0) {\n info('No environment variables set');\n return;\n }\n\n for (const key of keys) {\n info(`${key}=${vars[key]}`);\n }\n } catch (err) {\n error(\n err instanceof Error ? err.message : 'Failed to list env vars',\n );\n process.exitCode = 1;\n }\n });\n\n return functions;\n}\n\n/** Look up a function by name from the list endpoint. */\nasync function findFunctionByName(\n client: ApiClient,\n projectId: string,\n name: string,\n): Promise<FunctionEntry> {\n const result = await client.get<FunctionEntry[] | FunctionListResponse>(\n `/projects/${projectId}/functions`,\n );\n\n const fnList: FunctionEntry[] = Array.isArray(result)\n ? result\n : (result as FunctionListResponse).data || [];\n\n const fn = fnList.find((f) => f.name === name);\n if (!fn) {\n throw new Error(`Function \"${name}\" not found`);\n }\n return fn;\n}\n\nfunction collectEnvVars(\n value: string,\n previous: Record<string, string>,\n): Record<string, string> {\n const eqIndex = value.indexOf('=');\n if (eqIndex === -1) return previous;\n const key = value.substring(0, eqIndex);\n const val = value.substring(eqIndex + 1);\n return { ...previous, [key]: val };\n}\n"],"mappings":"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","names":["import_commander","pc","ora","crypto","fs","path","open","resolve","import_commander","import_commander","path","import_commander","import_commander","resolve","fs","path","import_commander","path","import_commander","fs","path","resolve","archiver","resolve","import_commander","import_commander","import_commander","import_commander","import_commander","import_commander","path","import_commander"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spacelr/cli",
3
- "version": "0.1.7",
3
+ "version": "0.2.0",
4
4
  "description": "CLI tool for the Spacelr platform - deploy hosting sites and manage databases",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",