cli-invoice 0.1.1
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/LICENSE +21 -0
- package/README.md +173 -0
- package/dist/bin/inv.js +2010 -0
- package/dist/bin/inv.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/storage/paths.ts","../../src/core/config.ts","../../src/utils/format.ts","../../src/storage/store.ts","../../src/utils/validate.ts","../../src/utils/date.ts","../../src/core/license.ts","../../src/core/client.ts","../../src/utils/currency.ts","../../src/core/invoice.ts","../../src/templates/default.ts","../../src/core/pdf.ts","../../bin/inv.ts","../../src/cli/config.ts","../../src/cli/client.ts","../../src/cli/invoice.ts","../../src/cli/status.ts","../../src/cli/export.ts","../../src/cli/license.ts"],"sourcesContent":["/**\n * XDG-compliant directory resolution for CLI Invoice data.\n *\n * Data location: ~/.config/cli-invoice/ (respects XDG_CONFIG_HOME)\n */\n\nimport * as path from 'path';\nimport * as os from 'os';\nimport * as fs from 'fs';\n\n/** Resolve the base config directory, respecting XDG_CONFIG_HOME */\nexport function getConfigDir(): string {\n const xdgConfig = process.env['XDG_CONFIG_HOME'];\n const base = xdgConfig || path.join(os.homedir(), '.config');\n return path.join(base, 'cli-invoice');\n}\n\n/** Resolve the data subdirectory within the config dir */\nexport function getDataDir(): string {\n return path.join(getConfigDir(), 'data');\n}\n\n/** Resolve the path to config.toml */\nexport function getConfigPath(): string {\n return path.join(getConfigDir(), 'config.toml');\n}\n\n/** Resolve the path to clients.json */\nexport function getClientsPath(): string {\n return path.join(getDataDir(), 'clients.json');\n}\n\n/** Resolve the path to invoices.json */\nexport function getInvoicesPath(): string {\n return path.join(getDataDir(), 'invoices.json');\n}\n\n/** Resolve the path to counter.json */\nexport function getCounterPath(): string {\n return path.join(getDataDir(), 'counter.json');\n}\n\n/**\n * Ensure that a directory exists, creating it recursively if needed.\n * This is called on first use to set up the data directory.\n */\nexport function ensureDir(dirPath: string): void {\n if (!fs.existsSync(dirPath)) {\n fs.mkdirSync(dirPath, { recursive: true });\n }\n}\n\n/** Ensure all required directories exist */\nexport function ensureDataDirs(): void {\n ensureDir(getConfigDir());\n ensureDir(getDataDir());\n}\n","/**\n * Config management — read/write config.toml, init wizard, update individual keys.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as crypto from 'crypto';\nimport * as TOML from 'smol-toml';\nimport { getConfigPath, ensureDataDirs } from '../storage/paths.js';\nimport type { Config } from '../types.js';\n\n/** Default config values */\nexport function defaultConfig(): Config {\n return {\n sender: {\n name: '',\n business_name: '',\n email: '',\n address: '',\n logo: '',\n },\n defaults: {\n currency: 'USD',\n payment_terms: 30,\n tax_rate: 0,\n output_dir: '',\n },\n invoice: {\n number_prefix: 'INV',\n next_number: 1,\n },\n license: {\n key: '',\n activated_at: '',\n },\n };\n}\n\n/** Load config from disk, merging with defaults for any missing fields */\nexport function loadConfig(): Config {\n const configPath = getConfigPath();\n const defaults = defaultConfig();\n\n try {\n const raw = fs.readFileSync(configPath, 'utf-8');\n const parsed = TOML.parse(raw) as Record<string, unknown>;\n\n // Deep merge parsed config over defaults\n return deepMerge(defaults as unknown as Record<string, unknown>, parsed) as unknown as Config;\n } catch (err: unknown) {\n if (isNodeError(err) && err.code === 'ENOENT') {\n return defaults;\n }\n throw err;\n }\n}\n\n/** Save full config to disk as TOML (atomic write) */\nexport function saveConfig(config: Config): void {\n ensureDataDirs();\n const configPath = getConfigPath();\n const dir = path.dirname(configPath);\n\n const tomlString = TOML.stringify(config as unknown as Record<string, unknown>);\n\n // Atomic write: temp file + rename\n const tempFile = path.join(dir, `.tmp-config-${crypto.randomBytes(8).toString('hex')}.toml`);\n try {\n fs.writeFileSync(tempFile, tomlString, 'utf-8');\n fs.renameSync(tempFile, configPath);\n } catch (err) {\n try {\n if (fs.existsSync(tempFile)) {\n fs.unlinkSync(tempFile);\n }\n } catch {\n // Ignore cleanup errors\n }\n throw err;\n }\n}\n\n/**\n * Update a single config value by dot-notation key path.\n * e.g. updateConfig(\"defaults.currency\", \"EUR\")\n */\nexport function updateConfig(key: string, value: string): void {\n const config = loadConfig();\n const parts = key.split('.');\n\n if (parts.length !== 2) {\n throw new Error(`Invalid config key: \"${key}\". Use section.field format (e.g., defaults.currency).`);\n }\n\n const [section, field] = parts as [string, string];\n\n // Validate section exists\n if (!(section in config)) {\n const validSections = Object.keys(config).join(', ');\n throw new Error(`Unknown config section: \"${section}\". Valid sections: ${validSections}`);\n }\n\n const sectionObj = config[section as keyof Config] as unknown as Record<string, unknown>;\n if (!(field in sectionObj)) {\n const validFields = Object.keys(sectionObj).join(', ');\n throw new Error(`Unknown config field: \"${field}\" in section \"${section}\". Valid fields: ${validFields}`);\n }\n\n // Coerce value to the correct type based on the current value's type\n const currentValue = sectionObj[field];\n if (typeof currentValue === 'number') {\n const num = Number(value);\n if (isNaN(num)) {\n throw new Error(`\"${field}\" expects a number, got \"${value}\".`);\n }\n sectionObj[field] = num;\n } else {\n sectionObj[field] = value;\n }\n\n saveConfig(config);\n}\n\n/**\n * Interactive init — collects sender profile and writes config.\n * Returns the created config.\n */\nexport async function initConfig(): Promise<Config> {\n // Lazy-load inquirer to keep startup fast\n const { input } = await import('@inquirer/prompts');\n\n const config = defaultConfig();\n\n config.sender.name = await input({\n message: 'Your name (appears on invoices):',\n validate: (v: string) => v.trim().length > 0 || 'Name is required.',\n });\n\n config.sender.business_name = await input({\n message: 'Business name (optional, press Enter to skip):',\n default: '',\n });\n\n config.sender.email = await input({\n message: 'Email address:',\n validate: (v: string) => {\n if (v.trim().length === 0) return 'Email is required.';\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(v)) return 'Invalid email format.';\n return true;\n },\n });\n\n config.sender.address = await input({\n message: 'Address (use \\\\n for new lines):',\n default: '',\n });\n\n config.sender.logo = await input({\n message: 'Path to logo file (optional, press Enter to skip):',\n default: '',\n });\n\n config.defaults.currency = await input({\n message: 'Default currency (ISO code):',\n default: 'USD',\n });\n\n const termsStr = await input({\n message: 'Default payment terms (days):',\n default: '30',\n validate: (v: string) => {\n const n = Number(v);\n return (!isNaN(n) && n > 0 && Number.isInteger(n)) || 'Must be a positive integer.';\n },\n });\n config.defaults.payment_terms = parseInt(termsStr, 10);\n\n ensureDataDirs();\n saveConfig(config);\n\n return config;\n}\n\n/** Check if config has been initialized (config.toml exists) */\nexport function isConfigInitialized(): boolean {\n return fs.existsSync(getConfigPath());\n}\n\n/** Keys that must never be merged (prototype pollution prevention) */\nconst UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\n/** Deep merge source into target (non-destructive) */\nfunction deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = { ...target };\n for (const key of Object.keys(source)) {\n if (UNSAFE_KEYS.has(key)) continue;\n if (\n source[key] !== null &&\n typeof source[key] === 'object' &&\n !Array.isArray(source[key]) &&\n key in target &&\n target[key] !== null &&\n typeof target[key] === 'object' &&\n !Array.isArray(target[key])\n ) {\n result[key] = deepMerge(\n target[key] as Record<string, unknown>,\n source[key] as Record<string, unknown>,\n );\n } else {\n result[key] = source[key];\n }\n }\n return result;\n}\n\n/** Type guard for Node.js system errors */\nfunction isNodeError(err: unknown): err is NodeJS.ErrnoException {\n return err instanceof Error && 'code' in err;\n}\n","/**\n * Terminal output formatting helpers.\n */\n\nimport chalk from 'chalk';\n\nexport function success(message: string): void {\n console.log(chalk.green('✓') + ' ' + message);\n}\n\nexport function error(message: string): void {\n console.error(chalk.red('Error:') + ' ' + message);\n}\n\nexport function warn(message: string): void {\n console.log(chalk.yellow('Warning:') + ' ' + message);\n}\n\nexport function info(message: string): void {\n console.log(chalk.blue('ℹ') + ' ' + message);\n}\n","/**\n * Generic JSON store — read/write with atomic file writes.\n *\n * Atomic writes: write to a temp file, then rename. This prevents\n * data corruption if the process is interrupted mid-write.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as crypto from 'crypto';\nimport { ensureDir } from './paths.js';\n\n/**\n * Read and parse a JSON file. Returns the default value if the file\n * does not exist.\n */\nexport function readStore<T>(filePath: string, defaultValue: T): T {\n try {\n const raw = fs.readFileSync(filePath, 'utf-8');\n return JSON.parse(raw) as T;\n } catch (err: unknown) {\n if (isNodeError(err) && err.code === 'ENOENT') {\n return defaultValue;\n }\n throw err;\n }\n}\n\n/**\n * Write data to a JSON file using atomic rename.\n *\n * 1. Write to a temp file in the same directory\n * 2. Rename temp file to target (atomic on POSIX)\n *\n * This ensures the file is never in a partially-written state.\n */\nexport function writeStore<T>(filePath: string, data: T): void {\n const dir = path.dirname(filePath);\n ensureDir(dir);\n\n const tempFile = path.join(dir, `.tmp-${crypto.randomBytes(8).toString('hex')}.json`);\n\n try {\n const content = JSON.stringify(data, null, 2) + '\\n';\n fs.writeFileSync(tempFile, content, 'utf-8');\n fs.renameSync(tempFile, filePath);\n } catch (err) {\n // Clean up temp file if rename failed\n try {\n if (fs.existsSync(tempFile)) {\n fs.unlinkSync(tempFile);\n }\n } catch {\n // Ignore cleanup errors\n }\n throw err;\n }\n}\n\n/** Type guard for Node.js system errors (with .code property) */\nfunction isNodeError(err: unknown): err is NodeJS.ErrnoException {\n return err instanceof Error && 'code' in err;\n}\n","/**\n * Input validation helpers.\n */\n\n/** Validate email format (basic RFC 5322 check) */\nexport function isValidEmail(email: string): boolean {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailRegex.test(email);\n}\n\n/** Validate that a string is non-empty after trimming */\nexport function isNonEmpty(value: string): boolean {\n return value.trim().length > 0;\n}\n\n/** Validate that a number is a positive integer */\nexport function isPositiveInt(value: number): boolean {\n return Number.isInteger(value) && value > 0;\n}\n\n/** Validate that a number is non-negative */\nexport function isNonNegative(value: number): boolean {\n return typeof value === 'number' && !isNaN(value) && value >= 0;\n}\n","/**\n * Date helpers — using built-in Date + Intl.DateTimeFormat.\n */\n\n/** Get today's date as YYYY-MM-DD */\nexport function today(): string {\n return new Date().toISOString().split('T')[0]!;\n}\n\n/** Get current ISO 8601 datetime string */\nexport function nowISO(): string {\n return new Date().toISOString();\n}\n\n/** Add days to a date string (YYYY-MM-DD) and return YYYY-MM-DD */\nexport function addDays(dateStr: string, days: number): string {\n const date = new Date(dateStr);\n date.setDate(date.getDate() + days);\n return date.toISOString().split('T')[0]!;\n}\n\n/** Check if a date string is before today */\nexport function isPast(dateStr: string): boolean {\n const date = new Date(dateStr);\n const now = new Date();\n now.setHours(0, 0, 0, 0);\n return date < now;\n}\n\n/** Format a date string for display */\nexport function formatDate(dateStr: string): string {\n // Parse YYYY-MM-DD as local date (not UTC) to avoid timezone shift\n const [year, month, day] = dateStr.split('-').map(Number);\n const date = new Date(year!, month! - 1, day);\n return date.toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n}\n","/**\n * License validation, freemium enforcement, and Ed25519 key operations.\n *\n * Free tier limits:\n * - 3 clients\n * - 5 invoices per calendar month\n *\n * License keys are Ed25519-signed tokens verified with an embedded public key.\n * Format: base64url({payload}.{signature})\n * payload = base64url-encoded JSON { email, plan, issued_at, expires_at }\n * signature = Ed25519 signature of the payload bytes\n */\n\nimport * as crypto from 'crypto';\nimport type { LicenseStatus, Config } from '../types.js';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nexport const FREE_CLIENT_LIMIT = 3;\nexport const FREE_INVOICE_MONTHLY_LIMIT = 5;\nexport const UPGRADE_URL = 'https://cli-invoice.dev/pro';\nexport const PRO_PRICE = '$8/month';\n\n// ---------------------------------------------------------------------------\n// Embedded public key for license verification\n// ---------------------------------------------------------------------------\n\n/**\n * Production Ed25519 public key for verifying license key signatures.\n * The corresponding private key is stored offline and NEVER shipped\n * in the binary. Only the public key is needed for verification.\n */\nconst EMBEDDED_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAaTSk6e9jU9ASnDDNPIxFnmULgKwQgFC+Z6l23JwNyoo=\n-----END PUBLIC KEY-----`;\n\n/**\n * Get the embedded public key for license verification.\n */\nexport function getEmbeddedPublicKey(): string {\n return EMBEDDED_PUBLIC_KEY;\n}\n\n// ---------------------------------------------------------------------------\n// License key payload\n// ---------------------------------------------------------------------------\n\nexport interface LicensePayload {\n email: string;\n plan: 'pro';\n issued_at: string; // ISO date YYYY-MM-DD\n expires_at: string; // ISO date YYYY-MM-DD\n}\n\n// ---------------------------------------------------------------------------\n// Freemium enforcement\n// ---------------------------------------------------------------------------\n\n/**\n * Get the license status from config.\n * Returns 'pro' if a valid license key is present, 'free' otherwise.\n */\nexport function getLicenseStatus(config: Config): LicenseStatus {\n const key = config.license?.key;\n if (!key) return 'free';\n\n try {\n const payload = validateLicenseKey(key);\n if (payload.plan === 'pro') return 'pro';\n return 'free';\n } catch {\n return 'free';\n }\n}\n\n/**\n * Check whether the client limit has been reached for free tier.\n * Throws with an upgrade message if the limit is exceeded.\n *\n * @param clientCount Current number of clients\n * @param licenseStatus Current license status\n */\nexport function checkClientLimit(clientCount: number, licenseStatus: LicenseStatus): void {\n if (licenseStatus === 'pro') return;\n\n if (clientCount >= FREE_CLIENT_LIMIT) {\n const message = formatUpgradeMessage('clients', FREE_CLIENT_LIMIT);\n throw new FreemiumLimitError(message);\n }\n}\n\n/**\n * Check whether the monthly invoice limit has been reached for free tier.\n * Counts invoices created in the current calendar month.\n *\n * @param monthlyInvoiceCount Number of invoices created this month\n * @param licenseStatus Current license status\n */\nexport function checkInvoiceLimit(monthlyInvoiceCount: number, licenseStatus: LicenseStatus): void {\n if (licenseStatus === 'pro') return;\n\n if (monthlyInvoiceCount >= FREE_INVOICE_MONTHLY_LIMIT) {\n const message = formatUpgradeMessage('invoices this month', FREE_INVOICE_MONTHLY_LIMIT);\n throw new FreemiumLimitError(message);\n }\n}\n\n/**\n * Count how many invoices were created in the current calendar month.\n */\nexport function countInvoicesThisMonth(invoices: Array<{ created_at: string }>): number {\n const now = new Date();\n const currentYear = now.getFullYear();\n const currentMonth = now.getMonth(); // 0-based\n\n return invoices.filter((inv) => {\n const d = new Date(inv.created_at);\n return d.getFullYear() === currentYear && d.getMonth() === currentMonth;\n }).length;\n}\n\n// ---------------------------------------------------------------------------\n// Upgrade message\n// ---------------------------------------------------------------------------\n\n/**\n * Format the upgrade message shown when a free tier limit is hit.\n * Designed to be helpful, not hostile.\n */\nexport function formatUpgradeMessage(resource: string, limit: number): string {\n return (\n `Free tier limit: ${limit} ${resource}. You've reached the maximum.\\n` +\n `\\n` +\n `Upgrade to CLI Invoice Pro (${PRO_PRICE}) for unlimited clients,\\n` +\n `recurring templates, revenue summaries, and more.\\n` +\n `\\n` +\n `Run \\`inv upgrade\\` for details, or visit ${UPGRADE_URL}`\n );\n}\n\n/**\n * Print the upgrade message to stderr and exit.\n * Used by CLI commands that hit the limit.\n */\nexport function printUpgradeMessage(resource: string, limit: number): void {\n console.error('\\n' + formatUpgradeMessage(resource, limit) + '\\n');\n}\n\n// ---------------------------------------------------------------------------\n// License key validation (Ed25519)\n// ---------------------------------------------------------------------------\n\n/**\n * Validate a license key string.\n *\n * Key format: {base64url-payload}.{base64url-signature}\n * Payload is JSON: { email, plan, issued_at, expires_at }\n * Signature is Ed25519 over the raw payload bytes.\n *\n * @throws Error if the key is invalid, corrupted, or expired\n */\nexport function validateLicenseKey(key: string, publicKeyPem?: string): LicensePayload {\n const pubKey = publicKeyPem || getEmbeddedPublicKey();\n\n // Split into payload and signature\n const dotIndex = key.lastIndexOf('.');\n if (dotIndex === -1 || dotIndex === 0 || dotIndex === key.length - 1) {\n throw new LicenseValidationError('Invalid license key format.');\n }\n\n const payloadB64 = key.substring(0, dotIndex);\n const signatureB64 = key.substring(dotIndex + 1);\n\n // Decode payload\n let payloadJson: string;\n try {\n payloadJson = Buffer.from(payloadB64, 'base64url').toString('utf-8');\n } catch {\n throw new LicenseValidationError('Invalid license key: could not decode payload.');\n }\n\n // Decode signature\n let signatureBuffer: Buffer;\n try {\n signatureBuffer = Buffer.from(signatureB64, 'base64url');\n } catch {\n throw new LicenseValidationError('Invalid license key: could not decode signature.');\n }\n\n // Verify Ed25519 signature\n const payloadBytes = Buffer.from(payloadB64, 'utf-8');\n let valid: boolean;\n try {\n valid = crypto.verify(\n null, // Ed25519 does not use a separate hash algorithm\n payloadBytes,\n pubKey,\n signatureBuffer,\n );\n } catch {\n throw new LicenseValidationError('Invalid license key: signature verification failed.');\n }\n\n if (!valid) {\n throw new LicenseValidationError('Invalid license key: signature does not match.');\n }\n\n // Parse payload JSON\n let payload: LicensePayload;\n try {\n payload = JSON.parse(payloadJson) as LicensePayload;\n } catch {\n throw new LicenseValidationError('Invalid license key: malformed payload.');\n }\n\n // Validate payload fields\n if (!payload.email || !payload.plan || !payload.issued_at || !payload.expires_at) {\n throw new LicenseValidationError('Invalid license key: missing required fields.');\n }\n\n if (payload.plan !== 'pro') {\n throw new LicenseValidationError(`Invalid license key: unknown plan \"${payload.plan}\".`);\n }\n\n // Check expiration\n const expiresAt = new Date(payload.expires_at);\n const now = new Date();\n now.setHours(0, 0, 0, 0);\n\n if (expiresAt < now) {\n throw new LicenseValidationError(\n `License key expired on ${payload.expires_at}. ` +\n `Visit ${UPGRADE_URL} to renew.`,\n );\n }\n\n return payload;\n}\n\n// ---------------------------------------------------------------------------\n// Custom error classes\n// ---------------------------------------------------------------------------\n\nexport class FreemiumLimitError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'FreemiumLimitError';\n }\n}\n\nexport class LicenseValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'LicenseValidationError';\n }\n}\n","/**\n * Client CRUD business logic.\n */\n\nimport * as crypto from 'crypto';\nimport { getClientsPath, getInvoicesPath } from '../storage/paths.js';\nimport { readStore, writeStore } from '../storage/store.js';\nimport { isValidEmail, isNonEmpty } from '../utils/validate.js';\nimport type { Client, ClientStore, InvoiceStore } from '../types.js';\nimport { nowISO } from '../utils/date.js';\nimport { checkClientLimit, getLicenseStatus } from './license.js';\nimport { loadConfig } from './config.js';\n\n/** Read all clients from disk */\nexport function getClients(): Client[] {\n const store = readStore<ClientStore>(getClientsPath(), { clients: [] });\n return store.clients;\n}\n\n/** Save the full client list to disk */\nfunction saveClients(clients: Client[]): void {\n writeStore<ClientStore>(getClientsPath(), { clients });\n}\n\n/** Input data for adding a new client */\nexport interface AddClientInput {\n name: string;\n email: string;\n address?: string;\n payment_terms?: number;\n}\n\n/**\n * Add a new client.\n * Validates inputs, checks for duplicate name, generates UUID, saves.\n */\nexport function addClient(input: AddClientInput): Client {\n // Validate required fields\n if (!isNonEmpty(input.name)) {\n throw new Error('Client name is required.');\n }\n if (!isNonEmpty(input.email)) {\n throw new Error('Client email is required.');\n }\n const trimmedEmail = input.email.trim();\n if (!isValidEmail(trimmedEmail)) {\n throw new Error(`Invalid email format: \"${trimmedEmail}\".`);\n }\n\n const clients = getClients();\n\n // Freemium limit check\n const config = loadConfig();\n const licenseStatus = getLicenseStatus(config);\n checkClientLimit(clients.length, licenseStatus);\n\n // Check for duplicate name (case-insensitive)\n const existing = clients.find(\n (c) => c.name.toLowerCase() === input.name.trim().toLowerCase(),\n );\n if (existing) {\n throw new Error(`A client named \"${existing.name}\" already exists.`);\n }\n\n const now = nowISO();\n const client: Client = {\n id: crypto.randomUUID(),\n name: input.name.trim(),\n email: input.email.trim(),\n address: input.address?.trim() ?? '',\n payment_terms: input.payment_terms ?? 30,\n created_at: now,\n updated_at: now,\n };\n\n clients.push(client);\n saveClients(clients);\n\n return client;\n}\n\n/** List all clients with invoice counts and totals */\nexport function listClients(): Array<Client & { invoice_count: number; total_billed: number }> {\n const clients = getClients();\n const invoiceStore = readStore<InvoiceStore>(getInvoicesPath(), { invoices: [] });\n\n return clients.map((client) => {\n const clientInvoices = invoiceStore.invoices.filter((inv) => inv.client_id === client.id);\n const totalBilled = clientInvoices.reduce((sum, inv) => sum + inv.total, 0);\n return {\n ...client,\n invoice_count: clientInvoices.length,\n total_billed: totalBilled,\n };\n });\n}\n\n/** Input data for editing a client */\nexport interface EditClientInput {\n email?: string;\n address?: string;\n payment_terms?: number;\n name?: string;\n}\n\n/**\n * Edit a client found by name (case-insensitive).\n * Only updates the fields provided in the updates object.\n */\nexport function editClient(name: string, updates: EditClientInput): Client {\n const clients = getClients();\n\n const index = clients.findIndex(\n (c) => c.name.toLowerCase() === name.toLowerCase(),\n );\n if (index === -1) {\n throw new Error(`Client not found: \"${name}\".`);\n }\n\n const client = clients[index]!;\n\n // Validate email if provided\n if (updates.email !== undefined) {\n if (!isValidEmail(updates.email)) {\n throw new Error(`Invalid email format: \"${updates.email}\".`);\n }\n client.email = updates.email.trim();\n }\n\n if (updates.address !== undefined) {\n client.address = updates.address.trim();\n }\n\n if (updates.payment_terms !== undefined) {\n if (updates.payment_terms <= 0 || !Number.isInteger(updates.payment_terms)) {\n throw new Error('Payment terms must be a positive integer.');\n }\n client.payment_terms = updates.payment_terms;\n }\n\n if (updates.name !== undefined) {\n if (!isNonEmpty(updates.name)) {\n throw new Error('Client name cannot be empty.');\n }\n // Check for name conflicts\n const conflict = clients.find(\n (c, i) => i !== index && c.name.toLowerCase() === updates.name!.toLowerCase(),\n );\n if (conflict) {\n throw new Error(`A client named \"${conflict.name}\" already exists.`);\n }\n client.name = updates.name.trim();\n }\n\n client.updated_at = nowISO();\n clients[index] = client;\n saveClients(clients);\n\n return client;\n}\n\n/**\n * Remove a client by name (case-insensitive).\n * Returns the removed client and whether it had associated invoices.\n */\nexport function removeClient(name: string): { client: Client; hadInvoices: boolean; invoiceCount: number } {\n const clients = getClients();\n\n const index = clients.findIndex(\n (c) => c.name.toLowerCase() === name.toLowerCase(),\n );\n if (index === -1) {\n throw new Error(`Client not found: \"${name}\".`);\n }\n\n const client = clients[index]!;\n\n // Check for associated invoices\n const invoiceStore = readStore<InvoiceStore>(getInvoicesPath(), { invoices: [] });\n const clientInvoices = invoiceStore.invoices.filter((inv) => inv.client_id === client.id);\n\n clients.splice(index, 1);\n saveClients(clients);\n\n return {\n client,\n hadInvoices: clientInvoices.length > 0,\n invoiceCount: clientInvoices.length,\n };\n}\n\n/** Find a client by name (case-insensitive) */\nexport function findClientByName(name: string): Client | undefined {\n const clients = getClients();\n return clients.find(\n (c) => c.name.toLowerCase() === name.toLowerCase(),\n );\n}\n","/**\n * Currency formatting helpers.\n */\n\n/** Format a number as currency using Intl.NumberFormat */\nexport function formatCurrency(amount: number, currency: string = 'USD'): string {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }).format(amount);\n}\n","/**\n * Invoice CRUD business logic — create, list, show, edit, delete,\n * status transitions, and revenue summary.\n */\n\nimport * as crypto from 'crypto';\nimport * as fs from 'fs';\nimport { getInvoicesPath, getCounterPath } from '../storage/paths.js';\nimport { readStore, writeStore } from '../storage/store.js';\nimport { findClientByName, getClients } from './client.js';\nimport { loadConfig } from './config.js';\nimport { checkInvoiceLimit, countInvoicesThisMonth, getLicenseStatus } from './license.js';\nimport { today, nowISO, addDays, isPast } from '../utils/date.js';\nimport type { Invoice, InvoiceStore, Counter, LineItem } from '../types.js';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Read all invoices from disk */\nfunction readInvoices(): Invoice[] {\n const store = readStore<InvoiceStore>(getInvoicesPath(), { invoices: [] });\n return store.invoices;\n}\n\n/** Save the full invoice list to disk */\nfunction saveInvoices(invoices: Invoice[]): void {\n writeStore<InvoiceStore>(getInvoicesPath(), { invoices });\n}\n\n/** Read the counter from disk */\nfunction readCounter(): Counter {\n return readStore<Counter>(getCounterPath(), { next_invoice_number: 1 });\n}\n\n/** Save the counter to disk */\nfunction saveCounter(counter: Counter): void {\n writeStore<Counter>(getCounterPath(), counter);\n}\n\n/**\n * Allocate the next invoice number.\n * Reads the counter, formats the number, increments, and saves.\n */\nfunction allocateInvoiceNumber(): string {\n const config = loadConfig();\n const counter = readCounter();\n const num = counter.next_invoice_number;\n const prefix = config.invoice.number_prefix || 'INV';\n const formatted = `${prefix}-${String(num).padStart(4, '0')}`;\n counter.next_invoice_number = num + 1;\n saveCounter(counter);\n return formatted;\n}\n\n/**\n * Compute the display status of an invoice.\n * Overdue is computed at read time: status === \"sent\" && due_date < today.\n */\nexport function computeDisplayStatus(inv: Invoice): 'draft' | 'sent' | 'paid' | 'overdue' {\n if (inv.status === 'sent' && isPast(inv.due_date)) {\n return 'overdue';\n }\n return inv.status;\n}\n\n/**\n * Round a number to 2 decimal places (for monetary values).\n */\nfunction round2(n: number): number {\n return Math.round(n * 100) / 100;\n}\n\n// ---------------------------------------------------------------------------\n// Create\n// ---------------------------------------------------------------------------\n\nexport interface CreateInvoiceInput {\n clientName: string;\n items: LineItem[];\n date?: string; // YYYY-MM-DD, defaults to today\n notes?: string;\n taxRate?: number; // percentage, defaults to config.defaults.tax_rate\n currency?: string; // ISO 4217, defaults to config.defaults.currency\n}\n\n/**\n * Create a new invoice.\n *\n * - Resolves client by name (case-insensitive)\n * - Snapshots client info at creation time\n * - Calculates subtotal, tax, total\n * - Auto-increments invoice number from counter.json\n */\nexport function createInvoice(input: CreateInvoiceInput): Invoice {\n // Validate client exists\n const client = findClientByName(input.clientName);\n if (!client) {\n throw new Error(`Client not found: \"${input.clientName}\". Run \\`inv client list\\` to see existing clients.`);\n }\n\n // Validate items\n if (!input.items || input.items.length === 0) {\n throw new Error('At least one line item is required.');\n }\n\n for (let i = 0; i < input.items.length; i++) {\n const item = input.items[i]!;\n if (!item.description || item.description.trim().length === 0) {\n throw new Error(`Line item ${i + 1}: description is required.`);\n }\n if (typeof item.quantity !== 'number' || item.quantity <= 0) {\n throw new Error(`Line item ${i + 1}: quantity must be > 0.`);\n }\n if (typeof item.unit_price !== 'number' || item.unit_price < 0) {\n throw new Error(`Line item ${i + 1}: unit_price must be >= 0.`);\n }\n }\n\n // Freemium limit check\n const existingInvoices = readInvoices();\n const config = loadConfig();\n const licenseStatus = getLicenseStatus(config);\n const monthlyCount = countInvoicesThisMonth(existingInvoices);\n checkInvoiceLimit(monthlyCount, licenseStatus);\n\n const invoiceDate = input.date || today();\n const taxRate = input.taxRate ?? config.defaults.tax_rate;\n const currency = input.currency || config.defaults.currency;\n const paymentTerms = client.payment_terms;\n const dueDate = addDays(invoiceDate, paymentTerms);\n\n // Calculate totals\n const subtotal = round2(\n input.items.reduce((sum, item) => sum + item.quantity * item.unit_price, 0),\n );\n const taxAmount = round2(subtotal * (taxRate / 100));\n const total = round2(subtotal + taxAmount);\n\n const now = nowISO();\n const invoiceNumber = allocateInvoiceNumber();\n\n const invoice: Invoice = {\n id: crypto.randomUUID(),\n number: invoiceNumber,\n client_id: client.id,\n client_snapshot: {\n name: client.name,\n email: client.email,\n address: client.address,\n },\n status: 'draft',\n items: input.items.map((item) => ({\n description: item.description.trim(),\n quantity: item.quantity,\n unit_price: item.unit_price,\n })),\n currency,\n tax_rate: taxRate,\n subtotal,\n tax_amount: taxAmount,\n total,\n date: invoiceDate,\n due_date: dueDate,\n paid_date: null,\n notes: input.notes?.trim() ?? '',\n created_at: now,\n updated_at: now,\n };\n\n existingInvoices.push(invoice);\n saveInvoices(existingInvoices);\n\n return invoice;\n}\n\n// ---------------------------------------------------------------------------\n// List\n// ---------------------------------------------------------------------------\n\nexport type InvoiceStatusFilter = 'draft' | 'sent' | 'paid' | 'overdue';\n\nexport interface ListInvoicesFilter {\n status?: InvoiceStatusFilter;\n clientName?: string;\n}\n\n/**\n * List invoices, optionally filtered by display status or client name.\n * Computes overdue at read time.\n */\nexport function listInvoices(filter?: ListInvoicesFilter): (Invoice & { display_status: string })[] {\n let invoices = readInvoices();\n\n // Compute display status and attach it\n let results = invoices.map((inv) => ({\n ...inv,\n display_status: computeDisplayStatus(inv),\n }));\n\n // Filter by status (including overdue)\n if (filter?.status) {\n results = results.filter((inv) => inv.display_status === filter.status);\n }\n\n // Filter by client name (case-insensitive)\n if (filter?.clientName) {\n const lowerName = filter.clientName.toLowerCase();\n results = results.filter(\n (inv) => inv.client_snapshot.name.toLowerCase().includes(lowerName),\n );\n }\n\n return results;\n}\n\n// ---------------------------------------------------------------------------\n// Get\n// ---------------------------------------------------------------------------\n\n/**\n * Look up an invoice by UUID or invoice number (e.g. INV-0001).\n */\nexport function getInvoice(idOrNumber: string): Invoice | undefined {\n const invoices = readInvoices();\n return invoices.find(\n (inv) =>\n inv.id === idOrNumber ||\n inv.number.toLowerCase() === idOrNumber.toLowerCase(),\n );\n}\n\n// ---------------------------------------------------------------------------\n// Edit\n// ---------------------------------------------------------------------------\n\nexport interface EditInvoiceInput {\n notes?: string;\n date?: string;\n taxRate?: number;\n currency?: string;\n}\n\n/**\n * Edit a draft invoice. Only drafts can be edited.\n * Updates recalculate totals if tax_rate changes.\n */\nexport function editInvoice(idOrNumber: string, updates: EditInvoiceInput): Invoice {\n const invoices = readInvoices();\n const index = invoices.findIndex(\n (inv) =>\n inv.id === idOrNumber ||\n inv.number.toLowerCase() === idOrNumber.toLowerCase(),\n );\n\n if (index === -1) {\n throw new Error(`Invoice not found: \"${idOrNumber}\".`);\n }\n\n const invoice = invoices[index]!;\n\n if (invoice.status !== 'draft') {\n throw new Error(\n `Cannot edit invoice ${invoice.number}: status is \"${invoice.status}\". Only draft invoices can be edited.`,\n );\n }\n\n if (updates.notes !== undefined) {\n invoice.notes = updates.notes.trim();\n }\n\n if (updates.date !== undefined) {\n invoice.date = updates.date;\n // Recalculate due date based on client payment terms\n const clients = getClients();\n const client = clients.find((c) => c.id === invoice.client_id);\n const terms = client?.payment_terms ?? 30;\n invoice.due_date = addDays(updates.date, terms);\n }\n\n if (updates.currency !== undefined) {\n invoice.currency = updates.currency;\n }\n\n if (updates.taxRate !== undefined) {\n invoice.tax_rate = updates.taxRate;\n invoice.tax_amount = round2(invoice.subtotal * (updates.taxRate / 100));\n invoice.total = round2(invoice.subtotal + invoice.tax_amount);\n }\n\n invoice.updated_at = nowISO();\n invoices[index] = invoice;\n saveInvoices(invoices);\n\n return invoice;\n}\n\n// ---------------------------------------------------------------------------\n// Delete\n// ---------------------------------------------------------------------------\n\n/**\n * Delete a draft invoice. Only drafts can be deleted.\n */\nexport function deleteInvoice(idOrNumber: string): Invoice {\n const invoices = readInvoices();\n const index = invoices.findIndex(\n (inv) =>\n inv.id === idOrNumber ||\n inv.number.toLowerCase() === idOrNumber.toLowerCase(),\n );\n\n if (index === -1) {\n throw new Error(`Invoice not found: \"${idOrNumber}\".`);\n }\n\n const invoice = invoices[index]!;\n\n if (invoice.status !== 'draft') {\n throw new Error(\n `Cannot delete invoice ${invoice.number}: status is \"${invoice.status}\". Only draft invoices can be deleted.`,\n );\n }\n\n invoices.splice(index, 1);\n saveInvoices(invoices);\n\n return invoice;\n}\n\n// ---------------------------------------------------------------------------\n// Status Transitions\n// ---------------------------------------------------------------------------\n\nconst VALID_TRANSITIONS: Record<string, string[]> = {\n draft: ['sent'],\n sent: ['paid'],\n paid: [],\n};\n\n/**\n * Update invoice status. Transitions are one-directional:\n * draft -> sent -> paid\n */\nexport function updateStatus(\n idOrNumber: string,\n newStatus: 'sent' | 'paid',\n paidDate?: string,\n): Invoice {\n const invoices = readInvoices();\n const index = invoices.findIndex(\n (inv) =>\n inv.id === idOrNumber ||\n inv.number.toLowerCase() === idOrNumber.toLowerCase(),\n );\n\n if (index === -1) {\n throw new Error(`Invoice not found: \"${idOrNumber}\".`);\n }\n\n const invoice = invoices[index]!;\n const allowed = VALID_TRANSITIONS[invoice.status] ?? [];\n\n if (!allowed.includes(newStatus)) {\n throw new Error(\n `Cannot transition invoice ${invoice.number} from \"${invoice.status}\" to \"${newStatus}\". ` +\n `Allowed transitions from \"${invoice.status}\": ${allowed.length > 0 ? allowed.join(', ') : 'none'}.`,\n );\n }\n\n invoice.status = newStatus;\n invoice.updated_at = nowISO();\n\n if (newStatus === 'paid') {\n invoice.paid_date = paidDate || today();\n }\n\n invoices[index] = invoice;\n saveInvoices(invoices);\n\n return invoice;\n}\n\n// ---------------------------------------------------------------------------\n// Summary\n// ---------------------------------------------------------------------------\n\nexport interface MonthlySummary {\n month: string; // YYYY-MM\n invoiced: number;\n paid: number;\n outstanding: number;\n count: number;\n}\n\nexport interface RevenueSummary {\n year: number;\n total_invoiced: number;\n total_paid: number;\n total_outstanding: number;\n invoice_count: number;\n months: MonthlySummary[];\n}\n\n/**\n * Generate a revenue summary for a given year (defaults to current year).\n */\nexport function getSummary(year?: number): RevenueSummary {\n const targetYear = year ?? new Date().getFullYear();\n const invoices = readInvoices();\n\n // Filter to the target year based on invoice date\n const yearInvoices = invoices.filter((inv) => {\n const invYear = parseInt(inv.date.split('-')[0]!, 10);\n return invYear === targetYear;\n });\n\n // Build monthly breakdown\n const monthMap = new Map<string, MonthlySummary>();\n\n for (const inv of yearInvoices) {\n const monthKey = inv.date.substring(0, 7); // YYYY-MM\n let entry = monthMap.get(monthKey);\n if (!entry) {\n entry = { month: monthKey, invoiced: 0, paid: 0, outstanding: 0, count: 0 };\n monthMap.set(monthKey, entry);\n }\n entry.invoiced = round2(entry.invoiced + inv.total);\n entry.count += 1;\n\n if (inv.status === 'paid') {\n entry.paid = round2(entry.paid + inv.total);\n } else {\n entry.outstanding = round2(entry.outstanding + inv.total);\n }\n }\n\n // Sort months chronologically\n const months = Array.from(monthMap.values()).sort((a, b) =>\n a.month.localeCompare(b.month),\n );\n\n const total_invoiced = round2(months.reduce((s, m) => s + m.invoiced, 0));\n const total_paid = round2(months.reduce((s, m) => s + m.paid, 0));\n const total_outstanding = round2(months.reduce((s, m) => s + m.outstanding, 0));\n const invoice_count = months.reduce((s, m) => s + m.count, 0);\n\n return {\n year: targetYear,\n total_invoiced,\n total_paid,\n total_outstanding,\n invoice_count,\n months,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Line Item Parsing (from file)\n// ---------------------------------------------------------------------------\n\n/**\n * Parse line items from a JSON file.\n * Expected format: array of { description, quantity, unit_price }\n */\nexport function parseLineItemsFromFile(filePath: string): LineItem[] {\n if (!fs.existsSync(filePath)) {\n throw new Error(`File not found: \"${filePath}\".`);\n }\n\n let raw: string;\n try {\n raw = fs.readFileSync(filePath, 'utf-8');\n } catch {\n throw new Error(`Could not read file: \"${filePath}\".`);\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(`Invalid JSON in file: \"${filePath}\".`);\n }\n\n if (!Array.isArray(parsed)) {\n throw new Error(`File must contain a JSON array of line items. Got ${typeof parsed}.`);\n }\n\n if (parsed.length === 0) {\n throw new Error('File contains an empty array. At least one line item is required.');\n }\n\n const items: LineItem[] = [];\n for (let i = 0; i < parsed.length; i++) {\n const entry = parsed[i] as Record<string, unknown>;\n if (!entry || typeof entry !== 'object') {\n throw new Error(`Line item ${i + 1}: must be an object with description, quantity, unit_price.`);\n }\n\n const description = entry.description;\n const quantity = entry.quantity;\n const unit_price = entry.unit_price;\n\n if (typeof description !== 'string' || description.trim().length === 0) {\n throw new Error(`Line item ${i + 1}: \"description\" is required and must be a non-empty string.`);\n }\n if (typeof quantity !== 'number' || quantity <= 0) {\n throw new Error(`Line item ${i + 1}: \"quantity\" must be a number > 0.`);\n }\n if (typeof unit_price !== 'number' || unit_price < 0) {\n throw new Error(`Line item ${i + 1}: \"unit_price\" must be a number >= 0.`);\n }\n\n items.push({\n description: description.trim(),\n quantity,\n unit_price,\n });\n }\n\n return items;\n}\n","/**\n * Default PDF template — layout constants, column positions, colors, and\n * styling helpers for the invoice PDF.\n *\n * All dimensions are in PDF points (1 point = 1/72 inch).\n * Page size: US Letter (612 x 792 points).\n */\n\n// ---------------------------------------------------------------------------\n// Page\n// ---------------------------------------------------------------------------\n\nexport const PAGE = {\n width: 612,\n height: 792,\n} as const;\n\nexport const MARGIN = {\n top: 50,\n bottom: 50,\n left: 50,\n right: 50,\n} as const;\n\n/** Usable content width inside margins */\nexport const CONTENT_WIDTH = PAGE.width - MARGIN.left - MARGIN.right; // 512\n\n// ---------------------------------------------------------------------------\n// Fonts\n// ---------------------------------------------------------------------------\n\nexport const FONT = {\n heading: 'Helvetica-Bold' as const,\n body: 'Helvetica' as const,\n bodyBold: 'Helvetica-Bold' as const,\n};\n\nexport const FONT_SIZE = {\n title: 28,\n sectionHeading: 11,\n body: 10,\n small: 8,\n tableHeader: 9,\n tableBody: 9,\n totalLabel: 10,\n totalValue: 10,\n grandTotal: 12,\n footer: 9,\n} as const;\n\n// ---------------------------------------------------------------------------\n// Colors\n// ---------------------------------------------------------------------------\n\nexport const COLOR = {\n primary: '#333333',\n secondary: '#666666',\n accent: '#2563EB', // blue-600\n border: '#D1D5DB', // gray-300\n tableHeaderBg: '#F3F4F6', // gray-100\n tableHeaderText: '#374151', // gray-700\n white: '#FFFFFF',\n lightGray: '#F9FAFB', // gray-50\n} as const;\n\n// ---------------------------------------------------------------------------\n// Spacing\n// ---------------------------------------------------------------------------\n\nexport const SPACING = {\n sectionGap: 20,\n lineHeight: 14,\n tableRowHeight: 22,\n tableHeaderHeight: 24,\n afterTitle: 4,\n beforeTable: 12,\n afterTable: 8,\n} as const;\n\n// ---------------------------------------------------------------------------\n// Line Items Table — column positions (x offsets relative to left margin)\n// ---------------------------------------------------------------------------\n\nexport const TABLE = {\n /** Column definitions: x-offset from left margin and width */\n columns: {\n description: { x: 0, width: 272 },\n quantity: { x: 272, width: 60 },\n rate: { x: 332, width: 90 },\n amount: { x: 422, width: 90 },\n },\n /** Total width (should equal CONTENT_WIDTH) */\n totalWidth: CONTENT_WIDTH,\n} as const;\n\n// ---------------------------------------------------------------------------\n// Helper: alignment offsets\n// ---------------------------------------------------------------------------\n\n/**\n * Compute the x position for right-aligned text within a column.\n * Call this with the text width to get the x coordinate.\n */\nexport function rightAlignX(columnX: number, columnWidth: number): number {\n return MARGIN.left + columnX + columnWidth;\n}\n\n// ---------------------------------------------------------------------------\n// Totals section — positioned right-aligned\n// ---------------------------------------------------------------------------\n\nexport const TOTALS = {\n labelWidth: 100,\n valueWidth: 100,\n /** x start of the totals block (right-aligned on the page) */\n x: MARGIN.left + CONTENT_WIDTH - 100 - 100, // 312\n};\n\n// ---------------------------------------------------------------------------\n// Consolidated template export\n// ---------------------------------------------------------------------------\n\nexport const defaultTemplate = {\n page: PAGE,\n margin: MARGIN,\n contentWidth: CONTENT_WIDTH,\n font: FONT,\n fontSize: FONT_SIZE,\n color: COLOR,\n spacing: SPACING,\n table: TABLE,\n totals: TOTALS,\n};\n","/**\n * PDF generation — renders an Invoice + Config into a professional PDF buffer.\n *\n * Uses PDFKit with built-in Helvetica font (no custom font files).\n * Page size: US Letter (612 x 792 points).\n */\n\nimport * as fs from 'fs';\nimport { PassThrough } from 'stream';\nimport type { Invoice, Config } from '../types.js';\nimport { formatCurrency } from '../utils/currency.js';\nimport {\n PAGE,\n MARGIN,\n CONTENT_WIDTH,\n FONT,\n FONT_SIZE,\n COLOR,\n SPACING,\n TABLE,\n TOTALS,\n} from '../templates/default.js';\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Generate a complete PDF invoice and return it as a Buffer.\n *\n * PDFKit is loaded lazily so it only impacts startup time when actually\n * generating a PDF.\n */\nexport interface GeneratePDFOptions {\n /** Disable stream compression (useful for testing — makes text searchable in raw buffer) */\n compress?: boolean;\n}\n\nexport async function generatePDF(invoice: Invoice, config: Config, options?: GeneratePDFOptions): Promise<Buffer> {\n // Lazy-load PDFKit (heavy dependency)\n const pdfkit = await import('pdfkit');\n const PDFDocument = pdfkit.default as unknown as new (options?: PDFKit.PDFDocumentOptions) => PDFKit.PDFDocument;\n\n const doc = new PDFDocument({\n size: 'LETTER',\n compress: options?.compress ?? true,\n margins: {\n top: MARGIN.top,\n bottom: MARGIN.bottom,\n left: MARGIN.left,\n right: MARGIN.right,\n },\n info: {\n Title: `Invoice ${invoice.number}`,\n Author: config.sender.name || config.sender.business_name || 'CLI Invoice',\n Subject: `Invoice for ${invoice.client_snapshot.name}`,\n Creator: 'CLI Invoice',\n },\n autoFirstPage: true,\n bufferPages: true,\n });\n\n // Collect PDF output into a buffer\n const bufferPromise = collectBuffer(doc);\n\n // --- Render the invoice ---\n let y: number = MARGIN.top;\n\n y = renderHeader(doc, invoice, config, y);\n y += SPACING.sectionGap;\n\n y = renderSenderAndMeta(doc, invoice, config, y);\n y += SPACING.sectionGap;\n\n y = renderBillTo(doc, invoice, y);\n y += SPACING.sectionGap;\n\n y = renderLineItemsTable(doc, invoice, y);\n y += SPACING.afterTable;\n\n y = renderTotals(doc, invoice, y);\n y += SPACING.sectionGap;\n\n if (invoice.notes && invoice.notes.trim().length > 0) {\n y = renderNotes(doc, invoice, y);\n y += SPACING.sectionGap;\n }\n\n renderFooter(doc);\n\n // Finalize the PDF\n doc.end();\n\n return bufferPromise;\n}\n\n// ---------------------------------------------------------------------------\n// Buffer collection\n// ---------------------------------------------------------------------------\n\nfunction collectBuffer(doc: PDFKit.PDFDocument): Promise<Buffer> {\n return new Promise<Buffer>((resolve, reject) => {\n const passThrough = new PassThrough();\n const chunks: Buffer[] = [];\n\n passThrough.on('data', (chunk: Buffer) => chunks.push(chunk));\n passThrough.on('end', () => resolve(Buffer.concat(chunks)));\n passThrough.on('error', reject);\n\n doc.pipe(passThrough);\n });\n}\n\n// ---------------------------------------------------------------------------\n// Header: Logo + \"INVOICE\" title\n// ---------------------------------------------------------------------------\n\nfunction renderHeader(\n doc: PDFKit.PDFDocument,\n _invoice: Invoice,\n config: Config,\n y: number,\n): number {\n let logoEndX = MARGIN.left;\n\n // Optional logo\n if (config.sender.logo && config.sender.logo.trim().length > 0) {\n try {\n if (fs.existsSync(config.sender.logo)) {\n doc.image(config.sender.logo, MARGIN.left, y, {\n height: 50,\n });\n logoEndX = MARGIN.left + 60; // Reserve space to the right of logo\n }\n } catch {\n // Logo failed to load — continue without it\n }\n }\n\n // \"INVOICE\" title — right-aligned\n doc\n .font(FONT.heading)\n .fontSize(FONT_SIZE.title)\n .fillColor(COLOR.accent)\n .text('INVOICE', logoEndX, y, {\n align: 'right',\n width: MARGIN.left + CONTENT_WIDTH - logoEndX,\n });\n\n return y + FONT_SIZE.title + SPACING.afterTitle;\n}\n\n// ---------------------------------------------------------------------------\n// Sender info (left) + Invoice meta (right)\n// ---------------------------------------------------------------------------\n\nfunction renderSenderAndMeta(\n doc: PDFKit.PDFDocument,\n invoice: Invoice,\n config: Config,\n startY: number,\n): number {\n const halfWidth = CONTENT_WIDTH / 2;\n let leftY = startY;\n let rightY = startY;\n\n // --- Left: Sender info ---\n const sender = config.sender;\n\n if (sender.business_name) {\n doc.font(FONT.bodyBold).fontSize(FONT_SIZE.sectionHeading).fillColor(COLOR.primary);\n doc.text(sender.business_name, MARGIN.left, leftY, { width: halfWidth });\n leftY += SPACING.lineHeight;\n }\n\n if (sender.name && sender.name !== sender.business_name) {\n doc.font(FONT.body).fontSize(FONT_SIZE.body).fillColor(COLOR.primary);\n doc.text(sender.name, MARGIN.left, leftY, { width: halfWidth });\n leftY += SPACING.lineHeight;\n }\n\n if (sender.email) {\n doc.font(FONT.body).fontSize(FONT_SIZE.body).fillColor(COLOR.secondary);\n doc.text(sender.email, MARGIN.left, leftY, { width: halfWidth });\n leftY += SPACING.lineHeight;\n }\n\n if (sender.address) {\n const lines = sender.address.split(/\\\\n|\\n/);\n for (const line of lines) {\n if (line.trim()) {\n doc.font(FONT.body).fontSize(FONT_SIZE.body).fillColor(COLOR.secondary);\n doc.text(line.trim(), MARGIN.left, leftY, { width: halfWidth });\n leftY += SPACING.lineHeight;\n }\n }\n }\n\n // --- Right: Invoice meta ---\n const rightX = MARGIN.left + halfWidth;\n const labelWidth = 60;\n const valueWidth = halfWidth - labelWidth;\n\n const metaLines: Array<{ label: string; value: string }> = [\n { label: 'Invoice:', value: invoice.number },\n { label: 'Date:', value: invoice.date },\n { label: 'Due:', value: invoice.due_date },\n ];\n if (invoice.status === 'paid' && invoice.paid_date) {\n metaLines.push({ label: 'Paid:', value: invoice.paid_date });\n }\n\n for (const meta of metaLines) {\n doc.font(FONT.bodyBold).fontSize(FONT_SIZE.body).fillColor(COLOR.secondary);\n doc.text(meta.label, rightX, rightY, { width: labelWidth });\n\n doc.font(FONT.body).fontSize(FONT_SIZE.body).fillColor(COLOR.primary);\n doc.text(meta.value, rightX + labelWidth, rightY, { width: valueWidth });\n rightY += SPACING.lineHeight;\n }\n\n return Math.max(leftY, rightY);\n}\n\n// ---------------------------------------------------------------------------\n// Bill To\n// ---------------------------------------------------------------------------\n\nfunction renderBillTo(\n doc: PDFKit.PDFDocument,\n invoice: Invoice,\n y: number,\n): number {\n const client = invoice.client_snapshot;\n\n doc.font(FONT.bodyBold).fontSize(FONT_SIZE.sectionHeading).fillColor(COLOR.accent);\n doc.text('Bill To', MARGIN.left, y);\n y += SPACING.lineHeight + 2;\n\n doc.font(FONT.bodyBold).fontSize(FONT_SIZE.body).fillColor(COLOR.primary);\n doc.text(client.name, MARGIN.left, y);\n y += SPACING.lineHeight;\n\n if (client.email) {\n doc.font(FONT.body).fontSize(FONT_SIZE.body).fillColor(COLOR.secondary);\n doc.text(client.email, MARGIN.left, y);\n y += SPACING.lineHeight;\n }\n\n if (client.address) {\n const lines = client.address.split(/\\\\n|\\n/);\n for (const line of lines) {\n if (line.trim()) {\n doc.font(FONT.body).fontSize(FONT_SIZE.body).fillColor(COLOR.secondary);\n doc.text(line.trim(), MARGIN.left, y);\n y += SPACING.lineHeight;\n }\n }\n }\n\n return y;\n}\n\n// ---------------------------------------------------------------------------\n// Line Items Table\n// ---------------------------------------------------------------------------\n\nfunction renderLineItemsTable(\n doc: PDFKit.PDFDocument,\n invoice: Invoice,\n y: number,\n): number {\n const cols = TABLE.columns;\n\n // --- Header row background ---\n doc\n .rect(MARGIN.left, y, CONTENT_WIDTH, SPACING.tableHeaderHeight)\n .fill(COLOR.tableHeaderBg);\n\n const headerTextY = y + (SPACING.tableHeaderHeight - FONT_SIZE.tableHeader) / 2;\n\n doc.font(FONT.bodyBold).fontSize(FONT_SIZE.tableHeader).fillColor(COLOR.tableHeaderText);\n\n // Description (left-aligned)\n doc.text('Description', MARGIN.left + cols.description.x + 6, headerTextY, {\n width: cols.description.width - 12,\n });\n\n // Qty (right-aligned)\n doc.text('Qty', MARGIN.left + cols.quantity.x, headerTextY, {\n width: cols.quantity.width - 6,\n align: 'right',\n });\n\n // Rate (right-aligned)\n doc.text('Rate', MARGIN.left + cols.rate.x, headerTextY, {\n width: cols.rate.width - 6,\n align: 'right',\n });\n\n // Amount (right-aligned)\n doc.text('Amount', MARGIN.left + cols.amount.x, headerTextY, {\n width: cols.amount.width - 6,\n align: 'right',\n });\n\n y += SPACING.tableHeaderHeight;\n\n // --- Divider line below header ---\n doc\n .moveTo(MARGIN.left, y)\n .lineTo(MARGIN.left + CONTENT_WIDTH, y)\n .strokeColor(COLOR.border)\n .lineWidth(0.5)\n .stroke();\n\n // --- Data rows ---\n for (let i = 0; i < invoice.items.length; i++) {\n const item = invoice.items[i]!;\n const amount = item.quantity * item.unit_price;\n const rowY = y + (SPACING.tableRowHeight - FONT_SIZE.tableBody) / 2;\n\n // Alternate row background\n if (i % 2 === 1) {\n doc\n .rect(MARGIN.left, y, CONTENT_WIDTH, SPACING.tableRowHeight)\n .fill(COLOR.lightGray);\n }\n\n doc.font(FONT.body).fontSize(FONT_SIZE.tableBody).fillColor(COLOR.primary);\n\n doc.text(item.description, MARGIN.left + cols.description.x + 6, rowY, {\n width: cols.description.width - 12,\n });\n\n doc.text(String(item.quantity), MARGIN.left + cols.quantity.x, rowY, {\n width: cols.quantity.width - 6,\n align: 'right',\n });\n\n doc.text(\n formatCurrency(item.unit_price, invoice.currency),\n MARGIN.left + cols.rate.x,\n rowY,\n { width: cols.rate.width - 6, align: 'right' },\n );\n\n doc.text(\n formatCurrency(amount, invoice.currency),\n MARGIN.left + cols.amount.x,\n rowY,\n { width: cols.amount.width - 6, align: 'right' },\n );\n\n y += SPACING.tableRowHeight;\n }\n\n // --- Bottom divider ---\n doc\n .moveTo(MARGIN.left, y)\n .lineTo(MARGIN.left + CONTENT_WIDTH, y)\n .strokeColor(COLOR.border)\n .lineWidth(0.5)\n .stroke();\n\n return y;\n}\n\n// ---------------------------------------------------------------------------\n// Totals\n// ---------------------------------------------------------------------------\n\nfunction renderTotals(\n doc: PDFKit.PDFDocument,\n invoice: Invoice,\n y: number,\n): number {\n const labelX = TOTALS.x;\n const valueX = labelX + TOTALS.labelWidth;\n const valueWidth = TOTALS.valueWidth;\n\n y += 6;\n\n // Subtotal\n doc.font(FONT.body).fontSize(FONT_SIZE.totalLabel).fillColor(COLOR.secondary);\n doc.text('Subtotal:', labelX, y, { width: TOTALS.labelWidth, align: 'right' });\n doc.font(FONT.body).fontSize(FONT_SIZE.totalValue).fillColor(COLOR.primary);\n doc.text(formatCurrency(invoice.subtotal, invoice.currency), valueX, y, {\n width: valueWidth,\n align: 'right',\n });\n y += SPACING.lineHeight;\n\n // Tax\n const taxLabel = `Tax (${invoice.tax_rate}%):`;\n doc.font(FONT.body).fontSize(FONT_SIZE.totalLabel).fillColor(COLOR.secondary);\n doc.text(taxLabel, labelX, y, { width: TOTALS.labelWidth, align: 'right' });\n doc.font(FONT.body).fontSize(FONT_SIZE.totalValue).fillColor(COLOR.primary);\n doc.text(formatCurrency(invoice.tax_amount, invoice.currency), valueX, y, {\n width: valueWidth,\n align: 'right',\n });\n y += SPACING.lineHeight + 4;\n\n // Divider before grand total\n doc\n .moveTo(labelX, y)\n .lineTo(valueX + valueWidth, y)\n .strokeColor(COLOR.border)\n .lineWidth(0.5)\n .stroke();\n y += 6;\n\n // Grand total\n doc.font(FONT.heading).fontSize(FONT_SIZE.grandTotal).fillColor(COLOR.primary);\n doc.text('Total:', labelX, y, { width: TOTALS.labelWidth, align: 'right' });\n doc.text(formatCurrency(invoice.total, invoice.currency), valueX, y, {\n width: valueWidth,\n align: 'right',\n });\n y += FONT_SIZE.grandTotal + 4;\n\n return y;\n}\n\n// ---------------------------------------------------------------------------\n// Notes\n// ---------------------------------------------------------------------------\n\nfunction renderNotes(\n doc: PDFKit.PDFDocument,\n invoice: Invoice,\n y: number,\n): number {\n doc.font(FONT.bodyBold).fontSize(FONT_SIZE.sectionHeading).fillColor(COLOR.accent);\n doc.text('Notes', MARGIN.left, y);\n y += SPACING.lineHeight;\n\n doc.font(FONT.body).fontSize(FONT_SIZE.body).fillColor(COLOR.secondary);\n doc.text(invoice.notes, MARGIN.left, y, {\n width: CONTENT_WIDTH,\n lineGap: 2,\n });\n y = doc.y;\n\n return y;\n}\n\n// ---------------------------------------------------------------------------\n// Footer\n// ---------------------------------------------------------------------------\n\nfunction renderFooter(doc: PDFKit.PDFDocument): void {\n const footerY = PAGE.height - MARGIN.bottom - FONT_SIZE.footer - 4;\n\n doc\n .moveTo(MARGIN.left, footerY - 6)\n .lineTo(MARGIN.left + CONTENT_WIDTH, footerY - 6)\n .strokeColor(COLOR.border)\n .lineWidth(0.25)\n .stroke();\n\n doc.font(FONT.body).fontSize(FONT_SIZE.footer).fillColor(COLOR.secondary);\n doc.text('Thank you for your business.', MARGIN.left, footerY, {\n width: CONTENT_WIDTH,\n align: 'center',\n });\n}\n","/**\n * CLI Invoice — Entry point\n *\n * Commander.js program setup with lazy imports for fast startup.\n * Only the module needed for the invoked command is loaded.\n */\n\nimport { Command } from 'commander';\n\nconst program = new Command();\n\nprogram\n .name('inv')\n .description('CLI Invoice — Generate professional invoices from the terminal')\n .version('0.1.0');\n\n// Register command groups — each uses lazy imports internally\n// so only the invoked command's dependencies are loaded.\n\n// Config commands: inv init, inv config set/show\nimport { registerInitCommand, registerConfigCommand } from '../src/cli/config.js';\nregisterInitCommand(program);\nregisterConfigCommand(program);\n\n// Client commands: inv client add/list/edit/remove\nimport { registerClientCommand } from '../src/cli/client.js';\nregisterClientCommand(program);\n\n// Invoice commands: inv create/show/edit/delete/list/summary\nimport { registerInvoiceCommands } from '../src/cli/invoice.js';\nregisterInvoiceCommands(program);\n\n// Status command: inv status <id> <status>\nimport { registerStatusCommand } from '../src/cli/status.js';\nregisterStatusCommand(program);\n\n// Export command: inv export <id>\nimport { registerExportCommand } from '../src/cli/export.js';\nregisterExportCommand(program);\n\n// License commands: inv upgrade, inv activate\nimport { registerLicenseCommands } from '../src/cli/license.js';\nregisterLicenseCommands(program);\n\n// Parse and execute\nprogram.parse(process.argv);\n","/**\n * CLI commands for config management: inv init, inv config set, inv config show\n */\n\nimport { Command } from 'commander';\n\nexport function registerInitCommand(program: Command): void {\n program\n .command('init')\n .description('Set up CLI Invoice with your sender profile')\n .action(async () => {\n const { initConfig, isConfigInitialized } = await import('../core/config.js');\n const { success, warn, info } = await import('../utils/format.js');\n\n if (isConfigInitialized()) {\n warn('Config already exists. Running init will overwrite your current settings.');\n }\n\n try {\n const config = await initConfig();\n console.log('');\n success(`Setup complete! Config saved.`);\n info(`Sender: ${config.sender.name}${config.sender.business_name ? ` (${config.sender.business_name})` : ''}`);\n info(`Currency: ${config.defaults.currency}, Payment terms: Net ${config.defaults.payment_terms}`);\n console.log('');\n info('Run `inv client add` to add your first client.');\n } catch (err) {\n if (err instanceof Error && err.message.includes('User force closed')) {\n console.log('\\nSetup cancelled.');\n process.exit(0);\n }\n throw err;\n }\n });\n}\n\nexport function registerConfigCommand(program: Command): void {\n const configCmd = program\n .command('config')\n .description('View or update configuration');\n\n configCmd\n .command('show')\n .description('Display current configuration')\n .action(async () => {\n const { loadConfig, isConfigInitialized } = await import('../core/config.js');\n const { error, info } = await import('../utils/format.js');\n\n if (!isConfigInitialized()) {\n error('No config found. Run `inv init` first.');\n process.exit(1);\n }\n\n const config = loadConfig();\n\n info('Current configuration:\\n');\n\n console.log('[sender]');\n console.log(` name = \"${config.sender.name}\"`);\n console.log(` business_name = \"${config.sender.business_name}\"`);\n console.log(` email = \"${config.sender.email}\"`);\n console.log(` address = \"${config.sender.address}\"`);\n console.log(` logo = \"${config.sender.logo}\"`);\n console.log('');\n console.log('[defaults]');\n console.log(` currency = \"${config.defaults.currency}\"`);\n console.log(` payment_terms = ${config.defaults.payment_terms}`);\n console.log(` tax_rate = ${config.defaults.tax_rate}`);\n console.log(` output_dir = \"${config.defaults.output_dir}\"`);\n console.log('');\n console.log('[invoice]');\n console.log(` number_prefix = \"${config.invoice.number_prefix}\"`);\n console.log(` next_number = ${config.invoice.next_number}`);\n console.log('');\n console.log('[license]');\n console.log(` key = \"${config.license.key ? '****' : ''}\"`);\n console.log(` activated_at = \"${config.license.activated_at}\"`);\n });\n\n configCmd\n .command('set')\n .description('Update a config value (e.g., inv config set defaults.currency EUR)')\n .argument('<key>', 'Config key in section.field format (e.g., defaults.currency)')\n .argument('<value>', 'New value')\n .action(async (key: string, value: string) => {\n const { updateConfig, isConfigInitialized } = await import('../core/config.js');\n const { success, error: showError } = await import('../utils/format.js');\n\n if (!isConfigInitialized()) {\n showError('No config found. Run `inv init` first.');\n process.exit(1);\n }\n\n try {\n updateConfig(key, value);\n success(`Config updated: ${key} = \"${value}\"`);\n } catch (err) {\n if (err instanceof Error) {\n showError(err.message);\n process.exit(1);\n }\n throw err;\n }\n });\n}\n","/**\n * CLI commands for client management: inv client add/list/edit/remove\n */\n\nimport { Command } from 'commander';\n\nexport function registerClientCommand(program: Command): void {\n const clientCmd = program\n .command('client')\n .description('Manage clients');\n\n clientCmd\n .command('add')\n .description('Add a new client')\n .option('-n, --name <name>', 'Client name (required)')\n .option('-e, --email <email>', 'Client email (required)')\n .option('-a, --address <address>', 'Client address')\n .option('-t, --terms <days>', 'Payment terms in days (default: 30)')\n .action(async (opts: { name?: string; email?: string; address?: string; terms?: string }) => {\n const { addClient } = await import('../core/client.js');\n const { success, error: showError } = await import('../utils/format.js');\n\n if (!opts.name || !opts.email) {\n showError('Both --name and --email are required. Example: inv client add --name \"Acme Corp\" --email \"billing@acme.com\"');\n process.exit(1);\n }\n\n try {\n const client = addClient({\n name: opts.name,\n email: opts.email,\n address: opts.address,\n payment_terms: opts.terms ? parseInt(opts.terms, 10) : undefined,\n });\n success(`Client added: ${client.name} (${client.email})`);\n } catch (err) {\n if (err instanceof Error) {\n showError(err.message);\n process.exit(1);\n }\n throw err;\n }\n });\n\n clientCmd\n .command('list')\n .description('List all clients')\n .action(async () => {\n const { listClients } = await import('../core/client.js');\n const { formatCurrency } = await import('../utils/currency.js');\n const Table = (await import('cli-table3')).default;\n\n const clients = listClients();\n\n if (clients.length === 0) {\n console.log('No clients yet. Run `inv client add` to add one.');\n return;\n }\n\n const table = new Table({\n head: ['Name', 'Email', 'Payment Terms', 'Invoices', 'Total Billed'],\n style: { head: ['cyan'] },\n });\n\n for (const c of clients) {\n table.push([\n c.name,\n c.email,\n `Net ${c.payment_terms}`,\n String(c.invoice_count),\n formatCurrency(c.total_billed),\n ]);\n }\n\n console.log(table.toString());\n });\n\n clientCmd\n .command('edit')\n .description('Edit a client')\n .argument('<name>', 'Client name to edit')\n .option('-e, --email <email>', 'New email')\n .option('-a, --address <address>', 'New address')\n .option('-t, --terms <days>', 'New payment terms in days')\n .option('-n, --name <newName>', 'New name')\n .action(async (name: string, opts: { email?: string; address?: string; terms?: string; name?: string }) => {\n const { editClient } = await import('../core/client.js');\n const { success, error: showError } = await import('../utils/format.js');\n\n try {\n const client = editClient(name, {\n email: opts.email,\n address: opts.address,\n payment_terms: opts.terms ? parseInt(opts.terms, 10) : undefined,\n name: opts.name,\n });\n success(`Client updated: ${client.name} (${client.email})`);\n } catch (err) {\n if (err instanceof Error) {\n showError(err.message);\n process.exit(1);\n }\n throw err;\n }\n });\n\n clientCmd\n .command('remove')\n .description('Remove a client')\n .argument('<name>', 'Client name to remove')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (name: string, opts: { yes?: boolean }) => {\n const { removeClient, findClientByName } = await import('../core/client.js');\n const { success, warn, error: showError } = await import('../utils/format.js');\n\n // Verify client exists first\n const client = findClientByName(name);\n if (!client) {\n showError(`Client not found: \"${name}\".`);\n process.exit(1);\n }\n\n // Check for invoices and prompt if not using --yes\n const { readStore } = await import('../storage/store.js');\n const { getInvoicesPath } = await import('../storage/paths.js');\n const { invoices } = readStore<{ invoices: Array<{ client_id: string }> }>(\n getInvoicesPath(),\n { invoices: [] },\n );\n const invoiceCount = invoices.filter((inv) => inv.client_id === client.id).length;\n\n if (invoiceCount > 0 && !opts.yes) {\n const { confirm } = await import('@inquirer/prompts');\n warn(`${client.name} has ${invoiceCount} invoice(s). Invoices will retain client info as snapshots.`);\n const confirmed = await confirm({\n message: `Remove ${client.name} anyway?`,\n default: false,\n });\n if (!confirmed) {\n console.log('Cancelled.');\n return;\n }\n } else if (!opts.yes) {\n const { confirm } = await import('@inquirer/prompts');\n const confirmed = await confirm({\n message: `Remove client \"${client.name}\"?`,\n default: false,\n });\n if (!confirmed) {\n console.log('Cancelled.');\n return;\n }\n }\n\n try {\n const result = removeClient(name);\n success(`Client removed: ${result.client.name}`);\n } catch (err) {\n if (err instanceof Error) {\n showError(err.message);\n process.exit(1);\n }\n throw err;\n }\n });\n}\n","/**\n * CLI commands for invoice management:\n * inv create, inv show, inv edit, inv delete, inv list, inv summary\n */\n\nimport { Command } from 'commander';\n\n/**\n * Collect repeated --item/--qty/--rate flags into arrays.\n * Commander calls the callback for each occurrence of the option.\n */\nfunction collect(value: string, previous: string[]): string[] {\n return previous.concat([value]);\n}\n\nexport function registerInvoiceCommands(program: Command): void {\n // -----------------------------------------------------------------------\n // inv create\n // -----------------------------------------------------------------------\n program\n .command('create')\n .description('Create a new invoice')\n .requiredOption('-c, --client <name>', 'Client name (required)')\n .option('--item <description>', 'Line item description (repeatable)', collect, [])\n .option('--qty <number>', 'Line item quantity (repeatable, matches --item order)', collect, [])\n .option('--rate <number>', 'Line item unit price (repeatable, matches --item order)', collect, [])\n .option('--from <file>', 'Load line items from a JSON file')\n .option('-d, --date <YYYY-MM-DD>', 'Invoice date (default: today)')\n .option('--notes <text>', 'Notes to include on the invoice')\n .option('--tax-rate <percent>', 'Tax rate as a percentage (e.g., 8.5)')\n .option('--currency <code>', 'Currency code (e.g., USD, EUR)')\n .action(async (opts: {\n client: string;\n item: string[];\n qty: string[];\n rate: string[];\n from?: string;\n date?: string;\n notes?: string;\n taxRate?: string;\n currency?: string;\n }) => {\n const { createInvoice, parseLineItemsFromFile } = await import('../core/invoice.js');\n const { success, error: showError } = await import('../utils/format.js');\n const { formatCurrency } = await import('../utils/currency.js');\n const { formatDate } = await import('../utils/date.js');\n\n try {\n let items: import('../types.js').LineItem[];\n\n if (opts.from) {\n // Load from file\n if (opts.item.length > 0) {\n showError('Cannot use both --item flags and --from file. Choose one.');\n process.exit(1);\n }\n items = parseLineItemsFromFile(opts.from);\n } else {\n // Build from repeated flags\n if (opts.item.length === 0) {\n showError(\n 'No line items provided. Use --item/--qty/--rate flags or --from <file>.\\n' +\n 'Example: inv create --client \"Acme\" --item \"Dev work\" --qty 10 --rate 150',\n );\n process.exit(1);\n }\n\n if (opts.item.length !== opts.qty.length || opts.item.length !== opts.rate.length) {\n showError(\n `Mismatched item counts: ${opts.item.length} items, ${opts.qty.length} quantities, ${opts.rate.length} rates. ` +\n 'Each --item must have a corresponding --qty and --rate.',\n );\n process.exit(1);\n }\n\n items = opts.item.map((desc, i) => ({\n description: desc,\n quantity: parseFloat(opts.qty[i]!),\n unit_price: parseFloat(opts.rate[i]!),\n }));\n\n // Validate parsed numbers\n for (let i = 0; i < items.length; i++) {\n if (isNaN(items[i]!.quantity) || items[i]!.quantity <= 0) {\n showError(`Invalid quantity for item \"${opts.item[i]}\": \"${opts.qty[i]}\". Must be a positive number.`);\n process.exit(1);\n }\n if (isNaN(items[i]!.unit_price) || items[i]!.unit_price < 0) {\n showError(`Invalid rate for item \"${opts.item[i]}\": \"${opts.rate[i]}\". Must be a non-negative number.`);\n process.exit(1);\n }\n }\n }\n\n const invoice = createInvoice({\n clientName: opts.client,\n items,\n date: opts.date,\n notes: opts.notes,\n taxRate: opts.taxRate !== undefined ? parseFloat(opts.taxRate) : undefined,\n currency: opts.currency,\n });\n\n success(`Invoice ${invoice.number} created. Total: ${formatCurrency(invoice.total, invoice.currency)}. Due: ${formatDate(invoice.due_date)}.`);\n } catch (err) {\n if (err instanceof Error) {\n showError(err.message);\n process.exit(1);\n }\n throw err;\n }\n });\n\n // -----------------------------------------------------------------------\n // inv show\n // -----------------------------------------------------------------------\n program\n .command('show')\n .description('Display full invoice details')\n .argument('<id>', 'Invoice ID or number (e.g., INV-0001)')\n .action(async (idOrNumber: string) => {\n const { getInvoice, computeDisplayStatus } = await import('../core/invoice.js');\n const { formatCurrency } = await import('../utils/currency.js');\n const { formatDate } = await import('../utils/date.js');\n const { error: showError } = await import('../utils/format.js');\n const chalk = (await import('chalk')).default;\n\n const invoice = getInvoice(idOrNumber);\n if (!invoice) {\n showError(`Invoice not found: \"${idOrNumber}\".`);\n process.exit(1);\n }\n\n const displayStatus = computeDisplayStatus(invoice);\n const statusColor =\n displayStatus === 'paid' ? chalk.green :\n displayStatus === 'overdue' ? chalk.red :\n displayStatus === 'sent' ? chalk.yellow :\n chalk.gray;\n\n console.log('');\n console.log(chalk.bold(`Invoice ${invoice.number}`) + ' ' + statusColor(`[${displayStatus}]`));\n console.log('─'.repeat(50));\n console.log(`Client: ${invoice.client_snapshot.name}`);\n console.log(`Email: ${invoice.client_snapshot.email}`);\n if (invoice.client_snapshot.address) {\n console.log(`Address: ${invoice.client_snapshot.address}`);\n }\n console.log(`Date: ${formatDate(invoice.date)}`);\n console.log(`Due: ${formatDate(invoice.due_date)}`);\n if (invoice.paid_date) {\n console.log(`Paid: ${formatDate(invoice.paid_date)}`);\n }\n console.log(`Currency: ${invoice.currency}`);\n console.log('');\n\n // Line items table\n const Table = (await import('cli-table3')).default;\n const table = new Table({\n head: ['Description', 'Qty', 'Rate', 'Amount'],\n style: { head: ['cyan'] },\n colAligns: ['left', 'right', 'right', 'right'],\n });\n\n for (const item of invoice.items) {\n const amount = item.quantity * item.unit_price;\n table.push([\n item.description,\n String(item.quantity),\n formatCurrency(item.unit_price, invoice.currency),\n formatCurrency(amount, invoice.currency),\n ]);\n }\n\n console.log(table.toString());\n console.log('');\n console.log(` Subtotal: ${formatCurrency(invoice.subtotal, invoice.currency)}`);\n console.log(` Tax (${invoice.tax_rate}%): ${formatCurrency(invoice.tax_amount, invoice.currency)}`);\n console.log(chalk.bold(` Total: ${formatCurrency(invoice.total, invoice.currency)}`));\n\n if (invoice.notes) {\n console.log('');\n console.log(`Notes: ${invoice.notes}`);\n }\n console.log('');\n });\n\n // -----------------------------------------------------------------------\n // inv edit\n // -----------------------------------------------------------------------\n program\n .command('edit')\n .description('Edit a draft invoice')\n .argument('<id>', 'Invoice ID or number')\n .option('--notes <text>', 'Update notes')\n .option('-d, --date <YYYY-MM-DD>', 'Update invoice date')\n .option('--tax-rate <percent>', 'Update tax rate')\n .option('--currency <code>', 'Update currency')\n .action(async (idOrNumber: string, opts: {\n notes?: string;\n date?: string;\n taxRate?: string;\n currency?: string;\n }) => {\n const { editInvoice } = await import('../core/invoice.js');\n const { success, error: showError } = await import('../utils/format.js');\n\n try {\n const invoice = editInvoice(idOrNumber, {\n notes: opts.notes,\n date: opts.date,\n taxRate: opts.taxRate !== undefined ? parseFloat(opts.taxRate) : undefined,\n currency: opts.currency,\n });\n success(`Invoice ${invoice.number} updated.`);\n } catch (err) {\n if (err instanceof Error) {\n showError(err.message);\n process.exit(1);\n }\n throw err;\n }\n });\n\n // -----------------------------------------------------------------------\n // inv delete\n // -----------------------------------------------------------------------\n program\n .command('delete')\n .description('Delete a draft invoice')\n .argument('<id>', 'Invoice ID or number')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (idOrNumber: string, opts: { yes?: boolean }) => {\n const { getInvoice, deleteInvoice } = await import('../core/invoice.js');\n const { success, error: showError } = await import('../utils/format.js');\n\n const invoice = getInvoice(idOrNumber);\n if (!invoice) {\n showError(`Invoice not found: \"${idOrNumber}\".`);\n process.exit(1);\n }\n\n if (!opts.yes) {\n const { confirm } = await import('@inquirer/prompts');\n const confirmed = await confirm({\n message: `Delete invoice ${invoice.number} (${invoice.client_snapshot.name}, $${invoice.total})?`,\n default: false,\n });\n if (!confirmed) {\n console.log('Cancelled.');\n return;\n }\n }\n\n try {\n deleteInvoice(idOrNumber);\n success(`Invoice ${invoice.number} deleted.`);\n } catch (err) {\n if (err instanceof Error) {\n showError(err.message);\n process.exit(1);\n }\n throw err;\n }\n });\n\n // -----------------------------------------------------------------------\n // inv list\n // -----------------------------------------------------------------------\n program\n .command('list')\n .description('List all invoices')\n .option('-s, --status <status>', 'Filter by status (draft, sent, paid, overdue)')\n .option('-c, --client <name>', 'Filter by client name')\n .action(async (opts: { status?: string; client?: string }) => {\n const { listInvoices } = await import('../core/invoice.js');\n const { formatCurrency } = await import('../utils/currency.js');\n const chalk = (await import('chalk')).default;\n const Table = (await import('cli-table3')).default;\n\n const filter: import('../core/invoice.js').ListInvoicesFilter = {};\n if (opts.status) {\n const validStatuses = ['draft', 'sent', 'paid', 'overdue'];\n if (!validStatuses.includes(opts.status)) {\n const { error: showError } = await import('../utils/format.js');\n showError(`Invalid status: \"${opts.status}\". Valid: ${validStatuses.join(', ')}`);\n process.exit(1);\n }\n filter.status = opts.status as import('../core/invoice.js').InvoiceStatusFilter;\n }\n if (opts.client) {\n filter.clientName = opts.client;\n }\n\n const invoices = listInvoices(filter);\n\n if (invoices.length === 0) {\n console.log('No invoices found.');\n return;\n }\n\n const table = new Table({\n head: ['Number', 'Client', 'Date', 'Due', 'Amount', 'Status'],\n style: { head: ['cyan'] },\n });\n\n for (const inv of invoices) {\n const statusColor =\n inv.display_status === 'paid' ? chalk.green :\n inv.display_status === 'overdue' ? chalk.red :\n inv.display_status === 'sent' ? chalk.yellow :\n chalk.gray;\n\n table.push([\n inv.number,\n inv.client_snapshot.name,\n inv.date,\n inv.due_date,\n formatCurrency(inv.total, inv.currency),\n statusColor(inv.display_status),\n ]);\n }\n\n console.log(table.toString());\n });\n\n // -----------------------------------------------------------------------\n // inv summary\n // -----------------------------------------------------------------------\n program\n .command('summary')\n .description('Revenue summary')\n .option('-y, --year <YYYY>', 'Year to summarize (default: current year)')\n .action(async (opts: { year?: string }) => {\n const { getSummary } = await import('../core/invoice.js');\n const { formatCurrency } = await import('../utils/currency.js');\n const chalk = (await import('chalk')).default;\n const Table = (await import('cli-table3')).default;\n\n const year = opts.year ? parseInt(opts.year, 10) : undefined;\n if (opts.year && (isNaN(year!) || year! < 1900 || year! > 2200)) {\n const { error: showError } = await import('../utils/format.js');\n showError(`Invalid year: \"${opts.year}\".`);\n process.exit(1);\n }\n\n const summary = getSummary(year);\n\n console.log('');\n console.log(chalk.bold(`Revenue Summary — ${summary.year}`));\n console.log('─'.repeat(50));\n console.log(`Total invoiced: ${formatCurrency(summary.total_invoiced)}`);\n console.log(`Total paid: ${chalk.green(formatCurrency(summary.total_paid))}`);\n console.log(`Total outstanding: ${chalk.yellow(formatCurrency(summary.total_outstanding))}`);\n console.log(`Invoice count: ${summary.invoice_count}`);\n\n if (summary.months.length > 0) {\n console.log('');\n const table = new Table({\n head: ['Month', 'Invoiced', 'Paid', 'Outstanding', 'Count'],\n style: { head: ['cyan'] },\n });\n\n for (const m of summary.months) {\n table.push([\n m.month,\n formatCurrency(m.invoiced),\n formatCurrency(m.paid),\n formatCurrency(m.outstanding),\n String(m.count),\n ]);\n }\n\n console.log(table.toString());\n }\n console.log('');\n });\n}\n","/**\n * CLI command for invoice status management: inv status <id> <status>\n */\n\nimport { Command } from 'commander';\n\nexport function registerStatusCommand(program: Command): void {\n program\n .command('status')\n .description('Update invoice status (draft -> sent -> paid)')\n .argument('<id>', 'Invoice ID or number (e.g., INV-0001)')\n .argument('<newStatus>', 'New status: \"sent\" or \"paid\"')\n .option('-d, --date <YYYY-MM-DD>', 'Payment date (only for \"paid\"; default: today)')\n .action(async (idOrNumber: string, newStatus: string, opts: { date?: string }) => {\n const { updateStatus } = await import('../core/invoice.js');\n const { success, error: showError } = await import('../utils/format.js');\n const { formatDate } = await import('../utils/date.js');\n\n const validStatuses = ['sent', 'paid'];\n if (!validStatuses.includes(newStatus)) {\n showError(\n `Invalid status: \"${newStatus}\". Valid values: ${validStatuses.join(', ')}.\\n` +\n 'Transitions: draft -> sent -> paid',\n );\n process.exit(1);\n }\n\n try {\n const invoice = updateStatus(\n idOrNumber,\n newStatus as 'sent' | 'paid',\n opts.date,\n );\n\n if (newStatus === 'paid') {\n success(`${invoice.number} marked as paid (${formatDate(invoice.paid_date!)}).`);\n } else {\n success(`${invoice.number} marked as ${newStatus}.`);\n }\n } catch (err) {\n if (err instanceof Error) {\n showError(err.message);\n process.exit(1);\n }\n throw err;\n }\n });\n}\n","/**\n * CLI command for PDF export: inv export <id-or-number>\n *\n * Generates a professional PDF invoice and writes it to disk.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { Command } from 'commander';\n\n/**\n * Slugify a string for use in filenames.\n * \"Acme Corp\" -> \"acme-corp\"\n */\nfunction slugify(text: string): string {\n return text\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n\nexport function registerExportCommand(program: Command): void {\n program\n .command('export')\n .description('Generate a PDF invoice')\n .argument('[id]', 'Invoice ID or number (e.g., INV-0001)')\n .option('-l, --latest', 'Export the most recently created invoice')\n .option('-o, --output <path>', 'Output file path or directory')\n .action(async (idArg: string | undefined, opts: { latest?: boolean; output?: string }) => {\n // Lazy-load heavy dependencies\n const { getInvoice, listInvoices } = await import('../core/invoice.js');\n const { generatePDF } = await import('../core/pdf.js');\n const { loadConfig } = await import('../core/config.js');\n const { success, error: showError, warn: showWarn } = await import('../utils/format.js');\n\n try {\n // Determine which invoice to export\n let invoice: import('../types.js').Invoice | undefined;\n\n if (opts.latest) {\n const all = listInvoices();\n if (all.length === 0) {\n showError('No invoices found. Create one first with `inv create`.');\n process.exit(1);\n }\n // Sort by created_at descending, take the first\n const sorted = [...all].sort(\n (a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime(),\n );\n invoice = sorted[0]!;\n } else if (idArg) {\n invoice = getInvoice(idArg);\n if (!invoice) {\n showError(`Invoice not found: \"${idArg}\". Run \\`inv list\\` to see existing invoices.`);\n process.exit(1);\n }\n } else {\n showError('Please provide an invoice ID/number or use --latest.\\nUsage: inv export <id> or inv export --latest');\n process.exit(1);\n }\n\n // Load config for sender info\n const config = loadConfig();\n\n // Warn about missing sender profile\n if (!config.sender.name && !config.sender.business_name) {\n showWarn('Sender profile is not configured. Run `inv init` to set up your business details.');\n }\n\n // Generate the PDF\n const pdfBuffer = await generatePDF(invoice!, config);\n\n // Determine output path\n const clientSlug = slugify(invoice!.client_snapshot.name || 'unknown');\n const defaultFilename = `${invoice!.number}-${clientSlug}.pdf`;\n\n let outputPath: string;\n\n if (opts.output) {\n // If the output path is a directory, append the default filename\n const resolved = path.resolve(opts.output);\n try {\n const stat = fs.statSync(resolved);\n if (stat.isDirectory()) {\n outputPath = path.join(resolved, defaultFilename);\n } else {\n outputPath = resolved;\n }\n } catch {\n // Path doesn't exist — treat as a file path\n // But if it ends with a path separator, treat as a directory\n if (opts.output.endsWith(path.sep) || opts.output.endsWith('/')) {\n fs.mkdirSync(resolved, { recursive: true });\n outputPath = path.join(resolved, defaultFilename);\n } else {\n // Ensure parent directory exists\n const dir = path.dirname(resolved);\n fs.mkdirSync(dir, { recursive: true });\n outputPath = resolved;\n }\n }\n } else {\n // Default: CWD with default filename\n const outputDir = config.defaults.output_dir\n ? path.resolve(config.defaults.output_dir)\n : process.cwd();\n outputPath = path.join(outputDir, defaultFilename);\n }\n\n // Write the PDF\n fs.writeFileSync(outputPath, pdfBuffer);\n\n success(`Exported to ${outputPath}`);\n } catch (err) {\n if (err instanceof Error) {\n showError(err.message);\n process.exit(1);\n }\n throw err;\n }\n });\n}\n","/**\n * CLI commands for license management: inv upgrade, inv activate\n */\n\nimport { Command } from 'commander';\n\nexport function registerLicenseCommands(program: Command): void {\n // -----------------------------------------------------------------------\n // inv upgrade — display Pro tier information\n // -----------------------------------------------------------------------\n program\n .command('upgrade')\n .description('Show Pro tier info, pricing, and purchase link')\n .action(async () => {\n const chalk = (await import('chalk')).default;\n const { getLicenseStatus, UPGRADE_URL, PRO_PRICE } = await import('../core/license.js');\n const { loadConfig } = await import('../core/config.js');\n\n const config = loadConfig();\n const status = getLicenseStatus(config);\n\n console.log('');\n if (status === 'pro') {\n console.log(chalk.green('You are already on CLI Invoice Pro!'));\n console.log('');\n console.log('Your Pro features are active:');\n } else {\n console.log(chalk.bold('CLI Invoice Pro'));\n console.log('');\n console.log(`Price: ${chalk.cyan(PRO_PRICE)}`);\n console.log('');\n console.log('Upgrade to unlock:');\n }\n\n console.log('');\n console.log(' ' + chalk.green('\\u2713') + ' Unlimited clients (free: 3)');\n console.log(' ' + chalk.green('\\u2713') + ' Unlimited invoices per month (free: 5)');\n console.log(' ' + chalk.green('\\u2713') + ' Recurring invoice templates');\n console.log(' ' + chalk.green('\\u2713') + ' Revenue summaries and reports');\n console.log(' ' + chalk.green('\\u2713') + ' Custom PDF templates');\n console.log(' ' + chalk.green('\\u2713') + ' Priority support');\n\n if (status !== 'pro') {\n console.log('');\n console.log(`Purchase: ${chalk.underline(UPGRADE_URL)}`);\n console.log('');\n console.log(`After purchase, activate with: ${chalk.cyan('inv activate <license-key>')}`);\n }\n console.log('');\n });\n\n // -----------------------------------------------------------------------\n // inv activate — validate and store a license key\n // -----------------------------------------------------------------------\n program\n .command('activate')\n .description('Activate a Pro license key')\n .argument('<key>', 'License key received after purchase')\n .action(async (key: string) => {\n const { validateLicenseKey, LicenseValidationError, UPGRADE_URL } = await import('../core/license.js');\n const { loadConfig, saveConfig } = await import('../core/config.js');\n const { success, error: showError } = await import('../utils/format.js');\n\n try {\n const payload = validateLicenseKey(key);\n\n // Save the key to config\n const config = loadConfig();\n config.license.key = key;\n config.license.activated_at = new Date().toISOString();\n saveConfig(config);\n\n success(`License activated! Welcome to CLI Invoice Pro.`);\n console.log(` Email: ${payload.email}`);\n console.log(` Plan: ${payload.plan}`);\n console.log(` Expires: ${payload.expires_at}`);\n console.log('');\n console.log('All Pro features are now unlocked. Enjoy!');\n } catch (err) {\n if (err instanceof LicenseValidationError) {\n showError(err.message);\n console.error('');\n console.error(`If you believe this is an error, visit ${UPGRADE_URL} for support.`);\n process.exit(1);\n }\n if (err instanceof Error) {\n showError(err.message);\n process.exit(1);\n }\n throw err;\n }\n });\n}\n"],"mappings":"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","names":["fs","path","chalk","isNodeError","fs","path","crypto","crypto","crypto","crypto","fs","resolve","fs","program","initConfig","isConfigInitialized","success","warn","info","loadConfig","error","updateConfig","program","addClient","success","listClients","formatCurrency","editClient","removeClient","findClientByName","warn","readStore","getInvoicesPath","program","createInvoice","parseLineItemsFromFile","success","formatCurrency","formatDate","getInvoice","computeDisplayStatus","chalk","editInvoice","deleteInvoice","listInvoices","getSummary","program","updateStatus","success","formatDate","fs","path","program","getInvoice","listInvoices","generatePDF","loadConfig","success","program","chalk","getLicenseStatus","UPGRADE_URL","PRO_PRICE","loadConfig","validateLicenseKey","LicenseValidationError","saveConfig","success"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cli-invoice",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Generate professional PDF invoices, manage clients, and track payments from the terminal",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"bin": {
|
|
7
|
+
"inv": "./dist/bin/inv.js"
|
|
8
|
+
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=18.0.0"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist/",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"test:watch": "vitest",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"dev": "tsx bin/inv.ts",
|
|
23
|
+
"prepublishOnly": "npm run typecheck && npm run test && npm run build"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@inquirer/prompts": "^7.0.0",
|
|
27
|
+
"chalk": "4.1.2",
|
|
28
|
+
"cli-table3": "0.6.5",
|
|
29
|
+
"commander": "^13.0.0",
|
|
30
|
+
"pdfkit": "^0.16.0",
|
|
31
|
+
"smol-toml": "^1.3.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^22.0.0",
|
|
35
|
+
"@types/pdfkit": "^0.13.0",
|
|
36
|
+
"tsup": "^8.0.0",
|
|
37
|
+
"tsx": "^4.0.0",
|
|
38
|
+
"typescript": "^5.5.0",
|
|
39
|
+
"vitest": "^3.0.0"
|
|
40
|
+
},
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://gitlab.com/jschen2/cli-invoice.git"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://gitlab.com/jschen2/cli-invoice#readme",
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://gitlab.com/jschen2/cli-invoice/-/issues"
|
|
48
|
+
},
|
|
49
|
+
"author": "jschen2",
|
|
50
|
+
"keywords": [
|
|
51
|
+
"invoice",
|
|
52
|
+
"cli",
|
|
53
|
+
"pdf",
|
|
54
|
+
"freelancer",
|
|
55
|
+
"billing"
|
|
56
|
+
],
|
|
57
|
+
"license": "MIT"
|
|
58
|
+
}
|