workmatic 1.1.2 β†’ 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/handlers.ts","../src/database.ts","../src/orchestrator.ts","../src/client.ts","../src/utils.ts","../src/worker.ts","../src/cli.ts"],"sourcesContent":["import Database from 'better-sqlite3';\nimport { createReadStream, createWriteStream } from 'fs';\nimport { finished } from 'stream/promises';\nimport { createInterface } from 'readline';\nimport Table from 'cli-table3';\nimport { createDatabase } from '../database.js';\nimport { createOrchestrator } from '../orchestrator.js';\nimport type { JobStatus } from '../types.js';\n\nexport function printUsage(): void {\n console.log(`\nWorkmatic CLI - Job Queue Management\n\nUsage:\n workmatic <command> [options]\n\nCommands:\n stats <db> Show job statistics\n queues <db> List all queues with status\n list <db> [--status=<status>] List jobs (optionally filter by status)\n export <db> [output.csv] Export jobs to CSV (default: stdout)\n import <db> <input.csv> Import jobs from CSV\n purge <db> --status=<status> Delete jobs by status\n retry <db> [--status=dead] Retry dead jobs (reset to ready)\n pause <db> <queue> Pause a queue (running workers stop claiming)\n resume <db> <queue> Resume a paused queue\n transfer <db> <from> <to> Move jobs between queues\n\nOptions:\n --status=<status> Filter by status (ready|running|done|dead), comma-separated for transfer\n --queue=<queue> Filter by queue name\n --limit=<n> Limit number of results or jobs to transfer (default: 100 / 10000)\n --retry When transferring dead jobs, reset them to ready for retry\n\nExamples:\n workmatic stats ./jobs.db\n workmatic list ./jobs.db --status=dead --limit=10\n workmatic transfer ./jobs.db emails retry-emails --status=dead --retry\n workmatic pause ./jobs.db emails\n workmatic resume ./jobs.db emails\n`);\n}\n\nexport function parseOptions(args: string[]): Record<string, string> {\n const options: Record<string, string> = {};\n for (const arg of args) {\n if (arg.startsWith('--')) {\n const [key, value] = arg.slice(2).split('=');\n options[key] = value ?? 'true';\n }\n }\n return options;\n}\n\nexport function getPositionalArgs(args: string[]): string[] {\n return args.filter((arg) => !arg.startsWith('--'));\n}\n\nexport function escapeCSV(value: string | null): string {\n if (value === null) return '';\n const str = String(value);\n if (str.includes(',') || str.includes('\"') || str.includes('\\n')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n return str;\n}\n\nexport function parseCSVLine(line: string): string[] {\n const result: string[] = [];\n let current = '';\n let inQuotes = false;\n\n for (let i = 0; i < line.length; i++) {\n const char = line[i];\n\n if (inQuotes) {\n if (char === '\"') {\n if (line[i + 1] === '\"') {\n current += '\"';\n i++;\n } else {\n inQuotes = false;\n }\n } else {\n current += char;\n }\n } else {\n if (char === '\"') {\n inQuotes = true;\n } else if (char === ',') {\n result.push(current);\n current = '';\n } else {\n current += char;\n }\n }\n }\n\n result.push(current);\n return result;\n}\n\nexport async function cmdStats(dbPath: string): Promise<void> {\n const db = new Database(dbPath, { readonly: true });\n\n try {\n const stats = db\n .prepare(\n `\n SELECT status, COUNT(*) as count \n FROM workmatic_jobs \n GROUP BY status\n `\n )\n .all() as { status: string; count: number }[];\n\n const queues = db\n .prepare(\n `\n SELECT queue, COUNT(*) as count \n FROM workmatic_jobs \n GROUP BY queue\n `\n )\n .all() as { queue: string; count: number }[];\n\n const total = stats.reduce((sum, s) => sum + s.count, 0);\n\n console.log('\\nπŸ“Š Job Statistics\\n');\n\n const statusOrder = ['ready', 'running', 'done', 'dead'];\n const statusTable = new Table({\n head: ['', 'Status', 'Count'],\n style: { head: ['cyan'], border: ['gray'] },\n colAligns: ['left', 'left', 'right'],\n });\n\n for (const status of statusOrder) {\n const stat = stats.find((s) => s.status === status);\n const count = stat?.count ?? 0;\n const emoji = jobStatusEmoji(status);\n statusTable.push([emoji, status, count.toLocaleString()]);\n }\n statusTable.push([{ colSpan: 2, content: 'Total', hAlign: 'right' }, total.toLocaleString()]);\n\n console.log(statusTable.toString());\n\n if (queues.length > 0) {\n console.log('\\nπŸ“‹ By Queue\\n');\n\n const queueTable = new Table({\n head: ['Queue', 'Jobs'],\n style: { head: ['cyan'], border: ['gray'] },\n colAligns: ['left', 'right'],\n });\n\n for (const q of queues) {\n queueTable.push([q.queue, q.count.toLocaleString()]);\n }\n\n console.log(queueTable.toString());\n }\n\n console.log();\n } finally {\n db.close();\n }\n}\n\nexport async function cmdList(dbPath: string, options: Record<string, string>): Promise<void> {\n const db = new Database(dbPath, { readonly: true });\n\n try {\n let query =\n 'SELECT public_id, queue, status, priority, attempts, max_attempts, created_at, last_error FROM workmatic_jobs WHERE 1=1';\n const params: unknown[] = [];\n\n if (options.status) {\n query += ' AND status = ?';\n params.push(options.status);\n }\n if (options.queue) {\n query += ' AND queue = ?';\n params.push(options.queue);\n }\n\n query += ' ORDER BY created_at DESC LIMIT ?';\n params.push(parseInt(options.limit || '100', 10));\n\n const jobs = db.prepare(query).all(...params) as {\n public_id: string;\n queue: string;\n status: string;\n priority: number;\n attempts: number;\n max_attempts: number;\n created_at: number;\n }[];\n\n if (jobs.length === 0) {\n console.log('No jobs found.');\n return;\n }\n\n const table = new Table({\n head: ['ID', 'Queue', 'Status', 'Pri', 'Attempts', 'Created'],\n style: { head: ['cyan'], border: ['gray'] },\n colAligns: ['left', 'left', 'left', 'right', 'center', 'left'],\n colWidths: [24, 16, 12, 5, 10, 21],\n wordWrap: true,\n });\n\n for (const job of jobs) {\n const emoji = jobStatusEmoji(job.status);\n table.push([\n job.public_id.slice(0, 21),\n job.queue.slice(0, 14),\n `${emoji} ${job.status}`,\n job.priority,\n `${job.attempts}/${job.max_attempts}`,\n new Date(job.created_at).toISOString().slice(0, 19),\n ]);\n }\n\n console.log();\n console.log(table.toString());\n console.log(`\\n Showing ${jobs.length} jobs\\n`);\n } finally {\n db.close();\n }\n}\n\nexport async function cmdExport(\n dbPath: string,\n outputPath: string | undefined,\n options: Record<string, string>\n): Promise<void> {\n const db = new Database(dbPath, { readonly: true });\n\n try {\n let query = 'SELECT * FROM workmatic_jobs WHERE 1=1';\n const params: unknown[] = [];\n\n if (options.status) {\n query += ' AND status = ?';\n params.push(options.status);\n }\n if (options.queue) {\n query += ' AND queue = ?';\n params.push(options.queue);\n }\n\n query += ' ORDER BY id';\n\n const jobs = db.prepare(query).all(...params) as Record<string, string | null>[];\n\n const output = outputPath ? createWriteStream(outputPath) : process.stdout;\n\n const columns = [\n 'public_id',\n 'queue',\n 'payload',\n 'status',\n 'priority',\n 'run_at',\n 'attempts',\n 'max_attempts',\n 'lease_until',\n 'created_at',\n 'updated_at',\n 'last_error',\n ];\n\n if (outputPath) {\n output.write(columns.join(',') + '\\n');\n } else {\n console.log(columns.join(','));\n }\n\n for (const job of jobs) {\n const row = columns.map((col) => escapeCSV(job[col] as string | null));\n if (outputPath) {\n output.write(row.join(',') + '\\n');\n } else {\n console.log(row.join(','));\n }\n }\n\n if (outputPath) {\n const stream = output as ReturnType<typeof createWriteStream>;\n stream.end();\n await finished(stream);\n console.error(`βœ… Exported ${jobs.length} jobs to ${outputPath}`);\n }\n } finally {\n db.close();\n }\n}\n\nexport async function cmdImport(dbPath: string, inputPath: string): Promise<void> {\n const db = new Database(dbPath);\n\n db.exec(`\n CREATE TABLE IF NOT EXISTS workmatic_jobs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n public_id TEXT UNIQUE NOT NULL,\n queue TEXT NOT NULL,\n payload TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'ready',\n priority INTEGER NOT NULL DEFAULT 0,\n run_at INTEGER NOT NULL,\n attempts INTEGER NOT NULL DEFAULT 0,\n max_attempts INTEGER NOT NULL DEFAULT 3,\n lease_until INTEGER NOT NULL DEFAULT 0,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n last_error TEXT\n )\n `);\n\n const insert = db.prepare(`\n INSERT OR REPLACE INTO workmatic_jobs \n (public_id, queue, payload, status, priority, run_at, attempts, max_attempts, lease_until, created_at, updated_at, last_error)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const rl = createInterface({\n input: createReadStream(inputPath),\n crlfDelay: Infinity,\n });\n\n let lineNum = 0;\n let imported = 0;\n let columns: string[] = [];\n\n try {\n const insertMany = db.transaction((rows: Record<string, string>[]) => {\n for (const row of rows) {\n insert.run(\n row.public_id,\n row.queue,\n row.payload,\n row.status,\n parseInt(row.priority, 10) || 0,\n parseInt(row.run_at, 10) || Date.now(),\n parseInt(row.attempts, 10) || 0,\n parseInt(row.max_attempts, 10) || 3,\n parseInt(row.lease_until, 10) || 0,\n parseInt(row.created_at, 10) || Date.now(),\n parseInt(row.updated_at, 10) || Date.now(),\n row.last_error || null\n );\n imported++;\n }\n });\n\n const batch: Record<string, string>[] = [];\n\n for await (const line of rl) {\n lineNum++;\n\n if (lineNum === 1) {\n columns = parseCSVLine(line);\n continue;\n }\n\n if (!line.trim()) continue;\n\n const values = parseCSVLine(line);\n const row: Record<string, string> = {};\n\n for (let i = 0; i < columns.length; i++) {\n row[columns[i]] = values[i] ?? '';\n }\n\n batch.push(row);\n\n if (batch.length >= 1000) {\n insertMany(batch);\n batch.length = 0;\n process.stderr.write(`\\rImported ${imported} jobs...`);\n }\n }\n\n if (batch.length > 0) {\n insertMany(batch);\n }\n\n console.log(`\\nβœ… Imported ${imported} jobs from ${inputPath}`);\n } finally {\n db.close();\n }\n}\n\nexport async function cmdPurge(\n dbPath: string,\n options: Record<string, string>\n): Promise<void> {\n if (!options.status) {\n throw new Error('--status is required for purge command');\n }\n\n const db = new Database(dbPath);\n\n try {\n const result = db\n .prepare('DELETE FROM workmatic_jobs WHERE status = ?')\n .run(options.status);\n console.log(`πŸ—‘οΈ Deleted ${result.changes} jobs with status '${options.status}'`);\n } finally {\n db.close();\n }\n}\n\nexport async function cmdRetry(dbPath: string, options: Record<string, string>): Promise<void> {\n const status = options.status || 'dead';\n const db = new Database(dbPath);\n\n try {\n const ts = Date.now();\n const result = db\n .prepare(\n `\n UPDATE workmatic_jobs \n SET status = 'ready', \n attempts = 0, \n run_at = ?, \n lease_until = 0,\n updated_at = ?\n WHERE status = ?\n `\n )\n .run(ts, ts, status);\n\n console.log(`πŸ”„ Reset ${result.changes} jobs from '${status}' to 'ready'`);\n } finally {\n db.close();\n }\n}\n\nexport async function cmdPause(dbPath: string, queueName: string): Promise<void> {\n const db = new Database(dbPath);\n\n try {\n db.exec(`\n CREATE TABLE IF NOT EXISTS workmatic_settings (\n queue TEXT PRIMARY KEY,\n paused INTEGER NOT NULL DEFAULT 0,\n updated_at INTEGER NOT NULL\n )\n `);\n\n const ts = Date.now();\n db.prepare(\n `\n INSERT INTO workmatic_settings (queue, paused, updated_at)\n VALUES (?, 1, ?)\n ON CONFLICT(queue) DO UPDATE SET paused = 1, updated_at = ?\n `\n ).run(queueName, ts, ts);\n\n console.log(`⏸️ Paused queue '${queueName}'`);\n console.log(` Running workers will stop claiming new jobs.`);\n } finally {\n db.close();\n }\n}\n\nexport async function cmdResume(dbPath: string, queueName: string): Promise<void> {\n const db = new Database(dbPath);\n\n try {\n db.exec(`\n CREATE TABLE IF NOT EXISTS workmatic_settings (\n queue TEXT PRIMARY KEY,\n paused INTEGER NOT NULL DEFAULT 0,\n updated_at INTEGER NOT NULL\n )\n `);\n\n const ts = Date.now();\n db.prepare(\n `\n INSERT INTO workmatic_settings (queue, paused, updated_at)\n VALUES (?, 0, ?)\n ON CONFLICT(queue) DO UPDATE SET paused = 0, updated_at = ?\n `\n ).run(queueName, ts, ts);\n\n console.log(`▢️ Resumed queue '${queueName}'`);\n console.log(` Workers will start claiming jobs again.`);\n } finally {\n db.close();\n }\n}\n\nexport async function cmdQueues(dbPath: string): Promise<void> {\n const db = new Database(dbPath, { readonly: true });\n\n try {\n const settingsExists = db\n .prepare(\n `\n SELECT name FROM sqlite_master WHERE type='table' AND name='workmatic_settings'\n `\n )\n .get();\n\n let queues: {\n queue: string;\n total: number;\n ready: number;\n running: number;\n paused: number;\n }[];\n\n if (settingsExists) {\n queues = db\n .prepare(\n `\n SELECT \n j.queue,\n COUNT(*) as total,\n SUM(CASE WHEN j.status = 'ready' THEN 1 ELSE 0 END) as ready,\n SUM(CASE WHEN j.status = 'running' THEN 1 ELSE 0 END) as running,\n COALESCE(s.paused, 0) as paused\n FROM workmatic_jobs j\n LEFT JOIN workmatic_settings s ON j.queue = s.queue\n GROUP BY j.queue\n `\n )\n .all() as typeof queues;\n } else {\n queues = db\n .prepare(\n `\n SELECT \n queue,\n COUNT(*) as total,\n SUM(CASE WHEN status = 'ready' THEN 1 ELSE 0 END) as ready,\n SUM(CASE WHEN status = 'running' THEN 1 ELSE 0 END) as running,\n 0 as paused\n FROM workmatic_jobs\n GROUP BY queue\n `\n )\n .all() as typeof queues;\n }\n\n if (queues.length === 0) {\n console.log('No queues found.');\n return;\n }\n\n console.log('\\nπŸ“‹ Queues\\n');\n\n const table = new Table({\n head: ['Queue', 'Status', 'Ready', 'Running', 'Total'],\n style: { head: ['cyan'], border: ['gray'] },\n colAligns: ['left', 'left', 'right', 'right', 'right'],\n });\n\n for (const q of queues) {\n const status = q.paused ? '⏸️ PAUSED' : '▢️ ACTIVE';\n table.push([\n q.queue,\n status,\n q.ready.toLocaleString(),\n q.running.toLocaleString(),\n q.total.toLocaleString(),\n ]);\n }\n\n console.log(table.toString());\n console.log();\n } finally {\n db.close();\n }\n}\n\nconst JOB_STATUS_EMOJI: Record<string, string> = {\n ready: '⏳',\n running: '▢️',\n done: 'βœ…',\n dead: 'πŸ’€',\n};\n\n/** @internal Exported for tests */\nexport function jobStatusEmoji(status: string): string {\n return JOB_STATUS_EMOJI[status] || '';\n}\n\nexport function parseTransferStatuses(raw?: string): JobStatus[] {\n if (!raw) return ['ready', 'dead'];\n return raw.split(',').map((s) => s.trim()) as JobStatus[];\n}\n\nexport async function cmdTransfer(\n dbPath: string,\n from: string,\n to: string,\n options: Record<string, string>\n): Promise<void> {\n const db = createDatabase({ filename: dbPath });\n\n try {\n const orch = createOrchestrator({ db });\n const status = parseTransferStatuses(options.status);\n const limit = options.limit ? parseInt(options.limit, 10) : undefined;\n const resetForRetry = options.retry === 'true';\n\n const { moved } = await orch.transfer({\n from,\n to,\n status,\n limit,\n resetForRetry,\n });\n\n console.log(`↔️ Moved ${moved} job(s) from '${from}' to '${to}'`);\n } finally {\n await db.destroy();\n }\n}\n\nexport type CliCommand =\n | 'stats'\n | 'list'\n | 'export'\n | 'import'\n | 'purge'\n | 'retry'\n | 'pause'\n | 'resume'\n | 'queues'\n | 'transfer';\n\nexport async function runCommand(\n command: CliCommand,\n dbPath: string,\n positionalArgs: string[],\n options: Record<string, string>\n): Promise<void> {\n switch (command) {\n case 'stats':\n await cmdStats(dbPath);\n break;\n case 'list':\n await cmdList(dbPath, options);\n break;\n case 'export':\n await cmdExport(dbPath, positionalArgs[1], options);\n break;\n case 'import':\n if (!positionalArgs[1]) {\n throw new Error('Input CSV file is required');\n }\n await cmdImport(dbPath, positionalArgs[1]);\n break;\n case 'purge':\n await cmdPurge(dbPath, options);\n break;\n case 'retry':\n await cmdRetry(dbPath, options);\n break;\n case 'pause':\n if (!positionalArgs[1]) {\n throw new Error('Queue name is required');\n }\n await cmdPause(dbPath, positionalArgs[1]);\n break;\n case 'resume':\n if (!positionalArgs[1]) {\n throw new Error('Queue name is required');\n }\n await cmdResume(dbPath, positionalArgs[1]);\n break;\n case 'queues':\n await cmdQueues(dbPath);\n break;\n case 'transfer':\n if (!positionalArgs[1] || !positionalArgs[2]) {\n throw new Error('Source and target queue names are required');\n }\n await cmdTransfer(dbPath, positionalArgs[1], positionalArgs[2], options);\n break;\n default:\n throw new Error(`Unknown command: ${command}`);\n }\n}\n","import Database from 'better-sqlite3';\nimport { Kysely, SqliteDialect } from 'kysely';\nimport type { WorkmaticDatabase, WorkmaticDb, DatabaseOptions } from './types.js';\n\n/** Maps Kysely instances created via {@link createDatabase} to the underlying driver DB. */\nconst kyselyToSqlite = new WeakMap<WorkmaticDb, Database.Database>();\n\n/**\n * Create and initialize the workmatic database\n * \n * @param options - Database options\n * @returns Kysely database instance\n * \n * @example\n * ```ts\n * // Using a file path\n * const db = createDatabase({ filename: './jobs.db' });\n * \n * // Using an existing better-sqlite3 instance\n * import Database from 'better-sqlite3';\n * const sqlite = new Database('./jobs.db');\n * const db = createDatabase({ db: sqlite });\n * \n * // In-memory database (for testing)\n * const db = createDatabase({ filename: ':memory:' });\n * ```\n */\nexport function createDatabase(options: DatabaseOptions = {}): WorkmaticDb {\n let sqliteDb: Database.Database;\n\n if (options.db) {\n sqliteDb = options.db;\n } else {\n const filename = options.filename ?? ':memory:';\n sqliteDb = new Database(filename);\n }\n\n // Set pragmas for performance and safety\n sqliteDb.pragma('journal_mode = WAL');\n sqliteDb.pragma('synchronous = NORMAL');\n sqliteDb.pragma('busy_timeout = 5000');\n\n // Create Kysely instance\n const db = new Kysely<WorkmaticDatabase>({\n dialect: new SqliteDialect({\n database: sqliteDb,\n }),\n });\n\n // Create schema synchronously using better-sqlite3 directly\n createSchema(sqliteDb);\n\n kyselyToSqlite.set(db, sqliteDb);\n\n return db;\n}\n\n/**\n * Create the database schema if it doesn't exist\n */\nfunction createSchema(db: Database.Database): void {\n // Create the jobs table\n db.exec(`\n CREATE TABLE IF NOT EXISTS workmatic_jobs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n public_id TEXT UNIQUE NOT NULL,\n queue TEXT NOT NULL,\n payload TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'ready',\n priority INTEGER NOT NULL DEFAULT 0,\n run_at INTEGER NOT NULL,\n attempts INTEGER NOT NULL DEFAULT 0,\n max_attempts INTEGER NOT NULL DEFAULT 3,\n lease_until INTEGER NOT NULL DEFAULT 0,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n last_error TEXT\n )\n `);\n\n // Create composite index for efficient job claiming\n // (queue, status, run_at, priority, id)\n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_workmatic_jobs_claim \n ON workmatic_jobs (queue, status, run_at, priority, id)\n `);\n\n // Create index for lease expiration checking\n // (status, lease_until)\n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_workmatic_jobs_lease \n ON workmatic_jobs (status, lease_until)\n `);\n\n // Create settings table for queue-level settings (pause state, etc.)\n db.exec(`\n CREATE TABLE IF NOT EXISTS workmatic_settings (\n queue TEXT PRIMARY KEY,\n paused INTEGER NOT NULL DEFAULT 0,\n updated_at INTEGER NOT NULL\n )\n `);\n\n // Legacy status no longer used in the state machine (retries use `ready`, terminal errors use `dead`)\n db.exec(`\n UPDATE workmatic_jobs SET status = 'dead' WHERE status = 'failed'\n `);\n}\n\n/**\n * Get the underlying better-sqlite3 database instance from a Kysely instance\n * created with {@link createDatabase}. For manually constructed `Kysely` instances,\n * falls back to reading the dialect adapter (may break across Kysely versions).\n */\nexport function getUnderlyingDb(db: WorkmaticDb): Database.Database {\n const mapped = kyselyToSqlite.get(db);\n if (mapped) {\n return mapped;\n }\n try {\n const ex = (db as unknown as { getExecutor?: () => { adapter: { db: Database.Database } } })\n .getExecutor?.();\n const dialect = ex?.adapter?.db;\n if (dialect) {\n return dialect;\n }\n } catch {\n /* ignore */\n }\n throw new Error(\n 'getUnderlyingDb: could not resolve better-sqlite3 instance (use createDatabase() or pass db from it)'\n );\n}\n","import { sql } from 'kysely';\nimport { createClient } from './client.js';\nimport { createWorker } from './worker.js';\nimport type {\n WorkmaticDb,\n OrchestratorOptions,\n RegisterQueueOptions,\n WorkmaticOrchestrator,\n WorkmaticClient,\n WorkmaticWorker,\n TransferOptions,\n TransferResult,\n MoveJobOptions,\n JobStats,\n JobStatus,\n JobProcessor,\n} from './types.js';\nimport { now } from './utils.js';\n\nconst DEFAULT_TRANSFER_STATUSES: JobStatus[] = ['ready', 'dead'];\nconst DEFAULT_TRANSFER_LIMIT = 10_000;\n\n/** @internal Exported for tests */\nexport function rowsUpdated(result: unknown): number {\n const row = (result as { numUpdatedRows?: number | bigint }[])[0];\n return Number(row?.numUpdatedRows ?? 0);\n}\n\nfunction normalizeStatuses(status?: JobStatus | JobStatus[]): JobStatus[] {\n if (!status) return [...DEFAULT_TRANSFER_STATUSES];\n return Array.isArray(status) ? status : [status];\n}\n\ninterface QueueEntry {\n client: WorkmaticClient;\n worker?: WorkmaticWorker;\n}\n\n/**\n * Create a multi-queue orchestrator for registration, lifecycle, and transfers.\n */\nexport function createOrchestrator(options: OrchestratorOptions): WorkmaticOrchestrator {\n const { db } = options;\n if (!db) {\n throw new Error('Database instance is required');\n }\n\n const registry = new Map<string, QueueEntry>();\n\n function ensureEntry(queue: string): QueueEntry {\n let entry = registry.get(queue);\n if (!entry) {\n entry = { client: createClient({ db, queue }) };\n registry.set(queue, entry);\n }\n return entry;\n }\n\n async function setQueuePaused(queue: string, paused: boolean): Promise<void> {\n const timestamp = now();\n const value = paused ? 1 : 0;\n await sql`\n INSERT INTO workmatic_settings (queue, paused, updated_at)\n VALUES (${queue}, ${value}, ${timestamp})\n ON CONFLICT(queue) DO UPDATE SET\n paused = ${value},\n updated_at = ${timestamp}\n `.execute(db);\n }\n\n async function selectJobIds(\n from: string,\n status: JobStatus,\n limit: number\n ): Promise<number[]> {\n const rows = await db\n .selectFrom('workmatic_jobs')\n .select('id')\n .where('queue', '=', from)\n .where('status', '=', status)\n .orderBy('priority', 'asc')\n .orderBy('id', 'asc')\n .limit(limit)\n .execute();\n return rows.map((r) => r.id);\n }\n\n async function transferReady(from: string, to: string, limit: number): Promise<number> {\n const ids = await selectJobIds(from, 'ready', limit);\n if (ids.length === 0) return 0;\n const timestamp = now();\n const result = await db\n .updateTable('workmatic_jobs')\n .set({ queue: to, updated_at: timestamp })\n .where('id', 'in', ids)\n .execute();\n return rowsUpdated(result);\n }\n\n async function transferDead(\n from: string,\n to: string,\n limit: number,\n resetForRetry: boolean\n ): Promise<number> {\n const ids = await selectJobIds(from, 'dead', limit);\n if (ids.length === 0) return 0;\n const timestamp = now();\n if (resetForRetry) {\n const result = await db\n .updateTable('workmatic_jobs')\n .set({\n queue: to,\n status: 'ready',\n attempts: 0,\n lease_until: 0,\n last_error: null,\n updated_at: timestamp,\n run_at: timestamp,\n })\n .where('id', 'in', ids)\n .execute();\n return rowsUpdated(result);\n }\n\n const result = await db\n .updateTable('workmatic_jobs')\n .set({ queue: to, updated_at: timestamp })\n .where('id', 'in', ids)\n .execute();\n return rowsUpdated(result);\n }\n\n async function transferOtherStatus(\n from: string,\n to: string,\n status: JobStatus,\n limit: number\n ): Promise<number> {\n const ids = await selectJobIds(from, status, limit);\n if (ids.length === 0) return 0;\n const timestamp = now();\n const result = await db\n .updateTable('workmatic_jobs')\n .set({ queue: to, updated_at: timestamp })\n .where('id', 'in', ids)\n .execute();\n return rowsUpdated(result);\n }\n\n const orchestrator: WorkmaticOrchestrator = {\n register(queue: string, opts: RegisterQueueOptions = {}): WorkmaticClient {\n const client = createClient({ db, queue });\n let worker: WorkmaticWorker | undefined;\n if (opts.worker) {\n worker = createWorker({ db, queue, ...opts.worker });\n }\n registry.set(queue, { client, worker });\n return client;\n },\n\n client(queue: string): WorkmaticClient {\n return ensureEntry(queue).client;\n },\n\n worker(queue: string): WorkmaticWorker {\n const entry = registry.get(queue);\n if (!entry?.worker) {\n throw new Error(`No worker registered for queue \"${queue}\"`);\n }\n return entry.worker;\n },\n\n workers(): WorkmaticWorker[] {\n return [...registry.values()]\n .map((e) => e.worker)\n .filter((w): w is WorkmaticWorker => w !== undefined);\n },\n\n async queues(): Promise<string[]> {\n const rows = await db\n .selectFrom('workmatic_jobs')\n .select('queue')\n .distinct()\n .execute();\n const names = new Set<string>(rows.map((r) => r.queue));\n for (const name of registry.keys()) {\n names.add(name);\n }\n return [...names].sort();\n },\n\n process<TPayload = unknown>(queue: string, fn: JobProcessor<TPayload>): void {\n this.worker(queue).process(fn);\n },\n\n startAll(): void {\n for (const entry of registry.values()) {\n entry.worker?.start();\n }\n },\n\n async stopAll(): Promise<void> {\n const stops = [...registry.values()]\n .map((e) => e.worker?.stop())\n .filter((p): p is Promise<void> => p !== undefined);\n await Promise.all(stops);\n },\n\n async pause(queue: string): Promise<void> {\n const entry = registry.get(queue);\n entry?.worker?.pause();\n await setQueuePaused(queue, true);\n },\n\n async resume(queue: string): Promise<void> {\n const entry = registry.get(queue);\n entry?.worker?.resume();\n await setQueuePaused(queue, false);\n },\n\n async isPaused(queue: string): Promise<boolean> {\n const setting = await db\n .selectFrom('workmatic_settings')\n .select('paused')\n .where('queue', '=', queue)\n .executeTakeFirst();\n return setting?.paused === 1;\n },\n\n async stats(queueName?: string): Promise<Record<string, JobStats>> {\n const names = queueName ? [queueName] : await this.queues();\n const result: Record<string, JobStats> = {};\n for (const name of names) {\n result[name] = await ensureEntry(name).client.stats();\n }\n return result;\n },\n\n async transfer(opts: TransferOptions): Promise<TransferResult> {\n const { from, to, resetForRetry = false } = opts;\n if (from === to) {\n return { moved: 0 };\n }\n\n const statuses = normalizeStatuses(opts.status);\n let remaining = opts.limit ?? DEFAULT_TRANSFER_LIMIT;\n let moved = 0;\n\n if (statuses.includes('ready') && remaining > 0) {\n const n = await transferReady(from, to, remaining);\n moved += n;\n remaining -= n;\n }\n if (statuses.includes('dead') && remaining > 0) {\n const n = await transferDead(from, to, remaining, resetForRetry);\n moved += n;\n remaining -= n;\n }\n for (const status of statuses) {\n if (status === 'ready' || status === 'dead' || remaining <= 0) continue;\n const n = await transferOtherStatus(from, to, status, remaining);\n moved += n;\n remaining -= n;\n }\n\n return { moved };\n },\n\n async moveJob(\n publicId: string,\n toQueue: string,\n opts: MoveJobOptions = {}\n ): Promise<void> {\n const allowed = normalizeStatuses(opts.status);\n const row = await db\n .selectFrom('workmatic_jobs')\n .select(['id', 'queue', 'status'])\n .where('public_id', '=', publicId)\n .executeTakeFirst();\n\n if (!row) {\n throw new Error(`Job not found: ${publicId}`);\n }\n if (row.queue === toQueue) {\n return;\n }\n if (!allowed.includes(row.status)) {\n throw new Error(\n `Job ${publicId} has status \"${row.status}\" and cannot be moved (allowed: ${allowed.join(', ')})`\n );\n }\n\n const timestamp = now();\n const resetForRetry = opts.resetForRetry ?? false;\n\n if (row.status === 'dead' && resetForRetry) {\n await db\n .updateTable('workmatic_jobs')\n .set({\n queue: toQueue,\n status: 'ready',\n attempts: 0,\n lease_until: 0,\n last_error: null,\n updated_at: timestamp,\n run_at: timestamp,\n })\n .where('public_id', '=', publicId)\n .execute();\n return;\n }\n\n await db\n .updateTable('workmatic_jobs')\n .set({ queue: toQueue, updated_at: timestamp })\n .where('public_id', '=', publicId)\n .execute();\n },\n };\n\n return orchestrator;\n}\n","import { nanoid } from 'nanoid';\nimport { sql } from 'kysely';\nimport type {\n WorkmaticDb,\n ClientOptions,\n WorkmaticClient,\n AddJobOptions,\n AddJobResult,\n AddManyResult,\n JobStats,\n JobStatus,\n} from './types.js';\nimport { validatePayload, now } from './utils.js';\n\n/**\n * Create a job queue client for adding jobs\n * \n * @param options - Client options\n * @returns Client instance\n * \n * @example\n * ```ts\n * const client = createClient({ db });\n * \n * // Add a simple job\n * const result = await client.add({ email: 'user@example.com' });\n * console.log(result.id); // Job public ID\n * \n * // Add a job with options\n * await client.add(\n * { userId: 123 },\n * { priority: 1, delayMs: 5000, maxAttempts: 5 }\n * );\n * \n * // Get queue statistics\n * const stats = await client.stats();\n * console.log(stats); // { ready: 5, running: 2, done: 100, ... }\n * ```\n */\nexport function createClient(options: ClientOptions): WorkmaticClient {\n const { db, queue = 'default' } = options;\n\n if (!db) {\n throw new Error('Database instance is required');\n }\n\n return {\n /**\n * Add a job to the queue\n */\n async add<TPayload = unknown>(\n payload: TPayload,\n opts: AddJobOptions = {}\n ): Promise<AddJobResult> {\n const {\n priority = 0,\n delayMs = 0,\n maxAttempts = 3,\n } = opts;\n\n // Validate and serialize payload\n const payloadJson = validatePayload(payload);\n \n // Generate unique public ID\n const publicId = nanoid();\n \n const timestamp = now();\n const runAt = timestamp + delayMs;\n\n // Insert job\n await db\n .insertInto('workmatic_jobs')\n .values({\n public_id: publicId,\n queue,\n payload: payloadJson,\n status: 'ready',\n priority,\n run_at: runAt,\n attempts: 0,\n max_attempts: maxAttempts,\n lease_until: 0,\n created_at: timestamp,\n updated_at: timestamp,\n last_error: null,\n })\n .execute();\n\n return { ok: true, id: publicId };\n },\n\n async addMany<TPayload = unknown>(\n payloads: TPayload[],\n opts: AddJobOptions = {}\n ): Promise<AddManyResult> {\n const {\n priority = 0,\n delayMs = 0,\n maxAttempts = 3,\n } = opts;\n\n if (payloads.length === 0) {\n return { ok: true, ids: [] };\n }\n\n const timestamp = now();\n const runAt = timestamp + delayMs;\n\n return await db.transaction().execute(async (trx) => {\n const ids: string[] = [];\n const rows = payloads.map((payload) => {\n const payloadJson = validatePayload(payload);\n const publicId = nanoid();\n ids.push(publicId);\n return {\n public_id: publicId,\n queue,\n payload: payloadJson,\n status: 'ready' as const,\n priority,\n run_at: runAt,\n attempts: 0,\n max_attempts: maxAttempts,\n lease_until: 0,\n created_at: timestamp,\n updated_at: timestamp,\n last_error: null,\n };\n });\n\n await trx.insertInto('workmatic_jobs').values(rows).execute();\n return { ok: true, ids };\n });\n },\n\n /**\n * Get job statistics for the queue\n */\n async stats(): Promise<JobStats> {\n const result = await db\n .selectFrom('workmatic_jobs')\n .select([\n 'status',\n sql<number>`count(*)`.as('count'),\n ])\n .where('queue', '=', queue)\n .groupBy('status')\n .execute();\n\n const stats: JobStats = {\n ready: 0,\n running: 0,\n done: 0,\n dead: 0,\n total: 0,\n };\n\n for (const row of result) {\n const status = row.status as JobStatus;\n const count = Number(row.count);\n if (status in stats) {\n stats[status] = count;\n }\n stats.total += count;\n }\n\n return stats;\n },\n\n /**\n * Clear all jobs from the queue\n */\n async clear(options: { status?: JobStatus } = {}): Promise<number> {\n let query = db\n .deleteFrom('workmatic_jobs')\n .where('queue', '=', queue);\n\n if (options.status) {\n query = query.where('status', '=', options.status);\n }\n\n const result = await query.execute();\n return Number(result[0]?.numDeletedRows ?? 0);\n },\n };\n}\n","import type { BackoffFunction } from './types.js';\n\n/**\n * Default exponential backoff function\n * Returns delay in milliseconds: 1000 * 2^attempts\n * \n * @param attempts - Number of failed attempts\n * @returns Delay in milliseconds\n * \n * @example\n * ```ts\n * defaultBackoff(0) // 1000ms (1 second)\n * defaultBackoff(1) // 2000ms (2 seconds)\n * defaultBackoff(2) // 4000ms (4 seconds)\n * defaultBackoff(3) // 8000ms (8 seconds)\n * ```\n */\nexport const defaultBackoff: BackoffFunction = (attempts: number): number => {\n return 1000 * Math.pow(2, attempts);\n};\n\n/**\n * Validate that a payload is JSON-serializable\n * \n * @param payload - The payload to validate\n * @throws Error if payload cannot be serialized to JSON\n * @returns The JSON string representation\n */\nexport function validatePayload(payload: unknown): string {\n try {\n return JSON.stringify(payload);\n } catch (error) {\n throw new Error(\n `Payload is not JSON-serializable: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n}\n\n/**\n * Parse a JSON payload safely\n * \n * @param json - JSON string to parse\n * @returns Parsed payload\n * @throws Error if JSON is invalid\n */\nexport function parsePayload<T = unknown>(json: string): T {\n try {\n return JSON.parse(json) as T;\n } catch (error) {\n throw new Error(\n `Invalid JSON payload: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n}\n\n/**\n * Sleep for a specified duration\n * \n * @param ms - Duration in milliseconds\n * @returns Promise that resolves after the duration\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Get current timestamp in milliseconds\n */\nexport function now(): number {\n return Date.now();\n}\n","import fastq from 'fastq';\nimport type { queueAsPromised } from 'fastq';\nimport { sql } from 'kysely';\nimport type {\n WorkmaticDb,\n WorkerOptions,\n WorkmaticWorker,\n JobProcessor,\n JobStats,\n JobStatus,\n Job,\n ClaimedJob,\n WorkerState,\n} from './types.js';\nimport { defaultBackoff, parsePayload, now } from './utils.js';\n\n/** Default job execution timeout when `timeoutMs` is omitted (1 minute). Use `timeoutMs: 0` for no limit. */\nexport const DEFAULT_WORKER_TIMEOUT_MS = 60_000;\n\n/** @internal Exported for tests β€” maps SQLite RETURNING result to claimed jobs */\nexport function parseClaimedRows(result: unknown): ClaimedJob[] {\n const rows = (result as { rows?: ClaimedJob[] }).rows;\n if (!rows || !Array.isArray(rows)) {\n return [];\n }\n return rows.map((row) => ({\n id: row.id,\n public_id: row.public_id,\n queue: row.queue,\n payload: row.payload,\n attempts: row.attempts,\n max_attempts: row.max_attempts,\n priority: row.priority,\n created_at: row.created_at,\n last_error: row.last_error,\n }));\n}\n\n/** @internal Exported for tests */\nexport function requireProcessor<T>(processor: JobProcessor<T> | null): JobProcessor<T> {\n if (!processor) {\n throw new Error('No processor set');\n }\n return processor;\n}\n\n/**\n * Create a job queue worker for processing jobs\n * \n * @param options - Worker options\n * @returns Worker instance\n * \n * @example\n * ```ts\n * const worker = createWorker({ db, concurrency: 4 });\n * \n * // Set the processor function\n * worker.process(async (job) => {\n * console.log('Processing job:', job.id);\n * await sendEmail(job.payload.email);\n * });\n * \n * // Start processing\n * worker.start();\n * \n * // Later, gracefully stop\n * await worker.stop();\n * ```\n */\nexport function createWorker(options: WorkerOptions): WorkmaticWorker {\n const {\n db,\n queue = 'default',\n concurrency = 1,\n leaseMs = 30000,\n pollMs = 1000,\n timeoutMs = DEFAULT_WORKER_TIMEOUT_MS,\n backoff = defaultBackoff,\n persistState = false,\n autoRestore = true,\n pauseCheckIntervalMs = 300,\n requeueExpiredIntervalMs = 0,\n onPumpError,\n } = options;\n\n if (!db) {\n throw new Error('Database instance is required');\n }\n\n // State\n let running = false;\n let paused = false;\n let processor: JobProcessor<any> | null = null;\n let pumpTimeout: NodeJS.Timeout | null = null;\n let fastqQueue: queueAsPromised<ClaimedJob, void> | null = null;\n let lastPauseCheckAt = 0;\n let cachedDbPaused = false;\n let lastRequeueAt = 0;\n\n function notifyPumpError(error: unknown): void {\n console.error('[workmatic] Pump error:', error);\n onPumpError?.(error);\n }\n\n /**\n * Get the settings key for this worker's state\n */\n function getStateKey(): string {\n return `worker_state_${queue}`;\n }\n\n /**\n * Save worker state to database\n */\n async function saveState(state: WorkerState): Promise<void> {\n if (!persistState) return;\n\n const timestamp = now();\n const key = getStateKey();\n\n // Use raw SQL for upsert since different SQLite versions have different syntax\n await sql`\n INSERT INTO workmatic_settings (queue, paused, updated_at)\n VALUES (${key}, ${state === 'paused' ? 1 : state === 'running' ? 2 : 0}, ${timestamp})\n ON CONFLICT(queue) DO UPDATE SET \n paused = ${state === 'paused' ? 1 : state === 'running' ? 2 : 0},\n updated_at = ${timestamp}\n `.execute(db);\n }\n\n /**\n * Load worker state from database\n */\n async function loadState(): Promise<WorkerState | null> {\n if (!persistState) return null;\n\n try {\n const key = getStateKey();\n const result = await db\n .selectFrom('workmatic_settings')\n .select('paused')\n .where('queue', '=', key)\n .executeTakeFirst();\n\n if (!result) return null;\n \n // paused: 0 = stopped, 1 = paused, 2 = running\n if (result.paused === 2) return 'running';\n if (result.paused === 1) return 'paused';\n return 'stopped';\n } catch {\n return null;\n }\n }\n\n /**\n * Requeue jobs with expired leases\n */\n async function requeueExpiredLeases(): Promise<number> {\n const timestamp = now();\n\n const result = await db\n .updateTable('workmatic_jobs')\n .set({\n status: 'ready',\n lease_until: 0,\n updated_at: timestamp,\n })\n .where('status', '=', 'running')\n .where('lease_until', '<', timestamp)\n .where('lease_until', '>', 0)\n .execute();\n\n return Number(result[0]?.numUpdatedRows ?? 0);\n }\n\n /**\n * Claim a batch of jobs for processing (single UPDATE … RETURNING per SQLite 3.35+)\n */\n async function claimBatch(limit: number): Promise<ClaimedJob[]> {\n const timestamp = now();\n const leaseUntil = timestamp + leaseMs;\n\n return await db.transaction().execute(async (trx) => {\n const result = await sql<{\n id: number;\n public_id: string;\n queue: string;\n payload: string;\n attempts: number;\n max_attempts: number;\n priority: number;\n created_at: number;\n last_error: string | null;\n }>`\n UPDATE workmatic_jobs\n SET status = 'running', lease_until = ${leaseUntil}, updated_at = ${timestamp}\n WHERE rowid IN (\n SELECT rowid FROM workmatic_jobs\n WHERE queue = ${queue}\n AND status = 'ready'\n AND run_at <= ${timestamp}\n ORDER BY priority ASC, id ASC\n LIMIT ${limit}\n )\n RETURNING id, public_id, queue, payload, attempts, max_attempts, priority, created_at, last_error\n `.execute(trx);\n\n return parseClaimedRows(result);\n });\n }\n\n /**\n * Mark a job as completed\n */\n async function markDone(jobId: number): Promise<void> {\n await db\n .updateTable('workmatic_jobs')\n .set({\n status: 'done',\n lease_until: 0,\n updated_at: now(),\n })\n .where('id', '=', jobId)\n .execute();\n }\n\n /**\n * Handle job failure\n */\n async function markFailed(\n jobId: number,\n attempts: number,\n maxAttempts: number,\n error: Error\n ): Promise<void> {\n const timestamp = now();\n const newAttempts = attempts + 1;\n const errorMessage = error.message || String(error);\n\n if (newAttempts < maxAttempts) {\n // Retry: set back to ready with backoff delay\n const runAt = timestamp + backoff(newAttempts);\n \n await db\n .updateTable('workmatic_jobs')\n .set({\n status: 'ready',\n attempts: newAttempts,\n run_at: runAt,\n lease_until: 0,\n last_error: errorMessage,\n updated_at: timestamp,\n })\n .where('id', '=', jobId)\n .execute();\n } else {\n // Max attempts reached: mark as dead\n await db\n .updateTable('workmatic_jobs')\n .set({\n status: 'dead',\n attempts: newAttempts,\n lease_until: 0,\n last_error: errorMessage,\n updated_at: timestamp,\n })\n .where('id', '=', jobId)\n .execute();\n }\n }\n\n /**\n * Run a promise with timeout\n */\n async function withTimeout<T>(\n promise: Promise<T>,\n ms: number,\n jobId: string\n ): Promise<T> {\n let timeoutId: NodeJS.Timeout;\n \n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new Error(`Job ${jobId} timed out after ${ms}ms`));\n }, ms);\n });\n\n try {\n return await Promise.race([promise, timeoutPromise]);\n } finally {\n clearTimeout(timeoutId!);\n }\n }\n\n /**\n * Process a single job\n */\n async function processJob(claimedJob: ClaimedJob): Promise<void> {\n const fn = requireProcessor(processor);\n\n // Parse payload and create job object\n const payload = parsePayload(claimedJob.payload);\n const job: Job = {\n id: claimedJob.public_id,\n queue: claimedJob.queue,\n payload,\n status: 'running',\n priority: claimedJob.priority,\n attempts: claimedJob.attempts,\n maxAttempts: claimedJob.max_attempts,\n createdAt: claimedJob.created_at,\n lastError: claimedJob.last_error,\n };\n\n try {\n // Run processor with optional timeout\n if (timeoutMs) {\n await withTimeout(fn(job), timeoutMs, job.id);\n } else {\n await fn(job);\n }\n await markDone(claimedJob.id);\n } catch (error) {\n await markFailed(\n claimedJob.id,\n claimedJob.attempts,\n claimedJob.max_attempts,\n error instanceof Error ? error : new Error(String(error))\n );\n }\n }\n\n /**\n * Check if queue is paused in database (for CLI control)\n */\n async function isQueuePausedInDb(): Promise<boolean> {\n const setting = await db\n .selectFrom('workmatic_settings')\n .select('paused')\n .where('queue', '=', queue)\n .executeTakeFirst();\n \n return setting?.paused === 1;\n }\n\n /**\n * Main pump loop\n */\n async function pump(): Promise<void> {\n if (!running) {\n return;\n }\n\n // Check both in-memory pause and database pause (for CLI control)\n if (paused) {\n pumpTimeout = setTimeout(pump, pollMs);\n return;\n }\n\n try {\n const t = now();\n if (t - lastPauseCheckAt >= pauseCheckIntervalMs) {\n lastPauseCheckAt = t;\n cachedDbPaused = await isQueuePausedInDb();\n }\n if (cachedDbPaused) {\n pumpTimeout = setTimeout(pump, pollMs);\n return;\n }\n\n if (\n requeueExpiredIntervalMs <= 0 ||\n t - lastRequeueAt >= requeueExpiredIntervalMs\n ) {\n if (requeueExpiredIntervalMs > 0) {\n lastRequeueAt = t;\n }\n await requeueExpiredLeases();\n }\n\n // Claim a batch of jobs\n const batchSize = concurrency * 2;\n const jobs = await claimBatch(batchSize);\n\n if (jobs.length > 0) {\n // Push jobs into fastq\n for (const job of jobs) {\n fastqQueue!.push(job);\n }\n // Immediately pump again\n pumpTimeout = setTimeout(pump, 0);\n } else {\n // No jobs, wait before polling again\n pumpTimeout = setTimeout(pump, pollMs);\n }\n } catch (error) {\n notifyPumpError(error);\n pumpTimeout = setTimeout(pump, pollMs);\n }\n }\n\n // Create the worker object\n const worker: WorkmaticWorker = {\n process<TPayload = unknown>(fn: JobProcessor<TPayload>): void {\n processor = fn as JobProcessor<any>;\n },\n\n start(): void {\n if (running) {\n return;\n }\n\n if (!processor) {\n throw new Error('No processor set. Call process() before start()');\n }\n\n running = true;\n paused = false;\n\n // Create fastq queue\n fastqQueue = fastq.promise(processJob, concurrency);\n\n // Save state to database\n saveState('running').catch(() => {});\n\n // Start pump loop\n pump();\n },\n\n async stop(): Promise<void> {\n if (!running) {\n return;\n }\n\n running = false;\n\n // Clear pump timeout\n if (pumpTimeout) {\n clearTimeout(pumpTimeout);\n pumpTimeout = null;\n }\n\n // Wait for fastq to drain\n if (fastqQueue) {\n await fastqQueue.drained();\n fastqQueue = null;\n }\n\n // Save state to database\n await saveState('stopped');\n },\n\n pause(): void {\n paused = true;\n saveState('paused').catch(() => {});\n },\n\n resume(): void {\n paused = false;\n saveState('running').catch(() => {});\n },\n\n async stats(): Promise<JobStats> {\n const result = await db\n .selectFrom('workmatic_jobs')\n .select([\n 'status',\n sql<number>`count(*)`.as('count'),\n ])\n .where('queue', '=', queue)\n .groupBy('status')\n .execute();\n\n const stats: JobStats = {\n ready: 0,\n running: 0,\n done: 0,\n dead: 0,\n total: 0,\n };\n\n for (const row of result) {\n const status = row.status as JobStatus;\n const count = Number(row.count);\n if (status in stats) {\n stats[status] = count;\n }\n stats.total += count;\n }\n\n return stats;\n },\n\n get isRunning(): boolean {\n return running;\n },\n\n get isPaused(): boolean {\n return paused;\n },\n\n get queue(): string {\n return queue;\n },\n\n async restoreState(): Promise<WorkerState | null> {\n const state = await loadState();\n if (state === 'running' && processor) {\n this.start();\n } else if (state === 'paused' && processor) {\n this.start();\n this.pause();\n }\n return state;\n },\n\n async clear(options: { status?: JobStatus } = {}): Promise<number> {\n let query = db\n .deleteFrom('workmatic_jobs')\n .where('queue', '=', queue);\n\n if (options.status) {\n query = query.where('status', '=', options.status);\n }\n\n const result = await query.execute();\n return Number(result[0]?.numDeletedRows ?? 0);\n },\n };\n\n // Auto-restore state if enabled\n if (persistState && autoRestore) {\n // Use setImmediate to allow processor to be set first\n setImmediate(async () => {\n if (processor) {\n await worker.restoreState();\n }\n });\n }\n\n return worker;\n}\n","#!/usr/bin/env node\n\n/**\n * Workmatic CLI β€” thin entrypoint; logic in ./cli/handlers.ts\n */\n\nimport {\n printUsage,\n parseOptions,\n getPositionalArgs,\n runCommand,\n type CliCommand,\n} from './cli/handlers.js';\n\nconst args = process.argv.slice(2);\nconst command = args[0];\n\nconst KNOWN_COMMANDS: readonly CliCommand[] = [\n 'stats',\n 'list',\n 'export',\n 'import',\n 'purge',\n 'retry',\n 'pause',\n 'resume',\n 'queues',\n 'transfer',\n];\n\nfunction isCliCommand(value: string): value is CliCommand {\n return (KNOWN_COMMANDS as readonly string[]).includes(value);\n}\n\nasync function main(): Promise<void> {\n if (!command || command === '--help' || command === '-h') {\n printUsage();\n process.exit(0);\n }\n\n if (!isCliCommand(command)) {\n console.error(`Unknown command: ${command}`);\n printUsage();\n process.exit(1);\n }\n\n const positionalArgs = getPositionalArgs(args.slice(1));\n const options = parseOptions(args);\n const dbPath = positionalArgs[0];\n\n if (!dbPath) {\n console.error('Error: Database path is required');\n printUsage();\n process.exit(1);\n }\n\n try {\n await runCommand(command, dbPath, positionalArgs, options);\n } catch (error) {\n console.error('Error:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n}\n\nmain();\n"],"mappings":"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","names":["import_better_sqlite3","Database","import_kysely","import_kysely","options","import_kysely","fastq","options","result","args","Database","Table","command"]}
1
+ {"version":3,"sources":["../src/cli/handlers.ts","../src/database.ts","../src/orchestrator.ts","../src/client.ts","../src/utils.ts","../src/worker.ts","../src/shutdown.ts","../src/mcp/server.ts","../src/mcp/tools.ts","../src/cli.ts"],"sourcesContent":["import Database from 'better-sqlite3';\nimport { createReadStream, createWriteStream } from 'fs';\nimport { finished } from 'stream/promises';\nimport { createInterface } from 'readline';\nimport Table from 'cli-table3';\nimport { createDatabase } from '../database.js';\nimport { createOrchestrator } from '../orchestrator.js';\nimport { createMcpServer } from '../mcp/server.js';\nimport type { JobStatus } from '../types.js';\n\nexport function printUsage(): void {\n console.log(`\nWorkmatic CLI - Job Queue Management\n\nUsage:\n workmatic <command> [options]\n\nCommands:\n stats <db> Show job statistics\n queues <db> List all queues with status\n list <db> [--status=<status>] List jobs (optionally filter by status)\n export <db> [output.csv] Export jobs to CSV (default: stdout)\n import <db> <input.csv> Import jobs from CSV\n purge <db> --status=<status> Delete jobs by status\n retry <db> [--status=dead] Retry dead jobs (reset to ready)\n pause <db> <queue> Pause a queue (running workers stop claiming)\n resume <db> <queue> Resume a paused queue\n transfer <db> <from> <to> Move jobs between queues\n mcp <db> Start Model Context Protocol (MCP) server\n\n\nOptions:\n --status=<status> Filter by status (ready|running|done|dead), comma-separated for transfer\n --queue=<queue> Filter by queue name\n --limit=<n> Limit number of results or jobs to transfer (default: 100 / 10000)\n --retry When transferring dead jobs, reset them to ready for retry\n\nExamples:\n workmatic stats ./jobs.db\n workmatic list ./jobs.db --status=dead --limit=10\n workmatic transfer ./jobs.db emails retry-emails --status=dead --retry\n workmatic pause ./jobs.db emails\n workmatic resume ./jobs.db emails\n`);\n}\n\nexport function parseOptions(args: string[]): Record<string, string> {\n const options: Record<string, string> = {};\n for (const arg of args) {\n if (arg.startsWith('--')) {\n const [key, value] = arg.slice(2).split('=');\n options[key] = value ?? 'true';\n }\n }\n return options;\n}\n\nexport function getPositionalArgs(args: string[]): string[] {\n return args.filter((arg) => !arg.startsWith('--'));\n}\n\nexport function escapeCSV(value: string | null): string {\n if (value === null) return '';\n const str = String(value);\n if (str.includes(',') || str.includes('\"') || str.includes('\\n')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n return str;\n}\n\nexport function parseCSVLine(line: string): string[] {\n const result: string[] = [];\n let current = '';\n let inQuotes = false;\n\n for (let i = 0; i < line.length; i++) {\n const char = line[i];\n\n if (inQuotes) {\n if (char === '\"') {\n if (line[i + 1] === '\"') {\n current += '\"';\n i++;\n } else {\n inQuotes = false;\n }\n } else {\n current += char;\n }\n } else {\n if (char === '\"') {\n inQuotes = true;\n } else if (char === ',') {\n result.push(current);\n current = '';\n } else {\n current += char;\n }\n }\n }\n\n result.push(current);\n return result;\n}\n\nexport async function cmdStats(dbPath: string): Promise<void> {\n const db = new Database(dbPath, { readonly: true });\n\n try {\n const stats = db\n .prepare(\n `\n SELECT status, COUNT(*) as count \n FROM workmatic_jobs \n GROUP BY status\n `\n )\n .all() as { status: string; count: number }[];\n\n const queues = db\n .prepare(\n `\n SELECT queue, COUNT(*) as count \n FROM workmatic_jobs \n GROUP BY queue\n `\n )\n .all() as { queue: string; count: number }[];\n\n const total = stats.reduce((sum, s) => sum + s.count, 0);\n\n console.log('\\nπŸ“Š Job Statistics\\n');\n\n const statusOrder = ['ready', 'running', 'done', 'dead'];\n const statusTable = new Table({\n head: ['', 'Status', 'Count'],\n style: { head: ['cyan'], border: ['gray'] },\n colAligns: ['left', 'left', 'right'],\n });\n\n for (const status of statusOrder) {\n const stat = stats.find((s) => s.status === status);\n const count = stat?.count ?? 0;\n const emoji = jobStatusEmoji(status);\n statusTable.push([emoji, status, count.toLocaleString()]);\n }\n statusTable.push([{ colSpan: 2, content: 'Total', hAlign: 'right' }, total.toLocaleString()]);\n\n console.log(statusTable.toString());\n\n if (queues.length > 0) {\n console.log('\\nπŸ“‹ By Queue\\n');\n\n const queueTable = new Table({\n head: ['Queue', 'Jobs'],\n style: { head: ['cyan'], border: ['gray'] },\n colAligns: ['left', 'right'],\n });\n\n for (const q of queues) {\n queueTable.push([q.queue, q.count.toLocaleString()]);\n }\n\n console.log(queueTable.toString());\n }\n\n console.log();\n } finally {\n db.close();\n }\n}\n\nexport async function cmdList(dbPath: string, options: Record<string, string>): Promise<void> {\n const db = new Database(dbPath, { readonly: true });\n\n try {\n let query =\n 'SELECT public_id, queue, status, priority, attempts, max_attempts, created_at, last_error FROM workmatic_jobs WHERE 1=1';\n const params: unknown[] = [];\n\n if (options.status) {\n query += ' AND status = ?';\n params.push(options.status);\n }\n if (options.queue) {\n query += ' AND queue = ?';\n params.push(options.queue);\n }\n\n query += ' ORDER BY created_at DESC LIMIT ?';\n params.push(parseInt(options.limit || '100', 10));\n\n const jobs = db.prepare(query).all(...params) as {\n public_id: string;\n queue: string;\n status: string;\n priority: number;\n attempts: number;\n max_attempts: number;\n created_at: number;\n }[];\n\n if (jobs.length === 0) {\n console.log('No jobs found.');\n return;\n }\n\n const table = new Table({\n head: ['ID', 'Queue', 'Status', 'Pri', 'Attempts', 'Created'],\n style: { head: ['cyan'], border: ['gray'] },\n colAligns: ['left', 'left', 'left', 'right', 'center', 'left'],\n colWidths: [24, 16, 12, 5, 10, 21],\n wordWrap: true,\n });\n\n for (const job of jobs) {\n const emoji = jobStatusEmoji(job.status);\n table.push([\n job.public_id.slice(0, 21),\n job.queue.slice(0, 14),\n `${emoji} ${job.status}`,\n job.priority,\n `${job.attempts}/${job.max_attempts}`,\n new Date(job.created_at).toISOString().slice(0, 19),\n ]);\n }\n\n console.log();\n console.log(table.toString());\n console.log(`\\n Showing ${jobs.length} jobs\\n`);\n } finally {\n db.close();\n }\n}\n\nexport async function cmdExport(\n dbPath: string,\n outputPath: string | undefined,\n options: Record<string, string>\n): Promise<void> {\n const db = new Database(dbPath, { readonly: true });\n\n try {\n let query = 'SELECT * FROM workmatic_jobs WHERE 1=1';\n const params: unknown[] = [];\n\n if (options.status) {\n query += ' AND status = ?';\n params.push(options.status);\n }\n if (options.queue) {\n query += ' AND queue = ?';\n params.push(options.queue);\n }\n\n query += ' ORDER BY id';\n\n const jobs = db.prepare(query).all(...params) as Record<string, string | null>[];\n\n const output = outputPath ? createWriteStream(outputPath) : process.stdout;\n\n const columns = [\n 'public_id',\n 'queue',\n 'payload',\n 'status',\n 'priority',\n 'run_at',\n 'attempts',\n 'max_attempts',\n 'lease_until',\n 'created_at',\n 'updated_at',\n 'last_error',\n ];\n\n if (outputPath) {\n output.write(columns.join(',') + '\\n');\n } else {\n console.log(columns.join(','));\n }\n\n for (const job of jobs) {\n const row = columns.map((col) => escapeCSV(job[col] as string | null));\n if (outputPath) {\n output.write(row.join(',') + '\\n');\n } else {\n console.log(row.join(','));\n }\n }\n\n if (outputPath) {\n const stream = output as ReturnType<typeof createWriteStream>;\n stream.end();\n await finished(stream);\n console.error(`βœ… Exported ${jobs.length} jobs to ${outputPath}`);\n }\n } finally {\n db.close();\n }\n}\n\nexport async function cmdImport(dbPath: string, inputPath: string): Promise<void> {\n const db = new Database(dbPath);\n\n db.exec(`\n CREATE TABLE IF NOT EXISTS workmatic_jobs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n public_id TEXT UNIQUE NOT NULL,\n queue TEXT NOT NULL,\n payload TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'ready',\n priority INTEGER NOT NULL DEFAULT 0,\n run_at INTEGER NOT NULL,\n attempts INTEGER NOT NULL DEFAULT 0,\n max_attempts INTEGER NOT NULL DEFAULT 3,\n lease_until INTEGER NOT NULL DEFAULT 0,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n last_error TEXT\n )\n `);\n\n const insert = db.prepare(`\n INSERT OR REPLACE INTO workmatic_jobs \n (public_id, queue, payload, status, priority, run_at, attempts, max_attempts, lease_until, created_at, updated_at, last_error)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const rl = createInterface({\n input: createReadStream(inputPath),\n crlfDelay: Infinity,\n });\n\n let lineNum = 0;\n let imported = 0;\n let columns: string[] = [];\n\n try {\n const insertMany = db.transaction((rows: Record<string, string>[]) => {\n for (const row of rows) {\n insert.run(\n row.public_id,\n row.queue,\n row.payload,\n row.status,\n parseInt(row.priority, 10) || 0,\n parseInt(row.run_at, 10) || Date.now(),\n parseInt(row.attempts, 10) || 0,\n parseInt(row.max_attempts, 10) || 3,\n parseInt(row.lease_until, 10) || 0,\n parseInt(row.created_at, 10) || Date.now(),\n parseInt(row.updated_at, 10) || Date.now(),\n row.last_error || null\n );\n imported++;\n }\n });\n\n const batch: Record<string, string>[] = [];\n\n for await (const line of rl) {\n lineNum++;\n\n if (lineNum === 1) {\n columns = parseCSVLine(line);\n continue;\n }\n\n if (!line.trim()) continue;\n\n const values = parseCSVLine(line);\n const row: Record<string, string> = {};\n\n for (let i = 0; i < columns.length; i++) {\n row[columns[i]] = values[i] ?? '';\n }\n\n batch.push(row);\n\n if (batch.length >= 1000) {\n insertMany(batch);\n batch.length = 0;\n process.stderr.write(`\\rImported ${imported} jobs...`);\n }\n }\n\n if (batch.length > 0) {\n insertMany(batch);\n }\n\n console.log(`\\nβœ… Imported ${imported} jobs from ${inputPath}`);\n } finally {\n db.close();\n }\n}\n\nexport async function cmdPurge(\n dbPath: string,\n options: Record<string, string>\n): Promise<void> {\n if (!options.status) {\n throw new Error('--status is required for purge command');\n }\n\n const db = new Database(dbPath);\n\n try {\n const result = db\n .prepare('DELETE FROM workmatic_jobs WHERE status = ?')\n .run(options.status);\n console.log(`πŸ—‘οΈ Deleted ${result.changes} jobs with status '${options.status}'`);\n } finally {\n db.close();\n }\n}\n\nexport async function cmdRetry(dbPath: string, options: Record<string, string>): Promise<void> {\n const status = options.status || 'dead';\n const db = new Database(dbPath);\n\n try {\n const ts = Date.now();\n const result = db\n .prepare(\n `\n UPDATE workmatic_jobs \n SET status = 'ready', \n attempts = 0, \n run_at = ?, \n lease_until = 0,\n updated_at = ?\n WHERE status = ?\n `\n )\n .run(ts, ts, status);\n\n console.log(`πŸ”„ Reset ${result.changes} jobs from '${status}' to 'ready'`);\n } finally {\n db.close();\n }\n}\n\nexport async function cmdPause(dbPath: string, queueName: string): Promise<void> {\n const db = new Database(dbPath);\n\n try {\n db.exec(`\n CREATE TABLE IF NOT EXISTS workmatic_settings (\n queue TEXT PRIMARY KEY,\n paused INTEGER NOT NULL DEFAULT 0,\n updated_at INTEGER NOT NULL\n )\n `);\n\n const ts = Date.now();\n db.prepare(\n `\n INSERT INTO workmatic_settings (queue, paused, updated_at)\n VALUES (?, 1, ?)\n ON CONFLICT(queue) DO UPDATE SET paused = 1, updated_at = ?\n `\n ).run(queueName, ts, ts);\n\n console.log(`⏸️ Paused queue '${queueName}'`);\n console.log(` Running workers will stop claiming new jobs.`);\n } finally {\n db.close();\n }\n}\n\nexport async function cmdResume(dbPath: string, queueName: string): Promise<void> {\n const db = new Database(dbPath);\n\n try {\n db.exec(`\n CREATE TABLE IF NOT EXISTS workmatic_settings (\n queue TEXT PRIMARY KEY,\n paused INTEGER NOT NULL DEFAULT 0,\n updated_at INTEGER NOT NULL\n )\n `);\n\n const ts = Date.now();\n db.prepare(\n `\n INSERT INTO workmatic_settings (queue, paused, updated_at)\n VALUES (?, 0, ?)\n ON CONFLICT(queue) DO UPDATE SET paused = 0, updated_at = ?\n `\n ).run(queueName, ts, ts);\n\n console.log(`▢️ Resumed queue '${queueName}'`);\n console.log(` Workers will start claiming jobs again.`);\n } finally {\n db.close();\n }\n}\n\nexport async function cmdQueues(dbPath: string): Promise<void> {\n const db = new Database(dbPath, { readonly: true });\n\n try {\n const settingsExists = db\n .prepare(\n `\n SELECT name FROM sqlite_master WHERE type='table' AND name='workmatic_settings'\n `\n )\n .get();\n\n let queues: {\n queue: string;\n total: number;\n ready: number;\n running: number;\n paused: number;\n }[];\n\n if (settingsExists) {\n queues = db\n .prepare(\n `\n SELECT \n j.queue,\n COUNT(*) as total,\n SUM(CASE WHEN j.status = 'ready' THEN 1 ELSE 0 END) as ready,\n SUM(CASE WHEN j.status = 'running' THEN 1 ELSE 0 END) as running,\n COALESCE(s.paused, 0) as paused\n FROM workmatic_jobs j\n LEFT JOIN workmatic_settings s ON j.queue = s.queue\n GROUP BY j.queue\n `\n )\n .all() as typeof queues;\n } else {\n queues = db\n .prepare(\n `\n SELECT \n queue,\n COUNT(*) as total,\n SUM(CASE WHEN status = 'ready' THEN 1 ELSE 0 END) as ready,\n SUM(CASE WHEN status = 'running' THEN 1 ELSE 0 END) as running,\n 0 as paused\n FROM workmatic_jobs\n GROUP BY queue\n `\n )\n .all() as typeof queues;\n }\n\n if (queues.length === 0) {\n console.log('No queues found.');\n return;\n }\n\n console.log('\\nπŸ“‹ Queues\\n');\n\n const table = new Table({\n head: ['Queue', 'Status', 'Ready', 'Running', 'Total'],\n style: { head: ['cyan'], border: ['gray'] },\n colAligns: ['left', 'left', 'right', 'right', 'right'],\n });\n\n for (const q of queues) {\n const status = q.paused ? '⏸️ PAUSED' : '▢️ ACTIVE';\n table.push([\n q.queue,\n status,\n q.ready.toLocaleString(),\n q.running.toLocaleString(),\n q.total.toLocaleString(),\n ]);\n }\n\n console.log(table.toString());\n console.log();\n } finally {\n db.close();\n }\n}\n\nconst JOB_STATUS_EMOJI: Record<string, string> = {\n ready: '⏳',\n running: '▢️',\n done: 'βœ…',\n dead: 'πŸ’€',\n};\n\n/** @internal Exported for tests */\nexport function jobStatusEmoji(status: string): string {\n return JOB_STATUS_EMOJI[status] || '';\n}\n\nexport function parseTransferStatuses(raw?: string): JobStatus[] {\n if (!raw) return ['ready', 'dead'];\n return raw.split(',').map((s) => s.trim()) as JobStatus[];\n}\n\nexport async function cmdTransfer(\n dbPath: string,\n from: string,\n to: string,\n options: Record<string, string>\n): Promise<void> {\n const db = createDatabase({ filename: dbPath });\n\n try {\n const orch = createOrchestrator({ db });\n const status = parseTransferStatuses(options.status);\n const limit = options.limit ? parseInt(options.limit, 10) : undefined;\n const resetForRetry = options.retry === 'true';\n\n const { moved } = await orch.transfer({\n from,\n to,\n status,\n limit,\n resetForRetry,\n });\n\n console.log(`↔️ Moved ${moved} job(s) from '${from}' to '${to}'`);\n } finally {\n await db.destroy();\n }\n}\n\nexport async function cmdMcp(\n dbPath: string,\n options: { input?: NodeJS.ReadableStream; output?: NodeJS.WritableStream } = {}\n): Promise<void> {\n const db = createDatabase({ filename: dbPath });\n const server = createMcpServer({\n db,\n input: options.input,\n output: options.output,\n });\n server.start();\n\n await new Promise<void>((resolve) => {\n const cleanup = () => {\n server.stop();\n if (!options.input) {\n process.removeListener('SIGINT', cleanup);\n process.removeListener('SIGTERM', cleanup);\n process.stdin.removeListener('end', cleanup);\n }\n resolve();\n };\n\n if (options.input) {\n options.input.once('end', cleanup);\n } else {\n process.stdin.once('end', cleanup);\n process.once('SIGINT', cleanup);\n process.once('SIGTERM', cleanup);\n }\n });\n\n\n await db.destroy();\n}\n\n\nexport type CliCommand =\n | 'stats'\n | 'list'\n | 'export'\n | 'import'\n | 'purge'\n | 'retry'\n | 'pause'\n | 'resume'\n | 'queues'\n | 'transfer'\n | 'mcp';\n\nexport async function runCommand(\n command: CliCommand,\n dbPath: string,\n positionalArgs: string[],\n options: Record<string, string>\n): Promise<void> {\n switch (command) {\n case 'stats':\n await cmdStats(dbPath);\n break;\n case 'list':\n await cmdList(dbPath, options);\n break;\n case 'export':\n await cmdExport(dbPath, positionalArgs[1], options);\n break;\n case 'import':\n if (!positionalArgs[1]) {\n throw new Error('Input CSV file is required');\n }\n await cmdImport(dbPath, positionalArgs[1]);\n break;\n case 'purge':\n await cmdPurge(dbPath, options);\n break;\n case 'retry':\n await cmdRetry(dbPath, options);\n break;\n case 'pause':\n if (!positionalArgs[1]) {\n throw new Error('Queue name is required');\n }\n await cmdPause(dbPath, positionalArgs[1]);\n break;\n case 'resume':\n if (!positionalArgs[1]) {\n throw new Error('Queue name is required');\n }\n await cmdResume(dbPath, positionalArgs[1]);\n break;\n case 'queues':\n await cmdQueues(dbPath);\n break;\n case 'transfer':\n if (!positionalArgs[1] || !positionalArgs[2]) {\n throw new Error('Source and target queue names are required');\n }\n await cmdTransfer(dbPath, positionalArgs[1], positionalArgs[2], options);\n break;\n case 'mcp':\n await cmdMcp(dbPath);\n break;\n default:\n throw new Error(`Unknown command: ${command}`);\n }\n}\n\n","import Database from 'better-sqlite3';\nimport { Kysely, SqliteDialect } from 'kysely';\nimport type { WorkmaticDatabase, WorkmaticDb, DatabaseOptions } from './types.js';\n\n/** Maps Kysely instances created via {@link createDatabase} to the underlying driver DB. */\nconst kyselyToSqlite = new WeakMap<WorkmaticDb, Database.Database>();\n\n/**\n * Create and initialize the workmatic database\n * \n * @param options - Database options\n * @returns Kysely database instance\n * \n * @example\n * ```ts\n * // Using a file path\n * const db = createDatabase({ filename: './jobs.db' });\n * \n * // Using an existing better-sqlite3 instance\n * import Database from 'better-sqlite3';\n * const sqlite = new Database('./jobs.db');\n * const db = createDatabase({ db: sqlite });\n * \n * // In-memory database (for testing)\n * const db = createDatabase({ filename: ':memory:' });\n * ```\n */\nexport function createDatabase(options: DatabaseOptions = {}): WorkmaticDb {\n let sqliteDb: Database.Database;\n\n if (options.db) {\n sqliteDb = options.db;\n } else {\n const filename = options.filename ?? ':memory:';\n sqliteDb = new Database(filename);\n }\n\n // Set pragmas for performance and safety\n sqliteDb.pragma('journal_mode = WAL');\n sqliteDb.pragma('synchronous = NORMAL');\n sqliteDb.pragma('busy_timeout = 5000');\n sqliteDb.pragma('cache_size = -64000');\n sqliteDb.pragma('temp_store = MEMORY');\n sqliteDb.pragma('mmap_size = 268435456');\n\n // Enable prepared statement cache\n const cacheSize = options.statementCacheSize ?? 1000;\n enableStatementCache(sqliteDb, cacheSize);\n\n // Create Kysely instance\n const db = new Kysely<WorkmaticDatabase>({\n dialect: new SqliteDialect({\n database: sqliteDb,\n }),\n });\n\n // Create schema synchronously using better-sqlite3 directly\n createSchema(sqliteDb);\n\n kyselyToSqlite.set(db, sqliteDb);\n\n return db;\n}\n\n/**\n * Create the database schema if it doesn't exist\n */\nfunction createSchema(db: Database.Database): void {\n // Create the jobs table\n db.exec(`\n CREATE TABLE IF NOT EXISTS workmatic_jobs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n public_id TEXT UNIQUE NOT NULL,\n queue TEXT NOT NULL,\n payload TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'ready',\n priority INTEGER NOT NULL DEFAULT 0,\n run_at INTEGER NOT NULL,\n attempts INTEGER NOT NULL DEFAULT 0,\n max_attempts INTEGER NOT NULL DEFAULT 3,\n lease_until INTEGER NOT NULL DEFAULT 0,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n last_error TEXT\n )\n `);\n\n // Create composite partial index for efficient job claiming\n // Only indexes active ready jobs, preventing unbounded index growth from done/dead jobs\n ensurePartialIndex(\n db,\n 'idx_workmatic_jobs_claim',\n `CREATE INDEX IF NOT EXISTS idx_workmatic_jobs_claim \n ON workmatic_jobs (queue, status, run_at, priority, id)\n WHERE status = 'ready'`\n );\n\n // Create partial index for lease expiration checking\n // Only indexes running jobs with active leases\n ensurePartialIndex(\n db,\n 'idx_workmatic_jobs_lease',\n `CREATE INDEX IF NOT EXISTS idx_workmatic_jobs_lease \n ON workmatic_jobs (status, lease_until)\n WHERE status = 'running'`\n );\n\n // Composite covering index for queue-level stats queries\n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_workmatic_jobs_queue_status \n ON workmatic_jobs (queue, status)\n `);\n\n // Create settings table for queue-level settings (pause state, etc.)\n db.exec(`\n CREATE TABLE IF NOT EXISTS workmatic_settings (\n queue TEXT PRIMARY KEY,\n paused INTEGER NOT NULL DEFAULT 0,\n updated_at INTEGER NOT NULL\n )\n `);\n\n // Legacy status no longer used in the state machine (retries use `ready`, terminal errors use `dead`)\n db.exec(`\n UPDATE workmatic_jobs SET status = 'dead' WHERE status = 'failed'\n `);\n}\n\n/**\n * Create or upgrade an index to a partial index\n */\nfunction ensurePartialIndex(db: Database.Database, indexName: string, createSql: string): void {\n const row = db\n .prepare(\n \"SELECT sql FROM sqlite_master WHERE type = 'index' AND name = ?\"\n )\n .get(indexName) as { sql?: string } | undefined;\n\n if (row?.sql && !row.sql.toUpperCase().includes('WHERE')) {\n db.exec(`DROP INDEX IF EXISTS ${indexName}`);\n }\n\n db.exec(createSql);\n}\n\n/**\n * Get the underlying better-sqlite3 database instance from a Kysely instance\n * created with {@link createDatabase}. For manually constructed `Kysely` instances,\n * falls back to reading the dialect adapter (may break across Kysely versions).\n */\nexport function getUnderlyingDb(db: WorkmaticDb): Database.Database {\n const mapped = kyselyToSqlite.get(db);\n if (mapped) {\n return mapped;\n }\n try {\n const ex = (db as unknown as { getExecutor?: () => { adapter: { db: Database.Database } } })\n .getExecutor?.();\n const dialect = ex?.adapter?.db;\n if (dialect) {\n return dialect;\n }\n } catch {\n /* ignore */\n }\n throw new Error(\n 'getUnderlyingDb: could not resolve better-sqlite3 instance (use createDatabase() or pass db from it)'\n );\n}\n\n/**\n * Enable prepared statement caching on a better-sqlite3 database instance.\n * Reuses compiled statements across queries, bypassing SQLite SQL parsing\n * and bytecode recompilation on repeated queries.\n *\n * @param db - better-sqlite3 database instance\n * @param maxStatements - Maximum cached statements (default: 1000). Set <= 0 to disable.\n */\nexport function enableStatementCache(\n db: Database.Database,\n maxStatements = 1000\n): Database.Database {\n if (maxStatements <= 0) {\n return db;\n }\n\n const originalPrepare = db.prepare.bind(db);\n const cache = new Map<string, Database.Statement>();\n\n db.prepare = function (sql: string) {\n const cached = cache.get(sql);\n if (cached) {\n cache.delete(sql);\n cache.set(sql, cached);\n if (!cached.busy) {\n return cached;\n }\n return originalPrepare(sql);\n }\n\n const stmt = originalPrepare(sql);\n if (cache.size >= maxStatements) {\n const oldestKey = cache.keys().next().value;\n cache.delete(oldestKey!);\n }\n cache.set(sql, stmt);\n return stmt;\n } as typeof db.prepare;\n\n const originalClose = db.close.bind(db);\n db.close = function () {\n cache.clear();\n return originalClose();\n };\n\n return db;\n}\n\n","import { sql } from 'kysely';\nimport { createClient } from './client.js';\nimport { createWorker } from './worker.js';\nimport type {\n WorkmaticDb,\n OrchestratorOptions,\n RegisterQueueOptions,\n WorkmaticOrchestrator,\n WorkmaticClient,\n WorkmaticWorker,\n TransferOptions,\n TransferResult,\n MoveJobOptions,\n JobStats,\n JobStatus,\n JobProcessor,\n GracefulShutdownOptions,\n} from './types.js';\nimport { now } from './utils.js';\nimport { attachGracefulShutdown } from './shutdown.js';\n\nconst DEFAULT_TRANSFER_STATUSES: JobStatus[] = ['ready', 'dead'];\nconst DEFAULT_TRANSFER_LIMIT = 10_000;\n\n/** @internal Exported for tests */\nexport function rowsUpdated(result: unknown): number {\n const row = (result as { numUpdatedRows?: number | bigint }[])[0];\n return Number(row?.numUpdatedRows ?? 0);\n}\n\nfunction normalizeStatuses(status?: JobStatus | JobStatus[]): JobStatus[] {\n if (!status) return [...DEFAULT_TRANSFER_STATUSES];\n return Array.isArray(status) ? status : [status];\n}\n\ninterface QueueEntry {\n client: WorkmaticClient;\n worker?: WorkmaticWorker;\n}\n\n/**\n * Create a multi-queue orchestrator for registration, lifecycle, and transfers.\n */\nexport function createOrchestrator(options: OrchestratorOptions): WorkmaticOrchestrator {\n const { db } = options;\n if (!db) {\n throw new Error('Database instance is required');\n }\n\n const registry = new Map<string, QueueEntry>();\n\n function ensureEntry(queue: string): QueueEntry {\n let entry = registry.get(queue);\n if (!entry) {\n entry = {\n client: createClient({\n db,\n queue,\n onJobAdded: () => {\n registry.get(queue)?.worker?.wakeUp();\n },\n }),\n };\n registry.set(queue, entry);\n }\n return entry;\n }\n\n async function setQueuePaused(queue: string, paused: boolean): Promise<void> {\n const timestamp = now();\n const value = paused ? 1 : 0;\n await sql`\n INSERT INTO workmatic_settings (queue, paused, updated_at)\n VALUES (${queue}, ${value}, ${timestamp})\n ON CONFLICT(queue) DO UPDATE SET\n paused = ${value},\n updated_at = ${timestamp}\n `.execute(db);\n }\n\n async function selectJobIds(\n from: string,\n status: JobStatus,\n limit: number\n ): Promise<number[]> {\n const rows = await db\n .selectFrom('workmatic_jobs')\n .select('id')\n .where('queue', '=', from)\n .where('status', '=', status)\n .orderBy('priority', 'asc')\n .orderBy('id', 'asc')\n .limit(limit)\n .execute();\n return rows.map((r) => r.id);\n }\n\n async function transferReady(from: string, to: string, limit: number): Promise<number> {\n const ids = await selectJobIds(from, 'ready', limit);\n if (ids.length === 0) return 0;\n const timestamp = now();\n const result = await db\n .updateTable('workmatic_jobs')\n .set({ queue: to, updated_at: timestamp })\n .where('id', 'in', ids)\n .execute();\n return rowsUpdated(result);\n }\n\n async function transferDead(\n from: string,\n to: string,\n limit: number,\n resetForRetry: boolean\n ): Promise<number> {\n const ids = await selectJobIds(from, 'dead', limit);\n if (ids.length === 0) return 0;\n const timestamp = now();\n if (resetForRetry) {\n const result = await db\n .updateTable('workmatic_jobs')\n .set({\n queue: to,\n status: 'ready',\n attempts: 0,\n lease_until: 0,\n last_error: null,\n updated_at: timestamp,\n run_at: timestamp,\n })\n .where('id', 'in', ids)\n .execute();\n return rowsUpdated(result);\n }\n\n const result = await db\n .updateTable('workmatic_jobs')\n .set({ queue: to, updated_at: timestamp })\n .where('id', 'in', ids)\n .execute();\n return rowsUpdated(result);\n }\n\n async function transferOtherStatus(\n from: string,\n to: string,\n status: JobStatus,\n limit: number\n ): Promise<number> {\n const ids = await selectJobIds(from, status, limit);\n if (ids.length === 0) return 0;\n const timestamp = now();\n const result = await db\n .updateTable('workmatic_jobs')\n .set({ queue: to, updated_at: timestamp })\n .where('id', 'in', ids)\n .execute();\n return rowsUpdated(result);\n }\n\n const orchestrator: WorkmaticOrchestrator = {\n register(queue: string, opts: RegisterQueueOptions = {}): WorkmaticClient {\n const client = createClient({ db, queue });\n let worker: WorkmaticWorker | undefined;\n if (opts.worker) {\n worker = createWorker({ db, queue, ...opts.worker });\n }\n registry.set(queue, { client, worker });\n return client;\n },\n\n client(queue: string): WorkmaticClient {\n return ensureEntry(queue).client;\n },\n\n worker(queue: string): WorkmaticWorker {\n const entry = registry.get(queue);\n if (!entry?.worker) {\n throw new Error(`No worker registered for queue \"${queue}\"`);\n }\n return entry.worker;\n },\n\n workers(): WorkmaticWorker[] {\n return [...registry.values()]\n .map((e) => e.worker)\n .filter((w): w is WorkmaticWorker => w !== undefined);\n },\n\n async queues(): Promise<string[]> {\n const rows = await db\n .selectFrom('workmatic_jobs')\n .select('queue')\n .distinct()\n .execute();\n const names = new Set<string>(rows.map((r) => r.queue));\n for (const name of registry.keys()) {\n names.add(name);\n }\n return [...names].sort();\n },\n\n process<TPayload = unknown>(queue: string, fn: JobProcessor<TPayload>): void {\n this.worker(queue).process(fn);\n },\n\n startAll(): void {\n for (const entry of registry.values()) {\n entry.worker?.start();\n }\n },\n\n async stopAll(): Promise<void> {\n const stops = [...registry.values()]\n .map((e) => e.worker?.stop())\n .filter((p): p is Promise<void> => p !== undefined);\n await Promise.all(stops);\n },\n\n async pause(queue: string): Promise<void> {\n const entry = registry.get(queue);\n entry?.worker?.pause();\n await setQueuePaused(queue, true);\n },\n\n async resume(queue: string): Promise<void> {\n const entry = registry.get(queue);\n entry?.worker?.resume();\n await setQueuePaused(queue, false);\n },\n\n async isPaused(queue: string): Promise<boolean> {\n const setting = await db\n .selectFrom('workmatic_settings')\n .select('paused')\n .where('queue', '=', queue)\n .executeTakeFirst();\n return setting?.paused === 1;\n },\n\n async stats(queueName?: string): Promise<Record<string, JobStats>> {\n const names = queueName ? [queueName] : await this.queues();\n const result: Record<string, JobStats> = {};\n for (const name of names) {\n result[name] = await ensureEntry(name).client.stats();\n }\n return result;\n },\n\n async transfer(opts: TransferOptions): Promise<TransferResult> {\n const { from, to, resetForRetry = false } = opts;\n if (from === to) {\n return { moved: 0 };\n }\n\n const statuses = normalizeStatuses(opts.status);\n let remaining = opts.limit ?? DEFAULT_TRANSFER_LIMIT;\n let moved = 0;\n\n if (statuses.includes('ready') && remaining > 0) {\n const n = await transferReady(from, to, remaining);\n moved += n;\n remaining -= n;\n }\n if (statuses.includes('dead') && remaining > 0) {\n const n = await transferDead(from, to, remaining, resetForRetry);\n moved += n;\n remaining -= n;\n }\n for (const status of statuses) {\n if (status === 'ready' || status === 'dead' || remaining <= 0) continue;\n const n = await transferOtherStatus(from, to, status, remaining);\n moved += n;\n remaining -= n;\n }\n\n return { moved };\n },\n\n async moveJob(\n publicId: string,\n toQueue: string,\n opts: MoveJobOptions = {}\n ): Promise<void> {\n const allowed = normalizeStatuses(opts.status);\n const row = await db\n .selectFrom('workmatic_jobs')\n .select(['id', 'queue', 'status'])\n .where('public_id', '=', publicId)\n .executeTakeFirst();\n\n if (!row) {\n throw new Error(`Job not found: ${publicId}`);\n }\n if (row.queue === toQueue) {\n return;\n }\n if (!allowed.includes(row.status)) {\n throw new Error(\n `Job ${publicId} has status \"${row.status}\" and cannot be moved (allowed: ${allowed.join(', ')})`\n );\n }\n\n const timestamp = now();\n const resetForRetry = opts.resetForRetry ?? false;\n\n if (row.status === 'dead' && resetForRetry) {\n await db\n .updateTable('workmatic_jobs')\n .set({\n queue: toQueue,\n status: 'ready',\n attempts: 0,\n lease_until: 0,\n last_error: null,\n updated_at: timestamp,\n run_at: timestamp,\n })\n .where('public_id', '=', publicId)\n .execute();\n return;\n }\n\n await db\n .updateTable('workmatic_jobs')\n .set({ queue: toQueue, updated_at: timestamp })\n .where('public_id', '=', publicId)\n .execute();\n },\n\n attachSignalHandlers(options?: GracefulShutdownOptions): () => void {\n return attachGracefulShutdown(this, options);\n },\n };\n\n return orchestrator;\n}\n","import { nanoid } from 'nanoid';\nimport { CompiledQuery } from 'kysely';\nimport type {\n WorkmaticDb,\n ClientOptions,\n WorkmaticClient,\n AddJobOptions,\n AddJobResult,\n AddManyResult,\n JobStats,\n JobStatus,\n} from './types.js';\nimport { validatePayload, now } from './utils.js';\n\n/**\n * Create a job queue client for adding jobs\n * \n * @param options - Client options\n * @returns Client instance\n * \n * @example\n * ```ts\n * const client = createClient({ db });\n * \n * // Add a simple job\n * const result = await client.add({ email: 'user@example.com' });\n * console.log(result.id); // Job public ID\n * \n * // Add a job with options\n * await client.add(\n * { userId: 123 },\n * { priority: 1, delayMs: 5000, maxAttempts: 5 }\n * );\n * \n * // Get queue statistics\n * const stats = await client.stats();\n * console.log(stats); // { ready: 5, running: 2, done: 100, ... }\n * ```\n */\nexport function createClient(options: ClientOptions): WorkmaticClient {\n const { db, queue = 'default', onJobAdded, worker } = options;\n\n if (!db) {\n throw new Error('Database instance is required');\n }\n\n function notifyJobAdded(delayMs: number): void {\n if (delayMs <= 0) {\n worker?.wakeUp();\n onJobAdded?.();\n }\n }\n\n return {\n /**\n * Add a job to the queue\n */\n async add<TPayload = unknown>(\n payload: TPayload,\n opts: AddJobOptions = {}\n ): Promise<AddJobResult> {\n const {\n priority = 0,\n delayMs = 0,\n maxAttempts = 3,\n } = opts;\n\n // Validate and serialize payload\n const payloadJson = validatePayload(payload);\n \n // Generate unique public ID\n const publicId = nanoid();\n \n const timestamp = now();\n const runAt = timestamp + delayMs;\n\n // Insert job\n await db.executeQuery(\n CompiledQuery.raw(\n `INSERT INTO workmatic_jobs (public_id, queue, payload, status, priority, run_at, attempts, max_attempts, lease_until, created_at, updated_at, last_error) VALUES (?, ?, ?, 'ready', ?, ?, 0, ?, 0, ?, ?, null)`,\n [publicId, queue, payloadJson, priority, runAt, maxAttempts, timestamp, timestamp]\n )\n );\n\n notifyJobAdded(delayMs);\n\n return { ok: true, id: publicId };\n },\n\n async addMany<TPayload = unknown>(\n payloads: TPayload[],\n opts: AddJobOptions = {}\n ): Promise<AddManyResult> {\n const {\n priority = 0,\n delayMs = 0,\n maxAttempts = 3,\n } = opts;\n\n if (payloads.length === 0) {\n return { ok: true, ids: [] };\n }\n\n const timestamp = now();\n const runAt = timestamp + delayMs;\n\n const result = await db.transaction().execute(async (trx) => {\n const ids: string[] = [];\n const rows = payloads.map((payload) => {\n const payloadJson = validatePayload(payload);\n const publicId = nanoid();\n ids.push(publicId);\n return {\n public_id: publicId,\n queue,\n payload: payloadJson,\n status: 'ready' as const,\n priority,\n run_at: runAt,\n attempts: 0,\n max_attempts: maxAttempts,\n lease_until: 0,\n created_at: timestamp,\n updated_at: timestamp,\n last_error: null,\n };\n });\n\n await trx.insertInto('workmatic_jobs').values(rows).execute();\n return { ok: true as const, ids };\n });\n\n notifyJobAdded(delayMs);\n\n return result;\n },\n\n /**\n * Get job statistics for the queue\n */\n async stats(): Promise<JobStats> {\n const result = await db.executeQuery<{ status: JobStatus; count: number }>(\n CompiledQuery.raw(\n 'SELECT status, count(*) AS count FROM workmatic_jobs WHERE queue = ? GROUP BY status',\n [queue]\n )\n );\n\n const stats: JobStats = {\n ready: 0,\n running: 0,\n done: 0,\n dead: 0,\n total: 0,\n };\n\n for (const row of result.rows) {\n const status = row.status;\n const count = Number(row.count);\n if (status in stats) {\n stats[status] = count;\n }\n stats.total += count;\n }\n\n return stats;\n },\n\n /**\n * Clear all jobs from the queue\n */\n async clear(options: { status?: JobStatus } = {}): Promise<number> {\n let query = db\n .deleteFrom('workmatic_jobs')\n .where('queue', '=', queue);\n\n if (options.status) {\n query = query.where('status', '=', options.status);\n }\n\n const result = await query.execute();\n return Number(result[0]?.numDeletedRows ?? 0);\n },\n };\n}\n","import type { BackoffFunction } from './types.js';\n\n/**\n * Default exponential backoff function\n * Returns delay in milliseconds: 1000 * 2^attempts\n * \n * @param attempts - Number of failed attempts\n * @returns Delay in milliseconds\n * \n * @example\n * ```ts\n * defaultBackoff(0) // 1000ms (1 second)\n * defaultBackoff(1) // 2000ms (2 seconds)\n * defaultBackoff(2) // 4000ms (4 seconds)\n * defaultBackoff(3) // 8000ms (8 seconds)\n * ```\n */\nexport const defaultBackoff: BackoffFunction = (attempts: number): number => {\n return 1000 * Math.pow(2, attempts);\n};\n\n/**\n * Validate that a payload is JSON-serializable\n * \n * @param payload - The payload to validate\n * @throws Error if payload cannot be serialized to JSON\n * @returns The JSON string representation\n */\nexport function validatePayload(payload: unknown): string {\n try {\n return JSON.stringify(payload);\n } catch (error) {\n throw new Error(\n `Payload is not JSON-serializable: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n}\n\n/**\n * Parse a JSON payload safely\n * \n * @param json - JSON string to parse\n * @returns Parsed payload\n * @throws Error if JSON is invalid\n */\nexport function parsePayload<T = unknown>(json: string): T {\n try {\n return JSON.parse(json) as T;\n } catch (error) {\n throw new Error(\n `Invalid JSON payload: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n}\n\n/**\n * Sleep for a specified duration\n * \n * @param ms - Duration in milliseconds\n * @returns Promise that resolves after the duration\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Get current timestamp in milliseconds\n */\nexport function now(): number {\n return Date.now();\n}\n","import fastq from 'fastq';\nimport type { queueAsPromised } from 'fastq';\nimport { sql, CompiledQuery } from 'kysely';\nimport type {\n WorkmaticDb,\n WorkerOptions,\n WorkmaticWorker,\n JobProcessor,\n JobStats,\n JobStatus,\n Job,\n ClaimedJob,\n WorkerState,\n GracefulShutdownOptions,\n} from './types.js';\nimport { defaultBackoff, parsePayload, now } from './utils.js';\nimport { attachGracefulShutdown } from './shutdown.js';\n\n/** Default job execution timeout when `timeoutMs` is omitted (1 minute). Use `timeoutMs: 0` for no limit. */\nexport const DEFAULT_WORKER_TIMEOUT_MS = 60_000;\n\n/** @internal Exported for tests β€” maps SQLite RETURNING result to claimed jobs */\nexport function parseClaimedRows(result: unknown): ClaimedJob[] {\n const rows = (result as { rows?: ClaimedJob[] }).rows;\n if (!rows || !Array.isArray(rows)) {\n return [];\n }\n return rows.map((row) => ({\n id: row.id,\n public_id: row.public_id,\n queue: row.queue,\n payload: row.payload,\n attempts: row.attempts,\n max_attempts: row.max_attempts,\n priority: row.priority,\n created_at: row.created_at,\n last_error: row.last_error,\n }));\n}\n\n/** @internal Exported for tests */\nexport function requireProcessor<T>(processor: JobProcessor<T> | null): JobProcessor<T> {\n if (!processor) {\n throw new Error('No processor set');\n }\n return processor;\n}\n\n/**\n * Create a job queue worker for processing jobs\n * \n * @param options - Worker options\n * @returns Worker instance\n * \n * @example\n * ```ts\n * const worker = createWorker({ db, concurrency: 4 });\n * \n * // Set the processor function\n * worker.process(async (job) => {\n * console.log('Processing job:', job.id);\n * await sendEmail(job.payload.email);\n * });\n * \n * // Start processing\n * worker.start();\n * \n * // Later, gracefully stop\n * await worker.stop();\n * ```\n */\nexport function createWorker(options: WorkerOptions): WorkmaticWorker {\n const {\n db,\n queue = 'default',\n concurrency = 1,\n leaseMs = 30000,\n pollMs = 1000,\n timeoutMs = DEFAULT_WORKER_TIMEOUT_MS,\n backoff = defaultBackoff,\n persistState = false,\n autoRestore = true,\n pauseCheckIntervalMs = 300,\n requeueExpiredIntervalMs = 0,\n onPumpError,\n completionBatchSize = 50,\n } = options;\n\n if (!db) {\n throw new Error('Database instance is required');\n }\n\n // State\n let running = false;\n let paused = false;\n let processor: JobProcessor<any> | null = null;\n let pumpTimeout: NodeJS.Timeout | null = null;\n let fastqQueue: queueAsPromised<ClaimedJob, void> | null = null;\n let lastPauseCheckAt = 0;\n let cachedDbPaused = false;\n let lastRequeueAt = 0;\n let pendingDone: Array<{ id: number; resolve: () => void; reject: (err: unknown) => void }> = [];\n let flushTimeout: NodeJS.Immediate | null = null;\n\n function notifyPumpError(error: unknown): void {\n console.error('[workmatic] Pump error:', error);\n onPumpError?.(error);\n }\n\n /**\n * Get the settings key for this worker's state\n */\n function getStateKey(): string {\n return `worker_state_${queue}`;\n }\n\n async function saveState(state: WorkerState): Promise<void> {\n if (!persistState) return;\n\n const timestamp = now();\n const key = getStateKey();\n\n try {\n // Use raw SQL for upsert since different SQLite versions have different syntax\n await sql`\n INSERT INTO workmatic_settings (queue, paused, updated_at)\n VALUES (${key}, ${state === 'paused' ? 1 : state === 'running' ? 2 : 0}, ${timestamp})\n ON CONFLICT(queue) DO UPDATE SET \n paused = ${state === 'paused' ? 1 : state === 'running' ? 2 : 0},\n updated_at = ${timestamp}\n `.execute(db);\n } catch {\n // Ignore errors\n }\n }\n\n /**\n * Load worker state from database\n */\n async function loadState(): Promise<WorkerState | null> {\n if (!persistState) return null;\n\n try {\n const key = getStateKey();\n const result = await db\n .selectFrom('workmatic_settings')\n .select('paused')\n .where('queue', '=', key)\n .executeTakeFirst();\n\n if (!result) return null;\n \n // paused: 0 = stopped, 1 = paused, 2 = running\n if (result.paused === 2) return 'running';\n if (result.paused === 1) return 'paused';\n return 'stopped';\n } catch {\n return null;\n }\n }\n\n /**\n * Requeue jobs with expired leases\n */\n async function requeueExpiredLeases(): Promise<number> {\n const timestamp = now();\n\n const result = await db\n .updateTable('workmatic_jobs')\n .set({\n status: 'ready',\n lease_until: 0,\n updated_at: timestamp,\n })\n .where('status', '=', 'running')\n .where('lease_until', '<', timestamp)\n .where('lease_until', '>', 0)\n .execute();\n\n return Number(result[0]?.numUpdatedRows ?? 0);\n }\n\n /**\n * Claim a batch of jobs for processing (single UPDATE … RETURNING per SQLite 3.35+)\n */\n async function claimBatch(limit: number): Promise<ClaimedJob[]> {\n const timestamp = now();\n const leaseUntil = timestamp + leaseMs;\n\n const result = await sql<{\n id: number;\n public_id: string;\n queue: string;\n payload: string;\n attempts: number;\n max_attempts: number;\n priority: number;\n created_at: number;\n last_error: string | null;\n }>`\n UPDATE workmatic_jobs\n SET status = 'running', lease_until = ${leaseUntil}, updated_at = ${timestamp}\n WHERE rowid IN (\n SELECT rowid FROM workmatic_jobs\n WHERE queue = ${queue}\n AND status = 'ready'\n AND run_at <= ${timestamp}\n ORDER BY priority ASC, id ASC\n LIMIT ${limit}\n )\n RETURNING id, public_id, queue, payload, attempts, max_attempts, priority, created_at, last_error\n `.execute(db);\n\n return parseClaimedRows(result);\n }\n\n /**\n * Flush all buffered completion updates in a single batch\n */\n async function flushDoneBatch(): Promise<void> {\n if (flushTimeout !== null) {\n clearImmediate(flushTimeout);\n flushTimeout = null;\n }\n if (pendingDone.length === 0) {\n return;\n }\n const current = pendingDone;\n pendingDone = [];\n\n const timestamp = now();\n try {\n if (current.length === 1) {\n await db.executeQuery(\n CompiledQuery.raw(\n \"UPDATE workmatic_jobs SET status = 'done', lease_until = 0, updated_at = ? WHERE id = ?\",\n [timestamp, current[0].id]\n )\n );\n } else {\n const CHUNK_SIZE = 500;\n for (let i = 0; i < current.length; i += CHUNK_SIZE) {\n const chunk = current.slice(i, i + CHUNK_SIZE);\n const placeholders = chunk.map(() => '?').join(', ');\n const params = [timestamp, ...chunk.map((item) => item.id)];\n await db.executeQuery(\n CompiledQuery.raw(\n `UPDATE workmatic_jobs SET status = 'done', lease_until = 0, updated_at = ? WHERE id IN (${placeholders})`,\n params\n )\n );\n }\n }\n for (const item of current) {\n item.resolve();\n }\n } catch (err) {\n for (const item of current) {\n item.reject(err);\n }\n }\n }\n\n /**\n * Mark a job as completed (buffers for micro-batching if completionBatchSize > 0)\n */\n function markDone(jobId: number): Promise<void> {\n if (completionBatchSize <= 0) {\n return db.executeQuery(\n CompiledQuery.raw(\n \"UPDATE workmatic_jobs SET status = 'done', lease_until = 0, updated_at = ? WHERE id = ?\",\n [now(), jobId]\n )\n ).then(() => {});\n }\n\n return new Promise((resolve, reject) => {\n pendingDone.push({ id: jobId, resolve, reject });\n if (pendingDone.length >= completionBatchSize) {\n void flushDoneBatch();\n } else if (!flushTimeout) {\n flushTimeout = setImmediate(() => {\n flushTimeout = null;\n void flushDoneBatch();\n });\n }\n });\n }\n\n /**\n * Handle job failure\n */\n async function markFailed(\n jobId: number,\n attempts: number,\n maxAttempts: number,\n error: Error\n ): Promise<void> {\n const timestamp = now();\n const newAttempts = attempts + 1;\n const errorMessage = error.message || String(error);\n\n if (newAttempts < maxAttempts) {\n // Retry: set back to ready with backoff delay\n const runAt = timestamp + backoff(newAttempts);\n \n await db.executeQuery(\n CompiledQuery.raw(\n \"UPDATE workmatic_jobs SET status = 'ready', attempts = ?, run_at = ?, lease_until = 0, last_error = ?, updated_at = ? WHERE id = ?\",\n [newAttempts, runAt, errorMessage, timestamp, jobId]\n )\n );\n } else {\n // Max attempts reached: mark as dead\n await db.executeQuery(\n CompiledQuery.raw(\n \"UPDATE workmatic_jobs SET status = 'dead', attempts = ?, lease_until = 0, last_error = ?, updated_at = ? WHERE id = ?\",\n [newAttempts, errorMessage, timestamp, jobId]\n )\n );\n }\n }\n\n /**\n * Run a promise with timeout\n */\n async function withTimeout<T>(\n promise: Promise<T>,\n ms: number,\n jobId: string\n ): Promise<T> {\n let timeoutId: NodeJS.Timeout;\n \n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new Error(`Job ${jobId} timed out after ${ms}ms`));\n }, ms);\n });\n\n try {\n return await Promise.race([promise, timeoutPromise]);\n } finally {\n clearTimeout(timeoutId!);\n }\n }\n\n /**\n * Process a single job\n */\n async function processJob(claimedJob: ClaimedJob): Promise<void> {\n const fn = requireProcessor(processor);\n\n // Parse payload and create job object\n const payload = parsePayload(claimedJob.payload);\n const job: Job = {\n id: claimedJob.public_id,\n queue: claimedJob.queue,\n payload,\n status: 'running',\n priority: claimedJob.priority,\n attempts: claimedJob.attempts,\n maxAttempts: claimedJob.max_attempts,\n createdAt: claimedJob.created_at,\n lastError: claimedJob.last_error,\n };\n\n try {\n // Run processor with optional timeout\n if (timeoutMs) {\n await withTimeout(fn(job), timeoutMs, job.id);\n } else {\n await fn(job);\n }\n await markDone(claimedJob.id);\n } catch (error) {\n await markFailed(\n claimedJob.id,\n claimedJob.attempts,\n claimedJob.max_attempts,\n error instanceof Error ? error : new Error(String(error))\n );\n }\n }\n\n /**\n * Check if queue is paused in database (for CLI control)\n */\n async function isQueuePausedInDb(): Promise<boolean> {\n const result = await db.executeQuery<{ paused: number }>(\n CompiledQuery.raw(\n 'SELECT paused FROM workmatic_settings WHERE queue = ? LIMIT 1',\n [queue]\n )\n );\n return result.rows[0]?.paused === 1;\n }\n\n /**\n * Main pump loop\n */\n async function pump(): Promise<void> {\n if (!running) {\n return;\n }\n\n // Check both in-memory pause and database pause (for CLI control)\n if (paused) {\n pumpTimeout = setTimeout(pump, pollMs);\n return;\n }\n\n try {\n const t = now();\n if (t - lastPauseCheckAt >= pauseCheckIntervalMs) {\n lastPauseCheckAt = t;\n cachedDbPaused = await isQueuePausedInDb();\n }\n if (cachedDbPaused) {\n pumpTimeout = setTimeout(pump, pollMs);\n return;\n }\n\n if (\n requeueExpiredIntervalMs <= 0 ||\n t - lastRequeueAt >= requeueExpiredIntervalMs\n ) {\n if (requeueExpiredIntervalMs > 0) {\n lastRequeueAt = t;\n }\n await requeueExpiredLeases();\n }\n\n // Claim a batch of jobs\n const batchSize = concurrency * 2;\n const jobs = await claimBatch(batchSize);\n\n if (jobs.length > 0) {\n // Push jobs into fastq\n for (const job of jobs) {\n fastqQueue!.push(job);\n }\n // Immediately pump again\n pumpTimeout = setTimeout(pump, 0);\n } else {\n // No jobs, wait before polling again\n pumpTimeout = setTimeout(pump, pollMs);\n }\n } catch (error) {\n notifyPumpError(error);\n pumpTimeout = setTimeout(pump, pollMs);\n }\n }\n\n // Create the worker object\n const worker: WorkmaticWorker = {\n process<TPayload = unknown>(fn: JobProcessor<TPayload>): void {\n processor = fn as JobProcessor<any>;\n },\n\n start(): void {\n if (running) {\n return;\n }\n\n if (!processor) {\n throw new Error('No processor set. Call process() before start()');\n }\n\n running = true;\n paused = false;\n\n // Create fastq queue\n fastqQueue = fastq.promise(processJob, concurrency);\n\n // Save state to database\n void saveState('running');\n\n // Start pump loop\n pump();\n },\n\n async stop(): Promise<void> {\n if (!running) {\n return;\n }\n\n running = false;\n\n // Clear pump timeout\n if (pumpTimeout) {\n clearTimeout(pumpTimeout);\n pumpTimeout = null;\n }\n\n // Wait for fastq to drain\n await fastqQueue!.drained();\n fastqQueue = null;\n\n // Flush remaining buffered completions\n await flushDoneBatch();\n\n // Save state to database\n await saveState('stopped');\n },\n\n pause(): void {\n paused = true;\n void flushDoneBatch();\n void saveState('paused');\n },\n\n resume(): void {\n paused = false;\n void saveState('running');\n },\n\n async stats(): Promise<JobStats> {\n await flushDoneBatch();\n\n const result = await db.executeQuery<{ status: JobStatus; count: number }>(\n CompiledQuery.raw(\n 'SELECT status, count(*) AS count FROM workmatic_jobs WHERE queue = ? GROUP BY status',\n [queue]\n )\n );\n\n const stats: JobStats = {\n ready: 0,\n running: 0,\n done: 0,\n dead: 0,\n total: 0,\n };\n\n for (const row of result.rows) {\n const status = row.status;\n const count = Number(row.count);\n if (status in stats) {\n stats[status] = count;\n }\n stats.total += count;\n }\n\n return stats;\n },\n\n get isRunning(): boolean {\n return running;\n },\n\n get isPaused(): boolean {\n return paused;\n },\n\n get queue(): string {\n return queue;\n },\n\n async restoreState(): Promise<WorkerState | null> {\n const state = await loadState();\n if (state === 'running' && processor) {\n this.start();\n } else if (state === 'paused' && processor) {\n this.start();\n this.pause();\n }\n return state;\n },\n\n async clear(options: { status?: JobStatus } = {}): Promise<number> {\n let query = db\n .deleteFrom('workmatic_jobs')\n .where('queue', '=', queue);\n\n if (options.status) {\n query = query.where('status', '=', options.status);\n }\n\n const result = await query.execute();\n return Number(result[0]?.numDeletedRows ?? 0);\n },\n\n wakeUp(): void {\n if (!running || paused) {\n return;\n }\n if (pumpTimeout) {\n clearTimeout(pumpTimeout);\n pumpTimeout = null;\n }\n pumpTimeout = setTimeout(pump, 0);\n },\n\n async flushCompletions(): Promise<void> {\n await flushDoneBatch();\n },\n\n attachSignalHandlers(options?: GracefulShutdownOptions): () => void {\n return attachGracefulShutdown(this, options);\n },\n };\n\n // Auto-restore state if enabled\n if (persistState && autoRestore) {\n // Use setImmediate to allow processor to be set first\n setImmediate(async () => {\n if (processor) {\n await worker.restoreState();\n }\n });\n }\n\n return worker;\n}\n","import type { WorkmaticWorker, WorkmaticOrchestrator, GracefulShutdownOptions } from './types.js';\n\nexport type GracefulShutdownTarget =\n | WorkmaticWorker\n | WorkmaticOrchestrator\n | WorkmaticWorker[];\n\n/**\n * Attach OS signal listeners (SIGINT, SIGTERM) to gracefully stop a worker,\n * an orchestrator, or a group of workers before the process exits.\n *\n * @param target - Worker, orchestrator, or array of workers to stop\n * @param options - Graceful shutdown options\n * @returns Detach function that unregisters the signal listeners\n *\n * @example\n * ```ts\n * const worker = createWorker({ db });\n * worker.start();\n *\n * const detach = attachGracefulShutdown(worker, {\n * timeoutMs: 15000,\n * onShutdownComplete: () => console.log('All jobs finished, shutting down'),\n * });\n * ```\n */\nexport function attachGracefulShutdown(\n target: GracefulShutdownTarget,\n options: GracefulShutdownOptions = {}\n): () => void {\n const {\n signals = ['SIGINT', 'SIGTERM'],\n timeoutMs = 30000,\n exitOnComplete = true,\n exitCode = 0,\n timeoutExitCode = 1,\n onShutdownStart,\n onShutdownComplete,\n onShutdownError,\n } = options;\n\n let shuttingDown = false;\n\n async function stopTarget(): Promise<void> {\n if (Array.isArray(target)) {\n await Promise.all(target.map((w) => w.stop()));\n } else if ('stopAll' in target) {\n await target.stopAll();\n } else {\n await target.stop();\n }\n }\n\n const handler = async (signal: NodeJS.Signals) => {\n if (shuttingDown) {\n return;\n }\n shuttingDown = true;\n\n onShutdownStart?.(signal);\n\n let timer: NodeJS.Timeout | null = null;\n if (timeoutMs > 0) {\n timer = setTimeout(() => {\n const err = new Error(`Graceful shutdown timed out after ${timeoutMs}ms`);\n onShutdownError?.(err);\n if (exitOnComplete) {\n process.exit(timeoutExitCode);\n }\n }, timeoutMs);\n\n timer.unref();\n }\n\n try {\n await stopTarget();\n if (timer) {\n clearTimeout(timer);\n }\n onShutdownComplete?.();\n if (exitOnComplete) {\n process.exit(exitCode);\n }\n } catch (err) {\n if (timer) {\n clearTimeout(timer);\n }\n onShutdownError?.(err);\n if (exitOnComplete) {\n process.exit(timeoutExitCode);\n }\n }\n };\n\n for (const sig of signals) {\n process.on(sig, handler);\n }\n\n return function detach(): void {\n for (const sig of signals) {\n process.removeListener(sig, handler);\n }\n };\n}\n","import readline from 'node:readline';\nimport { EventEmitter } from 'node:events';\nimport type {\n WorkmaticDb,\n McpServerOptions,\n WorkmaticMcpServer,\n JobStatusChangeEvent,\n} from '../types.js';\nimport { MCP_TOOL_DEFINITIONS, executeTool } from './tools.js';\n\nexport type { McpServerOptions, WorkmaticMcpServer } from '../types.js';\n\ninterface JsonRpcRequest {\n jsonrpc: string;\n id?: string | number | null;\n method: string;\n params?: Record<string, unknown>;\n}\n\n/**\n * Creates a lightweight stdio JSON-RPC 2.0 MCP server for Workmatic.\n * Conforms to the MCP Specification (protocol version 2024-11-05).\n */\nexport function createMcpServer(options: McpServerOptions): WorkmaticMcpServer {\n const db = options.db;\n const input = options.input ?? process.stdin;\n const output = options.output ?? process.stdout;\n\n const emitter = new EventEmitter();\n let rl: readline.Interface | null = null;\n let isRunning = false;\n\n function notifyJobStatusChanged(event: JobStatusChangeEvent): void {\n if (options.onJobStatusChanged) {\n options.onJobStatusChanged(event);\n }\n emitter.emit('jobStatusChanged', event);\n\n if (event.status === 'ready') {\n if (options.orchestrator) {\n if (event.queue === '*') {\n for (const worker of options.orchestrator.workers()) {\n worker.wakeUp();\n }\n } else {\n try {\n options.orchestrator.worker(event.queue).wakeUp();\n } catch {\n // Queue might not have a registered worker\n }\n }\n }\n\n if (options.workers) {\n for (const worker of options.workers) {\n if (event.queue === '*' || worker.queue === event.queue) {\n worker.wakeUp();\n }\n }\n }\n }\n\n if (isRunning) {\n (output as NodeJS.WritableStream).write(\n JSON.stringify({\n jsonrpc: '2.0',\n method: 'notifications/workmatic/job_status_changed',\n params: event,\n }) + '\\n'\n );\n }\n }\n\n async function handleMessage(raw: string): Promise<string | null> {\n const trimmed = raw.trim();\n if (!trimmed) {\n return null;\n }\n\n let msg: JsonRpcRequest;\n try {\n msg = JSON.parse(trimmed);\n } catch {\n return JSON.stringify({\n jsonrpc: '2.0',\n id: null,\n error: {\n code: -32700,\n message: 'Parse error',\n },\n });\n }\n\n // Validate JSON-RPC 2.0 format\n if (!msg || typeof msg !== 'object' || msg.jsonrpc !== '2.0' || typeof msg.method !== 'string') {\n return JSON.stringify({\n jsonrpc: '2.0',\n id: (msg as { id?: unknown })?.id ?? null,\n error: {\n code: -32600,\n message: 'Invalid Request',\n },\n });\n }\n\n const isNotification = msg.id === undefined;\n\n switch (msg.method) {\n case 'initialize': {\n const result = {\n protocolVersion: '2024-11-05',\n capabilities: {\n tools: {},\n },\n serverInfo: {\n name: 'workmatic-mcp',\n version: '0.1.0',\n },\n };\n return isNotification ? null : JSON.stringify({ jsonrpc: '2.0', id: msg.id, result });\n }\n\n case 'notifications/initialized': {\n return null;\n }\n\n case 'ping': {\n return isNotification ? null : JSON.stringify({ jsonrpc: '2.0', id: msg.id, result: {} });\n }\n\n case 'tools/list': {\n const result = {\n tools: MCP_TOOL_DEFINITIONS,\n };\n return isNotification ? null : JSON.stringify({ jsonrpc: '2.0', id: msg.id, result });\n }\n\n case 'tools/call': {\n if (!msg.params || typeof msg.params.name !== 'string') {\n return isNotification\n ? null\n : JSON.stringify({\n jsonrpc: '2.0',\n id: msg.id,\n error: {\n code: -32602,\n message: 'Invalid params: tool \"name\" is required',\n },\n });\n }\n\n const toolName = msg.params.name;\n const toolArgs = (msg.params.arguments as Record<string, unknown>) ?? {};\n\n try {\n const toolResult = await executeTool(db, toolName, toolArgs, {\n onJobStatusChanged: notifyJobStatusChanged,\n });\n const response = {\n content: [\n {\n type: 'text',\n text: JSON.stringify(toolResult, null, 2),\n },\n ],\n };\n return isNotification ? null : JSON.stringify({ jsonrpc: '2.0', id: msg.id, result: response });\n } catch (err: unknown) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n const response = {\n content: [\n {\n type: 'text',\n text: errorMessage,\n },\n ],\n isError: true,\n };\n return isNotification ? null : JSON.stringify({ jsonrpc: '2.0', id: msg.id, result: response });\n }\n }\n\n default: {\n return isNotification\n ? null\n : JSON.stringify({\n jsonrpc: '2.0',\n id: msg.id,\n error: {\n code: -32601,\n message: `Method not found: ${msg.method}`,\n },\n });\n }\n }\n }\n\n const server: WorkmaticMcpServer = {\n start() {\n if (isRunning) return;\n isRunning = true;\n\n rl = readline.createInterface({\n input: input as NodeJS.ReadableStream,\n terminal: false,\n });\n\n rl.on('line', (line) => {\n void handleMessage(line).then((response) => {\n if (response && isRunning) {\n (output as NodeJS.WritableStream).write(response + '\\n');\n }\n });\n });\n },\n\n stop() {\n if (!isRunning) return;\n isRunning = false;\n rl!.close();\n rl = null;\n },\n\n handleMessage,\n\n on(event: 'jobStatusChanged', listener: (event: JobStatusChangeEvent) => void) {\n emitter.on(event, listener);\n return server;\n },\n\n off(event: 'jobStatusChanged', listener: (event: JobStatusChangeEvent) => void) {\n emitter.off(event, listener);\n return server;\n },\n };\n\n return server;\n}\n","import { sql } from 'kysely';\nimport type { WorkmaticDb, JobStatus, JobStatusChangeEvent } from '../types.js';\nimport { createClient } from '../client.js';\nimport { createOrchestrator } from '../orchestrator.js';\nimport { now } from '../utils.js';\n\nexport interface ToolExecutionContext {\n onJobStatusChanged?: (event: JobStatusChangeEvent) => void;\n}\n\nexport interface McpToolDefinition {\n name: string;\n description: string;\n inputSchema: {\n type: 'object';\n properties: Record<string, unknown>;\n required?: string[];\n };\n}\n\n\nexport const MCP_TOOL_DEFINITIONS: McpToolDefinition[] = [\n {\n name: 'workmatic_list_queues',\n description: 'List all queues present in the Workmatic database along with job counts',\n inputSchema: {\n type: 'object',\n properties: {},\n },\n },\n {\n name: 'workmatic_get_stats',\n description: 'Get real-time job counts (ready, running, done, dead, total) for a specific queue or all queues',\n inputSchema: {\n type: 'object',\n properties: {\n queue: {\n type: 'string',\n description: 'Optional queue name. If omitted, stats for all queues will be returned.',\n },\n },\n },\n },\n {\n name: 'workmatic_list_jobs',\n description: 'List jobs in the database filtered by queue, status, and limit',\n inputSchema: {\n type: 'object',\n properties: {\n queue: {\n type: 'string',\n description: 'Filter by queue name',\n },\n status: {\n type: 'string',\n enum: ['ready', 'running', 'done', 'dead'],\n description: 'Filter by job status',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of jobs to return (default: 20, max: 100)',\n },\n offset: {\n type: 'number',\n description: 'Number of jobs to skip for pagination (default: 0)',\n },\n },\n },\n },\n {\n name: 'workmatic_get_dead_jobs',\n description: 'Retrieve failed/dead jobs with error details and payloads for debugging',\n inputSchema: {\n type: 'object',\n properties: {\n queue: {\n type: 'string',\n description: 'Filter dead jobs by queue name',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of dead jobs to return (default: 20)',\n },\n },\n },\n },\n {\n name: 'workmatic_add_job',\n description: 'Enqueue a new background job into Workmatic',\n inputSchema: {\n type: 'object',\n properties: {\n queue: {\n type: 'string',\n description: 'Target queue name (default: \"default\")',\n },\n payload: {\n description: 'Job payload (JSON object, string, number, etc.)',\n },\n priority: {\n type: 'number',\n description: 'Job priority (lower number = higher priority, default: 0)',\n },\n delayMs: {\n type: 'number',\n description: 'Delay in milliseconds before job can run (default: 0)',\n },\n maxAttempts: {\n type: 'number',\n description: 'Maximum execution retry attempts (default: 3)',\n },\n },\n required: ['payload'],\n },\n },\n {\n name: 'workmatic_retry_job',\n description: 'Retry a specific dead or failed job by resetting it to ready status',\n inputSchema: {\n type: 'object',\n properties: {\n publicId: {\n type: 'string',\n description: 'Public ID of the job to retry',\n },\n },\n required: ['publicId'],\n },\n },\n {\n name: 'workmatic_retry_all_dead',\n description: 'Retry all dead jobs (optionally in a specific queue) by resetting them to ready status',\n inputSchema: {\n type: 'object',\n properties: {\n queue: {\n type: 'string',\n description: 'Optional queue name to restrict retrying',\n },\n },\n },\n },\n {\n name: 'workmatic_pause_queue',\n description: 'Pause a queue so workers stop claiming new jobs from it',\n inputSchema: {\n type: 'object',\n properties: {\n queue: {\n type: 'string',\n description: 'Queue name to pause',\n },\n },\n required: ['queue'],\n },\n },\n {\n name: 'workmatic_resume_queue',\n description: 'Resume a paused queue so workers resume claiming jobs',\n inputSchema: {\n type: 'object',\n properties: {\n queue: {\n type: 'string',\n description: 'Queue name to resume',\n },\n },\n required: ['queue'],\n },\n },\n {\n name: 'workmatic_purge_jobs',\n description: 'Permanently remove done or dead jobs from the database',\n inputSchema: {\n type: 'object',\n properties: {\n queue: {\n type: 'string',\n description: 'Queue name to purge jobs from (optional)',\n },\n status: {\n type: 'string',\n enum: ['done', 'dead', 'all'],\n description: 'Status of jobs to purge (default: \"done\")',\n },\n },\n },\n },\n {\n name: 'workmatic_transfer_jobs',\n description: 'Move jobs from one queue to another (e.g. from dead-letter queue back to primary)',\n inputSchema: {\n type: 'object',\n properties: {\n fromQueue: {\n type: 'string',\n description: 'Source queue name',\n },\n toQueue: {\n type: 'string',\n description: 'Destination queue name',\n },\n status: {\n type: 'string',\n enum: ['ready', 'dead'],\n description: 'Status of jobs to transfer (default: \"ready\")',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of jobs to transfer (default: 1000)',\n },\n resetForRetry: {\n type: 'boolean',\n description: 'If transferring dead jobs, reset their status to ready (default: false)',\n },\n },\n required: ['fromQueue', 'toQueue'],\n },\n },\n {\n name: 'workmatic_update_job_status',\n description: 'Update the status of a specific job (ready, done, dead) and signal workers / listeners',\n inputSchema: {\n type: 'object',\n properties: {\n publicId: {\n type: 'string',\n description: 'Public ID of the job to update',\n },\n status: {\n type: 'string',\n enum: ['ready', 'done', 'dead'],\n description: 'New status for the job',\n },\n error: {\n type: 'string',\n description: 'Optional error message when marking as dead or recording failure details',\n },\n resetAttempts: {\n type: 'boolean',\n description: 'Whether to reset attempts to 0 (default: true if status is ready, false otherwise)',\n },\n delayMs: {\n type: 'number',\n description: 'Delay in milliseconds before the job becomes ready (default: 0)',\n },\n },\n required: ['publicId', 'status'],\n },\n },\n];\n\n/**\n * Execute an MCP tool invocation against a Workmatic database\n */\nexport async function executeTool(\n db: WorkmaticDb,\n name: string,\n args: Record<string, unknown> = {},\n context?: ToolExecutionContext\n): Promise<unknown> {\n\n switch (name) {\n case 'workmatic_list_queues': {\n const qJobs = await db\n .selectFrom('workmatic_jobs')\n .select('queue')\n .distinct()\n .execute();\n\n const qSettings = await db\n .selectFrom('workmatic_settings')\n .select('queue')\n .distinct()\n .execute();\n\n const set = new Set<string>();\n for (const r of qJobs) set.add(r.queue);\n for (const r of qSettings) {\n // filter out internal worker_state_ keys\n if (!r.queue.startsWith('worker_state_')) {\n set.add(r.queue);\n }\n }\n\n const queueList = Array.from(set).sort();\n const result: Array<{ queue: string; stats: Record<string, number>; isPaused: boolean }> = [];\n\n for (const q of queueList) {\n const client = createClient({ db, queue: q });\n const stats = await client.stats();\n const setting = await db\n .selectFrom('workmatic_settings')\n .select('paused')\n .where('queue', '=', q)\n .executeTakeFirst();\n\n result.push({\n queue: q,\n stats: {\n ready: stats.ready,\n running: stats.running,\n done: stats.done,\n dead: stats.dead,\n total: stats.total,\n },\n isPaused: setting?.paused === 1,\n });\n }\n\n return { queues: result, totalQueues: result.length };\n }\n\n case 'workmatic_get_stats': {\n const queue = args.queue as string | undefined;\n if (queue) {\n const client = createClient({ db, queue });\n return { queue, stats: await client.stats() };\n }\n\n // All queues\n const listRes = (await executeTool(db, 'workmatic_list_queues')) as {\n queues: Array<{ queue: string; stats: Record<string, number> }>;\n };\n\n const summary: Record<string, Record<string, number>> = {};\n const grandTotal = { ready: 0, running: 0, done: 0, dead: 0, total: 0 };\n\n for (const item of listRes.queues) {\n summary[item.queue] = item.stats;\n grandTotal.ready += item.stats.ready;\n grandTotal.running += item.stats.running;\n grandTotal.done += item.stats.done;\n grandTotal.dead += item.stats.dead;\n grandTotal.total += item.stats.total;\n }\n\n return { queues: summary, grandTotal };\n }\n\n case 'workmatic_list_jobs': {\n const queue = args.queue as string | undefined;\n const status = args.status as JobStatus | undefined;\n const limit = Math.min(Math.max(Number(args.limit ?? 20), 1), 100);\n const offset = Math.max(Number(args.offset ?? 0), 0);\n\n let query = db\n .selectFrom('workmatic_jobs')\n .select([\n 'id',\n 'public_id',\n 'queue',\n 'status',\n 'priority',\n 'payload',\n 'attempts',\n 'max_attempts',\n 'run_at',\n 'created_at',\n 'updated_at',\n 'last_error',\n ]);\n\n if (queue) {\n query = query.where('queue', '=', queue);\n }\n if (status) {\n query = query.where('status', '=', status);\n }\n\n const rows = await query\n .orderBy('priority', 'asc')\n .orderBy('id', 'asc')\n .limit(limit)\n .offset(offset)\n .execute();\n\n const jobs = rows.map((r) => {\n let parsedPayload: unknown;\n try {\n parsedPayload = JSON.parse(r.payload);\n } catch {\n parsedPayload = r.payload;\n }\n return {\n id: r.id,\n publicId: r.public_id,\n queue: r.queue,\n status: r.status,\n priority: r.priority,\n attempts: r.attempts,\n maxAttempts: r.max_attempts,\n runAt: r.run_at,\n createdAt: r.created_at,\n updatedAt: r.updated_at,\n lastError: r.last_error,\n payload: parsedPayload,\n };\n });\n\n return { jobs, count: jobs.length, limit, offset };\n }\n\n case 'workmatic_get_dead_jobs': {\n const queue = args.queue as string | undefined;\n const limit = Math.min(Math.max(Number(args.limit ?? 20), 1), 100);\n\n return executeTool(db, 'workmatic_list_jobs', {\n queue,\n status: 'dead',\n limit,\n });\n }\n\n case 'workmatic_add_job': {\n const queue = (args.queue as string) || 'default';\n const payload = args.payload;\n const priority = args.priority !== undefined ? Number(args.priority) : 0;\n const delayMs = args.delayMs !== undefined ? Number(args.delayMs) : 0;\n const maxAttempts = args.maxAttempts !== undefined ? Number(args.maxAttempts) : 3;\n\n const client = createClient({ db, queue });\n const result = await client.add(payload, { priority, delayMs, maxAttempts });\n return { ok: true, id: result.id, queue };\n }\n\n case 'workmatic_retry_job': {\n const publicId = args.publicId as string;\n if (!publicId) {\n throw new Error('publicId is required');\n }\n\n const job = await db\n .selectFrom('workmatic_jobs')\n .select(['queue', 'status'])\n .where('public_id', '=', publicId)\n .executeTakeFirst();\n\n if (!job) {\n throw new Error(`Job not found: ${publicId}`);\n }\n\n const timestamp = now();\n await db\n .updateTable('workmatic_jobs')\n .set({\n status: 'ready',\n attempts: 0,\n lease_until: 0,\n last_error: null,\n run_at: timestamp,\n updated_at: timestamp,\n })\n .where('public_id', '=', publicId)\n .execute();\n\n context?.onJobStatusChanged?.({\n publicId,\n queue: job.queue,\n previousStatus: job.status as JobStatus,\n status: 'ready',\n timestamp,\n error: null,\n });\n\n return { ok: true, id: publicId, message: `Job ${publicId} reset to ready` };\n }\n\n case 'workmatic_retry_all_dead': {\n const queue = args.queue as string | undefined;\n const timestamp = now();\n\n let query = db\n .updateTable('workmatic_jobs')\n .set({\n status: 'ready',\n attempts: 0,\n lease_until: 0,\n last_error: null,\n run_at: timestamp,\n updated_at: timestamp,\n })\n .where('status', '=', 'dead');\n\n if (queue) {\n query = query.where('queue', '=', queue);\n }\n\n const res = await query.execute();\n const retriedCount = Number(res[0].numUpdatedRows);\n\n if (retriedCount > 0) {\n context?.onJobStatusChanged?.({\n publicId: '*',\n queue: queue ?? '*',\n previousStatus: 'dead',\n status: 'ready',\n timestamp,\n error: null,\n });\n }\n\n return { ok: true, retriedCount, queue: queue ?? 'all' };\n }\n\n case 'workmatic_update_job_status': {\n const publicId = args.publicId as string;\n const status = args.status as JobStatus;\n if (!publicId) {\n throw new Error('publicId is required');\n }\n if (!status || !['ready', 'done', 'dead'].includes(status)) {\n throw new Error(\"status is required and must be 'ready', 'done', or 'dead'\");\n }\n\n const job = await db\n .selectFrom('workmatic_jobs')\n .select(['id', 'public_id', 'queue', 'status', 'attempts'])\n .where('public_id', '=', publicId)\n .executeTakeFirst();\n\n if (!job) {\n throw new Error(`Job not found: ${publicId}`);\n }\n\n if (job.status === status) {\n return {\n ok: true,\n id: publicId,\n queue: job.queue,\n status,\n unchanged: true,\n };\n }\n\n const timestamp = now();\n const previousStatus = job.status as JobStatus;\n const delayMs = Math.max(Number(args.delayMs ?? 0), 0);\n const resetAttempts =\n args.resetAttempts !== undefined\n ? Boolean(args.resetAttempts)\n : status === 'ready';\n\n const updateData: Record<string, unknown> = {\n status,\n updated_at: timestamp,\n lease_until: 0,\n };\n\n if (status === 'ready') {\n updateData.run_at = timestamp + delayMs;\n }\n if (resetAttempts) {\n updateData.attempts = 0;\n }\n if (args.error !== undefined) {\n updateData.last_error = args.error;\n } else if (status === 'ready') {\n updateData.last_error = null;\n }\n\n await db\n .updateTable('workmatic_jobs')\n .set(updateData)\n .where('public_id', '=', publicId)\n .execute();\n\n const event: JobStatusChangeEvent = {\n publicId,\n queue: job.queue,\n previousStatus,\n status,\n timestamp,\n error: (updateData.last_error as string | null) ?? null,\n };\n\n context?.onJobStatusChanged?.(event);\n\n return {\n ok: true,\n id: publicId,\n queue: job.queue,\n previousStatus,\n status,\n signaled: true,\n };\n }\n\n\n case 'workmatic_pause_queue': {\n const queue = args.queue as string;\n if (!queue) {\n throw new Error('queue is required');\n }\n\n const timestamp = now();\n await sql`\n INSERT INTO workmatic_settings (queue, paused, updated_at)\n VALUES (${queue}, 1, ${timestamp})\n ON CONFLICT(queue) DO UPDATE SET\n paused = 1,\n updated_at = ${timestamp}\n `.execute(db);\n\n return { ok: true, queue, paused: true };\n }\n\n case 'workmatic_resume_queue': {\n const queue = args.queue as string;\n if (!queue) {\n throw new Error('queue is required');\n }\n\n const timestamp = now();\n await sql`\n INSERT INTO workmatic_settings (queue, paused, updated_at)\n VALUES (${queue}, 0, ${timestamp})\n ON CONFLICT(queue) DO UPDATE SET\n paused = 0,\n updated_at = ${timestamp}\n `.execute(db);\n\n return { ok: true, queue, paused: false };\n }\n\n case 'workmatic_purge_jobs': {\n const queue = args.queue as string | undefined;\n const status = (args.status as string) || 'done';\n\n let query = db.deleteFrom('workmatic_jobs');\n\n if (queue) {\n query = query.where('queue', '=', queue);\n }\n\n if (status !== 'all') {\n query = query.where('status', '=', status as JobStatus);\n }\n\n const res = await query.execute();\n const deletedCount = Number(res[0].numDeletedRows);\n return { ok: true, deletedCount, queue: queue ?? 'all', status };\n }\n\n\n case 'workmatic_transfer_jobs': {\n const fromQueue = args.fromQueue as string;\n const toQueue = args.toQueue as string;\n if (!fromQueue || !toQueue) {\n throw new Error('fromQueue and toQueue are required');\n }\n if (fromQueue === toQueue) {\n return { ok: true, moved: 0 };\n }\n\n const status = (args.status as JobStatus) || 'ready';\n const limit = Math.max(Number(args.limit ?? 1000), 1);\n const resetForRetry = Boolean(args.resetForRetry);\n\n const orch = createOrchestrator({ db });\n const result = await orch.transfer({\n from: fromQueue,\n to: toQueue,\n status,\n limit,\n resetForRetry,\n });\n\n return {\n ok: true,\n moved: result.moved,\n fromQueue,\n toQueue,\n status: resetForRetry && status === 'dead' ? 'ready' : status,\n };\n }\n\n\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n}\n","#!/usr/bin/env node\n\n/**\n * Workmatic CLI β€” thin entrypoint; logic in ./cli/handlers.ts\n */\n\nimport {\n printUsage,\n parseOptions,\n getPositionalArgs,\n runCommand,\n type CliCommand,\n} from './cli/handlers.js';\n\nconst args = process.argv.slice(2);\nconst command = args[0];\n\nconst KNOWN_COMMANDS: readonly CliCommand[] = [\n 'stats',\n 'list',\n 'export',\n 'import',\n 'purge',\n 'retry',\n 'pause',\n 'resume',\n 'queues',\n 'transfer',\n 'mcp',\n];\n\n\nfunction isCliCommand(value: string): value is CliCommand {\n return (KNOWN_COMMANDS as readonly string[]).includes(value);\n}\n\nasync function main(): Promise<void> {\n if (!command || command === '--help' || command === '-h') {\n printUsage();\n process.exit(0);\n }\n\n if (!isCliCommand(command)) {\n console.error(`Unknown command: ${command}`);\n printUsage();\n process.exit(1);\n }\n\n const positionalArgs = getPositionalArgs(args.slice(1));\n const options = parseOptions(args);\n const dbPath = positionalArgs[0];\n\n if (!dbPath) {\n console.error('Error: Database path is required');\n printUsage();\n process.exit(1);\n }\n\n try {\n await runCommand(command, dbPath, positionalArgs, options);\n } catch (error) {\n console.error('Error:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n}\n\nmain();\n"],"mappings":"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","names":["import_better_sqlite3","Database","sql","import_kysely","import_kysely","options","import_kysely","fastq","options","result","options","import_kysely","args","readline","args","Database","Table","command"]}