@happyvertical/jobs 0.80.0 → 0.80.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"bull.js","sources":["../../src/adapters/bull.ts"],"sourcesContent":["/**\n * Bull (Redis) Job Store Adapter\n *\n * Uses Bull queue library for Redis-based job storage with real-time updates.\n * Bull provides robust job processing with features like priority queues,\n * delayed jobs, retries, and job events.\n *\n * @example\n * ```typescript\n * import { BullJobStore } from '@happyvertical/jobs/adapters/bull';\n *\n * const store = new BullJobStore({\n * redis: {\n * host: 'localhost',\n * port: 6379,\n * },\n * defaultJobOptions: {\n * removeOnComplete: 100,\n * removeOnFail: 500,\n * },\n * });\n *\n * await store.initialize();\n * ```\n *\n * Note: This adapter requires the `bull` package as a peer dependency.\n * Install it with: npm install bull @types/bull\n */\n\nimport { createId } from '@happyvertical/utils';\nimport type {\n Job as BullJob,\n JobOptions as BullJobOptions,\n Queue as BullQueue,\n} from 'bull';\nimport { BaseJobStore, priorityToNumber } from '../base-store.js';\nimport type {\n CleanupOptions,\n Job,\n JobCreateOptions,\n JobFilter,\n QueueStats,\n} from '../types.js';\n\n/**\n * Redis connection options\n */\nexport interface RedisOptions {\n host?: string;\n port?: number;\n password?: string;\n db?: number;\n url?: string;\n}\n\n/**\n * Bull adapter configuration\n */\nexport interface BullJobStoreConfig {\n /** Redis connection options */\n redis?: RedisOptions;\n /** Default queue name prefix */\n prefix?: string;\n /** Default job options */\n defaultJobOptions?: BullJobOptions;\n}\n\n/**\n * Job data stored in Bull\n */\ninterface BullJobData {\n /** Original job payload */\n payload: Job['payload'];\n /** Additional metadata */\n meta: {\n maxAttempts: number;\n timeout: number;\n timeoutBehavior: Job['timeoutBehavior'];\n retryStrategy: Job['retryStrategy'];\n workerId: string | null;\n };\n}\n\n/**\n * Bull-based job store implementation\n */\nexport class BullJobStore extends BaseJobStore {\n private config: BullJobStoreConfig;\n private queues: Map<string, BullQueue<BullJobData>> = new Map();\n // biome-ignore lint/style/useNamingConvention: bull module reference\n private bullModule: typeof import('bull') | null = null;\n\n constructor(config: BullJobStoreConfig = {}) {\n super();\n this.config = {\n prefix: 'smrt_jobs',\n defaultJobOptions: {\n removeOnComplete: 100,\n removeOnFail: 500,\n },\n ...config,\n };\n }\n\n /**\n * Initialize the store - dynamically imports Bull\n */\n async initialize(): Promise<void> {\n if (this.initialized) return;\n\n try {\n // Dynamic import to avoid requiring bull as a hard dependency\n this.bullModule = (await import('bull')).default;\n } catch {\n throw new Error(\n 'Bull is required for BullJobStore. Install it with: npm install bull',\n );\n }\n\n this.initialized = true;\n }\n\n /**\n * Get or create a Bull queue for a queue name\n */\n private getQueue(queueName: string): BullQueue<BullJobData> {\n if (!this.bullModule) {\n throw new Error('BullJobStore not initialized');\n }\n\n if (!this.queues.has(queueName)) {\n const queue = new this.bullModule<BullJobData>(queueName, {\n redis: this.config.redis,\n prefix: this.config.prefix,\n defaultJobOptions: this.config.defaultJobOptions,\n });\n\n // Set up event listeners\n queue.on('completed', (bullJob) => {\n this.handleJobCompleted(bullJob, queueName);\n });\n\n queue.on('failed', (bullJob, error) => {\n this.handleJobFailed(bullJob, error, queueName);\n });\n\n this.queues.set(queueName, queue);\n }\n\n const result = this.queues.get(queueName);\n if (!result) {\n throw new Error(`Queue ${queueName} was not found after initialization`);\n }\n return result;\n }\n\n /**\n * Handle Bull job completed event\n */\n private async handleJobCompleted(\n bullJob: BullJob<BullJobData>,\n queueName: string,\n ): Promise<void> {\n const job = this.bullJobToJob(bullJob, queueName);\n await this.emitEvent('job.completed', job);\n }\n\n /**\n * Handle Bull job failed event\n */\n private async handleJobFailed(\n bullJob: BullJob<BullJobData>,\n error: Error,\n queueName: string,\n ): Promise<void> {\n const job = this.bullJobToJob(bullJob, queueName);\n job.lastError = error.message;\n await this.emitEvent('job.failed', job, { error: error.message });\n }\n\n /**\n * Convert Bull job to our Job format\n */\n private bullJobToJob(bullJob: BullJob<BullJobData>, queueName: string): Job {\n const data = bullJob.data;\n const status = this.mapBullStatus(bullJob);\n\n return {\n id: String(bullJob.id),\n queue: queueName,\n payload: data.payload,\n status,\n priority: bullJob.opts.priority ?? 50,\n attempts: bullJob.attemptsMade,\n maxAttempts: data.meta.maxAttempts,\n runAt: bullJob.opts.delay\n ? new Date(bullJob.timestamp + bullJob.opts.delay)\n : new Date(bullJob.timestamp),\n startedAt: bullJob.processedOn ? new Date(bullJob.processedOn) : null,\n completedAt: bullJob.finishedOn ? new Date(bullJob.finishedOn) : null,\n timeout: data.meta.timeout,\n timeoutBehavior: data.meta.timeoutBehavior,\n lastError: bullJob.failedReason ?? null,\n resultPointer: bullJob.returnvalue?.resultPointer ?? null,\n retryStrategy: data.meta.retryStrategy,\n workerId: data.meta.workerId,\n workerHeartbeat: null,\n createdAt: new Date(bullJob.timestamp),\n updatedAt: new Date(),\n };\n }\n\n /**\n * Map Bull job state to our JobStatus\n */\n private mapBullStatus(bullJob: BullJob<BullJobData>): Job['status'] {\n // Bull doesn't expose state directly, so we check various properties\n if (bullJob.finishedOn) {\n return bullJob.failedReason ? 'failed' : 'completed';\n }\n if (bullJob.processedOn) {\n return 'running';\n }\n return 'pending';\n }\n\n /**\n * Enqueue a new job\n */\n async enqueue(options: JobCreateOptions): Promise<Job> {\n if (!this.initialized) {\n throw new Error('BullJobStore not initialized');\n }\n\n const queueName = options.queue ?? 'default';\n const queue = this.getQueue(queueName);\n\n const jobData: BullJobData = {\n payload: options.payload,\n meta: {\n maxAttempts: options.maxAttempts ?? 3,\n timeout: options.timeout ?? 300000,\n timeoutBehavior: options.timeoutBehavior ?? 'fail',\n retryStrategy:\n options.retryStrategy && 'toConfig' in options.retryStrategy\n ? options.retryStrategy.toConfig()\n : ((options.retryStrategy as Job['retryStrategy']) ?? {\n type: 'exponential',\n config: { initialDelay: 1000, multiplier: 2 },\n }),\n workerId: null,\n },\n };\n\n const bullJobOptions: BullJobOptions = {\n priority: priorityToNumber(options.priority),\n attempts: options.maxAttempts ?? 3,\n timeout: options.timeout ?? 300000,\n delay: options.runAt\n ? Math.max(0, options.runAt.getTime() - Date.now())\n : undefined,\n jobId: createId(),\n };\n\n const bullJob = await queue.add(jobData, bullJobOptions);\n const job = this.bullJobToJob(bullJob, queueName);\n\n await this.emitEvent('job.created', job);\n return job;\n }\n\n /**\n * Dequeue jobs ready for processing\n */\n async dequeue(\n queues: string[],\n limit: number,\n workerId: string,\n ): Promise<Job[]> {\n if (!this.initialized) {\n throw new Error('BullJobStore not initialized');\n }\n\n // Bull handles job claiming internally through its processor\n // This method is primarily for compatibility with the interface\n // In Bull, you would use queue.process() instead\n\n const jobs: Job[] = [];\n\n for (const queueName of queues) {\n if (jobs.length >= limit) break;\n\n const queue = this.getQueue(queueName);\n const waiting = await queue.getWaiting(0, limit - jobs.length - 1);\n\n for (const bullJob of waiting) {\n // Update worker ID\n bullJob.data.meta.workerId = workerId;\n await bullJob.update(bullJob.data);\n\n jobs.push(this.bullJobToJob(bullJob, queueName));\n }\n }\n\n return jobs;\n }\n\n /**\n * Update a job\n */\n async update(id: string, updates: Partial<Job>): Promise<Job> {\n if (!this.initialized) {\n throw new Error('BullJobStore not initialized');\n }\n\n // Find the job across queues\n for (const [queueName, queue] of this.queues) {\n const bullJob = await queue.getJob(id);\n if (bullJob) {\n // Update the job data\n if (updates.payload) {\n bullJob.data.payload = updates.payload;\n }\n if (updates.maxAttempts !== undefined) {\n bullJob.data.meta.maxAttempts = updates.maxAttempts;\n }\n if (updates.timeout !== undefined) {\n bullJob.data.meta.timeout = updates.timeout;\n }\n if (updates.workerId !== undefined) {\n bullJob.data.meta.workerId = updates.workerId;\n }\n\n await bullJob.update(bullJob.data);\n return this.bullJobToJob(bullJob, queueName);\n }\n }\n\n throw new Error(`Job ${id} not found`);\n }\n\n /**\n * Get a job by ID\n */\n async get(id: string): Promise<Job | null> {\n if (!this.initialized) {\n throw new Error('BullJobStore not initialized');\n }\n\n // Search across all queues\n for (const [queueName, queue] of this.queues) {\n const bullJob = await queue.getJob(id);\n if (bullJob) {\n return this.bullJobToJob(bullJob, queueName);\n }\n }\n\n return null;\n }\n\n /**\n * List jobs with filtering\n */\n async list(filter: JobFilter): Promise<Job[]> {\n if (!this.initialized) {\n throw new Error('BullJobStore not initialized');\n }\n\n const jobs: Job[] = [];\n const limit = filter.limit ?? 100;\n const offset = filter.offset ?? 0;\n\n const targetQueues = filter.queue\n ? [this.getQueue(filter.queue)]\n : Array.from(this.queues.values());\n\n for (const queue of targetQueues) {\n const queueName =\n Array.from(this.queues.entries()).find(([, q]) => q === queue)?.[0] ??\n 'unknown';\n\n // Get jobs by status\n const statuses = filter.status\n ? Array.isArray(filter.status)\n ? filter.status\n : [filter.status]\n : ['pending', 'running', 'completed', 'failed'];\n\n for (const status of statuses) {\n let bullJobs: BullJob<BullJobData>[] = [];\n\n switch (status) {\n case 'pending':\n bullJobs = await queue.getWaiting(offset, offset + limit - 1);\n break;\n case 'running':\n bullJobs = await queue.getActive(offset, offset + limit - 1);\n break;\n case 'completed':\n bullJobs = await queue.getCompleted(offset, offset + limit - 1);\n break;\n case 'failed':\n bullJobs = await queue.getFailed(offset, offset + limit - 1);\n break;\n }\n\n for (const bullJob of bullJobs) {\n const job = this.bullJobToJob(bullJob, queueName);\n\n // Apply additional filters\n if (filter.objectType && job.payload.objectType !== filter.objectType)\n continue;\n if (filter.method && job.payload.method !== filter.method) continue;\n if (filter.createdAfter && job.createdAt < filter.createdAfter)\n continue;\n if (filter.createdBefore && job.createdAt > filter.createdBefore)\n continue;\n\n jobs.push(job);\n\n if (jobs.length >= limit) break;\n }\n\n if (jobs.length >= limit) break;\n }\n }\n\n return jobs.slice(0, limit);\n }\n\n /**\n * Cancel a job\n */\n async cancel(id: string): Promise<void> {\n if (!this.initialized) {\n throw new Error('BullJobStore not initialized');\n }\n\n for (const [queueName, queue] of this.queues) {\n const bullJob = await queue.getJob(id);\n if (bullJob) {\n await bullJob.remove();\n const job = this.bullJobToJob(bullJob, queueName);\n job.status = 'cancelled';\n await this.emitEvent('job.cancelled', job);\n return;\n }\n }\n\n throw new Error(`Job ${id} not found`);\n }\n\n /**\n * Clean up old jobs\n */\n async cleanup(options: CleanupOptions): Promise<number> {\n if (!this.initialized) {\n throw new Error('BullJobStore not initialized');\n }\n\n let cleaned = 0;\n\n for (const queue of this.queues.values()) {\n if (options.completedBefore) {\n const grace = Date.now() - options.completedBefore.getTime();\n const result = await queue.clean(grace, 'completed', options.limit);\n cleaned += result.length;\n }\n\n if (options.failedBefore) {\n const grace = Date.now() - options.failedBefore.getTime();\n const result = await queue.clean(grace, 'failed', options.limit);\n cleaned += result.length;\n }\n }\n\n return cleaned;\n }\n\n /**\n * Update worker heartbeat (no-op for Bull - handled internally)\n */\n async heartbeat(_jobId: string, _workerId: string): Promise<void> {\n // Bull handles heartbeat/stalled job detection internally\n }\n\n /**\n * Get queue statistics\n */\n async stats(queue?: string): Promise<QueueStats> {\n if (!this.initialized) {\n throw new Error('BullJobStore not initialized');\n }\n\n const totals: QueueStats = {\n pending: 0,\n running: 0,\n completed: 0,\n failed: 0,\n cancelled: 0,\n avgDuration: null,\n };\n\n const targetQueues = queue\n ? [this.getQueue(queue)]\n : Array.from(this.queues.values());\n\n for (const q of targetQueues) {\n const counts = await q.getJobCounts();\n totals.pending += counts.waiting + counts.delayed;\n totals.running += counts.active;\n totals.completed += counts.completed;\n totals.failed += counts.failed;\n }\n\n return totals;\n }\n\n /**\n * Close all queues\n */\n async close(): Promise<void> {\n for (const queue of this.queues.values()) {\n await queue.close();\n }\n this.queues.clear();\n this.initialized = false;\n }\n}\n\n/**\n * Create a Bull job store instance\n */\nexport function createBullJobStore(config?: BullJobStoreConfig): BullJobStore {\n return new BullJobStore(config);\n}\n\nexport default BullJobStore;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bull.js","names":[],"sources":["../../src/adapters/bull.ts"],"sourcesContent":["/**\n * Bull (Redis) Job Store Adapter\n *\n * Uses Bull queue library for Redis-based job storage with real-time updates.\n * Bull provides robust job processing with features like priority queues,\n * delayed jobs, retries, and job events.\n *\n * @example\n * ```typescript\n * import { BullJobStore } from '@happyvertical/jobs/adapters/bull';\n *\n * const store = new BullJobStore({\n * redis: {\n * host: 'localhost',\n * port: 6379,\n * },\n * defaultJobOptions: {\n * removeOnComplete: 100,\n * removeOnFail: 500,\n * },\n * });\n *\n * await store.initialize();\n * ```\n *\n * Note: This adapter requires the `bull` package as a peer dependency.\n * Install it with: npm install bull @types/bull\n */\n\nimport { createId } from '@happyvertical/utils';\nimport type {\n Job as BullJob,\n JobOptions as BullJobOptions,\n Queue as BullQueue,\n} from 'bull';\nimport { BaseJobStore, priorityToNumber } from '../base-store.js';\nimport type {\n CleanupOptions,\n Job,\n JobCreateOptions,\n JobFilter,\n QueueStats,\n} from '../types.js';\n\n/**\n * Redis connection options\n */\nexport interface RedisOptions {\n host?: string;\n port?: number;\n password?: string;\n db?: number;\n url?: string;\n}\n\n/**\n * Bull adapter configuration\n */\nexport interface BullJobStoreConfig {\n /** Redis connection options */\n redis?: RedisOptions;\n /** Default queue name prefix */\n prefix?: string;\n /** Default job options */\n defaultJobOptions?: BullJobOptions;\n}\n\n/**\n * Job data stored in Bull\n */\ninterface BullJobData {\n /** Original job payload */\n payload: Job['payload'];\n /** Additional metadata */\n meta: {\n maxAttempts: number;\n timeout: number;\n timeoutBehavior: Job['timeoutBehavior'];\n retryStrategy: Job['retryStrategy'];\n workerId: string | null;\n };\n}\n\n/**\n * Bull-based job store implementation\n */\nexport class BullJobStore extends BaseJobStore {\n private config: BullJobStoreConfig;\n private queues: Map<string, BullQueue<BullJobData>> = new Map();\n // biome-ignore lint/style/useNamingConvention: bull module reference\n private bullModule: typeof import('bull') | null = null;\n\n constructor(config: BullJobStoreConfig = {}) {\n super();\n this.config = {\n prefix: 'smrt_jobs',\n defaultJobOptions: {\n removeOnComplete: 100,\n removeOnFail: 500,\n },\n ...config,\n };\n }\n\n /**\n * Initialize the store - dynamically imports Bull\n */\n async initialize(): Promise<void> {\n if (this.initialized) return;\n\n try {\n // Dynamic import to avoid requiring bull as a hard dependency\n this.bullModule = (await import('bull')).default;\n } catch {\n throw new Error(\n 'Bull is required for BullJobStore. Install it with: npm install bull',\n );\n }\n\n this.initialized = true;\n }\n\n /**\n * Get or create a Bull queue for a queue name\n */\n private getQueue(queueName: string): BullQueue<BullJobData> {\n if (!this.bullModule) {\n throw new Error('BullJobStore not initialized');\n }\n\n if (!this.queues.has(queueName)) {\n const queue = new this.bullModule<BullJobData>(queueName, {\n redis: this.config.redis,\n prefix: this.config.prefix,\n defaultJobOptions: this.config.defaultJobOptions,\n });\n\n // Set up event listeners\n queue.on('completed', (bullJob) => {\n this.handleJobCompleted(bullJob, queueName);\n });\n\n queue.on('failed', (bullJob, error) => {\n this.handleJobFailed(bullJob, error, queueName);\n });\n\n this.queues.set(queueName, queue);\n }\n\n const result = this.queues.get(queueName);\n if (!result) {\n throw new Error(`Queue ${queueName} was not found after initialization`);\n }\n return result;\n }\n\n /**\n * Handle Bull job completed event\n */\n private async handleJobCompleted(\n bullJob: BullJob<BullJobData>,\n queueName: string,\n ): Promise<void> {\n const job = this.bullJobToJob(bullJob, queueName);\n await this.emitEvent('job.completed', job);\n }\n\n /**\n * Handle Bull job failed event\n */\n private async handleJobFailed(\n bullJob: BullJob<BullJobData>,\n error: Error,\n queueName: string,\n ): Promise<void> {\n const job = this.bullJobToJob(bullJob, queueName);\n job.lastError = error.message;\n await this.emitEvent('job.failed', job, { error: error.message });\n }\n\n /**\n * Convert Bull job to our Job format\n */\n private bullJobToJob(bullJob: BullJob<BullJobData>, queueName: string): Job {\n const data = bullJob.data;\n const status = this.mapBullStatus(bullJob);\n\n return {\n id: String(bullJob.id),\n queue: queueName,\n payload: data.payload,\n status,\n priority: bullJob.opts.priority ?? 50,\n attempts: bullJob.attemptsMade,\n maxAttempts: data.meta.maxAttempts,\n runAt: bullJob.opts.delay\n ? new Date(bullJob.timestamp + bullJob.opts.delay)\n : new Date(bullJob.timestamp),\n startedAt: bullJob.processedOn ? new Date(bullJob.processedOn) : null,\n completedAt: bullJob.finishedOn ? new Date(bullJob.finishedOn) : null,\n timeout: data.meta.timeout,\n timeoutBehavior: data.meta.timeoutBehavior,\n lastError: bullJob.failedReason ?? null,\n resultPointer: bullJob.returnvalue?.resultPointer ?? null,\n retryStrategy: data.meta.retryStrategy,\n workerId: data.meta.workerId,\n workerHeartbeat: null,\n createdAt: new Date(bullJob.timestamp),\n updatedAt: new Date(),\n };\n }\n\n /**\n * Map Bull job state to our JobStatus\n */\n private mapBullStatus(bullJob: BullJob<BullJobData>): Job['status'] {\n // Bull doesn't expose state directly, so we check various properties\n if (bullJob.finishedOn) {\n return bullJob.failedReason ? 'failed' : 'completed';\n }\n if (bullJob.processedOn) {\n return 'running';\n }\n return 'pending';\n }\n\n /**\n * Enqueue a new job\n */\n async enqueue(options: JobCreateOptions): Promise<Job> {\n if (!this.initialized) {\n throw new Error('BullJobStore not initialized');\n }\n\n const queueName = options.queue ?? 'default';\n const queue = this.getQueue(queueName);\n\n const jobData: BullJobData = {\n payload: options.payload,\n meta: {\n maxAttempts: options.maxAttempts ?? 3,\n timeout: options.timeout ?? 300000,\n timeoutBehavior: options.timeoutBehavior ?? 'fail',\n retryStrategy:\n options.retryStrategy && 'toConfig' in options.retryStrategy\n ? options.retryStrategy.toConfig()\n : ((options.retryStrategy as Job['retryStrategy']) ?? {\n type: 'exponential',\n config: { initialDelay: 1000, multiplier: 2 },\n }),\n workerId: null,\n },\n };\n\n const bullJobOptions: BullJobOptions = {\n priority: priorityToNumber(options.priority),\n attempts: options.maxAttempts ?? 3,\n timeout: options.timeout ?? 300000,\n delay: options.runAt\n ? Math.max(0, options.runAt.getTime() - Date.now())\n : undefined,\n jobId: createId(),\n };\n\n const bullJob = await queue.add(jobData, bullJobOptions);\n const job = this.bullJobToJob(bullJob, queueName);\n\n await this.emitEvent('job.created', job);\n return job;\n }\n\n /**\n * Dequeue jobs ready for processing\n */\n async dequeue(\n queues: string[],\n limit: number,\n workerId: string,\n ): Promise<Job[]> {\n if (!this.initialized) {\n throw new Error('BullJobStore not initialized');\n }\n\n // Bull handles job claiming internally through its processor\n // This method is primarily for compatibility with the interface\n // In Bull, you would use queue.process() instead\n\n const jobs: Job[] = [];\n\n for (const queueName of queues) {\n if (jobs.length >= limit) break;\n\n const queue = this.getQueue(queueName);\n const waiting = await queue.getWaiting(0, limit - jobs.length - 1);\n\n for (const bullJob of waiting) {\n // Update worker ID\n bullJob.data.meta.workerId = workerId;\n await bullJob.update(bullJob.data);\n\n jobs.push(this.bullJobToJob(bullJob, queueName));\n }\n }\n\n return jobs;\n }\n\n /**\n * Update a job\n */\n async update(id: string, updates: Partial<Job>): Promise<Job> {\n if (!this.initialized) {\n throw new Error('BullJobStore not initialized');\n }\n\n // Find the job across queues\n for (const [queueName, queue] of this.queues) {\n const bullJob = await queue.getJob(id);\n if (bullJob) {\n // Update the job data\n if (updates.payload) {\n bullJob.data.payload = updates.payload;\n }\n if (updates.maxAttempts !== undefined) {\n bullJob.data.meta.maxAttempts = updates.maxAttempts;\n }\n if (updates.timeout !== undefined) {\n bullJob.data.meta.timeout = updates.timeout;\n }\n if (updates.workerId !== undefined) {\n bullJob.data.meta.workerId = updates.workerId;\n }\n\n await bullJob.update(bullJob.data);\n return this.bullJobToJob(bullJob, queueName);\n }\n }\n\n throw new Error(`Job ${id} not found`);\n }\n\n /**\n * Get a job by ID\n */\n async get(id: string): Promise<Job | null> {\n if (!this.initialized) {\n throw new Error('BullJobStore not initialized');\n }\n\n // Search across all queues\n for (const [queueName, queue] of this.queues) {\n const bullJob = await queue.getJob(id);\n if (bullJob) {\n return this.bullJobToJob(bullJob, queueName);\n }\n }\n\n return null;\n }\n\n /**\n * List jobs with filtering\n */\n async list(filter: JobFilter): Promise<Job[]> {\n if (!this.initialized) {\n throw new Error('BullJobStore not initialized');\n }\n\n const jobs: Job[] = [];\n const limit = filter.limit ?? 100;\n const offset = filter.offset ?? 0;\n\n const targetQueues = filter.queue\n ? [this.getQueue(filter.queue)]\n : Array.from(this.queues.values());\n\n for (const queue of targetQueues) {\n const queueName =\n Array.from(this.queues.entries()).find(([, q]) => q === queue)?.[0] ??\n 'unknown';\n\n // Get jobs by status\n const statuses = filter.status\n ? Array.isArray(filter.status)\n ? filter.status\n : [filter.status]\n : ['pending', 'running', 'completed', 'failed'];\n\n for (const status of statuses) {\n let bullJobs: BullJob<BullJobData>[] = [];\n\n switch (status) {\n case 'pending':\n bullJobs = await queue.getWaiting(offset, offset + limit - 1);\n break;\n case 'running':\n bullJobs = await queue.getActive(offset, offset + limit - 1);\n break;\n case 'completed':\n bullJobs = await queue.getCompleted(offset, offset + limit - 1);\n break;\n case 'failed':\n bullJobs = await queue.getFailed(offset, offset + limit - 1);\n break;\n }\n\n for (const bullJob of bullJobs) {\n const job = this.bullJobToJob(bullJob, queueName);\n\n // Apply additional filters\n if (filter.objectType && job.payload.objectType !== filter.objectType)\n continue;\n if (filter.method && job.payload.method !== filter.method) continue;\n if (filter.createdAfter && job.createdAt < filter.createdAfter)\n continue;\n if (filter.createdBefore && job.createdAt > filter.createdBefore)\n continue;\n\n jobs.push(job);\n\n if (jobs.length >= limit) break;\n }\n\n if (jobs.length >= limit) break;\n }\n }\n\n return jobs.slice(0, limit);\n }\n\n /**\n * Cancel a job\n */\n async cancel(id: string): Promise<void> {\n if (!this.initialized) {\n throw new Error('BullJobStore not initialized');\n }\n\n for (const [queueName, queue] of this.queues) {\n const bullJob = await queue.getJob(id);\n if (bullJob) {\n await bullJob.remove();\n const job = this.bullJobToJob(bullJob, queueName);\n job.status = 'cancelled';\n await this.emitEvent('job.cancelled', job);\n return;\n }\n }\n\n throw new Error(`Job ${id} not found`);\n }\n\n /**\n * Clean up old jobs\n */\n async cleanup(options: CleanupOptions): Promise<number> {\n if (!this.initialized) {\n throw new Error('BullJobStore not initialized');\n }\n\n let cleaned = 0;\n\n for (const queue of this.queues.values()) {\n if (options.completedBefore) {\n const grace = Date.now() - options.completedBefore.getTime();\n const result = await queue.clean(grace, 'completed', options.limit);\n cleaned += result.length;\n }\n\n if (options.failedBefore) {\n const grace = Date.now() - options.failedBefore.getTime();\n const result = await queue.clean(grace, 'failed', options.limit);\n cleaned += result.length;\n }\n }\n\n return cleaned;\n }\n\n /**\n * Update worker heartbeat (no-op for Bull - handled internally)\n */\n async heartbeat(_jobId: string, _workerId: string): Promise<void> {\n // Bull handles heartbeat/stalled job detection internally\n }\n\n /**\n * Get queue statistics\n */\n async stats(queue?: string): Promise<QueueStats> {\n if (!this.initialized) {\n throw new Error('BullJobStore not initialized');\n }\n\n const totals: QueueStats = {\n pending: 0,\n running: 0,\n completed: 0,\n failed: 0,\n cancelled: 0,\n avgDuration: null,\n };\n\n const targetQueues = queue\n ? [this.getQueue(queue)]\n : Array.from(this.queues.values());\n\n for (const q of targetQueues) {\n const counts = await q.getJobCounts();\n totals.pending += counts.waiting + counts.delayed;\n totals.running += counts.active;\n totals.completed += counts.completed;\n totals.failed += counts.failed;\n }\n\n return totals;\n }\n\n /**\n * Close all queues\n */\n async close(): Promise<void> {\n for (const queue of this.queues.values()) {\n await queue.close();\n }\n this.queues.clear();\n this.initialized = false;\n }\n}\n\n/**\n * Create a Bull job store instance\n */\nexport function createBullJobStore(config?: BullJobStoreConfig): BullJobStore {\n return new BullJobStore(config);\n}\n\nexport default BullJobStore;\n"],"mappings":"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"}