silent-cronx 1.0.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/LICENSE +21 -0
- package/README.md +314 -0
- package/dist/index.cjs +1169 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +321 -0
- package/dist/index.d.ts +321 -0
- package/dist/index.js +1138 -0
- package/dist/index.js.map +1 -0
- package/dist/workers/workerRunner.cjs +29 -0
- package/dist/workers/workerRunner.cjs.map +1 -0
- package/dist/workers/workerRunner.d.cts +2 -0
- package/dist/workers/workerRunner.d.ts +2 -0
- package/dist/workers/workerRunner.js +27 -0
- package/dist/workers/workerRunner.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/core/eventBus.ts","../src/core/retryManager.ts","../src/utils/errors.ts","../src/core/timeoutManager.ts","../src/utils/time.ts","../src/core/jobRunner.ts","../src/core/lockManager.ts","../src/utils/id.ts","../src/utils/safeSerialize.ts","../src/utils/validation.ts","../src/core/queueManager.ts","../src/core/cronParser.ts","../src/storage/MemoryStorageAdapter.ts","../src/workers/workerPool.ts","../src/workers/workerBridge.ts","../src/utils/logger.ts","../src/core/SilentCronX.ts","../src/core/createSilentCronX.ts","../src/storage/RedisStorageAdapter.placeholder.ts","../src/storage/PostgresStorageAdapter.placeholder.ts"],"sourcesContent":["export { createSilentCronX } from \"./core/createSilentCronX.js\";\nexport { SilentCronX } from \"./core/SilentCronX.js\";\nexport { MemoryStorageAdapter } from \"./storage/MemoryStorageAdapter.js\";\nexport { RedisStorageAdapter } from \"./storage/RedisStorageAdapter.placeholder.js\";\nexport { PostgresStorageAdapter } from \"./storage/PostgresStorageAdapter.placeholder.js\";\nexport type * from \"./types/config.js\";\nexport type * from \"./types/events.js\";\nexport type * from \"./types/health.js\";\nexport type * from \"./types/job.js\";\nexport type * from \"./types/queue.js\";\nexport type * from \"./types/retry.js\";\nexport type * from \"./types/storage.js\";\n","import { EventEmitter } from \"node:events\";\nimport type {\n SilentCronXEventHandler,\n SilentCronXEventMap,\n SilentCronXEventName,\n} from \"../types/events.js\";\n\nexport class EventBus {\n private readonly emitter = new EventEmitter();\n\n on<TName extends SilentCronXEventName>(eventName: TName, handler: SilentCronXEventHandler<TName>): void {\n this.emitter.on(eventName, handler as (...args: unknown[]) => void);\n }\n\n off<TName extends SilentCronXEventName>(eventName: TName, handler: SilentCronXEventHandler<TName>): void {\n this.emitter.off(eventName, handler as (...args: unknown[]) => void);\n }\n\n emit<TName extends SilentCronXEventName>(eventName: TName, event: SilentCronXEventMap[TName]): void {\n this.emitter.emit(eventName, event);\n }\n}\n","import type { RetryConfig } from \"../types/retry.js\";\n\nexport function getMaxAttempts(retry?: RetryConfig): number {\n return Math.max(1, retry?.attempts ?? 1);\n}\n\nexport function shouldRetry(error: unknown, attempt: number, retry?: RetryConfig): boolean {\n if (!retry || attempt >= getMaxAttempts(retry)) return false;\n return retry.shouldRetry ? retry.shouldRetry(error) : true;\n}\n\nexport function getRetryDelayMs(attempt: number, retry?: RetryConfig): number {\n if (!retry) return 0;\n const base = retry.delayMs ?? 1000;\n switch (retry.backoff ?? \"fixed\") {\n case \"linear\":\n return base * attempt;\n case \"exponential\":\n return base * 2 ** Math.max(0, attempt - 1);\n case \"fixed\":\n default:\n return base;\n }\n}\n","import type { SerializedError } from \"../types/job.js\";\n\nexport class SilentCronXError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SilentCronXError\";\n }\n}\n\nexport class JobTimeoutError extends SilentCronXError {\n constructor(message = \"Job timed out\") {\n super(message);\n this.name = \"JobTimeoutError\";\n }\n}\n\nexport class JobCancelledError extends SilentCronXError {\n constructor(message = \"Job cancelled\") {\n super(message);\n this.name = \"JobCancelledError\";\n }\n}\n\nexport function serializeError(error: unknown): SerializedError {\n if (error instanceof Error) {\n return {\n name: error.name,\n message: error.message,\n stack: error.stack,\n };\n }\n return {\n name: \"Error\",\n message: typeof error === \"string\" ? error : JSON.stringify(error),\n };\n}\n","import { JobTimeoutError } from \"../utils/errors.js\";\n\nexport async function withTimeout<T>(\n work: (signal: AbortSignal) => Promise<T>,\n timeoutMs: number,\n externalSignal?: AbortSignal\n): Promise<T> {\n const controller = new AbortController();\n const abort = (reason?: unknown) => controller.abort(reason);\n if (externalSignal?.aborted) abort(externalSignal.reason);\n externalSignal?.addEventListener(\"abort\", () => abort(externalSignal.reason), { once: true });\n\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n const error = new JobTimeoutError(`Job timed out after ${timeoutMs}ms`);\n abort(error);\n reject(error);\n }, timeoutMs);\n timer.unref?.();\n });\n\n try {\n return await Promise.race([work(controller.signal), timeout]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n","export function nowIso(): string {\n return new Date().toISOString();\n}\n\nexport function delay(ms: number, signal?: AbortSignal): Promise<void> {\n if (ms <= 0) return Promise.resolve();\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason ?? new Error(\"Operation aborted\"));\n return;\n }\n const timer = setTimeout(resolve, ms);\n timer.unref?.();\n signal?.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timer);\n reject(signal.reason ?? new Error(\"Operation aborted\"));\n },\n { once: true }\n );\n });\n}\n\nexport function toDate(value?: string): Date | undefined {\n return value ? new Date(value) : undefined;\n}\n","import type { EventBus } from \"./eventBus.js\";\nimport { getRetryDelayMs, shouldRetry } from \"./retryManager.js\";\nimport { withTimeout } from \"./timeoutManager.js\";\nimport type { JobRecord, JobResult, JobTask } from \"../types/job.js\";\nimport type { RetryConfig } from \"../types/retry.js\";\nimport type { StorageAdapter } from \"../types/storage.js\";\nimport { JobCancelledError, JobTimeoutError, serializeError } from \"../utils/errors.js\";\nimport { delay, nowIso } from \"../utils/time.js\";\n\nexport type RunnerOptions<TPayload = unknown, TResult = unknown> = {\n record: JobRecord<TPayload, TResult>;\n task: JobTask<TPayload, TResult>;\n retry?: RetryConfig;\n timeoutMs: number;\n signal?: AbortSignal;\n lockKey?: string;\n lockTtlMs?: number;\n storage: StorageAdapter;\n eventBus: EventBus;\n acquireLock?: (lockKey: string, ttlMs: number) => Promise<boolean>;\n releaseLock?: (lockKey: string) => Promise<void>;\n};\n\nexport class JobRunner {\n private activeCount = 0;\n\n getActiveCount(): number {\n return this.activeCount;\n }\n\n async run<TPayload, TResult>(options: RunnerOptions<TPayload, TResult>): Promise<JobResult<TResult>> {\n const { record, storage, eventBus } = options;\n const lockKey = options.lockKey;\n let locked = false;\n if (lockKey && options.acquireLock) {\n locked = await options.acquireLock(lockKey, options.lockTtlMs ?? options.timeoutMs);\n if (!locked) {\n const skipped: JobResult<TResult> = {\n jobId: record.id,\n name: record.name,\n status: \"scheduled\",\n attempt: record.attempts,\n durationMs: 0,\n };\n return skipped;\n }\n }\n\n this.activeCount += 1;\n try {\n let attempt = record.attempts;\n while (true) {\n attempt += 1;\n const startedAt = new Date();\n await storage.updateJob(record.id, {\n status: \"running\",\n attempts: attempt,\n startedAt: startedAt.toISOString(),\n lastRunAt: startedAt.toISOString(),\n });\n eventBus.emit(\"job:started\", { jobId: record.id, name: record.name, attempt });\n\n try {\n const result = await withTimeout(\n async (timeoutSignal) => {\n const signal = mergeSignals(options.signal, timeoutSignal);\n if (signal.aborted) throw signal.reason ?? new JobCancelledError();\n return options.task({\n jobId: record.id,\n name: record.name,\n payload: record.payload as TPayload,\n attempt,\n signal,\n createdAt: new Date(record.createdAt),\n startedAt,\n });\n },\n options.timeoutMs,\n options.signal\n );\n\n const finishedAt = nowIso();\n const durationMs = Date.now() - startedAt.getTime();\n const finalResult: JobResult<TResult> = {\n jobId: record.id,\n name: record.name,\n status: \"success\",\n result,\n attempt,\n durationMs,\n startedAt: startedAt.toISOString(),\n finishedAt,\n };\n const latest = await storage.getJob(record.id);\n await storage.updateJob(record.id, {\n status: \"success\",\n result,\n finishedAt,\n successCount: (latest?.successCount ?? record.successCount) + 1,\n });\n eventBus.emit(\"job:success\", finalResult);\n return finalResult;\n } catch (error) {\n const finishedAt = nowIso();\n const durationMs = Date.now() - startedAt.getTime();\n const status = error instanceof JobTimeoutError ? \"timeout\" : isAbortError(error) ? \"cancelled\" : \"failed\";\n const finalResult: JobResult<TResult> = {\n jobId: record.id,\n name: record.name,\n status,\n error: serializeError(error),\n attempt,\n durationMs,\n startedAt: startedAt.toISOString(),\n finishedAt,\n };\n\n if (status === \"cancelled\" || status === \"timeout\" || !shouldRetry(error, attempt, options.retry)) {\n const latest = await storage.getJob(record.id);\n await storage.updateJob(record.id, {\n status,\n error: finalResult.error,\n finishedAt,\n failureCount: (latest?.failureCount ?? record.failureCount) + 1,\n });\n if (status === \"timeout\") {\n eventBus.emit(\"job:timeout\", finalResult);\n } else if (status === \"cancelled\") {\n eventBus.emit(\"job:cancelled\", { jobId: record.id, name: record.name });\n } else {\n eventBus.emit(\"job:failed\", finalResult);\n }\n return finalResult;\n }\n\n const retryDelayMs = getRetryDelayMs(attempt, options.retry);\n eventBus.emit(\"job:retry\", { jobId: record.id, name: record.name, attempt, delayMs: retryDelayMs });\n await delay(retryDelayMs, options.signal);\n }\n }\n } finally {\n this.activeCount -= 1;\n if (locked && lockKey && options.releaseLock) await options.releaseLock(lockKey);\n }\n }\n}\n\nfunction mergeSignals(a?: AbortSignal, b?: AbortSignal): AbortSignal {\n const controller = new AbortController();\n const abort = (signal: AbortSignal) => controller.abort(signal.reason);\n if (a?.aborted) abort(a);\n if (b?.aborted) abort(b);\n a?.addEventListener(\"abort\", () => abort(a), { once: true });\n b?.addEventListener(\"abort\", () => abort(b), { once: true });\n return controller.signal;\n}\n\nfunction isAbortError(error: unknown): boolean {\n return error instanceof JobCancelledError || (error instanceof Error && error.name === \"AbortError\");\n}\n","import type { StorageAdapter } from \"../types/storage.js\";\n\nexport class LockManager {\n constructor(\n private readonly storage: StorageAdapter,\n private readonly defaultTtlMs: number\n ) {}\n\n acquire(lockKey: string, ttlMs = this.defaultTtlMs): Promise<boolean> {\n return this.storage.acquireLock(lockKey, ttlMs);\n }\n\n release(lockKey: string): Promise<void> {\n return this.storage.releaseLock(lockKey);\n }\n}\n","import { randomUUID } from \"node:crypto\";\n\nexport function createJobId(prefix = \"job\"): string {\n return `${prefix}_${randomUUID()}`;\n}\n","import { SilentCronXError } from \"./errors.js\";\n\nexport function assertSerializablePayload(payload: unknown, maxBytes?: number): void {\n if (payload === undefined) return;\n try {\n const json = JSON.stringify(payload);\n if (maxBytes && Buffer.byteLength(json, \"utf8\") > maxBytes) {\n throw new SilentCronXError(`Payload exceeds configured maxPayloadBytes (${maxBytes})`);\n }\n } catch (error) {\n if (error instanceof SilentCronXError) throw error;\n throw new SilentCronXError(\"Payload must be JSON-serializable\");\n }\n}\n","import { SilentCronXError } from \"./errors.js\";\n\nconst JOB_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,127}$/;\n\nexport function validateJobName(name: string): void {\n if (!JOB_NAME_RE.test(name)) {\n throw new SilentCronXError(\n \"Job name must start with a letter or number and contain only letters, numbers, underscore, dash, dot, or colon\"\n );\n }\n}\n\nexport function assertPositiveNumber(value: number, label: string): void {\n if (!Number.isFinite(value) || value <= 0) {\n throw new SilentCronXError(`${label} must be a positive number`);\n }\n}\n\nexport function assertTask(task: unknown, label = \"task\"): asserts task is (...args: never[]) => unknown {\n if (typeof task !== \"function\") {\n throw new SilentCronXError(`${label} must be a function`);\n }\n}\n","import type { EventBus } from \"./eventBus.js\";\nimport { getMaxAttempts } from \"./retryManager.js\";\nimport type { AddQueueJobOptions, QueueOptions } from \"../types/queue.js\";\nimport type { JobRecord, JobTask } from \"../types/job.js\";\nimport type { StorageAdapter } from \"../types/storage.js\";\nimport { createJobId } from \"../utils/id.js\";\nimport { assertSerializablePayload } from \"../utils/safeSerialize.js\";\nimport { nowIso } from \"../utils/time.js\";\nimport { assertPositiveNumber, assertTask, validateJobName } from \"../utils/validation.js\";\n\ntype QueueRuntime = {\n name: string;\n options: Required<Pick<QueueOptions, \"concurrency\" | \"maxSize\">> & QueueOptions;\n pending: string[];\n running: number;\n rateWindowStartedAt: number;\n rateCount: number;\n};\n\nexport class QueueManager {\n private readonly queues = new Map<string, QueueRuntime>();\n\n constructor(\n private readonly storage: StorageAdapter,\n private readonly eventBus: EventBus,\n private readonly maxPayloadBytes: number | undefined,\n private readonly runJob: (jobId: string, task?: JobTask, queueName?: string) => Promise<unknown>\n ) {}\n\n createQueue(name: string, options: QueueOptions = {}): void {\n validateJobName(name);\n const concurrency = options.concurrency ?? 1;\n assertPositiveNumber(concurrency, \"queue concurrency\");\n const runtime: QueueRuntime = {\n name,\n options: {\n ...options,\n concurrency,\n maxSize: options.maxSize ?? 1000,\n },\n pending: [],\n running: 0,\n rateWindowStartedAt: Date.now(),\n rateCount: 0,\n };\n this.queues.set(name, runtime);\n this.eventBus.emit(\"queue:created\", { queueName: name, concurrency });\n }\n\n async addJob<TPayload, TResult>(queueName: string, job: AddQueueJobOptions<TPayload, TResult>): Promise<string> {\n const queue = this.getQueue(queueName);\n validateJobName(job.name);\n assertSerializablePayload(job.payload, this.maxPayloadBytes);\n if (!job.task && !queue.options.processor) {\n throw new Error(`Queue \"${queueName}\" requires either a queue processor or a task on addJob`);\n }\n if (queue.pending.length >= queue.options.maxSize) {\n throw new Error(`Queue \"${queueName}\" is full`);\n }\n\n const id = job.id ?? createJobId(\"queue\");\n const createdAt = nowIso();\n const record: JobRecord<TPayload> = {\n id,\n name: job.name,\n kind: \"queue\",\n status: \"pending\",\n payload: job.payload,\n priority: job.priority ?? 0,\n attempts: 0,\n maxAttempts: getMaxAttempts(job.retry ?? queue.options.retry),\n createdAt,\n updatedAt: createdAt,\n successCount: 0,\n failureCount: 0,\n queueName,\n };\n await this.storage.saveJob(record);\n await this.insertByPriority(queue, id, record.priority);\n void this.drain(queueName, (job.task ?? queue.options.processor) as JobTask);\n return id;\n }\n\n getQueuedCount(): number {\n return [...this.queues.values()].reduce((total, queue) => total + queue.pending.length, 0);\n }\n\n async drain(queueName: string, task?: JobTask): Promise<void> {\n const queue = this.getQueue(queueName);\n while (queue.running < queue.options.concurrency && queue.pending.length > 0 && this.canRunByRateLimit(queue)) {\n const jobId = queue.pending.shift();\n if (!jobId) break;\n queue.running += 1;\n void this.runJob(jobId, task, queueName).finally(() => {\n queue.running = Math.max(0, queue.running - 1);\n if (queue.pending.length === 0 && queue.running === 0) this.eventBus.emit(\"queue:drain\", { queueName });\n void this.drain(queueName, task);\n });\n }\n }\n\n private getQueue(name: string): QueueRuntime {\n const queue = this.queues.get(name);\n if (!queue) throw new Error(`Queue not found: ${name}`);\n return queue;\n }\n\n private async insertByPriority(queue: QueueRuntime, jobId: string, priority: number): Promise<void> {\n let index = queue.pending.length;\n for (let i = 0; i < queue.pending.length; i += 1) {\n const existing = await this.storage.getJob(queue.pending[i] as string);\n if ((existing?.priority ?? 0) < priority) {\n index = i;\n break;\n }\n }\n queue.pending.splice(index, 0, jobId);\n }\n\n private canRunByRateLimit(queue: QueueRuntime): boolean {\n const rateLimit = queue.options.rateLimit;\n if (!rateLimit) return true;\n const now = Date.now();\n if (now - queue.rateWindowStartedAt >= rateLimit.intervalMs) {\n queue.rateWindowStartedAt = now;\n queue.rateCount = 0;\n }\n if (queue.rateCount >= rateLimit.limit) {\n const waitMs = rateLimit.intervalMs - (now - queue.rateWindowStartedAt);\n setTimeout(() => void this.drain(queue.name), Math.max(1, waitMs)).unref?.();\n return false;\n }\n queue.rateCount += 1;\n return true;\n }\n}\n","import { SilentCronXError } from \"../utils/errors.js\";\n\ntype CronField = Set<number>;\n\nexport type ParsedCron = {\n hasSeconds: boolean;\n seconds: CronField;\n minutes: CronField;\n hours: CronField;\n daysOfMonth: CronField;\n months: CronField;\n daysOfWeek: CronField;\n expression: string;\n};\n\nconst MONTHS: Record<string, number> = {\n jan: 1,\n feb: 2,\n mar: 3,\n apr: 4,\n may: 5,\n jun: 6,\n jul: 7,\n aug: 8,\n sep: 9,\n oct: 10,\n nov: 11,\n dec: 12,\n};\n\nconst DOW: Record<string, number> = {\n sun: 0,\n mon: 1,\n tue: 2,\n wed: 3,\n thu: 4,\n fri: 5,\n sat: 6,\n};\n\nexport function parseCronExpression(expression: string): ParsedCron {\n const parts = expression.trim().replace(/\\s+/g, \" \").split(\" \");\n if (parts.length !== 5 && parts.length !== 6) {\n throw new SilentCronXError(\"Invalid cron expression. Expected 5 fields, or 6 fields with seconds.\");\n }\n\n const hasSeconds = parts.length === 6;\n const [secondsRaw, minutesRaw, hoursRaw, domRaw, monthsRaw, dowRaw] = hasSeconds\n ? parts\n : [\"0\", ...parts];\n\n return {\n hasSeconds,\n seconds: parseField(secondsRaw, 0, 59),\n minutes: parseField(minutesRaw, 0, 59),\n hours: parseField(hoursRaw, 0, 23),\n daysOfMonth: parseField(domRaw, 1, 31),\n months: parseField(monthsRaw, 1, 12, MONTHS),\n daysOfWeek: normalizeDow(parseField(dowRaw, 0, 7, DOW)),\n expression,\n };\n}\n\nexport function validateCronExpression(expression: string): void {\n parseCronExpression(expression);\n}\n\nexport function getNextCronDate(expression: string | ParsedCron, from = new Date(), timezone = \"UTC\"): Date {\n const parsed = typeof expression === \"string\" ? parseCronExpression(expression) : expression;\n const stepMs = parsed.hasSeconds ? 1000 : 60_000;\n let candidate = new Date(Math.ceil((from.getTime() + stepMs) / stepMs) * stepMs);\n const limit = candidate.getTime() + 366 * 24 * 60 * 60 * 1000;\n\n while (candidate.getTime() <= limit) {\n const parts = getZonedParts(candidate, timezone);\n if (\n parsed.seconds.has(parts.second) &&\n parsed.minutes.has(parts.minute) &&\n parsed.hours.has(parts.hour) &&\n parsed.daysOfMonth.has(parts.day) &&\n parsed.months.has(parts.month) &&\n parsed.daysOfWeek.has(parts.weekday)\n ) {\n return candidate;\n }\n candidate = new Date(candidate.getTime() + stepMs);\n }\n\n throw new SilentCronXError(`Unable to find next run for cron expression: ${parsed.expression}`);\n}\n\nfunction parseField(raw: string | undefined, min: number, max: number, aliases: Record<string, number> = {}): CronField {\n if (!raw) throw new SilentCronXError(\"Cron field is missing\");\n const values = new Set<number>();\n for (const token of raw.toLowerCase().split(\",\")) {\n const [rangeRaw, stepRaw] = token.split(\"/\");\n const step = stepRaw ? Number(stepRaw) : 1;\n if (!Number.isInteger(step) || step <= 0) {\n throw new SilentCronXError(`Invalid cron step: ${token}`);\n }\n\n let start: number;\n let end: number;\n if (rangeRaw === \"*\") {\n start = min;\n end = max;\n } else if (rangeRaw?.includes(\"-\")) {\n const [a, b] = rangeRaw.split(\"-\");\n start = parseValue(a, aliases);\n end = parseValue(b, aliases);\n } else {\n start = parseValue(rangeRaw, aliases);\n end = start;\n }\n\n if (start < min || end > max || start > end) {\n throw new SilentCronXError(`Cron value out of range: ${token}`);\n }\n for (let value = start; value <= end; value += step) values.add(value);\n }\n return values;\n}\n\nfunction parseValue(raw: string | undefined, aliases: Record<string, number>): number {\n if (!raw) throw new SilentCronXError(\"Invalid empty cron value\");\n const aliased = aliases[raw] ?? Number(raw);\n if (!Number.isInteger(aliased)) throw new SilentCronXError(`Invalid cron value: ${raw}`);\n return aliased;\n}\n\nfunction normalizeDow(values: CronField): CronField {\n const normalized = new Set<number>();\n for (const value of values) normalized.add(value === 7 ? 0 : value);\n return normalized;\n}\n\nfunction getZonedParts(date: Date, timezone: string): {\n second: number;\n minute: number;\n hour: number;\n day: number;\n month: number;\n weekday: number;\n} {\n const formatter = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: timezone,\n second: \"numeric\",\n minute: \"numeric\",\n hour: \"numeric\",\n hourCycle: \"h23\",\n day: \"numeric\",\n month: \"numeric\",\n weekday: \"short\",\n });\n const map = new Map(formatter.formatToParts(date).map((part) => [part.type, part.value]));\n return {\n second: Number(map.get(\"second\")),\n minute: Number(map.get(\"minute\")),\n hour: Number(map.get(\"hour\")),\n day: Number(map.get(\"day\")),\n month: Number(map.get(\"month\")),\n weekday: DOW[(map.get(\"weekday\") ?? \"sun\").toLowerCase()] ?? 0,\n };\n}\n","import type { JobFilter, JobRecord } from \"../types/job.js\";\nimport type { StorageAdapter } from \"../types/storage.js\";\nimport { SilentCronXError } from \"../utils/errors.js\";\nimport { nowIso } from \"../utils/time.js\";\n\ntype LockRecord = {\n expiresAt: number;\n};\n\nexport class MemoryStorageAdapter implements StorageAdapter {\n private readonly jobs = new Map<string, JobRecord>();\n private readonly locks = new Map<string, LockRecord>();\n\n async saveJob(job: JobRecord): Promise<void> {\n if (this.jobs.has(job.id)) {\n throw new SilentCronXError(`Duplicate job id rejected: ${job.id}`);\n }\n this.jobs.set(job.id, { ...job });\n }\n\n async updateJob(jobId: string, patch: Partial<JobRecord>): Promise<void> {\n const existing = this.jobs.get(jobId);\n if (!existing) throw new SilentCronXError(`Job not found: ${jobId}`);\n this.jobs.set(jobId, { ...existing, ...patch, updatedAt: nowIso() });\n }\n\n async getJob(jobId: string): Promise<JobRecord | null> {\n const job = this.jobs.get(jobId);\n return job ? { ...job } : null;\n }\n\n async listJobs(filter: JobFilter = {}): Promise<JobRecord[]> {\n return [...this.jobs.values()]\n .filter((job) => !filter.status || job.status === filter.status)\n .filter((job) => !filter.name || job.name === filter.name)\n .filter((job) => !filter.kind || job.kind === filter.kind)\n .filter((job) => !filter.queueName || job.queueName === filter.queueName)\n .map((job) => ({ ...job }));\n }\n\n async deleteJob(jobId: string): Promise<void> {\n this.jobs.delete(jobId);\n }\n\n async acquireLock(lockKey: string, ttlMs: number): Promise<boolean> {\n this.cleanupExpiredLocks();\n const existing = this.locks.get(lockKey);\n if (existing && existing.expiresAt > Date.now()) return false;\n this.locks.set(lockKey, { expiresAt: Date.now() + ttlMs });\n return true;\n }\n\n async releaseLock(lockKey: string): Promise<void> {\n this.locks.delete(lockKey);\n }\n\n private cleanupExpiredLocks(): void {\n const now = Date.now();\n for (const [key, lock] of this.locks) {\n if (lock.expiresAt <= now) this.locks.delete(key);\n }\n }\n}\n","import { Worker } from \"node:worker_threads\";\nimport type { WorkerModuleReference } from \"../types/job.js\";\nimport { serializeError } from \"../utils/errors.js\";\nimport { normalizeWorkerReference } from \"./workerBridge.js\";\n\ntype PendingWorker = {\n run: () => void;\n};\n\nexport class WorkerPool {\n private busy = 0;\n private readonly pending: PendingWorker[] = [];\n private readonly liveWorkers = new Set<Worker>();\n\n constructor(private readonly maxWorkers: number) {}\n\n getStats(): { max: number; busy: number; idle: number } {\n return {\n max: this.maxWorkers,\n busy: this.busy,\n idle: Math.max(0, this.maxWorkers - this.busy),\n };\n }\n\n run<TPayload, TResult>(options: {\n worker: WorkerModuleReference;\n payload: TPayload;\n jobId: string;\n name: string;\n attempt: number;\n timeoutMs: number;\n createdAt: string;\n startedAt: string;\n }): Promise<TResult> {\n return new Promise((resolve, reject) => {\n const execute = () => {\n this.busy += 1;\n const normalized = normalizeWorkerReference(options.worker);\n const worker = new Worker(getWorkerBridgeUrl(), {\n workerData: {\n modulePath: normalized.modulePath,\n exportName: normalized.exportName,\n payload: options.payload,\n jobId: options.jobId,\n name: options.name,\n attempt: options.attempt,\n createdAt: options.createdAt,\n startedAt: options.startedAt,\n },\n });\n this.liveWorkers.add(worker);\n\n let settled = false;\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n void worker.terminate();\n reject(new Error(`Worker timed out after ${options.timeoutMs}ms`));\n this.finish(worker);\n }, options.timeoutMs);\n timer.unref?.();\n\n worker.once(\"message\", (message: { ok: boolean; result?: TResult; error?: unknown }) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n if (message.ok) resolve(message.result as TResult);\n else reject(serializeError(message.error));\n void worker.terminate();\n this.finish(worker);\n });\n\n worker.once(\"error\", (error) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n reject(error);\n this.finish(worker);\n });\n\n worker.once(\"exit\", (code) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n if (code === 0) resolve(undefined as TResult);\n else reject(new Error(`Worker exited with code ${code}`));\n this.finish(worker);\n });\n };\n\n if (this.busy < this.maxWorkers) execute();\n else this.pending.push({ run: execute });\n });\n }\n\n async shutdown(): Promise<void> {\n this.pending.length = 0;\n await Promise.all([...this.liveWorkers].map((worker) => worker.terminate()));\n this.liveWorkers.clear();\n this.busy = 0;\n }\n\n private finish(worker: Worker): void {\n this.liveWorkers.delete(worker);\n this.busy = Math.max(0, this.busy - 1);\n const next = this.pending.shift();\n if (next) queueMicrotask(next.run);\n }\n}\n\nlet workerBridgeUrl: URL | undefined;\n\nfunction getWorkerBridgeUrl(): URL {\n workerBridgeUrl ??= new URL(\n `data:text/javascript;charset=utf-8,${encodeURIComponent(`\n import { parentPort, workerData } from \"node:worker_threads\";\n\n async function run() {\n const mod = await import(workerData.modulePath);\n const worker = mod[workerData.exportName];\n if (typeof worker !== \"function\") {\n throw new Error(\\`Worker export \"\\${workerData.exportName}\" was not found or is not a function\\`);\n }\n const result = await worker({\n jobId: workerData.jobId,\n name: workerData.name,\n payload: workerData.payload,\n attempt: workerData.attempt,\n signal: new AbortController().signal,\n createdAt: new Date(workerData.createdAt),\n startedAt: new Date(workerData.startedAt)\n });\n parentPort?.postMessage({ ok: true, result });\n }\n\n run().catch((error) => {\n parentPort?.postMessage({\n ok: false,\n error: error instanceof Error\n ? { name: error.name, message: error.message, stack: error.stack }\n : error\n });\n });\n `)}`\n );\n return workerBridgeUrl;\n}\n","import type { WorkerModuleReference } from \"../types/job.js\";\n\nexport type WorkerBridgeRequest<TPayload = unknown> = {\n modulePath: string;\n exportName: string;\n payload: TPayload;\n jobId: string;\n name: string;\n attempt: number;\n createdAt: string;\n startedAt: string;\n};\n\nexport function normalizeWorkerReference(worker: WorkerModuleReference): {\n modulePath: string;\n exportName: string;\n} {\n return {\n modulePath: worker.path instanceof URL ? worker.path.href : worker.path,\n exportName: worker.exportName ?? \"default\",\n };\n}\n","import type { SilentCronXConfig, SilentCronXLogger } from \"../types/config.js\";\n\nconst noop = () => undefined;\n\nexport function createLogger(config: SilentCronXConfig): Required<SilentCronXLogger> {\n const base = config.logger ?? {};\n return {\n info: base.info ?? noop,\n warn: base.warn ?? noop,\n error: base.error ?? noop,\n debug: config.debug ? base.debug ?? noop : noop,\n };\n}\n","import { EventBus } from \"./eventBus.js\";\nimport { JobRunner } from \"./jobRunner.js\";\nimport { LockManager } from \"./lockManager.js\";\nimport { QueueManager } from \"./queueManager.js\";\nimport { getMaxAttempts } from \"./retryManager.js\";\nimport { getNextCronDate, parseCronExpression } from \"./cronParser.js\";\nimport { MemoryStorageAdapter } from \"../storage/MemoryStorageAdapter.js\";\nimport type { SilentCronXConfig, SilentCronXLogger } from \"../types/config.js\";\nimport type { SilentCronXEventHandler, SilentCronXEventName, StatusSnapshot } from \"../types/events.js\";\nimport type {\n DelayJobOptions,\n EveryJobOptions,\n JobRecord,\n JobResult,\n JobTask,\n RunNowOptions,\n ScheduleJobOptions,\n WorkerJobOptions,\n WorkerModuleReference,\n} from \"../types/job.js\";\nimport type { QueueOptions, AddQueueJobOptions } from \"../types/queue.js\";\nimport type { RetryConfig } from \"../types/retry.js\";\nimport type { StorageAdapter } from \"../types/storage.js\";\nimport type { SilentCronXHealth } from \"../types/health.js\";\nimport { WorkerPool } from \"../workers/workerPool.js\";\nimport { JobCancelledError, SilentCronXError } from \"../utils/errors.js\";\nimport { createJobId } from \"../utils/id.js\";\nimport { createLogger } from \"../utils/logger.js\";\nimport { assertSerializablePayload } from \"../utils/safeSerialize.js\";\nimport { nowIso } from \"../utils/time.js\";\nimport { assertPositiveNumber, assertTask, validateJobName } from \"../utils/validation.js\";\n\ntype RuntimeEntry = {\n id: string;\n name: string;\n kind: JobRecord[\"kind\"];\n task?: JobTask;\n cron?: string;\n intervalMs?: number;\n delayMs?: number;\n retry?: RetryConfig;\n timeoutMs: number;\n preventOverlap: boolean;\n timer?: ReturnType<typeof setTimeout>;\n};\n\nexport class SilentCronX {\n private readonly config: Required<Pick<SilentCronXConfig, \"timezone\" | \"maxWorkers\" | \"maxConcurrency\" | \"defaultTimeout\" | \"preventOverlapping\" | \"lockTimeout\">> &\n SilentCronXConfig;\n private readonly storage: StorageAdapter;\n private readonly eventBus = new EventBus();\n private readonly runner = new JobRunner();\n private readonly workerPool: WorkerPool;\n private readonly lockManager: LockManager;\n private readonly queueManager: QueueManager;\n private readonly logger: Required<SilentCronXLogger>;\n private readonly entries = new Map<string, RuntimeEntry>();\n private readonly controllers = new Map<string, AbortController>();\n private running = false;\n\n constructor(config: SilentCronXConfig = {}) {\n this.config = {\n timezone: config.timezone ?? \"UTC\",\n maxWorkers: config.maxWorkers ?? 2,\n maxConcurrency: config.maxConcurrency ?? 50,\n defaultTimeout: config.defaultTimeout ?? 30_000,\n preventOverlapping: config.preventOverlapping ?? true,\n lockTimeout: config.lockTimeout ?? config.defaultTimeout ?? 30_000,\n ...config,\n };\n this.storage = config.storage && config.storage !== \"memory\" ? config.storage : new MemoryStorageAdapter();\n this.logger = createLogger(config);\n this.workerPool = new WorkerPool(this.config.maxWorkers);\n this.lockManager = new LockManager(this.storage, this.config.lockTimeout);\n this.queueManager = new QueueManager(this.storage, this.eventBus, this.config.maxPayloadBytes, (jobId, task) =>\n this.executeJob(jobId, task)\n );\n }\n\n async schedule<TPayload = unknown>(name: string, options: ScheduleJobOptions<TPayload>): Promise<string> {\n validateJobName(name);\n assertTask(options.task);\n assertSerializablePayload(options.payload, this.config.maxPayloadBytes);\n parseCronExpression(options.cron);\n const id = createJobId(\"cron\");\n const nextRunAt = getNextCronDate(options.cron, new Date(), options.timezone ?? this.config.timezone).toISOString();\n await this.createRecord(id, name, \"cron\", options.payload, options.priority, getMaxAttempts(options.retry), {\n nextRunAt,\n metadata: { cron: options.cron, timezone: options.timezone ?? this.config.timezone },\n status: options.enabled === false ? \"paused\" : \"scheduled\",\n });\n this.entries.set(id, {\n id,\n name,\n kind: \"cron\",\n task: options.task as JobTask,\n cron: options.cron,\n retry: options.retry,\n timeoutMs: options.timeout ?? this.config.defaultTimeout,\n preventOverlap: options.preventOverlap ?? this.config.preventOverlapping,\n });\n this.eventBus.emit(\"job:scheduled\", { jobId: id, name, nextRunAt });\n if (this.running && options.enabled !== false) this.armCron(id);\n return id;\n }\n\n async delay<TPayload = unknown, TResult = unknown>(name: string, options: DelayJobOptions<TPayload, TResult>): Promise<string> {\n validateJobName(name);\n assertPositiveNumber(options.delayMs, \"delayMs\");\n assertTask(options.task);\n assertSerializablePayload(options.payload, this.config.maxPayloadBytes);\n const id = createJobId(\"delay\");\n const nextRunAt = new Date(Date.now() + options.delayMs).toISOString();\n await this.createRecord(id, name, \"delay\", options.payload, options.priority, getMaxAttempts(options.retry), {\n nextRunAt,\n status: \"scheduled\",\n });\n this.entries.set(id, {\n id,\n name,\n kind: \"delay\",\n task: options.task as JobTask,\n delayMs: options.delayMs,\n retry: options.retry,\n timeoutMs: options.timeout ?? this.config.defaultTimeout,\n preventOverlap: false,\n });\n if (this.running) this.armDelay(id, options.delayMs);\n return id;\n }\n\n async every<TPayload = unknown, TResult = unknown>(name: string, options: EveryJobOptions<TPayload, TResult>): Promise<string> {\n validateJobName(name);\n assertPositiveNumber(options.intervalMs, \"intervalMs\");\n assertTask(options.task);\n assertSerializablePayload(options.payload, this.config.maxPayloadBytes);\n const id = createJobId(\"every\");\n const nextRunAt = new Date(Date.now() + options.intervalMs).toISOString();\n await this.createRecord(id, name, \"every\", options.payload, options.priority, getMaxAttempts(options.retry), {\n nextRunAt,\n status: options.enabled === false ? \"paused\" : \"scheduled\",\n });\n this.entries.set(id, {\n id,\n name,\n kind: \"every\",\n task: options.task as JobTask,\n intervalMs: options.intervalMs,\n retry: options.retry,\n timeoutMs: options.timeout ?? this.config.defaultTimeout,\n preventOverlap: options.preventOverlap ?? this.config.preventOverlapping,\n });\n if (this.running && options.enabled !== false) this.armEvery(id);\n return id;\n }\n\n async runNow<TPayload = unknown, TResult = unknown>(name: string, options: RunNowOptions<TPayload, TResult>): Promise<JobResult<TResult>> {\n validateJobName(name);\n assertTask(options.task);\n assertSerializablePayload(options.payload, this.config.maxPayloadBytes);\n const id = createJobId(\"now\");\n await this.createRecord(id, name, \"runNow\", options.payload, options.priority, getMaxAttempts(options.retry), {\n status: \"pending\",\n });\n this.entries.set(id, {\n id,\n name,\n kind: \"runNow\",\n task: options.task as JobTask,\n retry: options.retry,\n timeoutMs: options.timeout ?? this.config.defaultTimeout,\n preventOverlap: false,\n });\n return this.executeJob(id) as Promise<JobResult<TResult>>;\n }\n\n async runWorker<TPayload = unknown, TResult = unknown>(name: string, options: WorkerJobOptions<TPayload>): Promise<JobResult<TResult>> {\n validateJobName(name);\n assertSerializablePayload(options.payload, this.config.maxPayloadBytes);\n const id = createJobId(\"worker\");\n await this.createRecord(id, name, \"worker\", options.payload, options.priority, getMaxAttempts(options.retry), {\n status: \"pending\",\n });\n const timeoutMs = options.timeout ?? this.config.defaultTimeout;\n const workerTask: JobTask<TPayload, TResult> =\n typeof options.worker === \"function\"\n ? (options.worker as JobTask<TPayload, TResult>)\n : async (context) =>\n this.workerPool.run<TPayload, TResult>({\n worker: options.worker as WorkerModuleReference,\n payload: context.payload,\n jobId: context.jobId,\n name: context.name,\n attempt: context.attempt,\n timeoutMs,\n createdAt: context.createdAt.toISOString(),\n startedAt: context.startedAt.toISOString(),\n });\n\n if (typeof options.worker === \"function\") {\n this.logger.warn(\n \"runWorker received an inline function. For security, SilentCronX does not eval code strings; the function will run through the async runner. Pass { path, exportName } to use worker_threads.\"\n );\n }\n\n this.entries.set(id, {\n id,\n name,\n kind: \"worker\",\n task: workerTask as JobTask,\n retry: options.retry,\n timeoutMs,\n preventOverlap: false,\n });\n return this.executeJob(id) as Promise<JobResult<TResult>>;\n }\n\n queue<TPayload = unknown, TResult = unknown>(name: string, options: QueueOptions<TPayload, TResult> = {}): void {\n this.queueManager.createQueue(name, options as QueueOptions);\n }\n\n addJob<TPayload = unknown, TResult = unknown>(queueName: string, job: AddQueueJobOptions<TPayload, TResult>): Promise<string> {\n return this.queueManager.addJob(queueName, job);\n }\n\n async cancel(jobId: string): Promise<void> {\n this.controllers.get(jobId)?.abort(new JobCancelledError());\n const job = await this.storage.getJob(jobId);\n if (!job) return;\n this.clearTimer(jobId);\n await this.storage.updateJob(jobId, { status: \"cancelled\", finishedAt: nowIso() });\n this.eventBus.emit(\"job:cancelled\", { jobId, name: job.name });\n }\n\n async pause(jobId: string): Promise<void> {\n const job = await this.storage.getJob(jobId);\n if (!job) return;\n this.clearTimer(jobId);\n await this.storage.updateJob(jobId, { status: \"paused\" });\n this.eventBus.emit(\"job:paused\", { jobId, name: job.name });\n }\n\n async resume(jobId: string): Promise<void> {\n const job = await this.storage.getJob(jobId);\n const entry = this.entries.get(jobId);\n if (!job || !entry) return;\n await this.storage.updateJob(jobId, { status: entry.kind === \"runNow\" ? \"pending\" : \"scheduled\" });\n this.eventBus.emit(\"job:resumed\", { jobId, name: job.name });\n if (this.running) this.armEntry(jobId);\n }\n\n async getStatus(jobId: string): Promise<StatusSnapshot | null> {\n const job = await this.storage.getJob(jobId);\n if (!job) return null;\n return {\n jobId,\n name: job.name,\n status: job.status,\n attempt: job.attempts,\n nextRunAt: job.nextRunAt,\n lastRunAt: job.lastRunAt,\n };\n }\n\n getJobs(): Promise<JobRecord[]> {\n return this.storage.listJobs();\n }\n\n start(): void {\n if (this.running) return;\n this.running = true;\n for (const jobId of this.entries.keys()) this.armEntry(jobId);\n this.eventBus.emit(\"scheduler:started\", { running: true, at: nowIso() });\n }\n\n stop(): void {\n if (!this.running) return;\n this.running = false;\n for (const jobId of this.entries.keys()) this.clearTimer(jobId);\n this.eventBus.emit(\"scheduler:stopped\", { running: false, at: nowIso() });\n }\n\n async shutdown(): Promise<void> {\n this.stop();\n for (const controller of this.controllers.values()) controller.abort(new JobCancelledError(\"Scheduler shutdown\"));\n this.controllers.clear();\n await this.workerPool.shutdown();\n this.eventBus.emit(\"scheduler:shutdown\", { at: nowIso() });\n }\n\n on<TName extends SilentCronXEventName>(eventName: TName, handler: SilentCronXEventHandler<TName>): void {\n this.eventBus.on(eventName, handler);\n }\n\n off<TName extends SilentCronXEventName>(eventName: TName, handler: SilentCronXEventHandler<TName>): void {\n this.eventBus.off(eventName, handler);\n }\n\n async getHealth(): Promise<SilentCronXHealth> {\n const jobs = await this.storage.listJobs();\n return {\n running: this.running,\n scheduledJobs: jobs.filter((job) => job.status === \"scheduled\").length,\n runningJobs: jobs.filter((job) => job.status === \"running\").length,\n queuedJobs: this.queueManager.getQueuedCount(),\n workers: this.workerPool.getStats(),\n memory: {\n storage: this.storage instanceof MemoryStorageAdapter ? \"memory\" : \"custom\",\n },\n };\n }\n\n private async executeJob<TResult = unknown>(jobId: string, taskOverride?: JobTask): Promise<JobResult<TResult>> {\n while (this.runner.getActiveCount() >= this.config.maxConcurrency) {\n await new Promise((resolve) => setTimeout(resolve, 10));\n }\n const record = await this.storage.getJob(jobId);\n const entry = this.entries.get(jobId);\n const task = taskOverride ?? entry?.task;\n if (!record || !entry || !task) throw new SilentCronXError(`Job cannot be executed: ${jobId}`);\n if (record.status === \"cancelled\" || record.status === \"paused\") {\n return { jobId, name: record.name, status: record.status, attempt: record.attempts, durationMs: 0 };\n }\n const controller = new AbortController();\n this.controllers.set(jobId, controller);\n try {\n return (await this.runner.run({\n record,\n task,\n retry: entry.retry,\n timeoutMs: entry.timeoutMs,\n signal: controller.signal,\n lockKey: entry.preventOverlap ? `job:${record.name}` : undefined,\n lockTtlMs: this.config.lockTimeout,\n storage: this.storage,\n eventBus: this.eventBus,\n acquireLock: (key, ttl) => this.lockManager.acquire(key, ttl),\n releaseLock: (key) => this.lockManager.release(key),\n })) as JobResult<TResult>;\n } finally {\n this.controllers.delete(jobId);\n }\n }\n\n private armEntry(jobId: string): void {\n const entry = this.entries.get(jobId);\n if (!entry) return;\n if (entry.kind === \"cron\") this.armCron(jobId);\n else if (entry.kind === \"delay\") this.armDelay(jobId, entry.delayMs ?? 0);\n else if (entry.kind === \"every\") this.armEvery(jobId);\n }\n\n private async armCron(jobId: string): Promise<void> {\n const entry = this.entries.get(jobId);\n const record = await this.storage.getJob(jobId);\n if (!entry?.cron || !record || record.status === \"paused\" || record.status === \"cancelled\") return;\n const next = getNextCronDate(entry.cron, new Date(), this.config.timezone);\n await this.storage.updateJob(jobId, { status: \"scheduled\", nextRunAt: next.toISOString() });\n this.clearTimer(jobId);\n const timer = setTimeout(() => {\n void this.executeJob(jobId).finally(() => {\n if (this.running) void this.armCron(jobId);\n });\n }, Math.max(1, next.getTime() - Date.now()));\n timer.unref?.();\n entry.timer = timer;\n }\n\n private armDelay(jobId: string, delayMs: number): void {\n const entry = this.entries.get(jobId);\n if (!entry) return;\n this.clearTimer(jobId);\n const timer = setTimeout(() => void this.executeJob(jobId), delayMs);\n timer.unref?.();\n entry.timer = timer;\n }\n\n private async armEvery(jobId: string): Promise<void> {\n const entry = this.entries.get(jobId);\n const record = await this.storage.getJob(jobId);\n if (!entry?.intervalMs || !record || record.status === \"paused\" || record.status === \"cancelled\") return;\n const next = new Date(Date.now() + entry.intervalMs);\n await this.storage.updateJob(jobId, { status: \"scheduled\", nextRunAt: next.toISOString() });\n this.clearTimer(jobId);\n const timer = setTimeout(() => {\n void this.executeJob(jobId).finally(() => {\n if (this.running) void this.armEvery(jobId);\n });\n }, entry.intervalMs);\n timer.unref?.();\n entry.timer = timer;\n }\n\n private clearTimer(jobId: string): void {\n const entry = this.entries.get(jobId);\n if (entry?.timer) clearTimeout(entry.timer);\n if (entry) entry.timer = undefined;\n }\n\n private async createRecord<TPayload>(\n id: string,\n name: string,\n kind: JobRecord[\"kind\"],\n payload: TPayload | undefined,\n priority = 0,\n maxAttempts = 1,\n extra: Partial<JobRecord> = {}\n ): Promise<void> {\n const createdAt = nowIso();\n await this.storage.saveJob({\n id,\n name,\n kind,\n status: extra.status ?? \"pending\",\n payload,\n priority,\n attempts: 0,\n maxAttempts,\n createdAt,\n updatedAt: createdAt,\n successCount: 0,\n failureCount: 0,\n ...extra,\n });\n }\n}\n","import { SilentCronX } from \"./SilentCronX.js\";\nimport type { SilentCronXConfig } from \"../types/config.js\";\n\nexport function createSilentCronX(config: SilentCronXConfig = {}): SilentCronX {\n return new SilentCronX(config);\n}\n","import type { JobFilter, JobRecord } from \"../types/job.js\";\nimport type { StorageAdapter } from \"../types/storage.js\";\n\nexport class RedisStorageAdapter implements StorageAdapter {\n constructor() {\n throw new Error(\n \"RedisStorageAdapter is a design placeholder. Implement StorageAdapter with SET NX PX locks, JSON job records, and atomic updates for multi-instance production use.\"\n );\n }\n\n saveJob(_job: JobRecord): Promise<void> {\n throw new Error(\"Not implemented\");\n }\n updateJob(_jobId: string, _patch: Partial<JobRecord>): Promise<void> {\n throw new Error(\"Not implemented\");\n }\n getJob(_jobId: string): Promise<JobRecord | null> {\n throw new Error(\"Not implemented\");\n }\n listJobs(_filter?: JobFilter): Promise<JobRecord[]> {\n throw new Error(\"Not implemented\");\n }\n deleteJob(_jobId: string): Promise<void> {\n throw new Error(\"Not implemented\");\n }\n acquireLock(_lockKey: string, _ttlMs: number): Promise<boolean> {\n throw new Error(\"Not implemented\");\n }\n releaseLock(_lockKey: string): Promise<void> {\n throw new Error(\"Not implemented\");\n }\n}\n","import type { JobFilter, JobRecord } from \"../types/job.js\";\nimport type { StorageAdapter } from \"../types/storage.js\";\n\nexport class PostgresStorageAdapter implements StorageAdapter {\n constructor() {\n throw new Error(\n \"PostgresStorageAdapter is a design placeholder. Implement StorageAdapter using transactions, row-level locks, indexed status columns, and advisory locks for production use.\"\n );\n }\n\n saveJob(_job: JobRecord): Promise<void> {\n throw new Error(\"Not implemented\");\n }\n updateJob(_jobId: string, _patch: Partial<JobRecord>): Promise<void> {\n throw new Error(\"Not implemented\");\n }\n getJob(_jobId: string): Promise<JobRecord | null> {\n throw new Error(\"Not implemented\");\n }\n listJobs(_filter?: JobFilter): Promise<JobRecord[]> {\n throw new Error(\"Not implemented\");\n }\n deleteJob(_jobId: string): Promise<void> {\n throw new Error(\"Not implemented\");\n }\n acquireLock(_lockKey: string, _ttlMs: number): Promise<boolean> {\n throw new Error(\"Not implemented\");\n }\n releaseLock(_lockKey: string): Promise<void> {\n throw new Error(\"Not implemented\");\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
type RetryBackoff = "fixed" | "linear" | "exponential";
|
|
2
|
+
type RetryConfig = {
|
|
3
|
+
attempts: number;
|
|
4
|
+
delayMs?: number;
|
|
5
|
+
backoff?: RetryBackoff;
|
|
6
|
+
shouldRetry?: (error: unknown) => boolean;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
type JobStatus = "pending" | "scheduled" | "running" | "success" | "failed" | "cancelled" | "paused" | "timeout";
|
|
10
|
+
type SerializedError = {
|
|
11
|
+
name: string;
|
|
12
|
+
message: string;
|
|
13
|
+
stack?: string;
|
|
14
|
+
};
|
|
15
|
+
type JobTask<TPayload = unknown, TResult = unknown> = (context: {
|
|
16
|
+
jobId: string;
|
|
17
|
+
name: string;
|
|
18
|
+
payload: TPayload;
|
|
19
|
+
attempt: number;
|
|
20
|
+
signal: AbortSignal;
|
|
21
|
+
createdAt: Date;
|
|
22
|
+
startedAt: Date;
|
|
23
|
+
}) => Promise<TResult> | TResult;
|
|
24
|
+
type ScheduleJobOptions<TPayload = unknown> = {
|
|
25
|
+
cron: string;
|
|
26
|
+
payload?: TPayload;
|
|
27
|
+
timezone?: string;
|
|
28
|
+
enabled?: boolean;
|
|
29
|
+
preventOverlap?: boolean;
|
|
30
|
+
timeout?: number;
|
|
31
|
+
retry?: RetryConfig;
|
|
32
|
+
priority?: number;
|
|
33
|
+
task: JobTask<TPayload>;
|
|
34
|
+
};
|
|
35
|
+
type DelayJobOptions<TPayload = unknown, TResult = unknown> = {
|
|
36
|
+
delayMs: number;
|
|
37
|
+
payload?: TPayload;
|
|
38
|
+
timeout?: number;
|
|
39
|
+
retry?: RetryConfig;
|
|
40
|
+
priority?: number;
|
|
41
|
+
task: JobTask<TPayload, TResult>;
|
|
42
|
+
};
|
|
43
|
+
type EveryJobOptions<TPayload = unknown, TResult = unknown> = {
|
|
44
|
+
intervalMs: number;
|
|
45
|
+
payload?: TPayload;
|
|
46
|
+
enabled?: boolean;
|
|
47
|
+
preventOverlap?: boolean;
|
|
48
|
+
timeout?: number;
|
|
49
|
+
retry?: RetryConfig;
|
|
50
|
+
priority?: number;
|
|
51
|
+
task: JobTask<TPayload, TResult>;
|
|
52
|
+
};
|
|
53
|
+
type RunNowOptions<TPayload = unknown, TResult = unknown> = {
|
|
54
|
+
payload?: TPayload;
|
|
55
|
+
timeout?: number;
|
|
56
|
+
retry?: RetryConfig;
|
|
57
|
+
priority?: number;
|
|
58
|
+
task: JobTask<TPayload, TResult>;
|
|
59
|
+
};
|
|
60
|
+
type WorkerModuleReference = {
|
|
61
|
+
path: string | URL;
|
|
62
|
+
exportName?: string;
|
|
63
|
+
};
|
|
64
|
+
type WorkerJobOptions<TPayload = unknown> = {
|
|
65
|
+
payload?: TPayload;
|
|
66
|
+
timeout?: number;
|
|
67
|
+
retry?: RetryConfig;
|
|
68
|
+
priority?: number;
|
|
69
|
+
worker: WorkerModuleReference | JobTask<TPayload>;
|
|
70
|
+
};
|
|
71
|
+
type JobResult<TResult = unknown> = {
|
|
72
|
+
jobId: string;
|
|
73
|
+
name: string;
|
|
74
|
+
status: JobStatus;
|
|
75
|
+
result?: TResult;
|
|
76
|
+
error?: SerializedError;
|
|
77
|
+
attempt: number;
|
|
78
|
+
durationMs: number;
|
|
79
|
+
startedAt?: string;
|
|
80
|
+
finishedAt?: string;
|
|
81
|
+
};
|
|
82
|
+
type JobKind = "cron" | "delay" | "every" | "runNow" | "worker" | "queue";
|
|
83
|
+
type JobRecord<TPayload = unknown, TResult = unknown> = {
|
|
84
|
+
id: string;
|
|
85
|
+
name: string;
|
|
86
|
+
kind: JobKind;
|
|
87
|
+
status: JobStatus;
|
|
88
|
+
payload?: TPayload;
|
|
89
|
+
priority: number;
|
|
90
|
+
attempts: number;
|
|
91
|
+
maxAttempts: number;
|
|
92
|
+
createdAt: string;
|
|
93
|
+
updatedAt: string;
|
|
94
|
+
startedAt?: string;
|
|
95
|
+
finishedAt?: string;
|
|
96
|
+
lastRunAt?: string;
|
|
97
|
+
nextRunAt?: string;
|
|
98
|
+
result?: TResult;
|
|
99
|
+
error?: SerializedError;
|
|
100
|
+
successCount: number;
|
|
101
|
+
failureCount: number;
|
|
102
|
+
queueName?: string;
|
|
103
|
+
metadata?: Record<string, unknown>;
|
|
104
|
+
};
|
|
105
|
+
type JobFilter = {
|
|
106
|
+
status?: JobStatus;
|
|
107
|
+
name?: string;
|
|
108
|
+
kind?: JobKind;
|
|
109
|
+
queueName?: string;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
interface StorageAdapter {
|
|
113
|
+
saveJob(job: JobRecord): Promise<void>;
|
|
114
|
+
updateJob(jobId: string, patch: Partial<JobRecord>): Promise<void>;
|
|
115
|
+
getJob(jobId: string): Promise<JobRecord | null>;
|
|
116
|
+
listJobs(filter?: JobFilter): Promise<JobRecord[]>;
|
|
117
|
+
deleteJob(jobId: string): Promise<void>;
|
|
118
|
+
acquireLock(lockKey: string, ttlMs: number): Promise<boolean>;
|
|
119
|
+
releaseLock(lockKey: string): Promise<void>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
type SilentCronXLogger = {
|
|
123
|
+
info?: (...args: unknown[]) => void;
|
|
124
|
+
warn?: (...args: unknown[]) => void;
|
|
125
|
+
error?: (...args: unknown[]) => void;
|
|
126
|
+
debug?: (...args: unknown[]) => void;
|
|
127
|
+
};
|
|
128
|
+
type SilentCronXConfig = {
|
|
129
|
+
timezone?: string;
|
|
130
|
+
maxWorkers?: number;
|
|
131
|
+
maxConcurrency?: number;
|
|
132
|
+
defaultTimeout?: number;
|
|
133
|
+
preventOverlapping?: boolean;
|
|
134
|
+
lockTimeout?: number;
|
|
135
|
+
maxPayloadBytes?: number;
|
|
136
|
+
logger?: SilentCronXLogger;
|
|
137
|
+
storage?: "memory" | StorageAdapter;
|
|
138
|
+
debug?: boolean;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
type SilentCronXEventMap = {
|
|
142
|
+
"scheduler:started": {
|
|
143
|
+
running: true;
|
|
144
|
+
at: string;
|
|
145
|
+
};
|
|
146
|
+
"scheduler:stopped": {
|
|
147
|
+
running: false;
|
|
148
|
+
at: string;
|
|
149
|
+
};
|
|
150
|
+
"scheduler:shutdown": {
|
|
151
|
+
at: string;
|
|
152
|
+
};
|
|
153
|
+
"job:scheduled": {
|
|
154
|
+
jobId: string;
|
|
155
|
+
name: string;
|
|
156
|
+
nextRunAt?: string;
|
|
157
|
+
};
|
|
158
|
+
"job:started": {
|
|
159
|
+
jobId: string;
|
|
160
|
+
name: string;
|
|
161
|
+
attempt: number;
|
|
162
|
+
};
|
|
163
|
+
"job:success": JobResult;
|
|
164
|
+
"job:failed": JobResult;
|
|
165
|
+
"job:timeout": JobResult;
|
|
166
|
+
"job:cancelled": {
|
|
167
|
+
jobId: string;
|
|
168
|
+
name: string;
|
|
169
|
+
};
|
|
170
|
+
"job:paused": {
|
|
171
|
+
jobId: string;
|
|
172
|
+
name: string;
|
|
173
|
+
};
|
|
174
|
+
"job:resumed": {
|
|
175
|
+
jobId: string;
|
|
176
|
+
name: string;
|
|
177
|
+
};
|
|
178
|
+
"job:retry": {
|
|
179
|
+
jobId: string;
|
|
180
|
+
name: string;
|
|
181
|
+
attempt: number;
|
|
182
|
+
delayMs: number;
|
|
183
|
+
};
|
|
184
|
+
"queue:created": {
|
|
185
|
+
queueName: string;
|
|
186
|
+
concurrency: number;
|
|
187
|
+
};
|
|
188
|
+
"queue:drain": {
|
|
189
|
+
queueName: string;
|
|
190
|
+
};
|
|
191
|
+
"error": {
|
|
192
|
+
error: unknown;
|
|
193
|
+
jobId?: string;
|
|
194
|
+
name?: string;
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
type SilentCronXEventName = keyof SilentCronXEventMap;
|
|
198
|
+
type SilentCronXEventHandler<TName extends SilentCronXEventName> = (event: SilentCronXEventMap[TName]) => void;
|
|
199
|
+
type StatusSnapshot = {
|
|
200
|
+
jobId: string;
|
|
201
|
+
name: string;
|
|
202
|
+
status: JobStatus;
|
|
203
|
+
attempt: number;
|
|
204
|
+
nextRunAt?: string;
|
|
205
|
+
lastRunAt?: string;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
type QueueOptions<TPayload = unknown, TResult = unknown> = {
|
|
209
|
+
concurrency?: number;
|
|
210
|
+
retry?: RetryConfig;
|
|
211
|
+
timeout?: number;
|
|
212
|
+
maxSize?: number;
|
|
213
|
+
rateLimit?: {
|
|
214
|
+
limit: number;
|
|
215
|
+
intervalMs: number;
|
|
216
|
+
};
|
|
217
|
+
processor?: JobTask<TPayload, TResult>;
|
|
218
|
+
};
|
|
219
|
+
type AddQueueJobOptions<TPayload = unknown, TResult = unknown> = {
|
|
220
|
+
id?: string;
|
|
221
|
+
name: string;
|
|
222
|
+
payload?: TPayload;
|
|
223
|
+
priority?: number;
|
|
224
|
+
timeout?: number;
|
|
225
|
+
retry?: RetryConfig;
|
|
226
|
+
task?: JobTask<TPayload, TResult>;
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
type SilentCronXHealth = {
|
|
230
|
+
running: boolean;
|
|
231
|
+
scheduledJobs: number;
|
|
232
|
+
runningJobs: number;
|
|
233
|
+
queuedJobs: number;
|
|
234
|
+
workers: {
|
|
235
|
+
max: number;
|
|
236
|
+
busy: number;
|
|
237
|
+
idle: number;
|
|
238
|
+
};
|
|
239
|
+
memory: {
|
|
240
|
+
storage: string;
|
|
241
|
+
};
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
declare class SilentCronX {
|
|
245
|
+
private readonly config;
|
|
246
|
+
private readonly storage;
|
|
247
|
+
private readonly eventBus;
|
|
248
|
+
private readonly runner;
|
|
249
|
+
private readonly workerPool;
|
|
250
|
+
private readonly lockManager;
|
|
251
|
+
private readonly queueManager;
|
|
252
|
+
private readonly logger;
|
|
253
|
+
private readonly entries;
|
|
254
|
+
private readonly controllers;
|
|
255
|
+
private running;
|
|
256
|
+
constructor(config?: SilentCronXConfig);
|
|
257
|
+
schedule<TPayload = unknown>(name: string, options: ScheduleJobOptions<TPayload>): Promise<string>;
|
|
258
|
+
delay<TPayload = unknown, TResult = unknown>(name: string, options: DelayJobOptions<TPayload, TResult>): Promise<string>;
|
|
259
|
+
every<TPayload = unknown, TResult = unknown>(name: string, options: EveryJobOptions<TPayload, TResult>): Promise<string>;
|
|
260
|
+
runNow<TPayload = unknown, TResult = unknown>(name: string, options: RunNowOptions<TPayload, TResult>): Promise<JobResult<TResult>>;
|
|
261
|
+
runWorker<TPayload = unknown, TResult = unknown>(name: string, options: WorkerJobOptions<TPayload>): Promise<JobResult<TResult>>;
|
|
262
|
+
queue<TPayload = unknown, TResult = unknown>(name: string, options?: QueueOptions<TPayload, TResult>): void;
|
|
263
|
+
addJob<TPayload = unknown, TResult = unknown>(queueName: string, job: AddQueueJobOptions<TPayload, TResult>): Promise<string>;
|
|
264
|
+
cancel(jobId: string): Promise<void>;
|
|
265
|
+
pause(jobId: string): Promise<void>;
|
|
266
|
+
resume(jobId: string): Promise<void>;
|
|
267
|
+
getStatus(jobId: string): Promise<StatusSnapshot | null>;
|
|
268
|
+
getJobs(): Promise<JobRecord[]>;
|
|
269
|
+
start(): void;
|
|
270
|
+
stop(): void;
|
|
271
|
+
shutdown(): Promise<void>;
|
|
272
|
+
on<TName extends SilentCronXEventName>(eventName: TName, handler: SilentCronXEventHandler<TName>): void;
|
|
273
|
+
off<TName extends SilentCronXEventName>(eventName: TName, handler: SilentCronXEventHandler<TName>): void;
|
|
274
|
+
getHealth(): Promise<SilentCronXHealth>;
|
|
275
|
+
private executeJob;
|
|
276
|
+
private armEntry;
|
|
277
|
+
private armCron;
|
|
278
|
+
private armDelay;
|
|
279
|
+
private armEvery;
|
|
280
|
+
private clearTimer;
|
|
281
|
+
private createRecord;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
declare function createSilentCronX(config?: SilentCronXConfig): SilentCronX;
|
|
285
|
+
|
|
286
|
+
declare class MemoryStorageAdapter implements StorageAdapter {
|
|
287
|
+
private readonly jobs;
|
|
288
|
+
private readonly locks;
|
|
289
|
+
saveJob(job: JobRecord): Promise<void>;
|
|
290
|
+
updateJob(jobId: string, patch: Partial<JobRecord>): Promise<void>;
|
|
291
|
+
getJob(jobId: string): Promise<JobRecord | null>;
|
|
292
|
+
listJobs(filter?: JobFilter): Promise<JobRecord[]>;
|
|
293
|
+
deleteJob(jobId: string): Promise<void>;
|
|
294
|
+
acquireLock(lockKey: string, ttlMs: number): Promise<boolean>;
|
|
295
|
+
releaseLock(lockKey: string): Promise<void>;
|
|
296
|
+
private cleanupExpiredLocks;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
declare class RedisStorageAdapter implements StorageAdapter {
|
|
300
|
+
constructor();
|
|
301
|
+
saveJob(_job: JobRecord): Promise<void>;
|
|
302
|
+
updateJob(_jobId: string, _patch: Partial<JobRecord>): Promise<void>;
|
|
303
|
+
getJob(_jobId: string): Promise<JobRecord | null>;
|
|
304
|
+
listJobs(_filter?: JobFilter): Promise<JobRecord[]>;
|
|
305
|
+
deleteJob(_jobId: string): Promise<void>;
|
|
306
|
+
acquireLock(_lockKey: string, _ttlMs: number): Promise<boolean>;
|
|
307
|
+
releaseLock(_lockKey: string): Promise<void>;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
declare class PostgresStorageAdapter implements StorageAdapter {
|
|
311
|
+
constructor();
|
|
312
|
+
saveJob(_job: JobRecord): Promise<void>;
|
|
313
|
+
updateJob(_jobId: string, _patch: Partial<JobRecord>): Promise<void>;
|
|
314
|
+
getJob(_jobId: string): Promise<JobRecord | null>;
|
|
315
|
+
listJobs(_filter?: JobFilter): Promise<JobRecord[]>;
|
|
316
|
+
deleteJob(_jobId: string): Promise<void>;
|
|
317
|
+
acquireLock(_lockKey: string, _ttlMs: number): Promise<boolean>;
|
|
318
|
+
releaseLock(_lockKey: string): Promise<void>;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export { type AddQueueJobOptions, type DelayJobOptions, type EveryJobOptions, type JobFilter, type JobKind, type JobRecord, type JobResult, type JobStatus, type JobTask, MemoryStorageAdapter, PostgresStorageAdapter, type QueueOptions, RedisStorageAdapter, type RetryBackoff, type RetryConfig, type RunNowOptions, type ScheduleJobOptions, type SerializedError, SilentCronX, type SilentCronXConfig, type SilentCronXEventHandler, type SilentCronXEventMap, type SilentCronXEventName, type SilentCronXHealth, type SilentCronXLogger, type StatusSnapshot, type StorageAdapter, type WorkerJobOptions, type WorkerModuleReference, createSilentCronX };
|