@gravito/stream 2.0.1 → 2.1.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.
Files changed (83) hide show
  1. package/README.md +127 -285
  2. package/README.zh-TW.md +146 -13
  3. package/dist/BatchConsumer.d.ts +81 -0
  4. package/dist/Consumer.d.ts +215 -0
  5. package/dist/DashboardProvider.d.ts +20 -0
  6. package/dist/Job.d.ts +183 -0
  7. package/dist/OrbitStream.d.ts +151 -0
  8. package/dist/QueueManager.d.ts +319 -0
  9. package/dist/Queueable.d.ts +91 -0
  10. package/dist/Scheduler.d.ts +214 -0
  11. package/dist/StreamEventBackend.d.ts +114 -0
  12. package/dist/SystemEventJob.d.ts +33 -0
  13. package/dist/Worker.d.ts +139 -0
  14. package/dist/benchmarks/PerformanceReporter.d.ts +99 -0
  15. package/dist/consumer/ConcurrencyGate.d.ts +55 -0
  16. package/dist/consumer/ConsumerStrategy.d.ts +41 -0
  17. package/dist/consumer/GroupSequencer.d.ts +57 -0
  18. package/dist/consumer/HeartbeatManager.d.ts +65 -0
  19. package/dist/consumer/JobExecutor.d.ts +61 -0
  20. package/dist/consumer/JobSourceGenerator.d.ts +31 -0
  21. package/dist/consumer/PollingStrategy.d.ts +42 -0
  22. package/dist/consumer/ReactiveStrategy.d.ts +41 -0
  23. package/dist/consumer/StreamingConsumer.d.ts +88 -0
  24. package/dist/consumer/index.d.ts +13 -0
  25. package/dist/consumer/types.d.ts +102 -0
  26. package/dist/drivers/BinaryJobFrame.d.ts +78 -0
  27. package/dist/drivers/BullMQDriver.d.ts +186 -0
  28. package/dist/drivers/DatabaseDriver.d.ts +131 -0
  29. package/dist/drivers/GrpcDriver.d.ts +16 -0
  30. package/dist/drivers/KafkaDriver.d.ts +148 -0
  31. package/dist/drivers/MemoryDriver.d.ts +108 -0
  32. package/dist/drivers/QueueDriver.d.ts +250 -0
  33. package/dist/drivers/RabbitMQDriver.d.ts +102 -0
  34. package/dist/drivers/RedisDriver.d.ts +294 -0
  35. package/dist/drivers/SQSDriver.d.ts +111 -0
  36. package/dist/drivers/kafka/BackpressureController.d.ts +60 -0
  37. package/dist/drivers/kafka/BatchProcessor.d.ts +50 -0
  38. package/dist/drivers/kafka/ConsumerLifecycleManager.d.ts +80 -0
  39. package/dist/drivers/kafka/ErrorCategorizer.d.ts +39 -0
  40. package/dist/drivers/kafka/ErrorRecoveryManager.d.ts +100 -0
  41. package/dist/drivers/kafka/HeartbeatManager.d.ts +57 -0
  42. package/dist/drivers/kafka/KafkaDriver.d.ts +138 -0
  43. package/dist/drivers/kafka/KafkaMetrics.d.ts +88 -0
  44. package/dist/drivers/kafka/KafkaNotifier.d.ts +54 -0
  45. package/dist/drivers/kafka/MessageBuffer.d.ts +71 -0
  46. package/dist/drivers/kafka/OffsetTracker.d.ts +63 -0
  47. package/dist/drivers/kafka/PerformanceMonitor.d.ts +88 -0
  48. package/dist/drivers/kafka/RateLimiter.d.ts +52 -0
  49. package/dist/drivers/kafka/RebalanceHandler.d.ts +104 -0
  50. package/dist/drivers/kafka/RingBuffer.d.ts +63 -0
  51. package/dist/drivers/kafka/index.d.ts +22 -0
  52. package/dist/drivers/kafka/types.d.ts +553 -0
  53. package/dist/drivers/prepareJobForTransport.d.ts +10 -0
  54. package/dist/index.cjs +6274 -3777
  55. package/dist/index.cjs.map +71 -0
  56. package/dist/index.d.ts +60 -2233
  57. package/dist/index.js +6955 -4446
  58. package/dist/index.js.map +71 -0
  59. package/dist/locks/DistributedLock.d.ts +175 -0
  60. package/dist/persistence/BufferedPersistence.d.ts +130 -0
  61. package/dist/persistence/BunBufferedPersistence.d.ts +173 -0
  62. package/dist/persistence/MySQLPersistence.d.ts +134 -0
  63. package/dist/persistence/SQLitePersistence.d.ts +133 -0
  64. package/dist/serializers/BinarySerializer.d.ts +42 -0
  65. package/dist/serializers/CachedSerializer.d.ts +38 -0
  66. package/dist/serializers/CborNativeSerializer.d.ts +56 -0
  67. package/dist/serializers/ClassNameSerializer.d.ts +58 -0
  68. package/dist/serializers/JobSerializer.d.ts +33 -0
  69. package/dist/serializers/JsonSerializer.d.ts +28 -0
  70. package/dist/serializers/JsonlSerializer.d.ts +90 -0
  71. package/dist/serializers/MessagePackSerializer.d.ts +29 -0
  72. package/dist/types.d.ts +653 -0
  73. package/dist/workers/BinaryWorkerProtocol.d.ts +77 -0
  74. package/dist/workers/BunWorker.d.ts +179 -0
  75. package/dist/workers/SandboxedWorker.d.ts +132 -0
  76. package/dist/workers/WorkerFactory.d.ts +128 -0
  77. package/dist/workers/WorkerPool.d.ts +186 -0
  78. package/dist/workers/bun-job-executor.d.ts +14 -0
  79. package/dist/workers/index.d.ts +13 -0
  80. package/dist/workers/job-executor.d.ts +9 -0
  81. package/package.json +13 -6
  82. package/proto/queue.proto +101 -0
  83. package/dist/index.d.cts +0 -2242
@@ -0,0 +1,71 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/drivers/BinaryJobFrame.ts", "../src/drivers/BullMQDriver.ts", "../src/drivers/DatabaseDriver.ts", "../src/drivers/KafkaDriver.ts", "../src/drivers/prepareJobForTransport.ts", "../src/drivers/RabbitMQDriver.ts", "../src/drivers/RedisDriver.ts", "../src/drivers/SQSDriver.ts", "../src/locks/DistributedLock.ts", "../src/persistence/BufferedPersistence.ts", "../../../node_modules/.bun/@msgpack+msgpack@3.1.3/node_modules/@msgpack/msgpack/dist.cjs/utils/utf8.cjs", "../../../node_modules/.bun/@msgpack+msgpack@3.1.3/node_modules/@msgpack/msgpack/dist.cjs/ExtData.cjs", "../../../node_modules/.bun/@msgpack+msgpack@3.1.3/node_modules/@msgpack/msgpack/dist.cjs/DecodeError.cjs", "../../../node_modules/.bun/@msgpack+msgpack@3.1.3/node_modules/@msgpack/msgpack/dist.cjs/utils/int.cjs", "../../../node_modules/.bun/@msgpack+msgpack@3.1.3/node_modules/@msgpack/msgpack/dist.cjs/timestamp.cjs", "../../../node_modules/.bun/@msgpack+msgpack@3.1.3/node_modules/@msgpack/msgpack/dist.cjs/ExtensionCodec.cjs", "../../../node_modules/.bun/@msgpack+msgpack@3.1.3/node_modules/@msgpack/msgpack/dist.cjs/utils/typedArrays.cjs", "../../../node_modules/.bun/@msgpack+msgpack@3.1.3/node_modules/@msgpack/msgpack/dist.cjs/Encoder.cjs", "../../../node_modules/.bun/@msgpack+msgpack@3.1.3/node_modules/@msgpack/msgpack/dist.cjs/encode.cjs", "../../../node_modules/.bun/@msgpack+msgpack@3.1.3/node_modules/@msgpack/msgpack/dist.cjs/utils/prettyByte.cjs", "../../../node_modules/.bun/@msgpack+msgpack@3.1.3/node_modules/@msgpack/msgpack/dist.cjs/CachedKeyDecoder.cjs", "../../../node_modules/.bun/@msgpack+msgpack@3.1.3/node_modules/@msgpack/msgpack/dist.cjs/Decoder.cjs", "../../../node_modules/.bun/@msgpack+msgpack@3.1.3/node_modules/@msgpack/msgpack/dist.cjs/decode.cjs", "../../../node_modules/.bun/@msgpack+msgpack@3.1.3/node_modules/@msgpack/msgpack/dist.cjs/utils/stream.cjs", "../../../node_modules/.bun/@msgpack+msgpack@3.1.3/node_modules/@msgpack/msgpack/dist.cjs/decodeAsync.cjs", "../../../node_modules/.bun/@msgpack+msgpack@3.1.3/node_modules/@msgpack/msgpack/dist.cjs/index.cjs", "../src/serializers/MessagePackSerializer.ts", "../src/Scheduler.ts", "../src/DashboardProvider.ts", "../src/BatchConsumer.ts", "../src/Consumer.ts", "../src/consumer/StreamingConsumer.ts", "../src/workers/SandboxedWorker.ts", "../src/Worker.ts", "../src/consumer/ConcurrencyGate.ts", "../src/consumer/GroupSequencer.ts", "../src/consumer/HeartbeatManager.ts", "../src/consumer/JobExecutor.ts", "../src/consumer/JobSourceGenerator.ts", "../src/consumer/PollingStrategy.ts", "../src/consumer/ReactiveStrategy.ts", "../src/index.ts", "../src/drivers/GrpcDriver.ts", "../src/drivers/MemoryDriver.ts", "../src/Job.ts", "../src/serializers/CachedSerializer.ts", "../src/serializers/ClassNameSerializer.ts", "../src/serializers/JsonSerializer.ts", "../src/QueueManager.ts", "../src/SystemEventJob.ts", "../src/StreamEventBackend.ts", "../src/OrbitStream.ts", "../src/persistence/BunBufferedPersistence.ts", "../src/persistence/MySQLPersistence.ts", "../src/persistence/SQLitePersistence.ts", "../src/serializers/CborNativeSerializer.ts", "../src/serializers/BinarySerializer.ts", "../src/serializers/JsonlSerializer.ts", "../src/workers/BinaryWorkerProtocol.ts", "../src/workers/BunWorker.ts", "../src/workers/WorkerFactory.ts", "../src/workers/WorkerPool.ts"],
4
+ "sourcesContent": [
5
+ "import type { SerializedJob } from '../types'\n\n/**\n * BinaryJobFrame - Gravito Job 的二進制幀格式\n *\n * 幀結構(Frame Format):\n * Magic(2B) + Version(1B) + Flags(1B) + MetaLen(2B Big-Endian) + Metadata(CBOR) + Payload\n *\n * - Magic:固定為 [0x47, 0x4A](\"GJ\" = Gravito Job)\n * - Version:目前為 0x01\n * - Flags:位元旗標,目前定義:\n * Bit 0 (HAS_CLASS_NAME):是否包含 className 欄位\n * Bit 1 (HAS_GROUP_ID):是否包含 groupId 欄位\n * Bit 2 (HAS_DELAY):是否包含 delaySeconds 欄位\n * Bit 3 (HAS_PRIORITY):是否包含 priority 欄位\n * Bit 4 (HAS_ERROR):是否包含 error / failedAt 欄位\n * - MetaLen:Metadata CBOR 資料的長度(2 bytes Big-Endian,最大 65535 bytes)\n * - Metadata:以 CBOR 或 JSON 編碼的 metadata 物件(id, createdAt, attempts 等)\n * - Payload:原始 Uint8Array 資料(job.data)\n *\n * @module BinaryJobFrame\n */\n\n// ─── 常數定義 ────────────────────────────────────────────────────────────────\n\n/** Magic bytes,標識 Gravito Job 二進制幀 */\nexport const MAGIC = [0x47, 0x4a] as const // \"GJ\"\n\n/** 幀格式版本號 */\nexport const VERSION = 0x01\n\n/** 幀 header 的固定大小(Magic 2B + Version 1B + Flags 1B + MetaLen 2B = 6 bytes) */\nexport const HEADER_SIZE = 6\n\n/** Flags 位元定義 */\nexport const Flags = {\n /** 包含 className 欄位 */\n HAS_CLASS_NAME: 0x01,\n /** 包含 groupId 欄位 */\n HAS_GROUP_ID: 0x02,\n /** 包含 delaySeconds 欄位 */\n HAS_DELAY: 0x04,\n /** 包含 priority 欄位 */\n HAS_PRIORITY: 0x08,\n /** 包含 error / failedAt 欄位 */\n HAS_ERROR: 0x10,\n} as const\n\n/**\n * Metadata 短鍵映射(節省序列化空間)\n * 完整鍵名 → 短鍵名\n */\nexport const META_KEY_MAP: Record<string, string> = {\n id: 'i',\n createdAt: 't',\n attempts: 'a',\n maxAttempts: 'm',\n className: 'c',\n groupId: 'g',\n delaySeconds: 'd',\n priority: 'p',\n retryAfterSeconds: 'r',\n retryMultiplier: 'x',\n error: 'e',\n failedAt: 'f',\n}\n\n/**\n * 短鍵反向映射(反序列化用)\n * 短鍵名 → 完整鍵名\n */\nexport const META_KEY_REVERSE_MAP: Record<string, string> = Object.fromEntries(\n Object.entries(META_KEY_MAP).map(([full, short]) => [short, full])\n)\n\n// ─── 型別定義 ────────────────────────────────────────────────────────────────\n\n/**\n * 序列化後的 Metadata(使用短鍵)\n */\ninterface MetadataShort {\n i: string // id\n t: number // createdAt\n a?: number // attempts\n m?: number // maxAttempts\n c?: string // className\n g?: string // groupId\n d?: number // delaySeconds\n p?: string | number // priority\n r?: number // retryAfterSeconds\n x?: number // retryMultiplier\n e?: string // error\n f?: number // failedAt\n}\n\n// ─── 工具函式 ────────────────────────────────────────────────────────────────\n\n/**\n * 將數字寫入 Big-Endian 格式的 Uint8Array\n *\n * @param value - 要寫入的數字\n * @param bytes - 位元組數(1-4)\n * @returns 包含 Big-Endian 值的 Uint8Array\n */\nfunction writeUInt16BE(value: number): Uint8Array {\n const buf = new Uint8Array(2)\n buf[0] = (value >> 8) & 0xff\n buf[1] = value & 0xff\n return buf\n}\n\n/**\n * 從 Uint8Array 讀取 Big-Endian 16-bit 無符號整數\n *\n * @param data - 資料來源\n * @param offset - 起始偏移量\n * @returns 16-bit 無符號整數\n */\nfunction readUInt16BE(data: Uint8Array, offset: number): number {\n return ((data[offset]! << 8) | data[offset + 1]!) >>> 0\n}\n\n/**\n * 以 JSON 方式序列化 metadata(輕量備用方案)\n *\n * 在沒有 CBOR 加速器的情況下,使用 JSON + TextEncoder 序列化 metadata。\n * 大小略大於 CBOR,但確保相容性。\n *\n * @param meta - 要序列化的 metadata\n * @returns 序列化後的 Uint8Array\n */\nfunction encodeMetaFallback(meta: MetadataShort): Uint8Array {\n const json = JSON.stringify(meta)\n return new TextEncoder().encode(json)\n}\n\n/**\n * 以 JSON 方式反序列化 metadata\n *\n * @param data - 序列化的 metadata bytes\n * @returns 反序列化的 metadata 物件\n */\nfunction decodeMetaFallback(data: Uint8Array): MetadataShort {\n const json = new TextDecoder().decode(data)\n return JSON.parse(json) as MetadataShort\n}\n\n// ─── 主要 API ────────────────────────────────────────────────────────────────\n\n/**\n * 判斷給定的資料是否為 Gravito Job 二進制幀\n *\n * 透過 Magic byte 嗅探識別:檢查前 2 bytes 是否為 [0x47, 0x4A]\n *\n * @param data - 要檢查的資料(Uint8Array 或 Buffer)\n * @returns 如果是 Gravito Job 幀則回傳 true\n */\nexport function isGravitoJobFrame(data: Uint8Array | Buffer): boolean {\n if (data.length < HEADER_SIZE) {\n return false\n }\n return data[0] === MAGIC[0] && data[1] === MAGIC[1]\n}\n\n/**\n * 將 SerializedJob 編碼為二進制幀格式\n *\n * 僅適用於 type === 'binary' 且 data 為 Uint8Array 的 Job。\n *\n * @param job - 要編碼的 SerializedJob(必須是 binary type)\n * @returns 編碼後的 Uint8Array\n * @throws {TypeError} 如果 job.data 不是 Uint8Array\n * @throws {Error} 如果 metadata 長度超過 65535 bytes\n */\nexport function encodeBinaryJobFrame(job: SerializedJob): Uint8Array {\n if (!(job.data instanceof Uint8Array)) {\n throw new TypeError(\n `[BinaryJobFrame] encodeBinaryJobFrame requires job.data to be Uint8Array, ` +\n `got ${typeof job.data}`\n )\n }\n\n // 計算 Flags\n let flags = 0x00\n if (job.className) {\n flags |= Flags.HAS_CLASS_NAME\n }\n if (job.groupId) {\n flags |= Flags.HAS_GROUP_ID\n }\n if (job.delaySeconds !== undefined) {\n flags |= Flags.HAS_DELAY\n }\n if (job.priority !== undefined) {\n flags |= Flags.HAS_PRIORITY\n }\n if (job.error || job.failedAt !== undefined) {\n flags |= Flags.HAS_ERROR\n }\n\n // 建構 metadata(使用短鍵減少大小)\n const meta: MetadataShort = {\n i: job.id,\n t: job.createdAt,\n }\n\n if (job.attempts !== undefined) {\n meta.a = job.attempts\n }\n if (job.maxAttempts !== undefined) {\n meta.m = job.maxAttempts\n }\n if (job.className) {\n meta.c = job.className\n }\n if (job.groupId) {\n meta.g = job.groupId\n }\n if (job.delaySeconds !== undefined) {\n meta.d = job.delaySeconds\n }\n if (job.priority !== undefined) {\n meta.p = job.priority\n }\n if (job.retryAfterSeconds !== undefined) {\n meta.r = job.retryAfterSeconds\n }\n if (job.retryMultiplier !== undefined) {\n meta.x = job.retryMultiplier\n }\n if (job.error) {\n meta.e = job.error\n }\n if (job.failedAt !== undefined) {\n meta.f = job.failedAt\n }\n\n // 序列化 metadata\n const metaBytes = encodeMetaFallback(meta)\n\n if (metaBytes.length > 0xffff) {\n throw new Error(\n `[BinaryJobFrame] Metadata size ${metaBytes.length} exceeds maximum of 65535 bytes`\n )\n }\n\n // 計算總大小並分配緩衝區\n const payloadBytes = job.data\n const totalSize = HEADER_SIZE + metaBytes.length + payloadBytes.length\n const frame = new Uint8Array(totalSize)\n\n // 寫入 header\n let offset = 0\n frame[offset++] = MAGIC[0] // 0x47 'G'\n frame[offset++] = MAGIC[1] // 0x4A 'J'\n frame[offset++] = VERSION // 0x01\n frame[offset++] = flags\n\n // 寫入 MetaLen(Big-Endian)\n const metaLenBytes = writeUInt16BE(metaBytes.length)\n frame[offset++] = metaLenBytes[0]!\n frame[offset++] = metaLenBytes[1]!\n\n // 寫入 metadata\n frame.set(metaBytes, offset)\n offset += metaBytes.length\n\n // 寫入 payload\n frame.set(payloadBytes, offset)\n\n return frame\n}\n\n/**\n * 將二進制幀解碼為 SerializedJob\n *\n * @param data - 要解碼的二進制幀(Uint8Array 或 Buffer)\n * @returns 解碼後的 SerializedJob,data 為 Uint8Array\n * @throws {Error} 如果資料格式無效\n */\nexport function decodeBinaryJobFrame(data: Uint8Array | Buffer): SerializedJob {\n const bytes = data instanceof Uint8Array ? data : new Uint8Array(data)\n\n // 驗證 Magic bytes\n if (bytes.length < HEADER_SIZE) {\n throw new Error(\n `[BinaryJobFrame] Frame too short: ${bytes.length} bytes, minimum is ${HEADER_SIZE}`\n )\n }\n\n if (bytes[0] !== MAGIC[0] || bytes[1] !== MAGIC[1]) {\n throw new Error(\n `[BinaryJobFrame] Invalid magic bytes: [${bytes[0]}, ${bytes[1]}], ` +\n `expected [${MAGIC[0]}, ${MAGIC[1]}]`\n )\n }\n\n // 讀取 header\n const version = bytes[2]\n if (version !== VERSION) {\n throw new Error(`[BinaryJobFrame] Unsupported version: ${version}, expected ${VERSION}`)\n }\n\n const flags = bytes[3]!\n const metaLen = readUInt16BE(bytes, 4)\n\n // 驗證資料長度\n if (bytes.length < HEADER_SIZE + metaLen) {\n throw new Error(\n `[BinaryJobFrame] Frame truncated: expected ${HEADER_SIZE + metaLen} bytes for header+meta, ` +\n `got ${bytes.length}`\n )\n }\n\n // 解析 metadata\n const metaBytes = bytes.slice(HEADER_SIZE, HEADER_SIZE + metaLen)\n const meta = decodeMetaFallback(metaBytes)\n\n // 提取 payload\n const payloadStart = HEADER_SIZE + metaLen\n const payloadBytes = bytes.slice(payloadStart)\n\n // 從短鍵還原完整 SerializedJob\n const job: SerializedJob = {\n id: meta.i,\n type: 'binary',\n data: payloadBytes,\n createdAt: meta.t,\n }\n\n // 根據 flags 和 metadata 還原可選欄位\n if (meta.a !== undefined) {\n job.attempts = meta.a\n }\n if (meta.m !== undefined) {\n job.maxAttempts = meta.m\n }\n\n if (flags! & Flags.HAS_CLASS_NAME && meta.c) {\n job.className = meta.c\n }\n if (flags! & Flags.HAS_GROUP_ID && meta.g) {\n job.groupId = meta.g\n }\n if (flags! & Flags.HAS_DELAY && meta.d !== undefined) {\n job.delaySeconds = meta.d\n }\n if (flags! & Flags.HAS_PRIORITY && meta.p !== undefined) {\n job.priority = meta.p\n }\n if (meta.r !== undefined) {\n job.retryAfterSeconds = meta.r\n }\n if (meta.x !== undefined) {\n job.retryMultiplier = meta.x\n }\n if (flags! & Flags.HAS_ERROR && meta.e) {\n job.error = meta.e\n }\n if (flags! & Flags.HAS_ERROR && meta.f !== undefined) {\n job.failedAt = meta.f\n }\n\n return job\n}\n",
6
+ "import type { JobPushOptions, QueueStats, SerializedJob, TopicOptions } from '../types'\nimport type { QueueDriver } from './QueueDriver'\n\n/**\n * Bull Queue client interface (compatible with bullmq package).\n */\nexport interface BullQueueClient {\n add(name: string, data: any, options?: any): Promise<any>\n getJob(id: string): Promise<any | null>\n count(): Promise<number>\n process(handler: (job: any) => Promise<void>): void\n on(event: string, handler: (...args: any[]) => void): void\n off(event: string, handler: (...args: any[]) => void): void\n pause(): Promise<void>\n resume(): Promise<void>\n clean(grace: number, limit?: number, type?: string): Promise<number>\n close(): Promise<void>\n getJobCounts(types?: string[]): Promise<Record<string, number>>\n getDelayedCount(): Promise<number>\n getFailedCount(): Promise<number>\n getActiveCount(): Promise<number>\n [key: string]: any\n}\n\nexport interface BullWorkerClient {\n [key: string]: any\n}\n\n/**\n * Bull Queue driver configuration.\n */\nexport interface BullMQDriverConfig {\n /**\n * Bull Queue instance (from bullmq package).\n */\n queue: BullQueueClient\n\n /**\n * Optional Bull Worker instance for processing jobs.\n */\n worker?: BullWorkerClient\n\n /**\n * Connection options (host, port, etc. for Redis).\n */\n connection?: {\n host?: string\n port?: number\n password?: string\n db?: number\n [key: string]: any\n }\n\n /**\n * Default number of concurrent workers (default: 1).\n */\n concurrency?: number\n\n /**\n * Key prefix for namespacing queues (default: 'gravito:').\n */\n prefix?: string\n\n /**\n * Enable debug logging.\n */\n debug?: boolean\n}\n\n/**\n * Bull Queue driver implementation.\n *\n * Provides high-performance, persistent job queuing using Bull Queue (backed by Redis).\n * Supports priority, delays, retries, and group-based FIFO processing.\n *\n * @public\n * @example\n * ```typescript\n * import { Queue } from 'bullmq'\n * import Redis from 'ioredis'\n *\n * const redis = new Redis()\n * const queue = new Queue('gravito-events', { connection: redis })\n * const driver = new BullMQDriver({ queue })\n * ```\n */\nexport class BullMQDriver implements QueueDriver {\n private queue: BullQueueClient\n private prefix: string\n private debug: boolean\n private queueMap = new Map<string, BullQueueClient>()\n\n constructor(config: BullMQDriverConfig) {\n this.queue = config.queue\n this.prefix = config.prefix ?? 'gravito:'\n this.debug = config.debug ?? false\n\n if (!this.queue) {\n throw new Error('[BullMQDriver] Bull Queue instance is required.')\n }\n }\n\n /**\n * Get or create a queue for the given queue name.\n */\n private getQueue(queueName: string): BullQueueClient {\n const fullName = `${this.prefix}${queueName}`\n if (this.queueMap.has(fullName)) {\n return this.queueMap.get(fullName)!\n }\n\n // For simplicity, we'll use the same queue for all queue names\n // In a real implementation, you might create separate Queue instances\n // However, Bull Queue typically uses a single Queue instance with job namespacing\n\n // Note: This is a limitation of the current implementation.\n // To fully support multiple queue names, you'd need a Queue factory or pool.\n // For now, we namespace jobs within the primary queue.\n return this.queue\n }\n\n /**\n * Build Job Options from JobPushOptions.\n */\n private buildJobOptions(options?: JobPushOptions): Record<string, any> {\n const bullOptions: Record<string, any> = {}\n\n // Priority mapping: 'high' -> 1, 'normal' -> 5, 'low' -> 10\n if (options?.priority) {\n if (options.priority === 'high' || options.priority === 'critical') {\n bullOptions.priority = 1\n } else if (options.priority === 'low') {\n bullOptions.priority = 10\n } else if (typeof options.priority === 'number') {\n bullOptions.priority = Math.min(Math.max(options.priority, 1), 10)\n } else {\n bullOptions.priority = 5 // 'normal' or 'default'\n }\n }\n\n return bullOptions\n }\n\n /**\n * Create Bull job data from SerializedJob.\n */\n private createBullJobData(job: SerializedJob): any {\n return {\n id: job.id,\n type: job.type,\n data: job.data,\n className: job.className,\n createdAt: job.createdAt,\n delaySeconds: job.delaySeconds,\n attempts: job.attempts ?? 0,\n maxAttempts: job.maxAttempts ?? 3,\n groupId: job.groupId,\n retryAfterSeconds: job.retryAfterSeconds,\n retryMultiplier: job.retryMultiplier,\n error: job.error,\n failedAt: job.failedAt,\n priority: job.priority,\n }\n }\n\n /**\n * Pushes a job to Bull Queue.\n */\n async push(queue: string, job: SerializedJob, options?: JobPushOptions): Promise<void> {\n try {\n const q = this.getQueue(queue)\n const bullJobData = this.createBullJobData(job)\n const bullOptions: Record<string, any> = this.buildJobOptions(options)\n\n // Add delay if specified\n if (job.delaySeconds && job.delaySeconds > 0) {\n bullOptions.delay = job.delaySeconds * 1000 // Convert to milliseconds\n }\n\n // Add retry configuration\n bullOptions.attempts = job.maxAttempts ?? 3\n if (job.retryAfterSeconds) {\n bullOptions.backoff = {\n type: 'exponential',\n delay: job.retryAfterSeconds * 1000,\n }\n }\n\n // Add group ID for FIFO processing (if supported by Bull extensions)\n if (options?.groupId) {\n bullOptions.group = {\n id: options.groupId,\n }\n }\n\n // Namespace the job by queue name\n const namespacedJobName = `${queue}:${job.id}`\n await q.add(namespacedJobName, bullJobData, bullOptions)\n\n if (this.debug) {\n console.log(`[BullMQDriver] Pushed job ${job.id} to queue ${queue}`)\n }\n } catch (error) {\n console.error(`[BullMQDriver] Failed to push job to queue ${queue}:`, error)\n throw error\n }\n }\n\n /**\n * Pops a job from Bull Queue.\n * Note: Bull Queue typically uses Workers, not manual pop.\n * This is a fallback implementation.\n */\n async pop(queue: string): Promise<SerializedJob | null> {\n try {\n this.getQueue(queue)\n\n // Bull Queue doesn't have a direct pop() method like Redis.\n // We'll use getJob to simulate, but this is not the intended usage pattern.\n // In production, use the Worker pattern.\n\n // For now, return null as Bull Queue is event-driven\n // Real implementation would require custom worker logic\n return null\n } catch (error) {\n console.error(`[BullMQDriver] Failed to pop from queue ${queue}:`, error)\n return null\n }\n }\n\n /**\n * Returns the size of the queue.\n */\n async size(queue: string): Promise<number> {\n try {\n const q = this.getQueue(queue)\n const count = await q.count?.()\n return count ?? 0\n } catch (error) {\n console.error(`[BullMQDriver] Failed to get queue size for ${queue}:`, error)\n return 0\n }\n }\n\n /**\n * Clears the queue.\n */\n async clear(queue: string): Promise<void> {\n try {\n const q = this.getQueue(queue)\n if (typeof q.clean === 'function') {\n await q.clean(0) // Remove all jobs\n }\n } catch (error) {\n console.error(`[BullMQDriver] Failed to clear queue ${queue}:`, error)\n throw error\n }\n }\n\n /**\n * Marks a job as failed (moves to failed list).\n */\n async fail(queue: string, job: SerializedJob): Promise<void> {\n try {\n const q = this.getQueue(queue)\n const bullJob = await q.getJob?.(job.id)\n\n if (bullJob) {\n const error = job.error ?? 'Job failed'\n const failureReasonError = new Error(error)\n await bullJob.moveToFailed?.(failureReasonError, true)\n }\n } catch (error) {\n console.error(`[BullMQDriver] Failed to mark job as failed:`, error)\n throw error\n }\n }\n\n /**\n * Returns detailed statistics for the queue.\n */\n async stats(queue: string): Promise<QueueStats> {\n try {\n const q = this.getQueue(queue)\n\n const counts = await q.getJobCounts?.(['active', 'completed', 'failed', 'delayed', 'waiting'])\n const delayed = await q.getDelayedCount?.()\n const failed = await q.getFailedCount?.()\n const active = await q.getActiveCount?.()\n\n return {\n queue,\n size: counts?.waiting ?? 0,\n delayed: delayed ?? 0,\n failed: failed ?? 0,\n reserved: active ?? 0,\n }\n } catch (error) {\n console.error(`[BullMQDriver] Failed to get stats for queue ${queue}:`, error)\n return {\n queue,\n size: 0,\n delayed: 0,\n failed: 0,\n }\n }\n }\n\n /**\n * Retrieves failed jobs from the Dead Letter Queue.\n */\n async getFailed(queue: string, _start = 0, _end = -1): Promise<SerializedJob[]> {\n try {\n this.getQueue(queue)\n\n // Bull Queue doesn't have a direct getFailed method\n // This would require custom implementation or using a separate failed list\n // For now, return empty array as placeholder\n return []\n } catch (error) {\n console.error(`[BullMQDriver] Failed to get failed jobs for queue ${queue}:`, error)\n return []\n }\n }\n\n /**\n * Retries failed jobs.\n */\n async retryFailed(queue: string, _count = 1): Promise<number> {\n try {\n this.getQueue(queue)\n\n // Bull Queue handles retries automatically via job.retry()\n // This is a placeholder for manual retry logic\n return 0\n } catch (error) {\n console.error(`[BullMQDriver] Failed to retry jobs for queue ${queue}:`, error)\n return 0\n }\n }\n\n /**\n * Clears the Dead Letter Queue.\n */\n async clearFailed(queue: string): Promise<void> {\n try {\n const q = this.getQueue(queue)\n\n if (typeof q.clean === 'function') {\n await q.clean(0, undefined, 'failed')\n }\n } catch (error) {\n console.error(`[BullMQDriver] Failed to clear failed jobs for queue ${queue}:`, error)\n throw error\n }\n }\n\n /**\n * Creates a new queue/topic.\n */\n async createTopic(_topic: string, _options?: TopicOptions): Promise<void> {\n // Bull Queue creates queues on-the-fly when adding jobs\n // No explicit creation needed\n }\n\n /**\n * Deletes a queue/topic.\n */\n async deleteTopic(topic: string): Promise<void> {\n try {\n const q = this.getQueue(topic)\n await q.close?.()\n } catch (error) {\n console.error(`[BullMQDriver] Failed to delete queue ${topic}:`, error)\n throw error\n }\n }\n\n /**\n * Pushes multiple jobs in batch.\n */\n async pushMany(queue: string, jobs: SerializedJob[]): Promise<void> {\n try {\n const q = this.getQueue(queue)\n const bullJobs = jobs.map((job) => {\n const bullJobData = this.createBullJobData(job)\n const namespacedJobName = `${queue}:${job.id}`\n return {\n name: namespacedJobName,\n data: bullJobData,\n }\n })\n\n // Bull Queue doesn't have direct pushMany, so use individual pushes\n // or batch using addBulk if available\n for (const bullJob of bullJobs) {\n await q.add(bullJob.name, bullJob.data)\n }\n } catch (error) {\n console.error(`[BullMQDriver] Failed to push multiple jobs to queue ${queue}:`, error)\n throw error\n }\n }\n\n /**\n * Pops multiple jobs in batch.\n */\n async popMany(_queue: string, _count: number): Promise<SerializedJob[]> {\n // Bull Queue is event-driven, not pull-based\n // Returning empty for now; real implementation uses Workers\n return []\n }\n\n /**\n * Reports worker heartbeat.\n */\n async reportHeartbeat(\n workerInfo: {\n id: string\n status: string\n hostname: string\n pid: number\n uptime: number\n last_ping: string\n queues: string[]\n metrics?: Record<string, any>\n [key: string]: any\n },\n _prefix?: string\n ): Promise<void> {\n // Placeholder for heartbeat reporting\n if (this.debug) {\n console.log(`[BullMQDriver] Worker heartbeat from ${workerInfo.id}`)\n }\n }\n\n /**\n * Publishes a log message.\n */\n async publishLog(\n logPayload: {\n level: string\n message: string\n workerId: string\n jobId?: string\n timestamp: string\n [key: string]: any\n },\n _prefix?: string\n ): Promise<void> {\n if (this.debug) {\n console.log(`[BullMQDriver] [${logPayload.level}] ${logPayload.message}`)\n }\n }\n\n /**\n * Checks rate limit for a queue.\n */\n async checkRateLimit(\n _queue: string,\n _config: { max: number; duration: number }\n ): Promise<boolean> {\n // Placeholder; would require Redis INCR/EXPIRE logic\n return true\n }\n\n /**\n * Retrieves all queue names.\n */\n async getQueues(): Promise<string[]> {\n // Placeholder; Bull Queue doesn't have built-in queue listing\n return ['default']\n }\n}\n",
7
+ "import type { QueueStats, SerializedJob } from '../types'\nimport type { QueueDriver } from './QueueDriver'\n\n/**\n * Generic database service interface.\n *\n * Adapts any SQL database client (e.g., pg, mysql2, sqlite3) for use with the DatabaseDriver.\n * Users must provide an implementation of this interface that wraps their specific DB library.\n */\nexport interface DatabaseService {\n /**\n * Execute a raw SQL query.\n *\n * @param sql - The SQL query string with placeholders (e.g., $1, ?).\n * @param bindings - The values to bind to the placeholders.\n * @returns The query result (rows or metadata).\n */\n execute<T = unknown>(sql: string, bindings?: unknown[]): Promise<T[] | T>\n\n /**\n * Execute multiple queries within a single transaction.\n *\n * @param callback - A function that receives a transaction-scoped service instance.\n * @returns The result of the callback.\n */\n transaction<T>(callback: (tx: DatabaseService) => Promise<T>): Promise<T>\n}\n\n/**\n * Configuration options for the DatabaseDriver.\n */\nexport interface DatabaseDriverConfig {\n /**\n * The name of the table used to store jobs.\n * @default 'jobs'\n */\n table?: string\n\n /**\n * The database service adapter instance.\n */\n dbService?: DatabaseService\n}\n\n/**\n * Database-backed queue driver.\n *\n * Persists jobs in a SQL database table. Supports delayed jobs, reservation (locking),\n * and reliable delivery. Compatible with PostgreSQL (SKIP LOCKED), MySQL, and SQLite.\n *\n * @public\n * @example\n * ```typescript\n * const driver = new DatabaseDriver({\n * dbService: myDbAdapter,\n * table: 'queue_jobs'\n * });\n * ```\n */\nexport class DatabaseDriver implements QueueDriver {\n private tableName: string\n private dbService: DatabaseService\n\n constructor(config: DatabaseDriverConfig) {\n this.tableName = config.table ?? 'jobs'\n this.dbService = config.dbService!\n\n if (!this.dbService) {\n throw new Error(\n '[DatabaseDriver] dbService is required. Please provide a database service that implements DatabaseService interface.'\n )\n }\n }\n\n /**\n * Pushes a job to the database queue.\n *\n * Inserts a new row into the jobs table.\n *\n * @param queue - The queue name.\n * @param job - The serialized job.\n */\n async push(queue: string, job: SerializedJob): Promise<void> {\n const availableAt = job.delaySeconds\n ? new Date(Date.now() + job.delaySeconds * 1000)\n : new Date()\n\n // Save the WHOLE job as JSON in payload column for zero-loss metadata\n const payload = JSON.stringify(job)\n\n await this.dbService.execute(\n `INSERT INTO ${this.tableName} (queue, payload, attempts, available_at, created_at)\n VALUES ($1, $2, $3, $4, $5)`,\n [queue, payload, job.attempts ?? 0, availableAt.toISOString(), new Date().toISOString()]\n )\n }\n\n /**\n * Pops the next available job from the queue.\n *\n * Uses transactional locking (SELECT ... FOR UPDATE SKIP LOCKED if supported) to ensure\n * atomic reservation of jobs by workers.\n *\n * @param queue - The queue name.\n * @returns The job or `null`.\n */\n async pop(queue: string): Promise<SerializedJob | null> {\n // Use SELECT FOR UPDATE to lock rows (PostgreSQL/MySQL).\n // Note: SKIP LOCKED is PostgreSQL-specific, and is supported by MySQL 8.0+ as well.\n // For databases that don't support SKIP LOCKED, this falls back to a plain SELECT FOR UPDATE.\n const result = await this.dbService\n .execute<{\n id: string\n payload: string\n attempts: number\n created_at: Date\n available_at: Date\n }>(\n `SELECT id, payload, attempts, created_at, available_at\n FROM ${this.tableName}\n WHERE queue = $1\n AND available_at <= NOW()\n AND (reserved_at IS NULL OR reserved_at < NOW() - INTERVAL '5 minutes')\n ORDER BY created_at ASC\n LIMIT 1\n FOR UPDATE SKIP LOCKED`,\n [queue]\n )\n .catch(() => {\n // Fallback: DB does not support SKIP LOCKED\n return this.dbService.execute<{\n id: string\n payload: string\n attempts: number\n created_at: Date\n available_at: Date\n }>(\n `SELECT id, payload, attempts, created_at, available_at\n FROM ${this.tableName}\n WHERE queue = $1\n AND available_at <= NOW()\n AND (reserved_at IS NULL OR reserved_at < NOW() - INTERVAL '5 minutes')\n ORDER BY created_at ASC\n LIMIT 1\n FOR UPDATE`,\n [queue]\n )\n })\n\n const rows = result as {\n id: string\n payload: string\n attempts: number\n created_at: Date\n available_at: Date\n }[]\n\n if (!rows || rows.length === 0) {\n return null\n }\n\n const row = rows[0]!\n\n // Mark as reserved\n await this.dbService.execute(\n `UPDATE ${this.tableName}\n SET reserved_at = NOW()\n WHERE id = $1`,\n [row.id]\n )\n\n // Compute delaySeconds\n const createdAt = new Date(row.created_at).getTime()\n const delaySeconds = row.available_at\n ? Math.max(0, Math.floor((new Date(row.available_at).getTime() - createdAt) / 1000))\n : undefined\n\n // Parse payload and restore metadata\n let job: SerializedJob\n try {\n const parsed = JSON.parse(row.payload)\n if (parsed && typeof parsed === 'object' && parsed.type && parsed.data) {\n job = {\n ...parsed,\n id: row.id, // DB ID is the source of truth for deletion\n attempts: row.attempts,\n }\n } else {\n throw new Error('Fallback')\n }\n } catch (_e) {\n // Fallback for old format\n job = {\n id: row.id,\n type: 'class',\n data: row.payload,\n createdAt,\n attempts: row.attempts,\n }\n }\n\n if (delaySeconds !== undefined) {\n job.delaySeconds = delaySeconds\n }\n\n return job\n }\n\n /**\n * Pops multiple jobs from the queue in a single transaction.\n *\n * @param queue - The queue name.\n * @param count - Max jobs to pop.\n */\n async popMany(queue: string, count: number): Promise<SerializedJob[]> {\n if (count <= 1) {\n const job = await this.pop(queue)\n return job ? [job] : []\n }\n\n try {\n // 1. Select and lock multiple rows\n const result = await this.dbService.execute<{\n id: string\n payload: string\n attempts: number\n created_at: Date\n available_at: Date\n }>(\n `SELECT id, payload, attempts, created_at, available_at\n FROM ${this.tableName}\n WHERE queue = $1\n AND available_at <= NOW()\n AND (reserved_at IS NULL OR reserved_at < NOW() - INTERVAL '5 minutes')\n ORDER BY created_at ASC\n LIMIT ${count}\n FOR UPDATE SKIP LOCKED`,\n [queue]\n )\n\n const rows = Array.isArray(result) ? result : result ? [result] : []\n if (!rows || rows.length === 0) {\n return []\n }\n\n // Ensure rows is treated as array of objects (DatabaseService might return different shapes)\n const validRows = rows.filter((r) => r?.id) as any[]\n if (validRows.length === 0) {\n return []\n }\n\n const ids = validRows.map((r) => r.id)\n\n // 2. Mark as reserved in batch\n await this.dbService.execute(\n `UPDATE ${this.tableName}\n SET reserved_at = NOW()\n WHERE id IN (${ids.map((_, i) => `$${i + 1}`).join(', ')})`,\n ids\n )\n\n // 3. Map to SerializedJob\n return validRows.map((row) => {\n const createdAt = new Date(row.created_at).getTime()\n try {\n const parsed = JSON.parse(row.payload)\n return {\n ...parsed,\n id: row.id,\n attempts: row.attempts,\n }\n } catch (_e) {\n return {\n id: row.id,\n type: 'class' as const,\n data: row.payload,\n createdAt,\n attempts: row.attempts,\n }\n }\n })\n } catch (_e) {\n // Fallback: If SKIP LOCKED is not supported, fall back to single pop loop\n // We avoid blocking FOR UPDATE on multiple rows to prevent deadlock/starvation\n const firstJob = await this.pop(queue)\n return firstJob ? [firstJob] : []\n }\n }\n\n /**\n * Retrieves queue statistics by querying the table.\n *\n * @param queue - The queue name.\n */\n async stats(queue: string): Promise<QueueStats> {\n const failedQueue = `failed:${queue}`\n\n try {\n // Pending: available now and not reserved\n const pendingRes = (await this.dbService.execute<{ count: number }>(\n `SELECT COUNT(*) as count FROM ${this.tableName} WHERE queue = $1 AND available_at <= NOW() AND reserved_at IS NULL`,\n [queue]\n )) as any[]\n\n // Delayed: available in future\n const delayedRes = (await this.dbService.execute<{ count: number }>(\n `SELECT COUNT(*) as count FROM ${this.tableName} WHERE queue = $1 AND available_at > NOW()`,\n [queue]\n )) as any[]\n\n // Reserved: currently in flight\n const reservedRes = (await this.dbService.execute<{ count: number }>(\n `SELECT COUNT(*) as count FROM ${this.tableName} WHERE queue = $1 AND reserved_at IS NOT NULL`,\n [queue]\n )) as any[]\n\n // Failed\n const failedRes = (await this.dbService.execute<{ count: number }>(\n `SELECT COUNT(*) as count FROM ${this.tableName} WHERE queue = $1`,\n [failedQueue]\n )) as any[]\n\n return {\n queue,\n size: pendingRes[0]?.count || 0,\n delayed: delayedRes[0]?.count || 0,\n reserved: reservedRes[0]?.count || 0,\n failed: failedRes[0]?.count || 0,\n }\n } catch (err) {\n console.error('[DatabaseDriver] Failed to get stats:', err)\n return { queue, size: 0, delayed: 0, reserved: 0, failed: 0 }\n }\n }\n\n /**\n * Returns the count of pending jobs.\n *\n * @param queue - The queue name.\n */\n async size(queue: string): Promise<number> {\n const result = (await this.dbService.execute<{ count: number }>(\n `SELECT COUNT(*) as count\n FROM ${this.tableName}\n WHERE queue = $1\n AND available_at <= NOW()\n AND (reserved_at IS NULL OR reserved_at < NOW() - INTERVAL '5 minutes')`,\n [queue]\n )) as { count: number }[]\n\n return result?.[0]?.count ?? 0\n }\n\n /**\n * Clears the queue by deleting all rows for the queue.\n *\n * @param queue - The queue name.\n */\n async clear(queue: string): Promise<void> {\n await this.dbService.execute(`DELETE FROM ${this.tableName} WHERE queue = $1`, [queue])\n }\n\n /**\n * Pops a job using a polling loop (Blocking simulation).\n *\n * @param queue - The queue name.\n * @param timeout - Timeout in seconds.\n */\n async popBlocking(queue: string, timeout: number): Promise<SerializedJob | null> {\n const start = Date.now()\n const timeoutMs = timeout * 1000\n\n while (true) {\n const job = await this.pop(queue)\n if (job) {\n return job\n }\n\n if (timeout > 0 && Date.now() - start >= timeoutMs) {\n return null\n }\n\n // Wait 1 second before next poll\n await new Promise((resolve) => setTimeout(resolve, 1000))\n }\n }\n\n /**\n * Pushes multiple jobs using a transaction.\n *\n * @param queue - The queue name.\n * @param jobs - Array of jobs.\n */\n async pushMany(queue: string, jobs: SerializedJob[]): Promise<void> {\n if (jobs.length === 0) {\n return\n }\n\n // For database drivers, multi-row INSERT is significantly faster\n // Constructing query manually for generality (assuming standard (?,?) or ($1,$2) syntax)\n // Note: DatabaseService provider handles the actual dialect.\n\n await this.dbService.transaction(async (tx) => {\n for (let i = 0; i < jobs.length; i += 100) {\n const batch = jobs.slice(i, i + 100)\n // Note: Generic multi-row insert is hard without knowing Dialect.\n // Falling back to individual inserts within a transaction for safety,\n // but it's already a batch because of the transaction.\n for (const job of batch) {\n const availableAt = job.delaySeconds\n ? new Date(Date.now() + job.delaySeconds * 1000)\n : new Date()\n\n const payload = JSON.stringify(job)\n await tx.execute(\n `INSERT INTO ${this.tableName} (queue, payload, attempts, available_at, created_at)\n VALUES ($1, $2, $3, $4, $5)`,\n [queue, payload, job.attempts ?? 0, availableAt.toISOString(), new Date().toISOString()]\n )\n }\n }\n })\n }\n\n /**\n * Marks a job as permanently failed by moving it to the DLQ (separate logical queue in DB).\n *\n * @param queue - The queue name.\n * @param job - The failed job.\n */\n async fail(queue: string, job: SerializedJob): Promise<void> {\n const failedQueue = `failed:${queue}`\n const payload = JSON.stringify(job)\n\n await this.dbService.execute(\n `INSERT INTO ${this.tableName} (queue, payload, attempts, available_at, created_at)\n VALUES ($1, $2, $3, $4, $5)`,\n [failedQueue, payload, job.attempts, new Date().toISOString(), new Date().toISOString()]\n )\n }\n\n /**\n * Deletes a job row from the database (completion).\n *\n * @param _queue - The queue name (unused).\n * @param job - The job to complete.\n */\n async complete(_queue: string, job: SerializedJob): Promise<void> {\n if (!job.id) {\n return\n }\n await this.dbService.execute(`DELETE FROM ${this.tableName} WHERE id = $1`, [job.id])\n }\n}\n",
8
+ "import type { SerializedJob, TopicOptions } from '../types'\nimport type { QueueDriver } from './QueueDriver'\n\n/**\n * Kafka driver configuration.\n */\nexport interface KafkaDriverConfig {\n /**\n * Kafka client instance (kafkajs).\n *\n * Must provide producer, admin, and consumer factories compatible with KafkaJS.\n */\n client: {\n producer: () => {\n connect: () => Promise<void>\n send: (args: {\n topic: string\n messages: Array<{ key?: string; value: string }>\n }) => Promise<void>\n disconnect: () => Promise<void>\n }\n admin: () => {\n connect: () => Promise<void>\n createTopics: (args: {\n topics: Array<{ topic: string; numPartitions?: number; replicationFactor?: number }>\n }) => Promise<void>\n deleteTopics: (args: { topics: string[] }) => Promise<void>\n disconnect: () => Promise<void>\n }\n consumer: (args: { groupId: string }) => {\n connect: () => Promise<void>\n subscribe: (args: { topics: string[] }) => Promise<void>\n run: (args: {\n eachMessage: (args: {\n topic: string\n partition: number\n message: { key?: Buffer; value: Buffer; offset: string }\n }) => Promise<void>\n }) => Promise<void>\n disconnect: () => Promise<void>\n }\n }\n\n /**\n * Consumer group ID used for reading messages.\n * @default 'gravito-workers'\n */\n consumerGroupId?: string\n}\n\n/**\n * Kafka-backed queue driver.\n *\n * Uses Apache Kafka topics as queues. Designed for high-throughput streaming\n * rather than traditional job queue semantics (pop/delete).\n * Supports push-based consumption via `subscribe()`.\n *\n * @public\n * @example\n * ```typescript\n * const driver = new KafkaDriver({ client: kafka, consumerGroupId: 'my-app' });\n * ```\n */\nexport class KafkaDriver implements QueueDriver {\n private client: KafkaDriverConfig['client']\n private consumerGroupId: string\n private producer?: ReturnType<KafkaDriverConfig['client']['producer']>\n private admin?: ReturnType<KafkaDriverConfig['client']['admin']>\n\n constructor(config: KafkaDriverConfig) {\n this.client = config.client\n this.consumerGroupId = config.consumerGroupId ?? 'gravito-workers'\n\n if (!this.client) {\n throw new Error('[KafkaDriver] Kafka client is required. Please install kafkajs package.')\n }\n }\n\n /**\n * Ensure the producer is connected.\n */\n private async ensureProducer(): Promise<ReturnType<KafkaDriverConfig['client']['producer']>> {\n if (!this.producer) {\n this.producer = this.client.producer()\n await this.producer.connect()\n }\n return this.producer\n }\n\n /**\n * Ensure the admin client is connected.\n */\n private async ensureAdmin(): Promise<ReturnType<KafkaDriverConfig['client']['admin']>> {\n if (!this.admin) {\n this.admin = this.client.admin()\n await this.admin.connect()\n }\n return this.admin\n }\n\n /**\n * Pushes a job to a Kafka topic.\n *\n * @param queue - The topic name.\n * @param job - The job to publish.\n */\n async push(queue: string, job: SerializedJob): Promise<void> {\n const producer = await this.ensureProducer()\n const payload = JSON.stringify({\n id: job.id,\n type: job.type,\n data: job.data,\n className: job.className,\n createdAt: job.createdAt,\n delaySeconds: job.delaySeconds,\n attempts: job.attempts,\n maxAttempts: job.maxAttempts,\n })\n\n await producer.send({\n topic: queue,\n messages: [\n {\n key: job.id,\n value: payload,\n },\n ],\n })\n }\n\n /**\n * Pop is not supported for Kafka (Push-based).\n *\n * Kafka consumers typically stream messages. Use `subscribe()` instead.\n *\n * @throws {Error} Always throws as Kafka does not support polling individual messages in this manner.\n */\n async pop(_queue: string): Promise<SerializedJob | null> {\n // Kafka is push-based; use subscribe() instead.\n throw new Error('[KafkaDriver] Kafka uses push-based model. Use subscribe() instead of pop().')\n }\n\n /**\n * Returns 0 as Kafka does not expose a simple \"queue size\".\n *\n * Monitoring lag requires external tools or Admin API checks not implemented here.\n */\n async size(_queue: string): Promise<number> {\n // Kafka does not directly support queue size.\n return 0\n }\n\n /**\n * Clears a queue by deleting the topic.\n *\n * @param queue - The topic name.\n */\n async clear(queue: string): Promise<void> {\n const admin = await this.ensureAdmin()\n await admin.deleteTopics({ topics: [queue] })\n }\n\n /**\n * Pushes multiple jobs to a Kafka topic.\n *\n * @param queue - The topic name.\n * @param jobs - Array of jobs.\n */\n async pushMany(queue: string, jobs: SerializedJob[]): Promise<void> {\n if (jobs.length === 0) {\n return\n }\n\n const producer = await this.ensureProducer()\n const messages = jobs.map((job) => {\n const payload = JSON.stringify({\n id: job.id,\n type: job.type,\n data: job.data,\n className: job.className,\n createdAt: job.createdAt,\n delaySeconds: job.delaySeconds,\n attempts: job.attempts,\n maxAttempts: job.maxAttempts,\n })\n\n return {\n key: job.id,\n value: payload,\n }\n })\n\n await producer.send({\n topic: queue,\n messages,\n })\n }\n\n /**\n * Creates a new Kafka topic.\n *\n * @param topic - The topic name.\n * @param options - Config for partitions/replication.\n */\n async createTopic(topic: string, options?: TopicOptions): Promise<void> {\n const admin = await this.ensureAdmin()\n await admin.createTopics({\n topics: [\n {\n topic,\n numPartitions: options?.partitions ?? 1,\n replicationFactor: options?.replicationFactor ?? 1,\n },\n ],\n })\n }\n\n /**\n * Deletes a Kafka topic.\n *\n * @param topic - The topic name.\n */\n async deleteTopic(topic: string): Promise<void> {\n await this.clear(topic)\n }\n\n /**\n * Subscribes to a topic for streaming jobs.\n *\n * Starts a Kafka consumer group and processes messages as they arrive.\n *\n * @param queue - The topic name.\n * @param callback - Function to handle the job.\n */\n async subscribe(queue: string, callback: (job: SerializedJob) => Promise<void>): Promise<void> {\n const consumer = this.client.consumer({ groupId: this.consumerGroupId })\n await consumer.connect()\n await consumer.subscribe({ topics: [queue] })\n\n await consumer.run({\n eachBatch: async ({ batch, resolveOffset, heartbeat, isRunning }: any) => {\n for (const message of batch.messages) {\n if (!isRunning() || !message.value) {\n continue\n }\n\n try {\n const payload = JSON.parse(message.value.toString())\n const job: SerializedJob = {\n id: payload.id,\n type: payload.type,\n data: payload.data,\n className: payload.className,\n createdAt: payload.createdAt,\n delaySeconds: payload.delaySeconds,\n attempts: payload.attempts,\n maxAttempts: payload.maxAttempts,\n }\n\n await callback(job)\n resolveOffset(message.offset)\n await heartbeat()\n } catch (error) {\n console.error('[KafkaDriver] Error processing message:', error)\n }\n }\n },\n } as any)\n }\n}\n",
9
+ "import type { SerializedJob } from '../types'\n\n/**\n * Prepares a job for transport by converting Uint8Array data to Base64 string.\n *\n * This ensures safe JSON serialization across all drivers (Redis, RabbitMQ, SQS, Database).\n *\n * @param job - The serialized job to prepare for transport.\n * @returns Job with data in transportable format (string for binary/msgpack types).\n */\nexport function prepareJobForTransport(job: SerializedJob): SerializedJob {\n if ((job.type === 'binary' || job.type === 'msgpack') && job.data instanceof Uint8Array) {\n // Convert Uint8Array to Base64 string for safe JSON transport\n const base64 = Buffer.from(job.data).toString('base64')\n return {\n ...job,\n data: base64,\n }\n }\n\n return job\n}\n",
10
+ "import type { SerializedJob } from '../types'\nimport { prepareJobForTransport } from './prepareJobForTransport'\nimport type { QueueDriver } from './QueueDriver'\n\n/**\n * RabbitMQ driver configuration.\n */\nexport interface RabbitMQDriverConfig {\n /**\n * RabbitMQ client (amqplib) Connection or Channel.\n * If a Connection is provided, the driver will create and manage a Channel.\n */\n client: any\n\n /**\n * Exchange name (optional).\n */\n exchange?: string\n\n /**\n * Exchange type (default: 'fanout').\n */\n exchangeType?: 'direct' | 'topic' | 'headers' | 'fanout' | 'match'\n}\n\n/**\n * RabbitMQ (AMQP) queue driver.\n *\n * Uses RabbitMQ as the backend. Supports standard AMQP queues, exchanges,\n * and reliable message acknowledgements.\n *\n * @public\n * @example\n * ```typescript\n * import amqp from 'amqplib';\n * const conn = await amqp.connect('amqp://localhost');\n * const driver = new RabbitMQDriver({ client: conn });\n * ```\n */\nexport class RabbitMQDriver implements QueueDriver {\n private connection: any\n private channel: any\n private exchange?: string\n private exchangeType: string\n\n constructor(config: RabbitMQDriverConfig) {\n this.connection = config.client\n this.exchange = config.exchange\n this.exchangeType = config.exchangeType ?? 'fanout'\n\n if (!this.connection) {\n throw new Error(\n '[RabbitMQDriver] RabbitMQ connection is required. Please provide a connection from amqplib.'\n )\n }\n }\n\n /**\n * Ensure channel is created.\n */\n public async ensureChannel(): Promise<any> {\n if (this.channel) {\n return this.channel\n }\n\n // If client is a connection, create channel\n if (typeof this.connection.createChannel === 'function') {\n this.channel = await this.connection.createChannel()\n } else {\n // Assume client is already a channel\n this.channel = this.connection\n }\n\n if (this.exchange) {\n await this.channel.assertExchange(this.exchange, this.exchangeType, { durable: true })\n }\n\n return this.channel\n }\n\n /**\n * Get the underlying connection.\n */\n public getRawConnection() {\n return this.connection\n }\n\n /**\n * Pushes a job to a RabbitMQ queue or exchange.\n *\n * @param queue - The queue name.\n * @param job - The serialized job.\n */\n async push(queue: string, job: SerializedJob): Promise<void> {\n const channel = await this.ensureChannel()\n const jobForTransport = prepareJobForTransport(job)\n const payload = Buffer.from(JSON.stringify(jobForTransport))\n\n if (this.exchange) {\n await channel.assertQueue(queue, { durable: true })\n await channel.bindQueue(queue, this.exchange, '')\n channel.publish(this.exchange, '', payload, { persistent: true })\n } else {\n await channel.assertQueue(queue, { durable: true })\n channel.sendToQueue(queue, payload, { persistent: true })\n }\n }\n\n /**\n * Pops a job from the queue.\n *\n * @param queue - The queue name.\n */\n async pop(queue: string): Promise<SerializedJob | null> {\n const channel = await this.ensureChannel()\n await channel.assertQueue(queue, { durable: true })\n const msg = await channel.get(queue, { noAck: false })\n if (!msg) {\n return null\n }\n\n const job = JSON.parse(msg.content.toString()) as SerializedJob\n // Attach raw message for acknowledgement if needed\n // Note: We use a Symbol or internal property to avoid leaking to serialization\n ;(job as any)._raw = msg\n\n return job\n }\n\n /**\n * Pops multiple jobs.\n *\n * @param queue - The queue name.\n * @param count - Max jobs.\n */\n async popMany(queue: string, count: number): Promise<SerializedJob[]> {\n const channel = await this.ensureChannel()\n await channel.assertQueue(queue, { durable: true })\n\n const results: SerializedJob[] = []\n\n // Attempt to get 'count' messages\n for (let i = 0; i < count; i++) {\n const msg = await channel.get(queue, { noAck: false })\n if (!msg) {\n break // Queue empty\n }\n\n const job = JSON.parse(msg.content.toString()) as SerializedJob\n ;(job as any)._raw = msg\n results.push(job)\n }\n\n return results\n }\n\n /**\n * Acknowledges a message.\n *\n * @param messageId - The message object (RabbitMQ requires object reference).\n */\n async acknowledge(messageId: string): Promise<void> {\n // Note: RabbitMQ acks by message object, not ID in amqplib.\n // However, our QueueDriver interface uses messageId.\n // In our implementation, we'll expect the caller to pass the raw msg as messageId\n // or we might need to adjust the interface/implementation.\n // For now, if messageId is the raw message object:\n const channel = await this.ensureChannel()\n if (typeof messageId === 'object') {\n channel.ack(messageId)\n }\n }\n\n /**\n * Negative acknowledge a message.\n */\n async nack(message: any, requeue = true): Promise<void> {\n const channel = await this.ensureChannel()\n channel.nack(message, false, requeue)\n }\n\n /**\n * Reject a message.\n */\n async reject(message: any, requeue = true): Promise<void> {\n const channel = await this.ensureChannel()\n channel.reject(message, requeue)\n }\n\n /**\n * Subscribes to a queue.\n */\n async subscribe(\n queue: string,\n callback: (job: SerializedJob) => Promise<void>,\n options: { autoAck?: boolean; prefetch?: number } = {}\n ): Promise<void> {\n const channel = await this.ensureChannel()\n await channel.assertQueue(queue, { durable: true })\n\n if (options.prefetch) {\n await channel.prefetch(options.prefetch)\n }\n\n if (this.exchange) {\n await channel.bindQueue(queue, this.exchange, '')\n }\n\n const { autoAck = true } = options\n\n await channel.consume(\n queue,\n async (msg: any) => {\n if (!msg) {\n return\n }\n\n const job = JSON.parse(msg.content.toString()) as SerializedJob\n // Attach raw message for manual control\n ;(job as any)._raw = msg\n\n await callback(job)\n\n if (autoAck) {\n channel.ack(msg)\n }\n },\n { noAck: false }\n )\n }\n\n /**\n * Returns the number of messages in the queue.\n *\n * @param queue - The queue name.\n */\n async size(queue: string): Promise<number> {\n const channel = await this.ensureChannel()\n const ok = await channel.checkQueue(queue)\n return ok.messageCount\n }\n\n /**\n * Purges the queue.\n *\n * @param queue - The queue name.\n */\n async clear(queue: string): Promise<void> {\n const channel = await this.ensureChannel()\n await channel.purgeQueue(queue)\n }\n}\n",
11
+ "import type { JobPushOptions, QueueStats, SerializedJob } from '../types'\nimport { decodeBinaryJobFrame, encodeBinaryJobFrame, isGravitoJobFrame } from './BinaryJobFrame'\nimport { prepareJobForTransport } from './prepareJobForTransport'\nimport type { QueueDriver } from './QueueDriver'\n\n/**\n * Interface for Redis clients (compatible with ioredis and node-redis).\n */\nexport interface RedisClient {\n lpush(key: string, ...values: string[]): Promise<number>\n rpop(key: string, count?: number): Promise<string | string[] | null>\n llen(key: string): Promise<number>\n del(key: string, ...keys: string[]): Promise<number>\n lpushx?(key: string, ...values: string[]): Promise<number>\n rpoplpush?(src: string, dst: string): Promise<string | null>\n zadd?(key: string, score: number, member: string): Promise<number>\n zrange?(key: string, start: number, end: number, ...args: string[]): Promise<string[]>\n zrem?(key: string, ...members: string[]): Promise<number>\n get?(key: string): Promise<string | null>\n set?(key: string, value: string, ...args: any[]): Promise<'OK' | null>\n ltrim?(key: string, start: number, stop: number): Promise<'OK'>\n lrange?(key: string, start: number, stop: number): Promise<string[]>\n publish?(channel: string, message: string): Promise<number>\n pipeline?(): any\n defineCommand?(name: string, options: { numberOfKeys: number; lua: string }): void\n incr?(key: string): Promise<number>\n expire?(key: string, seconds: number): Promise<number>\n eval(script: string, numKeys: number, ...args: (string | number)[]): Promise<any>\n\n /**\n * Binary-capable RPOP(ioredis Buffer mode)\n * 回傳 Buffer 而非 string,支援 binary frame 的零拷貝讀取\n */\n rpopBuffer?(key: string, count?: number): Promise<Buffer | Buffer[] | null>\n\n /**\n * Binary-capable BRPOP(ioredis Buffer mode)\n * 支援 blocking pop 的 binary frame 讀取\n */\n brpopBuffer?(...args: any[]): Promise<[Buffer, Buffer] | null>\n\n /**\n * Binary-capable LRANGE(ioredis Buffer mode)\n * 用於從 DLQ 讀取 binary frame\n */\n lrangeBuffer?(key: string, start: number, stop: number): Promise<Buffer[]>\n\n /**\n * Binary-capable LPUSH(接受 Buffer)\n * 用於將 binary frame 寫入 Redis list\n */\n lpushBuffer?(key: string, ...values: Buffer[]): Promise<number>\n\n [key: string]: any\n}\n\n/**\n * Extended Redis client with custom commands.\n */\nexport interface CustomRedisClient extends RedisClient {\n pushGroupJob(\n waitList: string,\n activeSet: string,\n pendingList: string,\n groupId: string,\n payload: string\n ): Promise<number>\n completeGroupJob(\n waitList: string,\n activeSet: string,\n pendingList: string,\n groupId: string\n ): Promise<number>\n popMany(queue: string, prefix: string, count: number, now: string): Promise<string[]>\n}\n\n/**\n * Extended Redis client with custom group commands (Legacy name).\n */\nexport type GroupRedisClient = CustomRedisClient\n\n/**\n * Redis driver configuration.\n */\nexport interface RedisDriverConfig {\n /**\n * Redis client instance (ioredis or node-redis).\n */\n client: RedisClient\n\n /**\n * Key prefix (default: `queue:`).\n */\n prefix?: string\n}\n\n/**\n * High-performance Redis queue driver.\n *\n * Implements FIFO queues using Redis Lists, reliable priority support, delayed jobs via Sorted Sets,\n * and rate limiting. Uses Lua scripts for atomic operations and advanced features like\n * group-based sequential processing.\n *\n * 支援 binary frame 格式:\n * - push/pushMany:type === 'binary' 且 data instanceof Uint8Array 時,使用 BinaryJobFrame 格式\n * - pop/popMany:透過 magic byte 嗅探自動偵測格式(binary frame 或 JSON)\n *\n * @public\n * @example\n * ```typescript\n * import Redis from 'ioredis';\n * const redis = new Redis();\n * const driver = new RedisDriver({ client: redis });\n * ```\n */\nexport class RedisDriver implements QueueDriver {\n private prefix: string\n private client: CustomRedisClient\n\n // Lua Logic:\n // IF (IS_MEMBER(activeSet, groupId)) -> PUSH(pendingList, job)\n // ELSE -> SADD(activeSet, groupId) & LPUSH(waitList, job)\n private static PUSH_SCRIPT = `\n local waitList = KEYS[1]\n local activeSet = KEYS[2]\n local pendingList = KEYS[3]\n local groupId = ARGV[1]\n local payload = ARGV[2]\n\n if redis.call('SISMEMBER', activeSet, groupId) == 1 then\n return redis.call('RPUSH', pendingList, payload)\n else\n redis.call('SADD', activeSet, groupId)\n return redis.call('LPUSH', waitList, payload)\n end\n `\n\n // Lua Logic:\n // local next = LPOP(pendingList)\n // IF (next) -> LPUSH(waitList, next)\n // ELSE -> SREM(activeSet, groupId)\n private static COMPLETE_SCRIPT = `\n local waitList = KEYS[1]\n local activeSet = KEYS[2]\n local pendingList = KEYS[3]\n local groupId = ARGV[1]\n\n local nextJob = redis.call('LPOP', pendingList)\n if nextJob then\n return redis.call('LPUSH', waitList, nextJob)\n else\n return redis.call('SREM', activeSet, groupId)\n end\n `\n\n // Lua Logic:\n // Iterate priorities.\n // Check delayed.\n // Check paused.\n // RPOP count.\n private static POP_MANY_SCRIPT = `\n local queue = KEYS[1]\n local prefix = ARGV[1]\n local count = tonumber(ARGV[2])\n local now = tonumber(ARGV[3])\n\n local priorities = {'critical', 'high', 'default', 'low'}\n local result = {}\n\n for _, priority in ipairs(priorities) do\n if #result >= count then break end\n\n local key = prefix .. queue\n if priority ~= 'default' then\n key = key .. ':' .. priority\n end\n\n -- Check Delayed (Move to Ready if due)\n local delayKey = key .. \":delayed\"\n -- Optimization: Only check delayed if we need more items\n -- Fetch up to (count - #result) delayed items\n local needed = count - #result\n local delayed = redis.call(\"ZRANGEBYSCORE\", delayKey, 0, now, \"LIMIT\", 0, needed)\n\n for _, job in ipairs(delayed) do\n redis.call(\"ZREM\", delayKey, job)\n -- We return it directly, assuming we want to process it now.\n -- Alternative: LPUSH to list and RPOP? No, direct return is faster.\n table.insert(result, job)\n needed = needed - 1\n end\n\n if #result >= count then break end\n\n -- Check Paused\n local isPaused = redis.call(\"GET\", key .. \":paused\")\n if isPaused ~= \"1\" then\n needed = count - #result\n -- Loop RPOP to get items\n for i = 1, needed do\n local job = redis.call(\"RPOP\", key)\n if job then\n table.insert(result, job)\n else\n break\n end\n end\n end\n end\n\n return result\n `\n\n constructor(config: RedisDriverConfig) {\n this.client = config.client as CustomRedisClient\n this.prefix = config.prefix ?? 'queue:'\n\n if (!this.client) {\n throw new Error(\n '[RedisDriver] Redis client is required. Please install ioredis or redis package.'\n )\n }\n\n // Register Lua scripts if defineCommand is available (ioredis)\n if (typeof this.client.defineCommand === 'function') {\n this.client.defineCommand('pushGroupJob', {\n numberOfKeys: 3,\n lua: RedisDriver.PUSH_SCRIPT,\n })\n this.client.defineCommand('completeGroupJob', {\n numberOfKeys: 3,\n lua: RedisDriver.COMPLETE_SCRIPT,\n })\n this.client.defineCommand('popMany', {\n numberOfKeys: 1,\n lua: RedisDriver.POP_MANY_SCRIPT,\n })\n }\n }\n\n /**\n * Get full Redis key for a queue.\n */\n private getKey(queue: string, priority?: string | number): string {\n if (priority) {\n return `${this.prefix}${queue}:${priority}`\n }\n return `${this.prefix}${queue}`\n }\n\n /**\n * 判斷 job 是否應使用 binary frame 格式傳輸\n *\n * 當 type === 'binary' 且 data 為 Uint8Array 時啟用 binary path\n */\n private isBinaryJob(job: SerializedJob): boolean {\n return job.type === 'binary' && job.data instanceof Uint8Array\n }\n\n /**\n * 序列化 Job 為適合 Redis 儲存的格式\n *\n * Binary path:使用 BinaryJobFrame 格式(Uint8Array → Buffer)\n * Legacy path:使用 JSON.stringify(string)\n *\n * @returns Buffer(binary path)或 string(legacy path)\n */\n private serializeJobForTransport(\n job: SerializedJob,\n groupId?: string\n ): { isBinary: true; buffer: Buffer } | { isBinary: false; payload: string } {\n // Binary path:job.type === 'binary' 且 data 是 Uint8Array\n if (this.isBinaryJob(job)) {\n // 若 groupId 來自 options,加入 job 中\n const jobWithGroup = groupId ? { ...job, groupId } : job\n const frame = encodeBinaryJobFrame(jobWithGroup)\n return { isBinary: true, buffer: Buffer.from(frame) }\n }\n\n // Legacy path:JSON 序列化\n const jobForTransport = prepareJobForTransport(job)\n const payloadObj = {\n id: jobForTransport.id,\n type: jobForTransport.type,\n data: jobForTransport.data,\n className: job.className,\n createdAt: job.createdAt,\n delaySeconds: job.delaySeconds,\n attempts: job.attempts,\n maxAttempts: job.maxAttempts,\n groupId: groupId ?? job.groupId,\n error: job.error,\n failedAt: job.failedAt,\n }\n return { isBinary: false, payload: JSON.stringify(payloadObj) }\n }\n\n /**\n * 自動偵測並解析 Redis payload 格式\n *\n * 1. 若輸入為 Buffer/Uint8Array 且以 Magic bytes 開頭 → 使用 BinaryJobFrame 解碼\n * 2. 否則 → 使用 JSON.parse(legacy path)\n *\n * @param payload - Redis 回傳的資料(string 或 Buffer)\n * @returns 解析後的 SerializedJob\n */\n private parsePayloadAuto(payload: string | Buffer): SerializedJob {\n // Binary frame 偵測:Buffer 類型且以 Magic bytes 開頭\n if (Buffer.isBuffer(payload)) {\n if (isGravitoJobFrame(payload)) {\n return decodeBinaryJobFrame(payload)\n }\n // 非 binary frame 的 Buffer:嘗試轉為字串後 JSON 解析\n return this.parseJsonPayload(payload.toString('utf8'))\n }\n\n // 字串類型:直接 JSON 解析\n return this.parseJsonPayload(payload)\n }\n\n /**\n * 解析 JSON 格式的 payload(legacy path)\n */\n private parseJsonPayload(payload: string): SerializedJob {\n const parsed = JSON.parse(payload)\n return {\n id: parsed.id,\n type: parsed.type,\n data: parsed.data,\n className: parsed.className,\n createdAt: parsed.createdAt,\n delaySeconds: parsed.delaySeconds,\n attempts: parsed.attempts,\n maxAttempts: parsed.maxAttempts,\n groupId: parsed.groupId,\n error: parsed.error,\n failedAt: parsed.failedAt,\n priority: parsed.priority,\n }\n }\n\n /**\n * Pushes a job to Redis.\n *\n * 支援 binary path 和 legacy path:\n * - Binary path:job.type === 'binary' 且 data instanceof Uint8Array → 使用 BinaryJobFrame\n * - Legacy path:其他格式 → 使用 JSON.stringify\n *\n * @param queue - The queue name.\n * @param job - The serialized job.\n * @param options - Push options.\n */\n async push(queue: string, job: SerializedJob, options?: JobPushOptions): Promise<void> {\n const key = this.getKey(queue, options?.priority)\n const groupId = options?.groupId\n\n if (typeof this.client.sadd === 'function') {\n await this.client.sadd(`${this.prefix}queues`, queue)\n }\n\n // Handle Group FIFO logic(只支援 legacy path,因為 Lua script 接受 string)\n if (groupId && typeof this.client.pushGroupJob === 'function') {\n const activeSetKey = `${this.prefix}active`\n const pendingListKey = `${this.prefix}pending:${groupId}`\n\n // Group FIFO 目前只支援 JSON(Lua script 接受 string payload)\n // Binary job 若有 groupId,改走一般 binary push(不使用 Lua)\n if (this.isBinaryJob(job)) {\n const { buffer } = this.serializeJobForTransport(job, groupId) as {\n isBinary: true\n buffer: Buffer\n }\n // 使用 lpushBuffer 若可用,否則用一般 lpush(string)\n if (typeof this.client.lpushBuffer === 'function') {\n await this.client.lpushBuffer(key, buffer)\n } else {\n // 降級:binary frame 轉為 base64 string 存入 JSON\n const base64 = buffer.toString('base64')\n const legacyPayload = JSON.stringify({\n __binaryFrame: true,\n data: base64,\n })\n await this.client.lpush(key, legacyPayload)\n }\n return\n }\n\n // Legacy path 走 Lua\n const { payload } = this.serializeJobForTransport(job, groupId) as {\n isBinary: false\n payload: string\n }\n await this.client.pushGroupJob(key, activeSetKey, pendingListKey, groupId, payload)\n return\n }\n\n // Binary path:直接 push Buffer\n if (this.isBinaryJob(job)) {\n const serialized = this.serializeJobForTransport(job, groupId)\n if (serialized.isBinary) {\n // For delayed binary jobs\n if (job.delaySeconds && job.delaySeconds > 0) {\n const delayKey = `${key}:delayed`\n const score = Date.now() + job.delaySeconds * 1000\n if (typeof this.client.zadd === 'function') {\n // ZADD 不支援 Buffer,將 binary frame 轉為 base64 存入 ZSET member\n await this.client.zadd(delayKey, score, serialized.buffer.toString('base64'))\n } else {\n if (typeof this.client.lpushBuffer === 'function') {\n await this.client.lpushBuffer(key, serialized.buffer)\n } else {\n await this.client.lpush(key, serialized.buffer.toString('base64'))\n }\n }\n } else {\n if (typeof this.client.lpushBuffer === 'function') {\n await this.client.lpushBuffer(key, serialized.buffer)\n } else {\n // 降級:以 base64 存入(decode 時需要特別處理)\n await this.client.lpush(key, serialized.buffer.toString('base64'))\n }\n }\n return\n }\n }\n\n // Legacy path\n const serialized = this.serializeJobForTransport(job, groupId)\n if (serialized.isBinary) {\n // 不應到達這裡,但作保護\n await this.client.lpush(key, serialized.buffer.toString('base64'))\n return\n }\n\n const payload = serialized.payload\n\n // For delayed jobs, prefer Sorted Sets (ZADD) when supported\n if (job.delaySeconds && job.delaySeconds > 0) {\n const delayKey = `${key}:delayed`\n const score = Date.now() + job.delaySeconds * 1000\n if (typeof this.client.zadd === 'function') {\n await this.client.zadd(delayKey, score, payload)\n } else {\n // Fallback: push directly (no delay support)\n await this.client.lpush(key, payload)\n }\n } else {\n await this.client.lpush(key, payload)\n }\n }\n\n /**\n * Completes a job.\n *\n * Crucial for Group FIFO logic to unlock the next job in the group.\n *\n * @param queue - The queue name.\n * @param job - The job to complete.\n */\n async complete(queue: string, job: SerializedJob): Promise<void> {\n if (!job.groupId) {\n return // Not a grouped job\n }\n\n const key = this.getKey(queue)\n const activeSetKey = `${this.prefix}active`\n const pendingListKey = `${this.prefix}pending:${job.groupId}`\n\n if (typeof this.client.completeGroupJob === 'function') {\n await this.client.completeGroupJob(key, activeSetKey, pendingListKey, job.groupId)\n }\n }\n\n /**\n * Pops a job from the queue.\n *\n * 支援 binary frame 自動偵測:\n * - 若 client 支援 rpopBuffer → 嘗試讀取 Buffer 並用 magic byte 判斷格式\n * - 否則降級為 string rpop,使用 parsePayloadAuto 解析\n *\n * @param queue - The queue name.\n * @returns The job or `null`.\n */\n async pop(queue: string): Promise<SerializedJob | null> {\n const priorities = ['critical', 'high', 'default', 'low']\n const keys: string[] = []\n\n for (const p of priorities) {\n keys.push(this.getKey(queue, p === 'default' ? undefined : p))\n }\n\n const script = `\n local now = tonumber(ARGV[1])\n for i, key in ipairs(KEYS) do\n -- 1. Check delayed\n local delayKey = key .. \":delayed\"\n local delayed = redis.call(\"ZRANGEBYSCORE\", delayKey, 0, now, \"LIMIT\", 0, 1)\n if delayed[1] then\n redis.call(\"ZREM\", delayKey, delayed[1])\n return {key, delayed[1]}\n end\n\n -- 2. Check paused\n local isPaused = redis.call(\"GET\", key .. \":paused\")\n if isPaused ~= \"1\" then\n -- 3. RPOP\n local payload = redis.call(\"RPOP\", key)\n if payload then\n return {key, payload}\n end\n end\n end\n return nil\n `\n\n try {\n const result = await this.client.eval(script, keys.length, ...keys, Date.now().toString())\n\n if (result?.[1]) {\n return this.parsePayloadAuto(result[1])\n }\n } catch (_err) {\n // Fallback to manual loop if script fails\n return this.popManualFallback(queue)\n }\n\n return null\n }\n\n /**\n * Manual fallback for pop if Lua fails.\n *\n * 優先使用 rpopBuffer 取得 binary frame,否則降級為 string\n */\n private async popManualFallback(queue: string): Promise<SerializedJob | null> {\n const priorities = ['critical', 'high', undefined, 'low']\n for (const priority of priorities) {\n const key = this.getKey(queue, priority)\n const delayKey = `${key}:delayed`\n\n const now = Date.now()\n const delayedJobs = await this.client.zrange?.(delayKey, 0, 0, 'WITHSCORES')\n if (delayedJobs && delayedJobs.length >= 2) {\n const score = parseFloat(delayedJobs[1]!)\n if (score <= now) {\n const payload = delayedJobs[0]!\n await this.client.zrem?.(delayKey, payload)\n return this.parsePayloadAuto(payload)\n }\n }\n\n const isPaused = await this.client.get?.(`${key}:paused`)\n if (isPaused === '1') {\n continue\n }\n\n // 優先使用 rpopBuffer(支援 binary frame)\n if (typeof this.client.rpopBuffer === 'function') {\n const bufPayload = await this.client.rpopBuffer(key)\n if (bufPayload) {\n return this.parsePayloadAuto(bufPayload as Buffer)\n }\n } else {\n const payload = await this.client.rpop(key)\n if (payload) {\n return this.parsePayloadAuto(payload as string)\n }\n }\n }\n return null\n }\n\n /**\n * Pops a job using blocking Redis commands (BRPOP).\n *\n * 支援 brpopBuffer 取得 binary frame,否則降級為 string\n *\n * @param queues - The queues to listen to.\n * @param timeout - Timeout in seconds.\n */\n async popBlocking(queues: string | string[], timeout: number): Promise<SerializedJob | null> {\n const queueList = Array.isArray(queues) ? queues : [queues]\n const priorities = ['critical', 'high', undefined, 'low']\n const keys: string[] = []\n\n for (const q of queueList) {\n for (const p of priorities) {\n keys.push(this.getKey(q, p))\n }\n }\n\n // 優先使用 brpopBuffer(支援 binary frame)\n if (typeof this.client.brpopBuffer === 'function') {\n try {\n const result = await this.client.brpopBuffer(...keys, timeout)\n if (result && Array.isArray(result) && result.length >= 2) {\n return this.parsePayloadAuto(result[1])\n }\n } catch (_e) {\n // Timeout or error\n }\n return null\n }\n\n if (typeof this.client.brpop !== 'function') {\n return this.pop(queueList[0]!)\n }\n\n try {\n const result = await this.client.brpop(...keys, timeout)\n if (result && Array.isArray(result) && result.length >= 2) {\n return this.parsePayloadAuto(result[1])\n }\n } catch (_e) {\n // Timeout or error\n }\n\n return null\n }\n\n /**\n * Returns the length of the queue (Redis List length).\n *\n * @param queue - The queue name.\n */\n async size(queue: string): Promise<number> {\n const key = this.getKey(queue)\n return this.client.llen(key)\n }\n\n /**\n * Marks a job as permanently failed by moving it to a DLQ list.\n *\n * 支援 binary path:binary job 使用 BinaryJobFrame 格式存入 DLQ\n *\n * @param queue - The queue name.\n * @param job - The failed job.\n */\n async fail(queue: string, job: SerializedJob): Promise<void> {\n const key = `${this.getKey(queue)}:failed`\n const failedJob: SerializedJob = { ...job, failedAt: Date.now() }\n\n if (this.isBinaryJob(failedJob) && failedJob.data instanceof Uint8Array) {\n // Binary path:使用 BinaryJobFrame 格式存入 DLQ\n const frame = encodeBinaryJobFrame(failedJob)\n const buffer = Buffer.from(frame)\n\n if (typeof this.client.lpushBuffer === 'function') {\n await this.client.lpushBuffer(key, buffer)\n } else {\n // 降級:以 base64 存入 legacy JSON 包裝\n await this.client.lpush(\n key,\n JSON.stringify({\n ...failedJob,\n data: Buffer.from(failedJob.data).toString('base64'),\n })\n )\n }\n } else {\n // Legacy path\n const payload = JSON.stringify(failedJob)\n await this.client.lpush(key, payload)\n }\n\n // Optional: Keep DLQ capped at 1000 items to avoid bloat\n if (typeof this.client.ltrim === 'function') {\n await this.client.ltrim(key, 0, 999)\n }\n }\n\n /**\n * Clears the queue and its associated delayed/active sets.\n *\n * @param queue - The queue name.\n */\n async clear(queue: string): Promise<void> {\n const key = this.getKey(queue)\n const delayKey = `${key}:delayed`\n const activeSetKey = `${this.prefix}active`\n\n await this.client.del(key)\n if (this.client.del) {\n await this.client.del(delayKey)\n await this.client.del(activeSetKey)\n }\n }\n\n /**\n * Retrieves full stats for the queue using Redis Pipelining.\n *\n * @param queue - The queue name.\n */\n async stats(queue: string): Promise<QueueStats> {\n const priorities = ['critical', 'high', 'default', 'low']\n const stats: QueueStats = {\n queue,\n size: 0,\n delayed: 0,\n failed: 0,\n }\n\n const keys: string[] = []\n for (const p of priorities) {\n keys.push(this.getKey(queue, p === 'default' ? undefined : p))\n }\n\n try {\n if (typeof this.client.pipeline === 'function') {\n const pipe = this.client.pipeline()\n for (const key of keys) {\n pipe.llen(key)\n pipe.zcard(`${key}:delayed`)\n }\n pipe.llen(`${this.getKey(queue)}:failed`)\n\n const results = await pipe.exec()\n if (results) {\n let i = 0\n for (const _p of priorities) {\n stats.size += (results[i][1] as number) || 0\n stats.delayed! += (results[i + 1][1] as number) || 0\n i += 2\n }\n stats.failed = (results[i][1] as number) || 0\n }\n } else {\n for (const key of keys) {\n stats.size += (await this.client.llen?.(key)) || 0\n stats.delayed! += (await this.client.zcard?.(`${key}:delayed`)) || 0\n }\n stats.failed = (await this.client.llen?.(`${this.getKey(queue)}:failed`)) || 0\n }\n } catch (_err) {\n // Stats 失敗不影響主流程\n }\n\n return stats\n }\n\n /**\n * Pushes multiple jobs to the queue.\n *\n * 批次 push 支援 binary path 和 legacy path 混合使用。\n * 對於含有 binary job 的批次,透過 pipeline 分批處理。\n *\n * @param queue - The queue name.\n * @param jobs - Array of jobs.\n */\n async pushMany(queue: string, jobs: SerializedJob[]): Promise<void> {\n if (jobs.length === 0) {\n return\n }\n\n const hasGroup = jobs.some((j) => j.groupId)\n const hasPriority = jobs.some((j) => (j as any).priority)\n\n if (hasGroup || hasPriority) {\n if (typeof this.client.pipeline === 'function') {\n const pipe = this.client.pipeline()\n for (const job of jobs) {\n const priority = (job as any).priority\n const key = this.getKey(queue, priority)\n const groupId = job.groupId\n\n if (this.isBinaryJob(job)) {\n // Binary path:使用 BinaryJobFrame\n const jobWithGroup = groupId ? { ...job, groupId } : job\n const frame = encodeBinaryJobFrame(jobWithGroup)\n const buffer = Buffer.from(frame)\n\n if (groupId) {\n // Binary group job 不走 Lua,直接 lpush\n // 注意:這會破壞嚴格 FIFO,但這是 binary group job 的限制\n if (typeof pipe.lpushBuffer === 'function') {\n pipe.lpushBuffer(key, buffer)\n } else {\n pipe.lpush(key, buffer.toString('base64'))\n }\n } else {\n if (job.delaySeconds && job.delaySeconds > 0) {\n const delayKey = `${key}:delayed`\n const score = Date.now() + job.delaySeconds * 1000\n pipe.zadd(delayKey, score, buffer.toString('base64'))\n } else if (typeof pipe.lpushBuffer === 'function') {\n pipe.lpushBuffer(key, buffer)\n } else {\n pipe.lpush(key, buffer.toString('base64'))\n }\n }\n } else {\n // Legacy path\n const jobForTransport = prepareJobForTransport(job)\n const payload = JSON.stringify({\n id: jobForTransport.id,\n type: jobForTransport.type,\n data: jobForTransport.data,\n className: job.className,\n createdAt: job.createdAt,\n delaySeconds: job.delaySeconds,\n attempts: job.attempts,\n maxAttempts: job.maxAttempts,\n groupId: groupId,\n priority: priority,\n error: job.error,\n failedAt: job.failedAt,\n })\n\n if (groupId && typeof pipe.pushGroupJob === 'function') {\n const activeSetKey = `${this.prefix}active`\n const pendingListKey = `${this.prefix}pending:${groupId}`\n pipe.pushGroupJob(key, activeSetKey, pendingListKey, groupId, payload)\n } else if (job.delaySeconds && job.delaySeconds > 0) {\n const delayKey = `${key}:delayed`\n const score = Date.now() + job.delaySeconds * 1000\n pipe.zadd(delayKey, score, payload)\n } else {\n pipe.lpush(key, payload)\n }\n }\n }\n await pipe.exec()\n return\n }\n\n // Fallback\n for (const job of jobs) {\n await this.push(queue, job, {\n groupId: job.groupId,\n priority: (job as any).priority,\n })\n }\n return\n }\n\n // 簡單批次(無 group 和 priority)\n const key = this.getKey(queue)\n\n // 分離 binary 和 legacy jobs\n const binaryJobs = jobs.filter((j) => this.isBinaryJob(j))\n const legacyJobs = jobs.filter((j) => !this.isBinaryJob(j))\n\n // Binary jobs:逐一 push(因為需要 Buffer API)\n if (binaryJobs.length > 0) {\n if (typeof this.client.lpushBuffer === 'function') {\n const buffers = binaryJobs.map((j) => Buffer.from(encodeBinaryJobFrame(j)))\n await this.client.lpushBuffer(key, ...buffers)\n } else {\n // 降級:sequential push\n for (const job of binaryJobs) {\n const frame = encodeBinaryJobFrame(job)\n await this.client.lpush(key, Buffer.from(frame).toString('base64'))\n }\n }\n }\n\n // Legacy jobs:batch push\n if (legacyJobs.length > 0) {\n const payloads = legacyJobs.map((job) => {\n const jobForTransport = prepareJobForTransport(job)\n return JSON.stringify({\n id: jobForTransport.id,\n type: jobForTransport.type,\n data: jobForTransport.data,\n className: job.className,\n createdAt: job.createdAt,\n delaySeconds: job.delaySeconds,\n attempts: job.attempts,\n maxAttempts: job.maxAttempts,\n groupId: job.groupId,\n priority: (job as any).priority,\n })\n })\n\n await this.client.lpush(key, ...payloads)\n }\n }\n\n /**\n * Pops multiple jobs from the queue.\n *\n * 支援 binary frame 自動偵測格式。\n *\n * @param queue - The queue name.\n * @param count - Max jobs to pop.\n */\n async popMany(queue: string, count: number): Promise<SerializedJob[]> {\n if (count <= 0) {\n return []\n }\n\n if (count === 1) {\n const job = await this.pop(queue)\n return job ? [job] : []\n }\n\n // Use Lua script for atomic batch pop across priorities\n if (typeof this.client.popMany === 'function') {\n try {\n const result = await this.client.popMany(queue, this.prefix, count, Date.now().toString())\n if (Array.isArray(result) && result.length > 0) {\n return result.map((p: string) => this.parsePayloadAuto(p))\n }\n if (Array.isArray(result)) {\n return result.map((p: string) => this.parsePayloadAuto(p))\n }\n } catch (_err) {\n // Fallback to manual loop\n }\n }\n\n const priorities = ['critical', 'high', 'default', 'low']\n const results: SerializedJob[] = []\n let remaining = count\n\n for (const priority of priorities) {\n if (remaining <= 0) {\n break\n }\n\n const key = this.getKey(queue, priority === 'default' ? undefined : priority)\n\n const isPaused = await this.client.get?.(`${key}:paused`)\n if (isPaused === '1') {\n continue\n }\n\n let fetched: Array<string | Buffer> = []\n\n // 優先使用 rpopBuffer(支援 binary frame)\n if (typeof this.client.rpopBuffer === 'function') {\n try {\n const reply = await this.client.rpopBuffer(key, remaining)\n if (reply) {\n fetched = Array.isArray(reply) ? reply : [reply]\n }\n } catch (_e) {\n // Fallback\n }\n } else {\n // 一般 string rpop\n try {\n const reply = await this.client.rpop(key, remaining)\n if (reply) {\n fetched = Array.isArray(reply) ? reply : [reply]\n }\n } catch (_e) {\n if (typeof this.client.pipeline === 'function') {\n const pipeline = this.client.pipeline()\n for (let i = 0; i < remaining; i++) {\n pipeline.rpop(key)\n }\n const replies = await pipeline.exec()\n if (replies) {\n fetched = replies.map((r: any) => r[1]).filter((r: any) => r !== null)\n }\n } else {\n for (let i = 0; i < remaining; i++) {\n const res = await this.client.rpop(key)\n if (res) {\n fetched.push(res as string)\n } else {\n break\n }\n }\n }\n }\n }\n\n if (fetched.length > 0) {\n for (const payload of fetched) {\n try {\n results.push(this.parsePayloadAuto(payload as string | Buffer))\n } catch (_e) {\n // 解析失敗的 payload 略過\n }\n }\n remaining -= fetched.length\n }\n }\n\n return results\n }\n\n /**\n * Reports a worker heartbeat.\n */\n async reportHeartbeat(workerInfo: any, prefix?: string): Promise<void> {\n const key = `${prefix ?? this.prefix}worker:${workerInfo.id}`\n if (typeof this.client.set === 'function') {\n await this.client.set(key, JSON.stringify(workerInfo), 'EX', 10)\n }\n }\n\n /**\n * Publishes monitoring logs.\n */\n async publishLog(logPayload: any, prefix?: string): Promise<void> {\n const payload = JSON.stringify(logPayload)\n const monitorPrefix = prefix ?? this.prefix\n\n if (typeof this.client.publish === 'function') {\n await this.client.publish(`${monitorPrefix}logs`, payload)\n }\n\n const historyKey = `${monitorPrefix}logs:history`\n if (typeof this.client.pipeline === 'function') {\n const pipe = this.client.pipeline()\n pipe.lpush(historyKey, payload)\n pipe.ltrim(historyKey, 0, 99)\n await pipe.exec()\n } else {\n await this.client.lpush(historyKey, payload)\n }\n }\n\n /**\n * Checks the rate limit for a queue.\n */\n async checkRateLimit(queue: string, config: { max: number; duration: number }): Promise<boolean> {\n const key = `${this.prefix}${queue}:ratelimit`\n const now = Date.now()\n const windowStart = Math.floor(now / config.duration)\n const windowKey = `${key}:${windowStart}`\n\n const client = this.client\n if (typeof client.incr === 'function') {\n const current = await client.incr(windowKey)\n if (current === 1 && client.expire) {\n await client.expire(windowKey, Math.ceil(config.duration / 1000) + 1)\n }\n return current <= config.max\n }\n\n return true\n }\n\n /**\n * Retrieves failed jobs from the DLQ.\n *\n * 支援 lrangeBuffer 讀取 binary frame,否則降級為 string lrange\n *\n * @param queue - The queue name.\n * @param start - Start index.\n * @param end - End index.\n */\n async getFailed(queue: string, start = 0, end = -1): Promise<SerializedJob[]> {\n const key = `${this.getKey(queue)}:failed`\n\n // 優先使用 lrangeBuffer(支援 binary frame)\n if (typeof this.client.lrangeBuffer === 'function') {\n const payloads = await this.client.lrangeBuffer(key, start, end)\n return payloads.map((p: Buffer) => this.parsePayloadAuto(p))\n }\n\n if (typeof this.client.lrange !== 'function') {\n return []\n }\n const payloads = await this.client.lrange(key, start, end)\n return payloads.map((p: string) => this.parsePayloadAuto(p))\n }\n\n /**\n * Retries failed jobs.\n *\n * @param queue - The queue name.\n * @param count - Jobs to retry.\n */\n async retryFailed(queue: string, count = 1): Promise<number> {\n const failedKey = `${this.getKey(queue)}:failed`\n let retried = 0\n\n for (let i = 0; i < count; i++) {\n if (typeof this.client.rpop !== 'function') {\n break\n }\n\n let job: SerializedJob | null = null\n\n // 優先使用 rpopBuffer(支援 binary frame)\n if (typeof this.client.rpopBuffer === 'function') {\n const bufPayload = await this.client.rpopBuffer(failedKey)\n if (!bufPayload) {\n break\n }\n job = this.parsePayloadAuto(bufPayload as Buffer)\n } else {\n const payload = await this.client.rpop(failedKey)\n if (!payload) {\n break\n }\n job = this.parsePayloadAuto(payload as string)\n }\n\n // Reset attempts and error\n const resetJob: SerializedJob = {\n ...job,\n attempts: 0,\n }\n delete resetJob.error\n delete resetJob.failedAt\n\n await this.push(queue, resetJob, {\n priority: (resetJob as any).priority,\n groupId: resetJob.groupId,\n })\n retried++\n }\n\n return retried\n }\n\n /**\n * Clears the Dead Letter Queue.\n *\n * @param queue - The queue name.\n */\n async clearFailed(queue: string): Promise<void> {\n const key = `${this.getKey(queue)}:failed`\n await this.client.del(key)\n }\n\n /**\n * Retrieves all discovered queue names from Redis.\n */\n async getQueues(): Promise<string[]> {\n if (typeof this.client.smembers === 'function') {\n const queues = await this.client.smembers(`${this.prefix}queues`)\n return Array.isArray(queues) ? queues.sort() : []\n }\n return ['default']\n }\n\n /**\n * Enables real-time notifications for job arrivals via Redis Pub/Sub.\n *\n * Sets up the pub/sub connection and prepares for notification callbacks.\n *\n * @throws {Error} If the Redis client doesn't support pub/sub operations.\n */\n async enableNotifications(): Promise<void> {\n if (!this.client.subscribe || !this.client.on) {\n throw new Error('[RedisDriver] Client does not support pub/sub for reactive notifications')\n }\n // Pub/sub is ready to use when onNotify is called\n }\n\n /**\n * Disables real-time notifications for job arrivals.\n *\n * Stops listening to notification channels.\n */\n async disableNotifications(): Promise<void> {\n if (this.client.unsubscribe && typeof this.client.unsubscribe === 'function') {\n try {\n await this.client.unsubscribe()\n } catch (_e) {\n // Ignore errors during unsubscribe\n }\n }\n }\n\n /**\n * Registers a notification listener for one or more queues.\n *\n * Uses Redis Pub/Sub to listen for job arrivals. When a job is pushed,\n * the driver publishes a notification that triggers the callback.\n *\n * @param queues - Queue name(s) to listen for.\n * @param callback - Function called with queue name when a job arrives.\n */\n async onNotify(\n queues: string | string[],\n callback: (queue: string) => Promise<void>\n ): Promise<void> {\n if (!this.client.subscribe || !this.client.on) {\n throw new Error('[RedisDriver] Client does not support pub/sub for reactive notifications')\n }\n\n const queueList = Array.isArray(queues) ? queues : [queues]\n const channels = queueList.map((q) => `${this.prefix}notify:${q}`)\n\n // Subscribe to notification channels\n try {\n await this.client.subscribe(...channels)\n } catch (err) {\n throw new Error(`[RedisDriver] Failed to subscribe to notifications: ${err}`)\n }\n\n // Set up message handler\n this.client.on('message', async (channel: string, _message: string) => {\n // Extract queue name from channel\n const prefix = `${this.prefix}notify:`\n if (channel.startsWith(prefix)) {\n const queueName = channel.slice(prefix.length)\n try {\n await callback(queueName)\n } catch (err) {\n // Log but don't fail the notification handler\n console.error(`[RedisDriver] Notification callback error: ${err}`)\n }\n }\n })\n }\n}\n",
12
+ "import type { SerializedJob } from '../types'\nimport type { QueueDriver } from './QueueDriver'\n\n/**\n * SQS driver configuration.\n */\nexport interface SQSDriverConfig {\n /**\n * SQS client instance (`@aws-sdk/client-sqs`).\n */\n client: {\n send: (command: unknown) => Promise<{\n MessageId?: string\n Messages?: Array<{\n MessageId?: string\n ReceiptHandle?: string\n Body?: string\n }>\n }>\n }\n\n /**\n * Queue URL prefix (used to build full queue URLs).\n */\n queueUrlPrefix?: string\n\n /**\n * Visibility timeout (seconds, default: 30).\n */\n visibilityTimeout?: number\n\n /**\n * Long-polling duration (seconds, default: 20).\n */\n waitTimeSeconds?: number\n}\n\n/**\n * Amazon SQS queue driver.\n *\n * Wraps the AWS SDK for SQS. Supports standard and FIFO queues, long polling,\n * and visibility timeouts.\n *\n * @public\n * @example\n * ```typescript\n * import { SQSClient } from '@aws-sdk/client-sqs';\n * const sqs = new SQSClient({ region: 'us-east-1' });\n * const driver = new SQSDriver({ client: sqs });\n * ```\n */\nexport class SQSDriver implements QueueDriver {\n private client: SQSDriverConfig['client']\n private queueUrlPrefix: string\n private visibilityTimeout: number\n private waitTimeSeconds: number\n private queueUrls = new Map<string, string>()\n\n constructor(config: SQSDriverConfig) {\n this.client = config.client\n this.queueUrlPrefix = config.queueUrlPrefix ?? ''\n this.visibilityTimeout = config.visibilityTimeout ?? 30\n this.waitTimeSeconds = config.waitTimeSeconds ?? 20\n\n if (!this.client) {\n throw new Error(\n '[SQSDriver] SQS client is required. Please install @aws-sdk/client-sqs package.'\n )\n }\n }\n\n /**\n * Resolve the full queue URL.\n */\n private async getQueueUrl(queue: string): Promise<string> {\n if (this.queueUrls.has(queue)) {\n return this.queueUrls.get(queue)!\n }\n\n // Build from prefix if provided\n if (this.queueUrlPrefix) {\n const url = `${this.queueUrlPrefix}/${queue}`\n this.queueUrls.set(queue, url)\n return url\n }\n\n // Otherwise, assume `queue` is already a full URL\n this.queueUrls.set(queue, queue)\n return queue\n }\n\n /**\n * Pushes a job to SQS.\n *\n * @param queue - The queue name (or URL).\n * @param job - The serialized job.\n */\n async push(queue: string, job: SerializedJob): Promise<void> {\n const { SendMessageCommand } = await import('@aws-sdk/client-sqs')\n const queueUrl = await this.getQueueUrl(queue)\n\n const payload = JSON.stringify({\n id: job.id,\n type: job.type,\n data: job.data,\n className: job.className,\n createdAt: job.createdAt,\n delaySeconds: job.delaySeconds,\n attempts: job.attempts,\n maxAttempts: job.maxAttempts,\n })\n\n const delaySeconds = job.delaySeconds ? Math.min(job.delaySeconds, 900) : 0 // SQS max delay is 15 minutes\n\n await this.client.send(\n new SendMessageCommand({\n QueueUrl: queueUrl,\n MessageBody: payload,\n DelaySeconds: delaySeconds,\n })\n )\n }\n\n /**\n * Pops a job from SQS (using long polling).\n *\n * @param queue - The queue name (or URL).\n */\n async pop(queue: string): Promise<SerializedJob | null> {\n const { ReceiveMessageCommand } = await import('@aws-sdk/client-sqs')\n const queueUrl = await this.getQueueUrl(queue)\n\n const response = await this.client.send(\n new ReceiveMessageCommand({\n QueueUrl: queueUrl,\n MaxNumberOfMessages: 1,\n WaitTimeSeconds: this.waitTimeSeconds,\n VisibilityTimeout: this.visibilityTimeout,\n })\n )\n\n if (!response.Messages || response.Messages.length === 0) {\n return null\n }\n\n const message = response.Messages[0]!\n const payload = JSON.parse(message.Body ?? '{}')\n\n return {\n id: payload.id ?? message.MessageId,\n type: payload.type,\n data: payload.data,\n className: payload.className,\n createdAt: payload.createdAt,\n delaySeconds: payload.delaySeconds,\n attempts: payload.attempts,\n maxAttempts: payload.maxAttempts,\n // Store ReceiptHandle for acknowledgement\n ...(message.ReceiptHandle && { receiptHandle: message.ReceiptHandle }),\n } as SerializedJob & { receiptHandle?: string }\n }\n\n /**\n * Pops multiple jobs (up to 10).\n *\n * @param queue - The queue name.\n * @param count - Max jobs (capped at 10 by SQS).\n */\n async popMany(queue: string, count: number): Promise<SerializedJob[]> {\n const { ReceiveMessageCommand } = await import('@aws-sdk/client-sqs')\n const queueUrl = await this.getQueueUrl(queue)\n\n // SQS max is 10\n const limit = Math.min(count, 10)\n\n const response = await this.client.send(\n new ReceiveMessageCommand({\n QueueUrl: queueUrl,\n MaxNumberOfMessages: limit,\n WaitTimeSeconds: this.waitTimeSeconds,\n VisibilityTimeout: this.visibilityTimeout,\n })\n )\n\n if (!response.Messages || response.Messages.length === 0) {\n return []\n }\n\n return response.Messages.map((message) => {\n const payload = JSON.parse(message.Body ?? '{}')\n return {\n id: payload.id ?? message.MessageId,\n type: payload.type,\n data: payload.data,\n className: payload.className,\n createdAt: payload.createdAt,\n delaySeconds: payload.delaySeconds,\n attempts: payload.attempts,\n maxAttempts: payload.maxAttempts,\n receiptHandle: message.ReceiptHandle,\n } as SerializedJob & { receiptHandle?: string }\n })\n }\n\n /**\n * Returns the approximate number of messages in the queue.\n *\n * @param queue - The queue name.\n */\n async size(queue: string): Promise<number> {\n const { GetQueueAttributesCommand } = await import('@aws-sdk/client-sqs')\n const queueUrl = await this.getQueueUrl(queue)\n\n try {\n const response = await this.client.send(\n new GetQueueAttributesCommand({\n QueueUrl: queueUrl,\n AttributeNames: ['ApproximateNumberOfMessages'],\n })\n )\n\n return parseInt((response as any).Attributes?.ApproximateNumberOfMessages ?? '0', 10)\n } catch (error) {\n console.error('[SQSDriver] Error getting queue size:', error)\n return 0\n }\n }\n\n /**\n * Clears the queue by continuously receiving and deleting messages.\n *\n * SQS does not have a \"purge\" command in the client data plane easily accessible here,\n * so we drain the queue.\n *\n * @param queue - The queue name.\n */\n async clear(queue: string): Promise<void> {\n const { DeleteMessageCommand } = await import('@aws-sdk/client-sqs')\n const queueUrl = await this.getQueueUrl(queue)\n\n // Keep receiving and deleting\n while (true) {\n const job = await this.pop(queue)\n if (!job) {\n break\n }\n\n // Delete message\n if ((job as SerializedJob & { receiptHandle?: string }).receiptHandle) {\n await this.client.send(\n new DeleteMessageCommand({\n QueueUrl: queueUrl,\n ReceiptHandle: (job as SerializedJob & { receiptHandle?: string }).receiptHandle,\n })\n )\n }\n }\n }\n\n /**\n * Pushes multiple jobs using SQS batch API.\n *\n * @param queue - The queue name.\n * @param jobs - Array of jobs.\n */\n async pushMany(queue: string, jobs: SerializedJob[]): Promise<void> {\n if (jobs.length === 0) {\n return\n }\n\n const { SendMessageBatchCommand } = await import('@aws-sdk/client-sqs')\n const queueUrl = await this.getQueueUrl(queue)\n\n // SQS batch operations are limited to 10 entries\n const batchSize = 10\n for (let i = 0; i < jobs.length; i += batchSize) {\n const batch = jobs.slice(i, i + batchSize)\n const entries = batch.map((job, index) => {\n const payload = JSON.stringify({\n id: job.id,\n type: job.type,\n data: job.data,\n className: job.className,\n createdAt: job.createdAt,\n delaySeconds: job.delaySeconds,\n attempts: job.attempts,\n maxAttempts: job.maxAttempts,\n })\n\n return {\n Id: `${job.id}-${index}`,\n MessageBody: payload,\n DelaySeconds: job.delaySeconds ? Math.min(job.delaySeconds, 900) : 0,\n }\n })\n\n await this.client.send(\n new SendMessageBatchCommand({\n QueueUrl: queueUrl,\n Entries: entries,\n })\n )\n }\n }\n\n /**\n * Throws error as SQS requires ReceiptHandle, not just MessageId.\n */\n async acknowledge(_messageId: string): Promise<void> {\n // SQS acknowledgements require a ReceiptHandle.\n throw new Error('[SQSDriver] Use deleteMessage() with ReceiptHandle instead of acknowledge().')\n }\n\n /**\n * Deletes a message using its ReceiptHandle (ACK).\n *\n * @param queue - The queue name.\n * @param receiptHandle - The SQS receipt handle.\n */\n async deleteMessage(queue: string, receiptHandle: string): Promise<void> {\n const { DeleteMessageCommand } = await import('@aws-sdk/client-sqs')\n const queueUrl = await this.getQueueUrl(queue)\n\n await this.client.send(\n new DeleteMessageCommand({\n QueueUrl: queueUrl,\n ReceiptHandle: receiptHandle,\n })\n )\n }\n}\n",
13
+ "import type { GroupRedisClient } from '../drivers/RedisDriver'\n\n/**\n * Configuration options for distributed locks.\n *\n * Defines the time-to-live (TTL), retry strategy, and automatic renewal behavior for a lock.\n *\n * @public\n * @since 3.1.0\n * @example\n * ```typescript\n * const options: LockOptions = {\n * ttl: 60000, // Lock held for 60 seconds\n * retryCount: 3, // Retry 3 times on failure\n * retryDelay: 100, // Wait 100ms between retries\n * refreshInterval: 20000 // Auto-renew every 20 seconds\n * };\n * ```\n */\nexport interface LockOptions {\n /**\n * Time-to-live for the lock in milliseconds.\n *\n * The lock will automatically expire if the holder does not release or renew it\n * before this duration elapses.\n */\n ttl: number\n\n /**\n * Number of retry attempts if lock acquisition fails.\n *\n * Set to 0 to disable retries.\n */\n retryCount: number\n\n /**\n * Delay between retry attempts in milliseconds.\n */\n retryDelay: number\n\n /**\n * Interval for automatic lock renewal in milliseconds.\n *\n * If set, the lock will automatically extend its TTL every `refreshInterval`.\n * Recommended value is 1/3 of the `ttl`.\n *\n * @optional\n */\n refreshInterval?: number\n}\n\n/**\n * Distributed lock implementation based on Redis (Redlock style).\n *\n * Provides mutual exclusion in a distributed environment, ensuring only one node\n * holds a specific lock at a time. Supports automatic renewal, retry mechanisms,\n * and safe release (only the holder can release).\n *\n * @public\n * @since 3.1.0\n * @example\n * ```typescript\n * const lock = new DistributedLock(redisClient);\n *\n * const acquired = await lock.acquire('my-resource', {\n * ttl: 60000,\n * retryCount: 3,\n * retryDelay: 100,\n * refreshInterval: 20000\n * });\n *\n * if (acquired) {\n * try {\n * // Perform exclusive operation\n * } finally {\n * await lock.release('my-resource');\n * }\n * }\n * ```\n */\nexport class DistributedLock {\n /**\n * Unique identifier for this lock instance.\n * Used to ensure only the owner can release the lock.\n */\n private lockId = crypto.randomUUID()\n\n /**\n * Timer for automatic renewal.\n */\n private refreshTimer: NodeJS.Timeout | null = null\n\n /**\n * The key of the currently held lock.\n */\n private currentLockKey: string | null = null\n\n /**\n * Creates a DistributedLock instance.\n *\n * @param client - Redis client instance. Must support SET, DEL, and EVAL commands.\n */\n constructor(private client: GroupRedisClient) {}\n\n /**\n * Attempts to acquire a distributed lock for the specified key.\n *\n * Uses Redis `SET key value EX ttl NX` for atomic acquisition.\n * If the lock is held by another node, it retries according to `retryCount`.\n * Upon success, if `refreshInterval` is set, automatic renewal starts.\n *\n * @param key - The lock key. Use a meaningful resource identifier.\n * @param options - Configuration options for the lock.\n * @returns `true` if the lock was acquired, `false` otherwise.\n *\n * @throws {Error} If the Redis client does not support the SET command.\n *\n * @example\n * ```typescript\n * const acquired = await lock.acquire('schedule:job-123', {\n * ttl: 30000,\n * retryCount: 5,\n * retryDelay: 200\n * });\n *\n * if (!acquired) {\n * console.log('Resource is currently locked by another node');\n * }\n * ```\n */\n async acquire(key: string, options: LockOptions): Promise<boolean> {\n if (typeof this.client.set !== 'function') {\n throw new Error('[DistributedLock] Redis client does not support SET command')\n }\n\n const ttlSeconds = Math.ceil(options.ttl / 1000)\n let attempts = 0\n\n while (attempts <= options.retryCount) {\n try {\n // Use SET key value EX ttl NX for atomic acquisition\n const result = await this.client.set(key, this.lockId, 'EX', ttlSeconds, 'NX')\n\n if (result === 'OK') {\n this.currentLockKey = key\n\n if (options.refreshInterval) {\n this.startRefresh(key, options)\n }\n\n return true\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n console.error(`[DistributedLock] Failed to acquire lock for ${key}:`, err.message)\n }\n\n attempts++\n if (attempts <= options.retryCount) {\n await this.sleep(options.retryDelay)\n }\n }\n\n return false\n }\n\n /**\n * Releases the lock for the specified key.\n *\n * Uses a Lua script to ensure atomicity: the lock is deleted ONLY if the value matches\n * this instance's `lockId`. This prevents deleting locks held by others.\n * Stops the auto-renewal timer upon success.\n *\n * @param key - The lock key to release.\n *\n * @throws {Error} If the Redis client does not support the EVAL command.\n *\n * @example\n * ```typescript\n * await lock.release('schedule:job-123');\n * ```\n */\n async release(key: string): Promise<void> {\n this.stopRefresh()\n\n if (typeof this.client.eval !== 'function') {\n throw new Error('[DistributedLock] Redis client does not support EVAL command')\n }\n\n try {\n // Lua script: verify ownership before deletion\n const script = `\n if redis.call(\"get\", KEYS[1]) == ARGV[1] then\n return redis.call(\"del\", KEYS[1])\n else\n return 0\n end\n `\n\n await this.client.eval(script, 1, key, this.lockId)\n this.currentLockKey = null\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n console.error(`[DistributedLock] Failed to release lock for ${key}:`, err.message)\n }\n }\n\n /**\n * Starts the automatic renewal mechanism.\n *\n * Periodically extends the lock's TTL to prevent expiration during long-running tasks.\n * Uses a Lua script to ensure only owned locks are renewed.\n *\n * @param key - The lock key.\n * @param options - Lock options containing `refreshInterval`.\n */\n private startRefresh(key: string, options: LockOptions): void {\n if (!options.refreshInterval) {\n return\n }\n\n this.stopRefresh()\n\n const ttlSeconds = Math.ceil(options.ttl / 1000)\n\n this.refreshTimer = setInterval(async () => {\n try {\n if (typeof this.client.eval !== 'function') {\n console.error('[DistributedLock] Redis client does not support EVAL command for refresh')\n return\n }\n\n const script = `\n if redis.call(\"get\", KEYS[1]) == ARGV[1] then\n return redis.call(\"expire\", KEYS[1], ARGV[2])\n else\n return 0\n end\n `\n\n const result = await this.client.eval(script, 1, key, this.lockId, ttlSeconds)\n\n if (result === 0) {\n console.warn(\n `[DistributedLock] Lock ${key} no longer held by this instance, stopping refresh`\n )\n this.stopRefresh()\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n console.error(`[DistributedLock] Failed to refresh lock ${key}:`, err.message)\n }\n }, options.refreshInterval)\n }\n\n /**\n * Stops the automatic renewal timer.\n */\n private stopRefresh(): void {\n if (this.refreshTimer) {\n clearInterval(this.refreshTimer)\n this.refreshTimer = null\n }\n }\n\n /**\n * Helper for delay.\n *\n * @param ms - Milliseconds to sleep.\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n }\n\n /**\n * Checks if the specified lock is currently held by this instance.\n *\n * @param key - The lock key.\n * @returns `true` if held, `false` otherwise.\n *\n * @example\n * ```typescript\n * if (lock.isHeld('schedule:job-123')) {\n * console.log('Lock is active');\n * }\n * ```\n */\n isHeld(key: string): boolean {\n return this.currentLockKey === key\n }\n}\n",
14
+ "import type { PersistenceAdapter, SerializedJob } from '../types'\n\n/**\n * Buffered Persistence Wrapper.\n *\n * Decorates any `PersistenceAdapter` to add write buffering. Instead of writing\n * to the database immediately for every event, it collects jobs and logs in memory\n * and flushes them in batches. This significantly reduces database I/O for high-throughput queues.\n *\n * @public\n * @example\n * ```typescript\n * const mysqlAdapter = new MySQLPersistence(db);\n * const bufferedAdapter = new BufferedPersistence(mysqlAdapter, {\n * maxBufferSize: 100,\n * flushInterval: 500\n * });\n * ```\n */\nexport class BufferedPersistence implements PersistenceAdapter {\n private jobBuffer: Array<{\n queue: string\n job: SerializedJob\n status: string\n }> = []\n\n private logBuffer: Array<{\n level: string\n message: string\n workerId: string\n queue?: string\n timestamp: Date\n }> = []\n\n private flushTimer: ReturnType<typeof setTimeout> | null = null\n private maxBufferSize: number\n private flushInterval: number\n\n constructor(\n private adapter: PersistenceAdapter,\n options: { maxBufferSize?: number; flushInterval?: number } = {}\n ) {\n this.maxBufferSize = options.maxBufferSize ?? 50\n this.flushInterval = options.flushInterval ?? 5000\n }\n\n /**\n * Buffers a job archive request.\n *\n * @param queue - The queue name.\n * @param job - The serialized job.\n * @param status - The final job status.\n */\n async archive(\n queue: string,\n job: SerializedJob,\n status: 'completed' | 'failed' | 'waiting' | string\n ): Promise<void> {\n this.jobBuffer.push({ queue, job, status })\n\n if (this.jobBuffer.length >= this.maxBufferSize) {\n this.flush().catch((err) => {\n console.error('[BufferedPersistence] Auto-flush failed (jobs):', err.message || err)\n })\n } else {\n this.ensureFlushTimer()\n }\n }\n\n /**\n * Delegates find to the underlying adapter (no buffering for reads).\n */\n async find(queue: string, id: string): Promise<SerializedJob | null> {\n return this.adapter.find(queue, id)\n }\n\n /**\n * Delegates list to the underlying adapter (no buffering for reads).\n */\n async list(\n queue: string,\n options?: {\n limit?: number\n offset?: number\n status?: 'completed' | 'failed' | 'waiting' | string\n jobId?: string\n startTime?: Date\n endTime?: Date\n }\n ): Promise<SerializedJob[]> {\n return this.adapter.list(queue, options)\n }\n\n /**\n * Archives multiple jobs directly (bypassing buffer, or flushing first).\n *\n * Actually, for consistency, this might just pass through.\n */\n async archiveMany(\n jobs: Array<{\n queue: string\n job: SerializedJob\n status: 'completed' | 'failed' | 'waiting' | string\n }>\n ): Promise<void> {\n if (this.adapter.archiveMany) {\n return this.adapter.archiveMany(jobs)\n }\n\n for (const item of jobs) {\n await this.adapter.archive(item.queue, item.job, item.status)\n }\n }\n\n /**\n * Delegates cleanup to the underlying adapter.\n */\n async cleanup(days: number): Promise<number> {\n return this.adapter.cleanup(days)\n }\n\n /**\n * Flushes all buffered data to the underlying adapter.\n *\n * Uses `archiveMany` and `archiveLogMany` if supported by the adapter for batch efficiency.\n */\n async flush(): Promise<void> {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer)\n this.flushTimer = null\n }\n\n const jobs = [...this.jobBuffer]\n const logs = [...this.logBuffer]\n this.jobBuffer = []\n this.logBuffer = []\n\n const promises: Promise<void>[] = []\n\n if (jobs.length > 0) {\n if (this.adapter.archiveMany) {\n promises.push(this.adapter.archiveMany(jobs))\n } else {\n promises.push(\n (async () => {\n for (const item of jobs) {\n await this.adapter.archive(item.queue, item.job, item.status)\n }\n })()\n )\n }\n }\n\n if (logs.length > 0) {\n if (this.adapter.archiveLogMany) {\n promises.push(this.adapter.archiveLogMany(logs))\n } else {\n promises.push(\n (async () => {\n for (const log of logs) {\n await this.adapter.archiveLog(log)\n }\n })()\n )\n }\n }\n\n await Promise.all(promises)\n }\n\n /**\n * Delegates count to the underlying adapter.\n */\n async count(\n queue: string,\n options?: {\n status?: 'completed' | 'failed' | 'waiting' | string\n jobId?: string\n startTime?: Date\n endTime?: Date\n }\n ): Promise<number> {\n return this.adapter.count(queue, options)\n }\n\n /**\n * Buffers a log message.\n */\n async archiveLog(log: {\n level: string\n message: string\n workerId: string\n queue?: string\n timestamp: Date\n }): Promise<void> {\n this.logBuffer.push(log)\n\n if (this.logBuffer.length >= this.maxBufferSize) {\n this.flush().catch((err) => {\n console.error('[BufferedPersistence] Auto-flush failed (logs):', err.message || err)\n })\n } else {\n this.ensureFlushTimer()\n }\n }\n\n /**\n * Archives multiple logs directly.\n */\n async archiveLogMany(\n logs: Array<{\n level: string\n message: string\n workerId: string\n queue?: string\n timestamp: Date\n }>\n ): Promise<void> {\n if (this.adapter.archiveLogMany) {\n return this.adapter.archiveLogMany(logs)\n }\n\n for (const log of logs) {\n await this.adapter.archiveLog(log)\n }\n }\n\n /**\n * Delegates listLogs to the underlying adapter.\n */\n async listLogs(options?: {\n limit?: number\n offset?: number\n level?: string\n workerId?: string\n queue?: string\n search?: string\n startTime?: Date\n endTime?: Date\n }): Promise<any[]> {\n return this.adapter.listLogs(options)\n }\n\n /**\n * Delegates countLogs to the underlying adapter.\n */\n async countLogs(options?: {\n level?: string\n workerId?: string\n queue?: string\n search?: string\n startTime?: Date\n endTime?: Date\n }): Promise<number> {\n return this.adapter.countLogs(options)\n }\n\n /**\n * Ensures the auto-flush timer is running.\n */\n private ensureFlushTimer(): void {\n if (this.flushTimer) {\n return\n }\n\n this.flushTimer = setTimeout(() => {\n this.flush().catch((err) => {\n console.error('[BufferedPersistence] Interval flush failed:', err.message || err)\n })\n }, this.flushInterval)\n }\n}\n",
15
+ "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.utf8Count = utf8Count;\nexports.utf8EncodeJs = utf8EncodeJs;\nexports.utf8EncodeTE = utf8EncodeTE;\nexports.utf8Encode = utf8Encode;\nexports.utf8DecodeJs = utf8DecodeJs;\nexports.utf8DecodeTD = utf8DecodeTD;\nexports.utf8Decode = utf8Decode;\nfunction utf8Count(str) {\n const strLength = str.length;\n let byteLength = 0;\n let pos = 0;\n while (pos < strLength) {\n let value = str.charCodeAt(pos++);\n if ((value & 0xffffff80) === 0) {\n // 1-byte\n byteLength++;\n continue;\n }\n else if ((value & 0xfffff800) === 0) {\n // 2-bytes\n byteLength += 2;\n }\n else {\n // handle surrogate pair\n if (value >= 0xd800 && value <= 0xdbff) {\n // high surrogate\n if (pos < strLength) {\n const extra = str.charCodeAt(pos);\n if ((extra & 0xfc00) === 0xdc00) {\n ++pos;\n value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000;\n }\n }\n }\n if ((value & 0xffff0000) === 0) {\n // 3-byte\n byteLength += 3;\n }\n else {\n // 4-byte\n byteLength += 4;\n }\n }\n }\n return byteLength;\n}\nfunction utf8EncodeJs(str, output, outputOffset) {\n const strLength = str.length;\n let offset = outputOffset;\n let pos = 0;\n while (pos < strLength) {\n let value = str.charCodeAt(pos++);\n if ((value & 0xffffff80) === 0) {\n // 1-byte\n output[offset++] = value;\n continue;\n }\n else if ((value & 0xfffff800) === 0) {\n // 2-bytes\n output[offset++] = ((value >> 6) & 0x1f) | 0xc0;\n }\n else {\n // handle surrogate pair\n if (value >= 0xd800 && value <= 0xdbff) {\n // high surrogate\n if (pos < strLength) {\n const extra = str.charCodeAt(pos);\n if ((extra & 0xfc00) === 0xdc00) {\n ++pos;\n value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000;\n }\n }\n }\n if ((value & 0xffff0000) === 0) {\n // 3-byte\n output[offset++] = ((value >> 12) & 0x0f) | 0xe0;\n output[offset++] = ((value >> 6) & 0x3f) | 0x80;\n }\n else {\n // 4-byte\n output[offset++] = ((value >> 18) & 0x07) | 0xf0;\n output[offset++] = ((value >> 12) & 0x3f) | 0x80;\n output[offset++] = ((value >> 6) & 0x3f) | 0x80;\n }\n }\n output[offset++] = (value & 0x3f) | 0x80;\n }\n}\n// TextEncoder and TextDecoder are standardized in whatwg encoding:\n// https://encoding.spec.whatwg.org/\n// and available in all the modern browsers:\n// https://caniuse.com/textencoder\n// They are available in Node.js since v12 LTS as well:\n// https://nodejs.org/api/globals.html#textencoder\nconst sharedTextEncoder = new TextEncoder();\n// This threshold should be determined by benchmarking, which might vary in engines and input data.\n// Run `npx ts-node benchmark/encode-string.ts` for details.\nconst TEXT_ENCODER_THRESHOLD = 50;\nfunction utf8EncodeTE(str, output, outputOffset) {\n sharedTextEncoder.encodeInto(str, output.subarray(outputOffset));\n}\nfunction utf8Encode(str, output, outputOffset) {\n if (str.length > TEXT_ENCODER_THRESHOLD) {\n utf8EncodeTE(str, output, outputOffset);\n }\n else {\n utf8EncodeJs(str, output, outputOffset);\n }\n}\nconst CHUNK_SIZE = 4096;\nfunction utf8DecodeJs(bytes, inputOffset, byteLength) {\n let offset = inputOffset;\n const end = offset + byteLength;\n const units = [];\n let result = \"\";\n while (offset < end) {\n const byte1 = bytes[offset++];\n if ((byte1 & 0x80) === 0) {\n // 1 byte\n units.push(byte1);\n }\n else if ((byte1 & 0xe0) === 0xc0) {\n // 2 bytes\n const byte2 = bytes[offset++] & 0x3f;\n units.push(((byte1 & 0x1f) << 6) | byte2);\n }\n else if ((byte1 & 0xf0) === 0xe0) {\n // 3 bytes\n const byte2 = bytes[offset++] & 0x3f;\n const byte3 = bytes[offset++] & 0x3f;\n units.push(((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3);\n }\n else if ((byte1 & 0xf8) === 0xf0) {\n // 4 bytes\n const byte2 = bytes[offset++] & 0x3f;\n const byte3 = bytes[offset++] & 0x3f;\n const byte4 = bytes[offset++] & 0x3f;\n let unit = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4;\n if (unit > 0xffff) {\n unit -= 0x10000;\n units.push(((unit >>> 10) & 0x3ff) | 0xd800);\n unit = 0xdc00 | (unit & 0x3ff);\n }\n units.push(unit);\n }\n else {\n units.push(byte1);\n }\n if (units.length >= CHUNK_SIZE) {\n result += String.fromCharCode(...units);\n units.length = 0;\n }\n }\n if (units.length > 0) {\n result += String.fromCharCode(...units);\n }\n return result;\n}\nconst sharedTextDecoder = new TextDecoder();\n// This threshold should be determined by benchmarking, which might vary in engines and input data.\n// Run `npx ts-node benchmark/decode-string.ts` for details.\nconst TEXT_DECODER_THRESHOLD = 200;\nfunction utf8DecodeTD(bytes, inputOffset, byteLength) {\n const stringBytes = bytes.subarray(inputOffset, inputOffset + byteLength);\n return sharedTextDecoder.decode(stringBytes);\n}\nfunction utf8Decode(bytes, inputOffset, byteLength) {\n if (byteLength > TEXT_DECODER_THRESHOLD) {\n return utf8DecodeTD(bytes, inputOffset, byteLength);\n }\n else {\n return utf8DecodeJs(bytes, inputOffset, byteLength);\n }\n}\n//# sourceMappingURL=utf8.cjs.map",
16
+ "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.ExtData = void 0;\n/**\n * ExtData is used to handle Extension Types that are not registered to ExtensionCodec.\n */\nclass ExtData {\n type;\n data;\n constructor(type, data) {\n this.type = type;\n this.data = data;\n }\n}\nexports.ExtData = ExtData;\n//# sourceMappingURL=ExtData.cjs.map",
17
+ "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.DecodeError = void 0;\nclass DecodeError extends Error {\n constructor(message) {\n super(message);\n // fix the prototype chain in a cross-platform way\n const proto = Object.create(DecodeError.prototype);\n Object.setPrototypeOf(this, proto);\n Object.defineProperty(this, \"name\", {\n configurable: true,\n enumerable: false,\n value: DecodeError.name,\n });\n }\n}\nexports.DecodeError = DecodeError;\n//# sourceMappingURL=DecodeError.cjs.map",
18
+ "\"use strict\";\n// Integer Utility\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.UINT32_MAX = void 0;\nexports.setUint64 = setUint64;\nexports.setInt64 = setInt64;\nexports.getInt64 = getInt64;\nexports.getUint64 = getUint64;\nexports.UINT32_MAX = 4294967295;\n// DataView extension to handle int64 / uint64,\n// where the actual range is 53-bits integer (a.k.a. safe integer)\nfunction setUint64(view, offset, value) {\n const high = value / 4294967296;\n const low = value; // high bits are truncated by DataView\n view.setUint32(offset, high);\n view.setUint32(offset + 4, low);\n}\nfunction setInt64(view, offset, value) {\n const high = Math.floor(value / 4294967296);\n const low = value; // high bits are truncated by DataView\n view.setUint32(offset, high);\n view.setUint32(offset + 4, low);\n}\nfunction getInt64(view, offset) {\n const high = view.getInt32(offset);\n const low = view.getUint32(offset + 4);\n return high * 4294967296 + low;\n}\nfunction getUint64(view, offset) {\n const high = view.getUint32(offset);\n const low = view.getUint32(offset + 4);\n return high * 4294967296 + low;\n}\n//# sourceMappingURL=int.cjs.map",
19
+ "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.timestampExtension = exports.EXT_TIMESTAMP = void 0;\nexports.encodeTimeSpecToTimestamp = encodeTimeSpecToTimestamp;\nexports.encodeDateToTimeSpec = encodeDateToTimeSpec;\nexports.encodeTimestampExtension = encodeTimestampExtension;\nexports.decodeTimestampToTimeSpec = decodeTimestampToTimeSpec;\nexports.decodeTimestampExtension = decodeTimestampExtension;\n// https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type\nconst DecodeError_ts_1 = require(\"./DecodeError.cjs\");;\nconst int_ts_1 = require(\"./utils/int.cjs\");;\nexports.EXT_TIMESTAMP = -1;\nconst TIMESTAMP32_MAX_SEC = 0x100000000 - 1; // 32-bit unsigned int\nconst TIMESTAMP64_MAX_SEC = 0x400000000 - 1; // 34-bit unsigned int\nfunction encodeTimeSpecToTimestamp({ sec, nsec }) {\n if (sec >= 0 && nsec >= 0 && sec <= TIMESTAMP64_MAX_SEC) {\n // Here sec >= 0 && nsec >= 0\n if (nsec === 0 && sec <= TIMESTAMP32_MAX_SEC) {\n // timestamp 32 = { sec32 (unsigned) }\n const rv = new Uint8Array(4);\n const view = new DataView(rv.buffer);\n view.setUint32(0, sec);\n return rv;\n }\n else {\n // timestamp 64 = { nsec30 (unsigned), sec34 (unsigned) }\n const secHigh = sec / 0x100000000;\n const secLow = sec & 0xffffffff;\n const rv = new Uint8Array(8);\n const view = new DataView(rv.buffer);\n // nsec30 | secHigh2\n view.setUint32(0, (nsec << 2) | (secHigh & 0x3));\n // secLow32\n view.setUint32(4, secLow);\n return rv;\n }\n }\n else {\n // timestamp 96 = { nsec32 (unsigned), sec64 (signed) }\n const rv = new Uint8Array(12);\n const view = new DataView(rv.buffer);\n view.setUint32(0, nsec);\n (0, int_ts_1.setInt64)(view, 4, sec);\n return rv;\n }\n}\nfunction encodeDateToTimeSpec(date) {\n const msec = date.getTime();\n const sec = Math.floor(msec / 1e3);\n const nsec = (msec - sec * 1e3) * 1e6;\n // Normalizes { sec, nsec } to ensure nsec is unsigned.\n const nsecInSec = Math.floor(nsec / 1e9);\n return {\n sec: sec + nsecInSec,\n nsec: nsec - nsecInSec * 1e9,\n };\n}\nfunction encodeTimestampExtension(object) {\n if (object instanceof Date) {\n const timeSpec = encodeDateToTimeSpec(object);\n return encodeTimeSpecToTimestamp(timeSpec);\n }\n else {\n return null;\n }\n}\nfunction decodeTimestampToTimeSpec(data) {\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n // data may be 32, 64, or 96 bits\n switch (data.byteLength) {\n case 4: {\n // timestamp 32 = { sec32 }\n const sec = view.getUint32(0);\n const nsec = 0;\n return { sec, nsec };\n }\n case 8: {\n // timestamp 64 = { nsec30, sec34 }\n const nsec30AndSecHigh2 = view.getUint32(0);\n const secLow32 = view.getUint32(4);\n const sec = (nsec30AndSecHigh2 & 0x3) * 0x100000000 + secLow32;\n const nsec = nsec30AndSecHigh2 >>> 2;\n return { sec, nsec };\n }\n case 12: {\n // timestamp 96 = { nsec32 (unsigned), sec64 (signed) }\n const sec = (0, int_ts_1.getInt64)(view, 4);\n const nsec = view.getUint32(0);\n return { sec, nsec };\n }\n default:\n throw new DecodeError_ts_1.DecodeError(`Unrecognized data size for timestamp (expected 4, 8, or 12): ${data.length}`);\n }\n}\nfunction decodeTimestampExtension(data) {\n const timeSpec = decodeTimestampToTimeSpec(data);\n return new Date(timeSpec.sec * 1e3 + timeSpec.nsec / 1e6);\n}\nexports.timestampExtension = {\n type: exports.EXT_TIMESTAMP,\n encode: encodeTimestampExtension,\n decode: decodeTimestampExtension,\n};\n//# sourceMappingURL=timestamp.cjs.map",
20
+ "\"use strict\";\n// ExtensionCodec to handle MessagePack extensions\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.ExtensionCodec = void 0;\nconst ExtData_ts_1 = require(\"./ExtData.cjs\");;\nconst timestamp_ts_1 = require(\"./timestamp.cjs\");;\nclass ExtensionCodec {\n static defaultCodec = new ExtensionCodec();\n // ensures ExtensionCodecType<X> matches ExtensionCodec<X>\n // this will make type errors a lot more clear\n // eslint-disable-next-line @typescript-eslint/naming-convention\n __brand;\n // built-in extensions\n builtInEncoders = [];\n builtInDecoders = [];\n // custom extensions\n encoders = [];\n decoders = [];\n constructor() {\n this.register(timestamp_ts_1.timestampExtension);\n }\n register({ type, encode, decode, }) {\n if (type >= 0) {\n // custom extensions\n this.encoders[type] = encode;\n this.decoders[type] = decode;\n }\n else {\n // built-in extensions\n const index = -1 - type;\n this.builtInEncoders[index] = encode;\n this.builtInDecoders[index] = decode;\n }\n }\n tryToEncode(object, context) {\n // built-in extensions\n for (let i = 0; i < this.builtInEncoders.length; i++) {\n const encodeExt = this.builtInEncoders[i];\n if (encodeExt != null) {\n const data = encodeExt(object, context);\n if (data != null) {\n const type = -1 - i;\n return new ExtData_ts_1.ExtData(type, data);\n }\n }\n }\n // custom extensions\n for (let i = 0; i < this.encoders.length; i++) {\n const encodeExt = this.encoders[i];\n if (encodeExt != null) {\n const data = encodeExt(object, context);\n if (data != null) {\n const type = i;\n return new ExtData_ts_1.ExtData(type, data);\n }\n }\n }\n if (object instanceof ExtData_ts_1.ExtData) {\n // to keep ExtData as is\n return object;\n }\n return null;\n }\n decode(data, type, context) {\n const decodeExt = type < 0 ? this.builtInDecoders[-1 - type] : this.decoders[type];\n if (decodeExt) {\n return decodeExt(data, type, context);\n }\n else {\n // decode() does not fail, returns ExtData instead.\n return new ExtData_ts_1.ExtData(type, data);\n }\n }\n}\nexports.ExtensionCodec = ExtensionCodec;\n//# sourceMappingURL=ExtensionCodec.cjs.map",
21
+ "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.ensureUint8Array = ensureUint8Array;\nfunction isArrayBufferLike(buffer) {\n return (buffer instanceof ArrayBuffer || (typeof SharedArrayBuffer !== \"undefined\" && buffer instanceof SharedArrayBuffer));\n}\nfunction ensureUint8Array(buffer) {\n if (buffer instanceof Uint8Array) {\n return buffer;\n }\n else if (ArrayBuffer.isView(buffer)) {\n return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);\n }\n else if (isArrayBufferLike(buffer)) {\n return new Uint8Array(buffer);\n }\n else {\n // ArrayLike<number>\n return Uint8Array.from(buffer);\n }\n}\n//# sourceMappingURL=typedArrays.cjs.map",
22
+ "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.Encoder = exports.DEFAULT_INITIAL_BUFFER_SIZE = exports.DEFAULT_MAX_DEPTH = void 0;\nconst utf8_ts_1 = require(\"./utils/utf8.cjs\");;\nconst ExtensionCodec_ts_1 = require(\"./ExtensionCodec.cjs\");;\nconst int_ts_1 = require(\"./utils/int.cjs\");;\nconst typedArrays_ts_1 = require(\"./utils/typedArrays.cjs\");;\nexports.DEFAULT_MAX_DEPTH = 100;\nexports.DEFAULT_INITIAL_BUFFER_SIZE = 2048;\nclass Encoder {\n extensionCodec;\n context;\n useBigInt64;\n maxDepth;\n initialBufferSize;\n sortKeys;\n forceFloat32;\n ignoreUndefined;\n forceIntegerToFloat;\n pos;\n view;\n bytes;\n entered = false;\n constructor(options) {\n this.extensionCodec = options?.extensionCodec ?? ExtensionCodec_ts_1.ExtensionCodec.defaultCodec;\n this.context = options?.context; // needs a type assertion because EncoderOptions has no context property when ContextType is undefined\n this.useBigInt64 = options?.useBigInt64 ?? false;\n this.maxDepth = options?.maxDepth ?? exports.DEFAULT_MAX_DEPTH;\n this.initialBufferSize = options?.initialBufferSize ?? exports.DEFAULT_INITIAL_BUFFER_SIZE;\n this.sortKeys = options?.sortKeys ?? false;\n this.forceFloat32 = options?.forceFloat32 ?? false;\n this.ignoreUndefined = options?.ignoreUndefined ?? false;\n this.forceIntegerToFloat = options?.forceIntegerToFloat ?? false;\n this.pos = 0;\n this.view = new DataView(new ArrayBuffer(this.initialBufferSize));\n this.bytes = new Uint8Array(this.view.buffer);\n }\n clone() {\n // Because of slightly special argument `context`,\n // type assertion is needed.\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n return new Encoder({\n extensionCodec: this.extensionCodec,\n context: this.context,\n useBigInt64: this.useBigInt64,\n maxDepth: this.maxDepth,\n initialBufferSize: this.initialBufferSize,\n sortKeys: this.sortKeys,\n forceFloat32: this.forceFloat32,\n ignoreUndefined: this.ignoreUndefined,\n forceIntegerToFloat: this.forceIntegerToFloat,\n });\n }\n reinitializeState() {\n this.pos = 0;\n }\n /**\n * This is almost equivalent to {@link Encoder#encode}, but it returns an reference of the encoder's internal buffer and thus much faster than {@link Encoder#encode}.\n *\n * @returns Encodes the object and returns a shared reference the encoder's internal buffer.\n */\n encodeSharedRef(object) {\n if (this.entered) {\n const instance = this.clone();\n return instance.encodeSharedRef(object);\n }\n try {\n this.entered = true;\n this.reinitializeState();\n this.doEncode(object, 1);\n return this.bytes.subarray(0, this.pos);\n }\n finally {\n this.entered = false;\n }\n }\n /**\n * @returns Encodes the object and returns a copy of the encoder's internal buffer.\n */\n encode(object) {\n if (this.entered) {\n const instance = this.clone();\n return instance.encode(object);\n }\n try {\n this.entered = true;\n this.reinitializeState();\n this.doEncode(object, 1);\n return this.bytes.slice(0, this.pos);\n }\n finally {\n this.entered = false;\n }\n }\n doEncode(object, depth) {\n if (depth > this.maxDepth) {\n throw new Error(`Too deep objects in depth ${depth}`);\n }\n if (object == null) {\n this.encodeNil();\n }\n else if (typeof object === \"boolean\") {\n this.encodeBoolean(object);\n }\n else if (typeof object === \"number\") {\n if (!this.forceIntegerToFloat) {\n this.encodeNumber(object);\n }\n else {\n this.encodeNumberAsFloat(object);\n }\n }\n else if (typeof object === \"string\") {\n this.encodeString(object);\n }\n else if (this.useBigInt64 && typeof object === \"bigint\") {\n this.encodeBigInt64(object);\n }\n else {\n this.encodeObject(object, depth);\n }\n }\n ensureBufferSizeToWrite(sizeToWrite) {\n const requiredSize = this.pos + sizeToWrite;\n if (this.view.byteLength < requiredSize) {\n this.resizeBuffer(requiredSize * 2);\n }\n }\n resizeBuffer(newSize) {\n const newBuffer = new ArrayBuffer(newSize);\n const newBytes = new Uint8Array(newBuffer);\n const newView = new DataView(newBuffer);\n newBytes.set(this.bytes);\n this.view = newView;\n this.bytes = newBytes;\n }\n encodeNil() {\n this.writeU8(0xc0);\n }\n encodeBoolean(object) {\n if (object === false) {\n this.writeU8(0xc2);\n }\n else {\n this.writeU8(0xc3);\n }\n }\n encodeNumber(object) {\n if (!this.forceIntegerToFloat && Number.isSafeInteger(object)) {\n if (object >= 0) {\n if (object < 0x80) {\n // positive fixint\n this.writeU8(object);\n }\n else if (object < 0x100) {\n // uint 8\n this.writeU8(0xcc);\n this.writeU8(object);\n }\n else if (object < 0x10000) {\n // uint 16\n this.writeU8(0xcd);\n this.writeU16(object);\n }\n else if (object < 0x100000000) {\n // uint 32\n this.writeU8(0xce);\n this.writeU32(object);\n }\n else if (!this.useBigInt64) {\n // uint 64\n this.writeU8(0xcf);\n this.writeU64(object);\n }\n else {\n this.encodeNumberAsFloat(object);\n }\n }\n else {\n if (object >= -0x20) {\n // negative fixint\n this.writeU8(0xe0 | (object + 0x20));\n }\n else if (object >= -0x80) {\n // int 8\n this.writeU8(0xd0);\n this.writeI8(object);\n }\n else if (object >= -0x8000) {\n // int 16\n this.writeU8(0xd1);\n this.writeI16(object);\n }\n else if (object >= -0x80000000) {\n // int 32\n this.writeU8(0xd2);\n this.writeI32(object);\n }\n else if (!this.useBigInt64) {\n // int 64\n this.writeU8(0xd3);\n this.writeI64(object);\n }\n else {\n this.encodeNumberAsFloat(object);\n }\n }\n }\n else {\n this.encodeNumberAsFloat(object);\n }\n }\n encodeNumberAsFloat(object) {\n if (this.forceFloat32) {\n // float 32\n this.writeU8(0xca);\n this.writeF32(object);\n }\n else {\n // float 64\n this.writeU8(0xcb);\n this.writeF64(object);\n }\n }\n encodeBigInt64(object) {\n if (object >= BigInt(0)) {\n // uint 64\n this.writeU8(0xcf);\n this.writeBigUint64(object);\n }\n else {\n // int 64\n this.writeU8(0xd3);\n this.writeBigInt64(object);\n }\n }\n writeStringHeader(byteLength) {\n if (byteLength < 32) {\n // fixstr\n this.writeU8(0xa0 + byteLength);\n }\n else if (byteLength < 0x100) {\n // str 8\n this.writeU8(0xd9);\n this.writeU8(byteLength);\n }\n else if (byteLength < 0x10000) {\n // str 16\n this.writeU8(0xda);\n this.writeU16(byteLength);\n }\n else if (byteLength < 0x100000000) {\n // str 32\n this.writeU8(0xdb);\n this.writeU32(byteLength);\n }\n else {\n throw new Error(`Too long string: ${byteLength} bytes in UTF-8`);\n }\n }\n encodeString(object) {\n const maxHeaderSize = 1 + 4;\n const byteLength = (0, utf8_ts_1.utf8Count)(object);\n this.ensureBufferSizeToWrite(maxHeaderSize + byteLength);\n this.writeStringHeader(byteLength);\n (0, utf8_ts_1.utf8Encode)(object, this.bytes, this.pos);\n this.pos += byteLength;\n }\n encodeObject(object, depth) {\n // try to encode objects with custom codec first of non-primitives\n const ext = this.extensionCodec.tryToEncode(object, this.context);\n if (ext != null) {\n this.encodeExtension(ext);\n }\n else if (Array.isArray(object)) {\n this.encodeArray(object, depth);\n }\n else if (ArrayBuffer.isView(object)) {\n this.encodeBinary(object);\n }\n else if (typeof object === \"object\") {\n this.encodeMap(object, depth);\n }\n else {\n // symbol, function and other special object come here unless extensionCodec handles them.\n throw new Error(`Unrecognized object: ${Object.prototype.toString.apply(object)}`);\n }\n }\n encodeBinary(object) {\n const size = object.byteLength;\n if (size < 0x100) {\n // bin 8\n this.writeU8(0xc4);\n this.writeU8(size);\n }\n else if (size < 0x10000) {\n // bin 16\n this.writeU8(0xc5);\n this.writeU16(size);\n }\n else if (size < 0x100000000) {\n // bin 32\n this.writeU8(0xc6);\n this.writeU32(size);\n }\n else {\n throw new Error(`Too large binary: ${size}`);\n }\n const bytes = (0, typedArrays_ts_1.ensureUint8Array)(object);\n this.writeU8a(bytes);\n }\n encodeArray(object, depth) {\n const size = object.length;\n if (size < 16) {\n // fixarray\n this.writeU8(0x90 + size);\n }\n else if (size < 0x10000) {\n // array 16\n this.writeU8(0xdc);\n this.writeU16(size);\n }\n else if (size < 0x100000000) {\n // array 32\n this.writeU8(0xdd);\n this.writeU32(size);\n }\n else {\n throw new Error(`Too large array: ${size}`);\n }\n for (const item of object) {\n this.doEncode(item, depth + 1);\n }\n }\n countWithoutUndefined(object, keys) {\n let count = 0;\n for (const key of keys) {\n if (object[key] !== undefined) {\n count++;\n }\n }\n return count;\n }\n encodeMap(object, depth) {\n const keys = Object.keys(object);\n if (this.sortKeys) {\n keys.sort();\n }\n const size = this.ignoreUndefined ? this.countWithoutUndefined(object, keys) : keys.length;\n if (size < 16) {\n // fixmap\n this.writeU8(0x80 + size);\n }\n else if (size < 0x10000) {\n // map 16\n this.writeU8(0xde);\n this.writeU16(size);\n }\n else if (size < 0x100000000) {\n // map 32\n this.writeU8(0xdf);\n this.writeU32(size);\n }\n else {\n throw new Error(`Too large map object: ${size}`);\n }\n for (const key of keys) {\n const value = object[key];\n if (!(this.ignoreUndefined && value === undefined)) {\n this.encodeString(key);\n this.doEncode(value, depth + 1);\n }\n }\n }\n encodeExtension(ext) {\n if (typeof ext.data === \"function\") {\n const data = ext.data(this.pos + 6);\n const size = data.length;\n if (size >= 0x100000000) {\n throw new Error(`Too large extension object: ${size}`);\n }\n this.writeU8(0xc9);\n this.writeU32(size);\n this.writeI8(ext.type);\n this.writeU8a(data);\n return;\n }\n const size = ext.data.length;\n if (size === 1) {\n // fixext 1\n this.writeU8(0xd4);\n }\n else if (size === 2) {\n // fixext 2\n this.writeU8(0xd5);\n }\n else if (size === 4) {\n // fixext 4\n this.writeU8(0xd6);\n }\n else if (size === 8) {\n // fixext 8\n this.writeU8(0xd7);\n }\n else if (size === 16) {\n // fixext 16\n this.writeU8(0xd8);\n }\n else if (size < 0x100) {\n // ext 8\n this.writeU8(0xc7);\n this.writeU8(size);\n }\n else if (size < 0x10000) {\n // ext 16\n this.writeU8(0xc8);\n this.writeU16(size);\n }\n else if (size < 0x100000000) {\n // ext 32\n this.writeU8(0xc9);\n this.writeU32(size);\n }\n else {\n throw new Error(`Too large extension object: ${size}`);\n }\n this.writeI8(ext.type);\n this.writeU8a(ext.data);\n }\n writeU8(value) {\n this.ensureBufferSizeToWrite(1);\n this.view.setUint8(this.pos, value);\n this.pos++;\n }\n writeU8a(values) {\n const size = values.length;\n this.ensureBufferSizeToWrite(size);\n this.bytes.set(values, this.pos);\n this.pos += size;\n }\n writeI8(value) {\n this.ensureBufferSizeToWrite(1);\n this.view.setInt8(this.pos, value);\n this.pos++;\n }\n writeU16(value) {\n this.ensureBufferSizeToWrite(2);\n this.view.setUint16(this.pos, value);\n this.pos += 2;\n }\n writeI16(value) {\n this.ensureBufferSizeToWrite(2);\n this.view.setInt16(this.pos, value);\n this.pos += 2;\n }\n writeU32(value) {\n this.ensureBufferSizeToWrite(4);\n this.view.setUint32(this.pos, value);\n this.pos += 4;\n }\n writeI32(value) {\n this.ensureBufferSizeToWrite(4);\n this.view.setInt32(this.pos, value);\n this.pos += 4;\n }\n writeF32(value) {\n this.ensureBufferSizeToWrite(4);\n this.view.setFloat32(this.pos, value);\n this.pos += 4;\n }\n writeF64(value) {\n this.ensureBufferSizeToWrite(8);\n this.view.setFloat64(this.pos, value);\n this.pos += 8;\n }\n writeU64(value) {\n this.ensureBufferSizeToWrite(8);\n (0, int_ts_1.setUint64)(this.view, this.pos, value);\n this.pos += 8;\n }\n writeI64(value) {\n this.ensureBufferSizeToWrite(8);\n (0, int_ts_1.setInt64)(this.view, this.pos, value);\n this.pos += 8;\n }\n writeBigUint64(value) {\n this.ensureBufferSizeToWrite(8);\n this.view.setBigUint64(this.pos, value);\n this.pos += 8;\n }\n writeBigInt64(value) {\n this.ensureBufferSizeToWrite(8);\n this.view.setBigInt64(this.pos, value);\n this.pos += 8;\n }\n}\nexports.Encoder = Encoder;\n//# sourceMappingURL=Encoder.cjs.map",
23
+ "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.encode = encode;\nconst Encoder_ts_1 = require(\"./Encoder.cjs\");;\n/**\n * It encodes `value` in the MessagePack format and\n * returns a byte buffer.\n *\n * The returned buffer is a slice of a larger `ArrayBuffer`, so you have to use its `#byteOffset` and `#byteLength` in order to convert it to another typed arrays including NodeJS `Buffer`.\n */\nfunction encode(value, options) {\n const encoder = new Encoder_ts_1.Encoder(options);\n return encoder.encodeSharedRef(value);\n}\n//# sourceMappingURL=encode.cjs.map",
24
+ "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.prettyByte = prettyByte;\nfunction prettyByte(byte) {\n return `${byte < 0 ? \"-\" : \"\"}0x${Math.abs(byte).toString(16).padStart(2, \"0\")}`;\n}\n//# sourceMappingURL=prettyByte.cjs.map",
25
+ "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.CachedKeyDecoder = void 0;\nconst utf8_ts_1 = require(\"./utils/utf8.cjs\");;\nconst DEFAULT_MAX_KEY_LENGTH = 16;\nconst DEFAULT_MAX_LENGTH_PER_KEY = 16;\nclass CachedKeyDecoder {\n hit = 0;\n miss = 0;\n caches;\n maxKeyLength;\n maxLengthPerKey;\n constructor(maxKeyLength = DEFAULT_MAX_KEY_LENGTH, maxLengthPerKey = DEFAULT_MAX_LENGTH_PER_KEY) {\n this.maxKeyLength = maxKeyLength;\n this.maxLengthPerKey = maxLengthPerKey;\n // avoid `new Array(N)`, which makes a sparse array,\n // because a sparse array is typically slower than a non-sparse array.\n this.caches = [];\n for (let i = 0; i < this.maxKeyLength; i++) {\n this.caches.push([]);\n }\n }\n canBeCached(byteLength) {\n return byteLength > 0 && byteLength <= this.maxKeyLength;\n }\n find(bytes, inputOffset, byteLength) {\n const records = this.caches[byteLength - 1];\n FIND_CHUNK: for (const record of records) {\n const recordBytes = record.bytes;\n for (let j = 0; j < byteLength; j++) {\n if (recordBytes[j] !== bytes[inputOffset + j]) {\n continue FIND_CHUNK;\n }\n }\n return record.str;\n }\n return null;\n }\n store(bytes, value) {\n const records = this.caches[bytes.length - 1];\n const record = { bytes, str: value };\n if (records.length >= this.maxLengthPerKey) {\n // `records` are full!\n // Set `record` to an arbitrary position.\n records[(Math.random() * records.length) | 0] = record;\n }\n else {\n records.push(record);\n }\n }\n decode(bytes, inputOffset, byteLength) {\n const cachedValue = this.find(bytes, inputOffset, byteLength);\n if (cachedValue != null) {\n this.hit++;\n return cachedValue;\n }\n this.miss++;\n const str = (0, utf8_ts_1.utf8DecodeJs)(bytes, inputOffset, byteLength);\n // Ensure to copy a slice of bytes because the bytes may be a NodeJS Buffer and Buffer#slice() returns a reference to its internal ArrayBuffer.\n const slicedCopyOfBytes = Uint8Array.prototype.slice.call(bytes, inputOffset, inputOffset + byteLength);\n this.store(slicedCopyOfBytes, str);\n return str;\n }\n}\nexports.CachedKeyDecoder = CachedKeyDecoder;\n//# sourceMappingURL=CachedKeyDecoder.cjs.map",
26
+ "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.Decoder = void 0;\nconst prettyByte_ts_1 = require(\"./utils/prettyByte.cjs\");;\nconst ExtensionCodec_ts_1 = require(\"./ExtensionCodec.cjs\");;\nconst int_ts_1 = require(\"./utils/int.cjs\");;\nconst utf8_ts_1 = require(\"./utils/utf8.cjs\");;\nconst typedArrays_ts_1 = require(\"./utils/typedArrays.cjs\");;\nconst CachedKeyDecoder_ts_1 = require(\"./CachedKeyDecoder.cjs\");;\nconst DecodeError_ts_1 = require(\"./DecodeError.cjs\");;\nconst STATE_ARRAY = \"array\";\nconst STATE_MAP_KEY = \"map_key\";\nconst STATE_MAP_VALUE = \"map_value\";\nconst mapKeyConverter = (key) => {\n if (typeof key === \"string\" || typeof key === \"number\") {\n return key;\n }\n throw new DecodeError_ts_1.DecodeError(\"The type of key must be string or number but \" + typeof key);\n};\nclass StackPool {\n stack = [];\n stackHeadPosition = -1;\n get length() {\n return this.stackHeadPosition + 1;\n }\n top() {\n return this.stack[this.stackHeadPosition];\n }\n pushArrayState(size) {\n const state = this.getUninitializedStateFromPool();\n state.type = STATE_ARRAY;\n state.position = 0;\n state.size = size;\n state.array = new Array(size);\n }\n pushMapState(size) {\n const state = this.getUninitializedStateFromPool();\n state.type = STATE_MAP_KEY;\n state.readCount = 0;\n state.size = size;\n state.map = {};\n }\n getUninitializedStateFromPool() {\n this.stackHeadPosition++;\n if (this.stackHeadPosition === this.stack.length) {\n const partialState = {\n type: undefined,\n size: 0,\n array: undefined,\n position: 0,\n readCount: 0,\n map: undefined,\n key: null,\n };\n this.stack.push(partialState);\n }\n return this.stack[this.stackHeadPosition];\n }\n release(state) {\n const topStackState = this.stack[this.stackHeadPosition];\n if (topStackState !== state) {\n throw new Error(\"Invalid stack state. Released state is not on top of the stack.\");\n }\n if (state.type === STATE_ARRAY) {\n const partialState = state;\n partialState.size = 0;\n partialState.array = undefined;\n partialState.position = 0;\n partialState.type = undefined;\n }\n if (state.type === STATE_MAP_KEY || state.type === STATE_MAP_VALUE) {\n const partialState = state;\n partialState.size = 0;\n partialState.map = undefined;\n partialState.readCount = 0;\n partialState.type = undefined;\n }\n this.stackHeadPosition--;\n }\n reset() {\n this.stack.length = 0;\n this.stackHeadPosition = -1;\n }\n}\nconst HEAD_BYTE_REQUIRED = -1;\nconst EMPTY_VIEW = new DataView(new ArrayBuffer(0));\nconst EMPTY_BYTES = new Uint8Array(EMPTY_VIEW.buffer);\ntry {\n // IE11: The spec says it should throw RangeError,\n // IE11: but in IE11 it throws TypeError.\n EMPTY_VIEW.getInt8(0);\n}\ncatch (e) {\n if (!(e instanceof RangeError)) {\n throw new Error(\"This module is not supported in the current JavaScript engine because DataView does not throw RangeError on out-of-bounds access\");\n }\n}\nconst MORE_DATA = new RangeError(\"Insufficient data\");\nconst sharedCachedKeyDecoder = new CachedKeyDecoder_ts_1.CachedKeyDecoder();\nclass Decoder {\n extensionCodec;\n context;\n useBigInt64;\n rawStrings;\n maxStrLength;\n maxBinLength;\n maxArrayLength;\n maxMapLength;\n maxExtLength;\n keyDecoder;\n mapKeyConverter;\n totalPos = 0;\n pos = 0;\n view = EMPTY_VIEW;\n bytes = EMPTY_BYTES;\n headByte = HEAD_BYTE_REQUIRED;\n stack = new StackPool();\n entered = false;\n constructor(options) {\n this.extensionCodec = options?.extensionCodec ?? ExtensionCodec_ts_1.ExtensionCodec.defaultCodec;\n this.context = options?.context; // needs a type assertion because EncoderOptions has no context property when ContextType is undefined\n this.useBigInt64 = options?.useBigInt64 ?? false;\n this.rawStrings = options?.rawStrings ?? false;\n this.maxStrLength = options?.maxStrLength ?? int_ts_1.UINT32_MAX;\n this.maxBinLength = options?.maxBinLength ?? int_ts_1.UINT32_MAX;\n this.maxArrayLength = options?.maxArrayLength ?? int_ts_1.UINT32_MAX;\n this.maxMapLength = options?.maxMapLength ?? int_ts_1.UINT32_MAX;\n this.maxExtLength = options?.maxExtLength ?? int_ts_1.UINT32_MAX;\n this.keyDecoder = options?.keyDecoder !== undefined ? options.keyDecoder : sharedCachedKeyDecoder;\n this.mapKeyConverter = options?.mapKeyConverter ?? mapKeyConverter;\n }\n clone() {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n return new Decoder({\n extensionCodec: this.extensionCodec,\n context: this.context,\n useBigInt64: this.useBigInt64,\n rawStrings: this.rawStrings,\n maxStrLength: this.maxStrLength,\n maxBinLength: this.maxBinLength,\n maxArrayLength: this.maxArrayLength,\n maxMapLength: this.maxMapLength,\n maxExtLength: this.maxExtLength,\n keyDecoder: this.keyDecoder,\n });\n }\n reinitializeState() {\n this.totalPos = 0;\n this.headByte = HEAD_BYTE_REQUIRED;\n this.stack.reset();\n // view, bytes, and pos will be re-initialized in setBuffer()\n }\n setBuffer(buffer) {\n const bytes = (0, typedArrays_ts_1.ensureUint8Array)(buffer);\n this.bytes = bytes;\n this.view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n this.pos = 0;\n }\n appendBuffer(buffer) {\n if (this.headByte === HEAD_BYTE_REQUIRED && !this.hasRemaining(1)) {\n this.setBuffer(buffer);\n }\n else {\n const remainingData = this.bytes.subarray(this.pos);\n const newData = (0, typedArrays_ts_1.ensureUint8Array)(buffer);\n // concat remainingData + newData\n const newBuffer = new Uint8Array(remainingData.length + newData.length);\n newBuffer.set(remainingData);\n newBuffer.set(newData, remainingData.length);\n this.setBuffer(newBuffer);\n }\n }\n hasRemaining(size) {\n return this.view.byteLength - this.pos >= size;\n }\n createExtraByteError(posToShow) {\n const { view, pos } = this;\n return new RangeError(`Extra ${view.byteLength - pos} of ${view.byteLength} byte(s) found at buffer[${posToShow}]`);\n }\n /**\n * @throws {@link DecodeError}\n * @throws {@link RangeError}\n */\n decode(buffer) {\n if (this.entered) {\n const instance = this.clone();\n return instance.decode(buffer);\n }\n try {\n this.entered = true;\n this.reinitializeState();\n this.setBuffer(buffer);\n const object = this.doDecodeSync();\n if (this.hasRemaining(1)) {\n throw this.createExtraByteError(this.pos);\n }\n return object;\n }\n finally {\n this.entered = false;\n }\n }\n *decodeMulti(buffer) {\n if (this.entered) {\n const instance = this.clone();\n yield* instance.decodeMulti(buffer);\n return;\n }\n try {\n this.entered = true;\n this.reinitializeState();\n this.setBuffer(buffer);\n while (this.hasRemaining(1)) {\n yield this.doDecodeSync();\n }\n }\n finally {\n this.entered = false;\n }\n }\n async decodeAsync(stream) {\n if (this.entered) {\n const instance = this.clone();\n return instance.decodeAsync(stream);\n }\n try {\n this.entered = true;\n let decoded = false;\n let object;\n for await (const buffer of stream) {\n if (decoded) {\n this.entered = false;\n throw this.createExtraByteError(this.totalPos);\n }\n this.appendBuffer(buffer);\n try {\n object = this.doDecodeSync();\n decoded = true;\n }\n catch (e) {\n if (!(e instanceof RangeError)) {\n throw e; // rethrow\n }\n // fallthrough\n }\n this.totalPos += this.pos;\n }\n if (decoded) {\n if (this.hasRemaining(1)) {\n throw this.createExtraByteError(this.totalPos);\n }\n return object;\n }\n const { headByte, pos, totalPos } = this;\n throw new RangeError(`Insufficient data in parsing ${(0, prettyByte_ts_1.prettyByte)(headByte)} at ${totalPos} (${pos} in the current buffer)`);\n }\n finally {\n this.entered = false;\n }\n }\n decodeArrayStream(stream) {\n return this.decodeMultiAsync(stream, true);\n }\n decodeStream(stream) {\n return this.decodeMultiAsync(stream, false);\n }\n async *decodeMultiAsync(stream, isArray) {\n if (this.entered) {\n const instance = this.clone();\n yield* instance.decodeMultiAsync(stream, isArray);\n return;\n }\n try {\n this.entered = true;\n let isArrayHeaderRequired = isArray;\n let arrayItemsLeft = -1;\n for await (const buffer of stream) {\n if (isArray && arrayItemsLeft === 0) {\n throw this.createExtraByteError(this.totalPos);\n }\n this.appendBuffer(buffer);\n if (isArrayHeaderRequired) {\n arrayItemsLeft = this.readArraySize();\n isArrayHeaderRequired = false;\n this.complete();\n }\n try {\n while (true) {\n yield this.doDecodeSync();\n if (--arrayItemsLeft === 0) {\n break;\n }\n }\n }\n catch (e) {\n if (!(e instanceof RangeError)) {\n throw e; // rethrow\n }\n // fallthrough\n }\n this.totalPos += this.pos;\n }\n }\n finally {\n this.entered = false;\n }\n }\n doDecodeSync() {\n DECODE: while (true) {\n const headByte = this.readHeadByte();\n let object;\n if (headByte >= 0xe0) {\n // negative fixint (111x xxxx) 0xe0 - 0xff\n object = headByte - 0x100;\n }\n else if (headByte < 0xc0) {\n if (headByte < 0x80) {\n // positive fixint (0xxx xxxx) 0x00 - 0x7f\n object = headByte;\n }\n else if (headByte < 0x90) {\n // fixmap (1000 xxxx) 0x80 - 0x8f\n const size = headByte - 0x80;\n if (size !== 0) {\n this.pushMapState(size);\n this.complete();\n continue DECODE;\n }\n else {\n object = {};\n }\n }\n else if (headByte < 0xa0) {\n // fixarray (1001 xxxx) 0x90 - 0x9f\n const size = headByte - 0x90;\n if (size !== 0) {\n this.pushArrayState(size);\n this.complete();\n continue DECODE;\n }\n else {\n object = [];\n }\n }\n else {\n // fixstr (101x xxxx) 0xa0 - 0xbf\n const byteLength = headByte - 0xa0;\n object = this.decodeString(byteLength, 0);\n }\n }\n else if (headByte === 0xc0) {\n // nil\n object = null;\n }\n else if (headByte === 0xc2) {\n // false\n object = false;\n }\n else if (headByte === 0xc3) {\n // true\n object = true;\n }\n else if (headByte === 0xca) {\n // float 32\n object = this.readF32();\n }\n else if (headByte === 0xcb) {\n // float 64\n object = this.readF64();\n }\n else if (headByte === 0xcc) {\n // uint 8\n object = this.readU8();\n }\n else if (headByte === 0xcd) {\n // uint 16\n object = this.readU16();\n }\n else if (headByte === 0xce) {\n // uint 32\n object = this.readU32();\n }\n else if (headByte === 0xcf) {\n // uint 64\n if (this.useBigInt64) {\n object = this.readU64AsBigInt();\n }\n else {\n object = this.readU64();\n }\n }\n else if (headByte === 0xd0) {\n // int 8\n object = this.readI8();\n }\n else if (headByte === 0xd1) {\n // int 16\n object = this.readI16();\n }\n else if (headByte === 0xd2) {\n // int 32\n object = this.readI32();\n }\n else if (headByte === 0xd3) {\n // int 64\n if (this.useBigInt64) {\n object = this.readI64AsBigInt();\n }\n else {\n object = this.readI64();\n }\n }\n else if (headByte === 0xd9) {\n // str 8\n const byteLength = this.lookU8();\n object = this.decodeString(byteLength, 1);\n }\n else if (headByte === 0xda) {\n // str 16\n const byteLength = this.lookU16();\n object = this.decodeString(byteLength, 2);\n }\n else if (headByte === 0xdb) {\n // str 32\n const byteLength = this.lookU32();\n object = this.decodeString(byteLength, 4);\n }\n else if (headByte === 0xdc) {\n // array 16\n const size = this.readU16();\n if (size !== 0) {\n this.pushArrayState(size);\n this.complete();\n continue DECODE;\n }\n else {\n object = [];\n }\n }\n else if (headByte === 0xdd) {\n // array 32\n const size = this.readU32();\n if (size !== 0) {\n this.pushArrayState(size);\n this.complete();\n continue DECODE;\n }\n else {\n object = [];\n }\n }\n else if (headByte === 0xde) {\n // map 16\n const size = this.readU16();\n if (size !== 0) {\n this.pushMapState(size);\n this.complete();\n continue DECODE;\n }\n else {\n object = {};\n }\n }\n else if (headByte === 0xdf) {\n // map 32\n const size = this.readU32();\n if (size !== 0) {\n this.pushMapState(size);\n this.complete();\n continue DECODE;\n }\n else {\n object = {};\n }\n }\n else if (headByte === 0xc4) {\n // bin 8\n const size = this.lookU8();\n object = this.decodeBinary(size, 1);\n }\n else if (headByte === 0xc5) {\n // bin 16\n const size = this.lookU16();\n object = this.decodeBinary(size, 2);\n }\n else if (headByte === 0xc6) {\n // bin 32\n const size = this.lookU32();\n object = this.decodeBinary(size, 4);\n }\n else if (headByte === 0xd4) {\n // fixext 1\n object = this.decodeExtension(1, 0);\n }\n else if (headByte === 0xd5) {\n // fixext 2\n object = this.decodeExtension(2, 0);\n }\n else if (headByte === 0xd6) {\n // fixext 4\n object = this.decodeExtension(4, 0);\n }\n else if (headByte === 0xd7) {\n // fixext 8\n object = this.decodeExtension(8, 0);\n }\n else if (headByte === 0xd8) {\n // fixext 16\n object = this.decodeExtension(16, 0);\n }\n else if (headByte === 0xc7) {\n // ext 8\n const size = this.lookU8();\n object = this.decodeExtension(size, 1);\n }\n else if (headByte === 0xc8) {\n // ext 16\n const size = this.lookU16();\n object = this.decodeExtension(size, 2);\n }\n else if (headByte === 0xc9) {\n // ext 32\n const size = this.lookU32();\n object = this.decodeExtension(size, 4);\n }\n else {\n throw new DecodeError_ts_1.DecodeError(`Unrecognized type byte: ${(0, prettyByte_ts_1.prettyByte)(headByte)}`);\n }\n this.complete();\n const stack = this.stack;\n while (stack.length > 0) {\n // arrays and maps\n const state = stack.top();\n if (state.type === STATE_ARRAY) {\n state.array[state.position] = object;\n state.position++;\n if (state.position === state.size) {\n object = state.array;\n stack.release(state);\n }\n else {\n continue DECODE;\n }\n }\n else if (state.type === STATE_MAP_KEY) {\n if (object === \"__proto__\") {\n throw new DecodeError_ts_1.DecodeError(\"The key __proto__ is not allowed\");\n }\n state.key = this.mapKeyConverter(object);\n state.type = STATE_MAP_VALUE;\n continue DECODE;\n }\n else {\n // it must be `state.type === State.MAP_VALUE` here\n state.map[state.key] = object;\n state.readCount++;\n if (state.readCount === state.size) {\n object = state.map;\n stack.release(state);\n }\n else {\n state.key = null;\n state.type = STATE_MAP_KEY;\n continue DECODE;\n }\n }\n }\n return object;\n }\n }\n readHeadByte() {\n if (this.headByte === HEAD_BYTE_REQUIRED) {\n this.headByte = this.readU8();\n // console.log(\"headByte\", prettyByte(this.headByte));\n }\n return this.headByte;\n }\n complete() {\n this.headByte = HEAD_BYTE_REQUIRED;\n }\n readArraySize() {\n const headByte = this.readHeadByte();\n switch (headByte) {\n case 0xdc:\n return this.readU16();\n case 0xdd:\n return this.readU32();\n default: {\n if (headByte < 0xa0) {\n return headByte - 0x90;\n }\n else {\n throw new DecodeError_ts_1.DecodeError(`Unrecognized array type byte: ${(0, prettyByte_ts_1.prettyByte)(headByte)}`);\n }\n }\n }\n }\n pushMapState(size) {\n if (size > this.maxMapLength) {\n throw new DecodeError_ts_1.DecodeError(`Max length exceeded: map length (${size}) > maxMapLengthLength (${this.maxMapLength})`);\n }\n this.stack.pushMapState(size);\n }\n pushArrayState(size) {\n if (size > this.maxArrayLength) {\n throw new DecodeError_ts_1.DecodeError(`Max length exceeded: array length (${size}) > maxArrayLength (${this.maxArrayLength})`);\n }\n this.stack.pushArrayState(size);\n }\n decodeString(byteLength, headerOffset) {\n if (!this.rawStrings || this.stateIsMapKey()) {\n return this.decodeUtf8String(byteLength, headerOffset);\n }\n return this.decodeBinary(byteLength, headerOffset);\n }\n /**\n * @throws {@link RangeError}\n */\n decodeUtf8String(byteLength, headerOffset) {\n if (byteLength > this.maxStrLength) {\n throw new DecodeError_ts_1.DecodeError(`Max length exceeded: UTF-8 byte length (${byteLength}) > maxStrLength (${this.maxStrLength})`);\n }\n if (this.bytes.byteLength < this.pos + headerOffset + byteLength) {\n throw MORE_DATA;\n }\n const offset = this.pos + headerOffset;\n let object;\n if (this.stateIsMapKey() && this.keyDecoder?.canBeCached(byteLength)) {\n object = this.keyDecoder.decode(this.bytes, offset, byteLength);\n }\n else {\n object = (0, utf8_ts_1.utf8Decode)(this.bytes, offset, byteLength);\n }\n this.pos += headerOffset + byteLength;\n return object;\n }\n stateIsMapKey() {\n if (this.stack.length > 0) {\n const state = this.stack.top();\n return state.type === STATE_MAP_KEY;\n }\n return false;\n }\n /**\n * @throws {@link RangeError}\n */\n decodeBinary(byteLength, headOffset) {\n if (byteLength > this.maxBinLength) {\n throw new DecodeError_ts_1.DecodeError(`Max length exceeded: bin length (${byteLength}) > maxBinLength (${this.maxBinLength})`);\n }\n if (!this.hasRemaining(byteLength + headOffset)) {\n throw MORE_DATA;\n }\n const offset = this.pos + headOffset;\n const object = this.bytes.subarray(offset, offset + byteLength);\n this.pos += headOffset + byteLength;\n return object;\n }\n decodeExtension(size, headOffset) {\n if (size > this.maxExtLength) {\n throw new DecodeError_ts_1.DecodeError(`Max length exceeded: ext length (${size}) > maxExtLength (${this.maxExtLength})`);\n }\n const extType = this.view.getInt8(this.pos + headOffset);\n const data = this.decodeBinary(size, headOffset + 1 /* extType */);\n return this.extensionCodec.decode(data, extType, this.context);\n }\n lookU8() {\n return this.view.getUint8(this.pos);\n }\n lookU16() {\n return this.view.getUint16(this.pos);\n }\n lookU32() {\n return this.view.getUint32(this.pos);\n }\n readU8() {\n const value = this.view.getUint8(this.pos);\n this.pos++;\n return value;\n }\n readI8() {\n const value = this.view.getInt8(this.pos);\n this.pos++;\n return value;\n }\n readU16() {\n const value = this.view.getUint16(this.pos);\n this.pos += 2;\n return value;\n }\n readI16() {\n const value = this.view.getInt16(this.pos);\n this.pos += 2;\n return value;\n }\n readU32() {\n const value = this.view.getUint32(this.pos);\n this.pos += 4;\n return value;\n }\n readI32() {\n const value = this.view.getInt32(this.pos);\n this.pos += 4;\n return value;\n }\n readU64() {\n const value = (0, int_ts_1.getUint64)(this.view, this.pos);\n this.pos += 8;\n return value;\n }\n readI64() {\n const value = (0, int_ts_1.getInt64)(this.view, this.pos);\n this.pos += 8;\n return value;\n }\n readU64AsBigInt() {\n const value = this.view.getBigUint64(this.pos);\n this.pos += 8;\n return value;\n }\n readI64AsBigInt() {\n const value = this.view.getBigInt64(this.pos);\n this.pos += 8;\n return value;\n }\n readF32() {\n const value = this.view.getFloat32(this.pos);\n this.pos += 4;\n return value;\n }\n readF64() {\n const value = this.view.getFloat64(this.pos);\n this.pos += 8;\n return value;\n }\n}\nexports.Decoder = Decoder;\n//# sourceMappingURL=Decoder.cjs.map",
27
+ "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.decode = decode;\nexports.decodeMulti = decodeMulti;\nconst Decoder_ts_1 = require(\"./Decoder.cjs\");;\n/**\n * It decodes a single MessagePack object in a buffer.\n *\n * This is a synchronous decoding function.\n * See other variants for asynchronous decoding: {@link decodeAsync}, {@link decodeMultiStream}, or {@link decodeArrayStream}.\n *\n * @throws {@link RangeError} if the buffer is incomplete, including the case where the buffer is empty.\n * @throws {@link DecodeError} if the buffer contains invalid data.\n */\nfunction decode(buffer, options) {\n const decoder = new Decoder_ts_1.Decoder(options);\n return decoder.decode(buffer);\n}\n/**\n * It decodes multiple MessagePack objects in a buffer.\n * This is corresponding to {@link decodeMultiStream}.\n *\n * @throws {@link RangeError} if the buffer is incomplete, including the case where the buffer is empty.\n * @throws {@link DecodeError} if the buffer contains invalid data.\n */\nfunction decodeMulti(buffer, options) {\n const decoder = new Decoder_ts_1.Decoder(options);\n return decoder.decodeMulti(buffer);\n}\n//# sourceMappingURL=decode.cjs.map",
28
+ "\"use strict\";\n// utility for whatwg streams\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.isAsyncIterable = isAsyncIterable;\nexports.asyncIterableFromStream = asyncIterableFromStream;\nexports.ensureAsyncIterable = ensureAsyncIterable;\nfunction isAsyncIterable(object) {\n return object[Symbol.asyncIterator] != null;\n}\nasync function* asyncIterableFromStream(stream) {\n const reader = stream.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n return;\n }\n yield value;\n }\n }\n finally {\n reader.releaseLock();\n }\n}\nfunction ensureAsyncIterable(streamLike) {\n if (isAsyncIterable(streamLike)) {\n return streamLike;\n }\n else {\n return asyncIterableFromStream(streamLike);\n }\n}\n//# sourceMappingURL=stream.cjs.map",
29
+ "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.decodeAsync = decodeAsync;\nexports.decodeArrayStream = decodeArrayStream;\nexports.decodeMultiStream = decodeMultiStream;\nconst Decoder_ts_1 = require(\"./Decoder.cjs\");;\nconst stream_ts_1 = require(\"./utils/stream.cjs\");;\n/**\n * @throws {@link RangeError} if the buffer is incomplete, including the case where the buffer is empty.\n * @throws {@link DecodeError} if the buffer contains invalid data.\n */\nasync function decodeAsync(streamLike, options) {\n const stream = (0, stream_ts_1.ensureAsyncIterable)(streamLike);\n const decoder = new Decoder_ts_1.Decoder(options);\n return decoder.decodeAsync(stream);\n}\n/**\n * @throws {@link RangeError} if the buffer is incomplete, including the case where the buffer is empty.\n * @throws {@link DecodeError} if the buffer contains invalid data.\n */\nfunction decodeArrayStream(streamLike, options) {\n const stream = (0, stream_ts_1.ensureAsyncIterable)(streamLike);\n const decoder = new Decoder_ts_1.Decoder(options);\n return decoder.decodeArrayStream(stream);\n}\n/**\n * @throws {@link RangeError} if the buffer is incomplete, including the case where the buffer is empty.\n * @throws {@link DecodeError} if the buffer contains invalid data.\n */\nfunction decodeMultiStream(streamLike, options) {\n const stream = (0, stream_ts_1.ensureAsyncIterable)(streamLike);\n const decoder = new Decoder_ts_1.Decoder(options);\n return decoder.decodeStream(stream);\n}\n//# sourceMappingURL=decodeAsync.cjs.map",
30
+ "\"use strict\";\n// Main Functions:\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.decodeTimestampExtension = exports.encodeTimestampExtension = exports.decodeTimestampToTimeSpec = exports.encodeTimeSpecToTimestamp = exports.encodeDateToTimeSpec = exports.EXT_TIMESTAMP = exports.ExtData = exports.ExtensionCodec = exports.Encoder = exports.DecodeError = exports.Decoder = exports.decodeMultiStream = exports.decodeArrayStream = exports.decodeAsync = exports.decodeMulti = exports.decode = exports.encode = void 0;\nconst encode_ts_1 = require(\"./encode.cjs\");;\nObject.defineProperty(exports, \"encode\", { enumerable: true, get: function () { return encode_ts_1.encode; } });\nconst decode_ts_1 = require(\"./decode.cjs\");;\nObject.defineProperty(exports, \"decode\", { enumerable: true, get: function () { return decode_ts_1.decode; } });\nObject.defineProperty(exports, \"decodeMulti\", { enumerable: true, get: function () { return decode_ts_1.decodeMulti; } });\nconst decodeAsync_ts_1 = require(\"./decodeAsync.cjs\");;\nObject.defineProperty(exports, \"decodeAsync\", { enumerable: true, get: function () { return decodeAsync_ts_1.decodeAsync; } });\nObject.defineProperty(exports, \"decodeArrayStream\", { enumerable: true, get: function () { return decodeAsync_ts_1.decodeArrayStream; } });\nObject.defineProperty(exports, \"decodeMultiStream\", { enumerable: true, get: function () { return decodeAsync_ts_1.decodeMultiStream; } });\nconst Decoder_ts_1 = require(\"./Decoder.cjs\");;\nObject.defineProperty(exports, \"Decoder\", { enumerable: true, get: function () { return Decoder_ts_1.Decoder; } });\nconst DecodeError_ts_1 = require(\"./DecodeError.cjs\");;\nObject.defineProperty(exports, \"DecodeError\", { enumerable: true, get: function () { return DecodeError_ts_1.DecodeError; } });\nconst Encoder_ts_1 = require(\"./Encoder.cjs\");;\nObject.defineProperty(exports, \"Encoder\", { enumerable: true, get: function () { return Encoder_ts_1.Encoder; } });\n// Utilities for Extension Types:\nconst ExtensionCodec_ts_1 = require(\"./ExtensionCodec.cjs\");;\nObject.defineProperty(exports, \"ExtensionCodec\", { enumerable: true, get: function () { return ExtensionCodec_ts_1.ExtensionCodec; } });\nconst ExtData_ts_1 = require(\"./ExtData.cjs\");;\nObject.defineProperty(exports, \"ExtData\", { enumerable: true, get: function () { return ExtData_ts_1.ExtData; } });\nconst timestamp_ts_1 = require(\"./timestamp.cjs\");;\nObject.defineProperty(exports, \"EXT_TIMESTAMP\", { enumerable: true, get: function () { return timestamp_ts_1.EXT_TIMESTAMP; } });\nObject.defineProperty(exports, \"encodeDateToTimeSpec\", { enumerable: true, get: function () { return timestamp_ts_1.encodeDateToTimeSpec; } });\nObject.defineProperty(exports, \"encodeTimeSpecToTimestamp\", { enumerable: true, get: function () { return timestamp_ts_1.encodeTimeSpecToTimestamp; } });\nObject.defineProperty(exports, \"decodeTimestampToTimeSpec\", { enumerable: true, get: function () { return timestamp_ts_1.decodeTimestampToTimeSpec; } });\nObject.defineProperty(exports, \"encodeTimestampExtension\", { enumerable: true, get: function () { return timestamp_ts_1.encodeTimestampExtension; } });\nObject.defineProperty(exports, \"decodeTimestampExtension\", { enumerable: true, get: function () { return timestamp_ts_1.decodeTimestampExtension; } });\n//# sourceMappingURL=index.cjs.map",
31
+ "import type { Job } from '../Job'\nimport type { SerializedJob } from '../types'\nimport type { JobSerializer } from './JobSerializer'\n\n/**\n * MessagePack Serializer.\n *\n * Serializes jobs using MessagePack (binary format), encoded as a Base64 string.\n * Offers smaller payload sizes than JSON for complex data structures.\n *\n * Requires the optional `@msgpack/msgpack` dependency.\n *\n * @public\n * @example\n * ```typescript\n * const serializer = new MessagePackSerializer();\n * ```\n */\nexport class MessagePackSerializer implements JobSerializer {\n private msgpack: any\n\n constructor() {\n try {\n this.msgpack = require('@msgpack/msgpack')\n } catch (_e) {\n throw new Error(\n 'MessagePackSerializer requires @msgpack/msgpack. Please install it: bun add @msgpack/msgpack'\n )\n }\n }\n\n /**\n * Serialize a job using MessagePack.\n */\n serialize(job: Job): SerializedJob {\n const id = job.id || `${Date.now()}-${crypto.randomUUID()}`\n\n // Extract properties (exclude methods)\n const properties: Record<string, unknown> = {}\n for (const key in job) {\n if (\n Object.hasOwn(job, key) &&\n typeof (job as unknown as Record<string, unknown>)[key] !== 'function'\n ) {\n properties[key] = (job as unknown as Record<string, unknown>)[key]\n }\n }\n\n const encoded = this.msgpack.encode(properties)\n const data = Buffer.from(encoded).toString('base64')\n\n return {\n id,\n type: 'msgpack',\n data,\n createdAt: Date.now(),\n ...(job.delaySeconds !== undefined ? { delaySeconds: job.delaySeconds } : {}),\n attempts: job.attempts ?? 0,\n ...(job.maxAttempts !== undefined ? { maxAttempts: job.maxAttempts } : {}),\n ...(job.groupId ? { groupId: job.groupId } : {}),\n ...(job.priority ? { priority: job.priority } : {}),\n }\n }\n\n /**\n * Deserialize a MessagePack job.\n */\n deserialize(serialized: SerializedJob): Job {\n if (serialized.type !== 'msgpack') {\n throw new Error('Invalid serialization type: expected \"msgpack\"')\n }\n\n const buffer =\n typeof serialized.data === 'string'\n ? Buffer.from(serialized.data, 'base64')\n : Buffer.from(serialized.data)\n const properties = this.msgpack.decode(buffer) as Record<string, any>\n\n const job = Object.create({}) as Record<string, any>\n Object.assign(job, properties)\n\n job.id = serialized.id\n if (serialized.groupId) {\n job.groupId = serialized.groupId\n }\n if (serialized.priority) {\n job.priority = serialized.priority\n }\n if (serialized.delaySeconds !== undefined) {\n job.delaySeconds = serialized.delaySeconds\n }\n if (serialized.attempts !== undefined) {\n job.attempts = serialized.attempts\n }\n\n return job as Job\n }\n}\n",
32
+ "import parser from 'cron-parser'\nimport type { GroupRedisClient } from './drivers/RedisDriver'\nimport { DistributedLock } from './locks/DistributedLock'\nimport type { QueueManager } from './QueueManager'\nimport type { SerializedJob } from './types'\n\n/**\n * Configuration for a recurring scheduled job.\n *\n * Defines the schedule (CRON), the job to execute, and metadata tracking execution times.\n *\n * @public\n * @since 3.0.0\n * @example\n * ```typescript\n * const config: ScheduledJobConfig = {\n * id: 'daily-report',\n * cron: '0 0 * * *',\n * queue: 'reports',\n * job: serializedJob,\n * enabled: true\n * };\n * ```\n */\nexport interface ScheduledJobConfig {\n /** Unique identifier for the scheduled task. */\n id: string\n /** Cron expression defining the schedule (e.g., '* * * * *'). */\n cron: string\n /** The target queue name where the job should be pushed. */\n queue: string\n /** The serialized job data. */\n job: SerializedJob\n /** Timestamp of the last successful execution in milliseconds. */\n lastRun?: number\n /** Timestamp of the next scheduled execution in milliseconds. */\n nextRun?: number\n /** Whether the scheduled job is active. */\n enabled: boolean\n}\n\n/**\n * Configuration options for the Scheduler.\n *\n * Defines behavior for scheduling tasks, including distributed lock settings.\n *\n * @public\n * @since 3.1.0\n * @example\n * ```typescript\n * const options: SchedulerOptions = {\n * prefix: 'myapp:queue:',\n * lockTtl: 60000, // Lock held for 60 seconds\n * lockRefreshInterval: 20000 // Auto-renew every 20 seconds\n * };\n * ```\n */\nexport interface SchedulerOptions {\n /**\n * Prefix for Redis keys.\n *\n * @default 'queue:'\n */\n prefix?: string\n\n /**\n * Time-to-live for the distributed lock in milliseconds.\n *\n * Setting a longer TTL ensures long-running tasks are not executed repeatedly\n * due to lock expiration. Recommended to be 2-3 times the expected execution time.\n *\n * @default 60000 (60 seconds)\n */\n lockTtl?: number\n\n /**\n * Interval for automatic lock renewal in milliseconds.\n *\n * If set, the lock will be automatically extended every `lockRefreshInterval`.\n * Recommended to be 1/3 of `lockTtl`.\n *\n * @default 20000 (20 seconds)\n */\n lockRefreshInterval?: number\n\n /**\n * Number of retries when acquiring a lock fails.\n *\n * @default 0\n */\n lockRetryCount?: number\n\n /**\n * Delay between lock acquisition retries in milliseconds.\n *\n * @default 100\n */\n lockRetryDelay?: number\n\n /**\n * The interval in milliseconds at which the scheduler checks for due tasks.\n *\n * @default 60000 (1 minute)\n */\n tickInterval?: number\n\n /**\n * The time-to-live for the leader lock in milliseconds.\n *\n * Ensures that only one node acts as the scheduler leader.\n * @default 30000 (30 seconds)\n */\n leaderTtl?: number\n}\n\n/**\n * Manages recurring tasks and cron jobs.\n *\n * The Scheduler allows you to register jobs to run at specific intervals using CRON syntax.\n * It uses Redis (or a compatible driver) to coordinate distributed execution, ensuring that\n * a scheduled job runs only once per interval across multiple scheduler instances.\n *\n * @public\n * @since 3.0.0\n * @example\n * ```typescript\n * const scheduler = manager.getScheduler();\n * await scheduler.register({\n * id: 'cleanup',\n * cron: '0 * * * *', // Every hour\n * job: new CleanupJob()\n * });\n *\n * // Automatically start the scheduler loop\n * await scheduler.start();\n * ```\n */\nexport class Scheduler {\n private prefix: string\n private lockTtl: number\n private lockRefreshInterval?: number\n private lockRetryCount: number\n private lockRetryDelay: number\n private tickInterval: number\n private leaderTtl: number\n private distributedLock?: DistributedLock\n private running = false\n private timer: NodeJS.Timeout | null = null\n private isLeader = false\n\n constructor(\n private manager: QueueManager,\n options: SchedulerOptions = {}\n ) {\n this.prefix = options.prefix ?? 'queue:'\n this.lockTtl = options.lockTtl ?? 60000\n this.lockRefreshInterval = options.lockRefreshInterval ?? 20000\n this.lockRetryCount = options.lockRetryCount ?? 0\n this.lockRetryDelay = options.lockRetryDelay ?? 100\n this.tickInterval = options.tickInterval ?? 60000\n this.leaderTtl = options.leaderTtl ?? 30000\n }\n\n private get client(): GroupRedisClient {\n const driver = this.manager.getDriver(this.manager.getDefaultConnection())\n if (!driver || !('client' in driver)) {\n throw new Error('[Scheduler] Driver does not support Redis client access')\n }\n return (driver as { client: GroupRedisClient }).client\n }\n\n /**\n * Gets or creates the distributed lock instance.\n *\n * @private\n */\n private getDistributedLock(): DistributedLock {\n if (!this.distributedLock) {\n this.distributedLock = new DistributedLock(this.client)\n }\n return this.distributedLock\n }\n\n /**\n * Registers a new scheduled job or updates an existing one.\n *\n * Calculates the next run time based on the CRON expression and stores the configuration in Redis.\n *\n * @param config - The job configuration (excluding nextRun and enabled status which are auto-set).\n * @throws {Error} If Redis client does not support pipelining.\n */\n async register(config: Omit<ScheduledJobConfig, 'nextRun' | 'enabled'>): Promise<void> {\n const nextRun = (parser as any).parse(config.cron).next().getTime()\n const fullConfig: ScheduledJobConfig = {\n ...config,\n nextRun,\n enabled: true,\n }\n\n const client = this.client\n if (typeof client.pipeline !== 'function') {\n throw new Error('[Scheduler] Redis client does not support pipeline')\n }\n\n const pipe = client.pipeline()\n // 1. Store metadata\n pipe.hset(`${this.prefix}schedule:${config.id}`, {\n ...fullConfig,\n job: JSON.stringify(fullConfig.job),\n })\n // 2. Add to timeline\n pipe.zadd(`${this.prefix}schedules`, nextRun, config.id)\n await pipe.exec()\n }\n\n /**\n * Removes a scheduled job.\n *\n * Deletes the job metadata and schedule entry from Redis.\n *\n * @param id - The unique identifier of the scheduled job.\n */\n async remove(id: string): Promise<void> {\n const client = this.client\n if (typeof client.pipeline !== 'function') {\n throw new Error('[Scheduler] Redis client does not support pipeline')\n }\n\n const pipe = client.pipeline()\n pipe.del(`${this.prefix}schedule:${id}`)\n pipe.zrem(`${this.prefix}schedules`, id)\n await pipe.exec()\n }\n\n /**\n * Lists all registered scheduled jobs.\n *\n * @returns An array of all scheduled job configurations.\n */\n async list(): Promise<ScheduledJobConfig[]> {\n const client = this.client\n if (typeof client.zrange !== 'function') {\n throw new Error('[Scheduler] Redis client does not support zrange')\n }\n\n const ids = await client.zrange(`${this.prefix}schedules`, 0, -1)\n const configs: ScheduledJobConfig[] = []\n\n for (const id of ids) {\n const data = await client.hgetall?.(`${this.prefix}schedule:${id}`)\n if (data?.id) {\n configs.push({\n ...data,\n lastRun: data.lastRun ? parseInt(data.lastRun, 10) : undefined,\n nextRun: data.nextRun ? parseInt(data.nextRun, 10) : undefined,\n enabled: data.enabled === 'true',\n job: JSON.parse(data.job),\n })\n }\n }\n\n return configs\n }\n\n /**\n * Starts the automatic scheduler loop.\n *\n * Periodically triggers `tick()` to process due jobs. Uses leader election\n * to ensure that only one node performs the scanning in a multi-node environment.\n */\n async start(): Promise<void> {\n if (this.running) {\n return\n }\n this.running = true\n\n const loop = async () => {\n if (!this.running) {\n return\n }\n\n try {\n await this.performTickWithLeaderElection()\n } catch (err) {\n console.error('[Scheduler] Loop error:', err)\n }\n\n this.timer = setTimeout(loop, this.tickInterval)\n }\n\n loop()\n }\n\n /**\n * Stops the automatic scheduler loop.\n */\n async stop(): Promise<void> {\n this.running = false\n if (this.timer) {\n clearTimeout(this.timer)\n this.timer = null\n }\n\n if (this.isLeader) {\n await this.releaseLeader()\n }\n }\n\n /**\n * Acquires the leader lock and performs a tick.\n *\n * @private\n */\n private async performTickWithLeaderElection(): Promise<void> {\n const lock = this.getDistributedLock()\n const leaderKey = `${this.prefix}scheduler:leader`\n\n this.isLeader = await lock.acquire(leaderKey, {\n ttl: this.leaderTtl,\n refreshInterval: Math.floor(this.leaderTtl / 3),\n retryCount: 0,\n retryDelay: 0,\n })\n\n if (this.isLeader) {\n await this.tick()\n }\n }\n\n /**\n * Releases the leader lock.\n *\n * @private\n */\n private async releaseLeader(): Promise<void> {\n const lock = this.getDistributedLock()\n const leaderKey = `${this.prefix}scheduler:leader`\n await lock.release(leaderKey)\n this.isLeader = false\n }\n\n /**\n * Manually triggers a scheduled job immediately.\n *\n * Forces execution of the job regardless of its schedule, without affecting the next scheduled run time.\n *\n * @param id - The unique identifier of the scheduled job.\n */\n async runNow(id: string): Promise<void> {\n const client = this.client\n const data = await client.hgetall?.(`${this.prefix}schedule:${id}`)\n\n if (data?.id) {\n const serialized = JSON.parse(data.job)\n const serializer = this.manager.getSerializer()\n const job = serializer.deserialize(serialized) as any\n await this.manager.push(job)\n }\n }\n\n /**\n * Checks for and triggers tasks that are due for execution.\n *\n * This method should be called periodically (e.g., via a system cron or a dedicated tick loop).\n * It scans the schedule for tasks with `nextRun <= now`, acquires a distributed lock for each,\n * pushes them to their queue, and updates the `nextRun` time.\n *\n * The distributed lock ensures that in a multi-node environment, each scheduled job is executed\n * only once per interval, even if multiple scheduler instances are running.\n *\n * @returns The number of jobs triggered in this tick.\n */\n async tick(): Promise<number> {\n const client = this.client\n if (typeof client.zrangebyscore !== 'function') {\n throw new Error('[Scheduler] Redis client does not support zrangebyscore')\n }\n\n const now = Date.now()\n const dueIds = await client.zrangebyscore(`${this.prefix}schedules`, 0, now)\n let fired = 0\n\n const lock = this.getDistributedLock()\n\n for (const id of dueIds) {\n // Use distributed lock to ensure only one worker processes this schedule\n // Lock key includes ID and current timestamp (seconds) to ensure once per window\n const lockKey = `${this.prefix}lock:schedule:${id}:${Math.floor(now / 1000)}`\n\n const acquired = await lock.acquire(lockKey, {\n ttl: this.lockTtl,\n retryCount: this.lockRetryCount,\n retryDelay: this.lockRetryDelay,\n refreshInterval: this.lockRefreshInterval,\n })\n\n if (acquired) {\n try {\n const data = await client.hgetall?.(`${this.prefix}schedule:${id}`)\n if (data?.id && data.enabled === 'true') {\n try {\n const serializedJob = JSON.parse(data.job) as SerializedJob\n const connection = data.connection || this.manager.getDefaultConnection()\n const driver = this.manager.getDriver(connection)\n\n // 1. Push directly to queue (pass serialized data)\n // This avoids needing to register job classes in the scheduler process\n await driver.push(data.queue, serializedJob)\n\n // 2. Schedule next run\n const nextRun = (parser as any).parse(data.cron).next().getTime()\n\n if (typeof client.pipeline === 'function') {\n const pipe = client.pipeline()\n pipe.hset(`${this.prefix}schedule:${id}`, {\n lastRun: now,\n nextRun: nextRun,\n })\n pipe.zadd(`${this.prefix}schedules`, nextRun, id)\n await pipe.exec()\n }\n\n fired++\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err))\n console.error(`[Scheduler] Failed to process schedule ${id}:`, error.message)\n }\n }\n } finally {\n // Ensure lock is released\n await lock.release(lockKey)\n }\n }\n }\n\n return fired\n }\n}\n",
33
+ "import type { GravitoContext } from '@gravito/core'\nimport type { QueueManager } from './QueueManager'\n\n/**\n * Provides API routes for the Stream Monitoring Dashboard.\n *\n * This class encapsulates the logic for querying queue statistics,\n * browsing archived jobs, and performing management actions like retrying jobs.\n *\n * @internal\n */\nexport class DashboardProvider {\n constructor(private manager: QueueManager) {}\n\n /**\n * Registers dashboard API routes on the provided core adapter.\n *\n * @param core - The PlanetCore instance.\n * @param basePath - The base path for API routes (default: '/_flux').\n */\n registerRoutes(core: any, basePath = '/_flux'): void {\n const router = core.adapter\n\n router.get(`${basePath}/stats`, async (c: GravitoContext) => {\n const stats = await this.manager.getGlobalStats()\n return c.json(stats)\n })\n\n router.get(`${basePath}/queues`, async (c: GravitoContext) => {\n const stats = await this.manager.getGlobalStats()\n const queues = Object.entries(stats.connections).flatMap(([conn, qList]) =>\n qList.map((q: any) => ({\n connection: conn,\n name: q.queue,\n size: q.size,\n failed: q.failed,\n }))\n )\n return c.json(queues)\n })\n\n router.get(`${basePath}/jobs`, async (c: GravitoContext) => {\n const queue = c.req.query('queue') || 'default'\n const status = c.req.query('status')\n const limit = parseInt(c.req.query('limit') || '50', 10)\n const offset = parseInt(c.req.query('offset') || '0', 10)\n\n const persistence = this.manager.getPersistence()\n if (!persistence) {\n return c.json({ error: 'Persistence not configured' }, 400)\n }\n\n const statuses = status ? (status.includes(',') ? status.split(',') : status) : undefined\n const [jobs, total] = await Promise.all([\n persistence.list(queue, { status: statuses as any, limit, offset }),\n persistence.count(queue, { status: statuses as any }),\n ])\n\n return c.json({\n data: jobs,\n meta: {\n total,\n limit,\n offset,\n },\n })\n })\n\n router.post(`${basePath}/jobs/retry`, async (c: GravitoContext) => {\n const { queue, count } = await c.req.json<{ queue: string; count?: number }>()\n if (!queue) {\n return c.json({ error: 'Queue name is required' }, 400)\n }\n\n const retried = await this.manager.retryFailed(queue, count || 1)\n return c.json({ success: true, retried })\n })\n\n router.get(`${basePath}/logs`, async (c: GravitoContext) => {\n const persistence = this.manager.getPersistence()\n if (!persistence) {\n return c.json({ error: 'Persistence not configured' }, 400)\n }\n\n const limit = parseInt(c.req.query('limit') || '100', 10)\n const offset = parseInt(c.req.query('offset') || '0', 10)\n const level = c.req.query('level')\n const search = c.req.query('search')\n\n const [logs, total] = await Promise.all([\n persistence.listLogs({ limit, offset, level, search }),\n persistence.countLogs({ level, search }),\n ])\n\n return c.json({\n data: logs,\n meta: {\n total,\n limit,\n offset,\n },\n })\n })\n }\n}\n",
34
+ "import type { Job } from './Job'\nimport type { QueueManager } from './QueueManager'\n\n/**\n * Configuration options for the BatchConsumer.\n *\n * @example\n * ```typescript\n * const options: BatchConsumerOptions = {\n * batchSize: 50,\n * autoAck: false\n * };\n * ```\n */\nexport interface BatchConsumerOptions {\n /**\n * The name of the queue to consume from.\n * @default 'default'\n */\n queue?: string\n\n /**\n * The connection name to use.\n * @default The default connection of QueueManager\n */\n connection?: string\n\n /**\n * The number of jobs to try to retrieve in each batch.\n * @default 10\n */\n batchSize?: number\n\n /**\n * The polling interval in milliseconds when the queue is empty.\n * @default 1000\n */\n pollInterval?: number\n\n /**\n * Whether to automatically complete jobs after the handler returns successfully.\n *\n * If set to `false`, the handler function is responsible for calling `manager.complete()`\n * or `manager.fail()` for each job.\n *\n * @default true\n */\n autoAck?: boolean\n}\n\n/**\n * Specialized consumer for processing jobs in bulk.\n *\n * Unlike the standard `Consumer` which processes jobs individually (even if fetched in batches),\n * the `BatchConsumer` passes an array of jobs to a single handler function. This is ideal for\n * operations that benefit from bulk processing, such as database inserts or API calls that support batching.\n *\n * @public\n * @example\n * ```typescript\n * const consumer = new BatchConsumer(manager, async (jobs) => {\n * // Process 100 jobs at once\n * await elasticsearch.bulkIndex(jobs.map(j => j.data));\n * }, { batchSize: 100 });\n *\n * consumer.start();\n * ```\n */\nexport class BatchConsumer {\n private running = false\n private options: BatchConsumerOptions\n\n constructor(\n private manager: QueueManager,\n private handler: (jobs: Job[]) => Promise<void>,\n options: BatchConsumerOptions = {}\n ) {\n this.options = {\n queue: 'default',\n batchSize: 10,\n pollInterval: 1000,\n autoAck: true,\n ...options,\n }\n }\n\n /**\n * Starts the batch consuming loop.\n *\n * Continuously polls for batches of jobs and passes them to the handler.\n */\n async start(): Promise<void> {\n if (this.running) {\n return\n }\n this.running = true\n\n const { queue, connection, batchSize, pollInterval, autoAck } = this.options\n\n while (this.running) {\n try {\n const jobs = await this.manager.popMany(queue, batchSize, connection)\n\n if (jobs.length > 0) {\n try {\n await this.handler(jobs)\n\n if (autoAck) {\n // Complete all jobs in parallel\n await Promise.all(jobs.map((job) => this.manager.complete(job)))\n }\n } catch (error) {\n console.error(`[BatchConsumer] Batch processing failed:`, error)\n const err = error instanceof Error ? error : new Error(String(error))\n\n if (autoAck) {\n // Fail all jobs in parallel\n await Promise.all(jobs.map((job) => this.manager.fail(job, err)))\n }\n }\n } else {\n // Empty queue, wait\n await new Promise((resolve) => setTimeout(resolve, pollInterval))\n }\n } catch (err) {\n console.error(`[BatchConsumer] Polling error:`, err)\n // Wait before retrying to avoid tight loop on error\n await new Promise((resolve) => setTimeout(resolve, pollInterval))\n }\n }\n }\n\n /**\n * Stops the consumer loop.\n *\n * Sets the running flag to false. The loop will exit after the current iteration finishes.\n */\n stop(): void {\n this.running = false\n }\n}\n",
35
+ "import { EventEmitter } from 'node:events'\nimport { StreamingConsumer } from './consumer/StreamingConsumer'\nimport type { ConsumerStats } from './consumer/types'\nimport type { QueueManager } from './QueueManager'\nimport type { WorkerOptions } from './Worker'\n\n/**\n * Configuration options for the Consumer.\n *\n * Defines which queues to listen to, connection settings, concurrency levels,\n * and advanced behavior like rate limiting and batch processing.\n *\n * @example\n * ```typescript\n * const options: ConsumerOptions = {\n * queues: ['emails', 'notifications'],\n * concurrency: 5,\n * pollInterval: 2000\n * };\n * ```\n */\nexport interface ConsumerOptions {\n /**\n * List of queue names to consume jobs from.\n *\n * The consumer will poll these queues in the order provided or based on driver logic.\n */\n queues: string[]\n\n /**\n * The connection name to use (e.g., 'redis', 'sqs').\n *\n * If not provided, uses the default connection from QueueManager.\n */\n connection?: string\n\n /**\n * Configuration options passed to the underlying Worker.\n */\n workerOptions?: WorkerOptions\n\n /**\n * The interval in milliseconds to wait before polling again when the queue is empty.\n */\n pollInterval?: number\n\n /**\n * Whether to keep the process alive when queues are empty.\n *\n * If false, the consumer will exit the loop when no jobs are found (useful for one-off scripts).\n */\n keepAlive?: boolean\n\n /**\n * Monitoring configuration.\n *\n * Can be a boolean to enable default monitoring, or an object for advanced configuration.\n */\n monitor?:\n | boolean\n | {\n /**\n * The interval in milliseconds for sending heartbeat updates.\n * @default 5000\n */\n interval?: number\n\n /**\n * Additional metadata to include in heartbeat payloads.\n */\n extraInfo?: Record<string, unknown>\n\n /**\n * Key prefix for monitoring events (e.g. for Redis Pub/Sub).\n */\n prefix?: string\n }\n\n /**\n * Rate limiting configuration per queue.\n *\n * Defines the maximum number of jobs to process within a given duration.\n *\n * @example\n * ```typescript\n * { 'emails': { max: 10, duration: 1000 } } // 10 emails per second\n * ```\n */\n rateLimits?: Record<string, { max: number; duration: number }>\n\n /**\n * The maximum number of jobs to process concurrently.\n *\n * @default 1\n */\n concurrency?: number\n\n /**\n * Whether to enforce sequential processing for jobs with the same `groupId`.\n *\n * If true, jobs sharing a `groupId` will be processed one after another,\n * even if global concurrency is high.\n *\n * @default true\n */\n groupJobsSequential?: boolean\n\n /**\n * The minimum polling interval in milliseconds for adaptive polling.\n *\n * @default 100\n */\n minPollInterval?: number\n\n /**\n * The maximum polling interval in milliseconds for adaptive polling.\n *\n * @default 5000\n */\n maxPollInterval?: number\n\n /**\n * The multiplier used to increase the polling interval when the queue is empty.\n *\n * @default 1.5\n */\n backoffMultiplier?: number\n\n /**\n * The number of jobs to try to fetch in a single request.\n *\n * If supported by the driver, fetching multiple jobs reduces network round-trips.\n *\n * @default 1\n */\n batchSize?: number\n\n /**\n * Whether to use blocking operations (like BLPOP in Redis) when polling.\n *\n * Significant optimization for low-latency job pickup. Only applies when `batchSize` is 1.\n *\n * @default true\n */\n useBlocking?: boolean\n\n /**\n * The timeout in seconds for blocking operations.\n *\n * @default 5\n */\n blockingTimeout?: number\n\n /**\n * Enable verbose debug logging for consumer activities.\n *\n * @default false\n */\n debug?: boolean\n\n /**\n * 最大處理請求數量。\n *\n * 當 consumer 處理完這個數量的 job 後會自動停止(觸發 max_requests_reached 事件)。\n * 適用於需要定期重啟 worker 的場景(避免記憶體累積、載入最新程式碼等)。\n *\n * @default undefined (無限制)\n */\n maxRequests?: number\n\n /**\n * Optional event callback for external monitoring systems.\n *\n * Called whenever a job lifecycle event occurs (started, processed, failed, etc.).\n */\n onEvent?: (event: string, payload: unknown) => void\n\n /**\n * Enable reactive (push-based) consumption mode.\n *\n * When enabled, the consumer listens for notifications and pulls jobs reactively\n * instead of polling continuously. This reduces latency and resource usage.\n *\n * @default false\n */\n reactive?: boolean\n\n /**\n * Fallback polling interval (ms) when no notifications are received.\n *\n * In reactive mode, if no notifications arrive for this duration,\n * the consumer will fallback to polling to ensure jobs aren't missed.\n * Prevents starvation if the notification system fails.\n *\n * @default 30000 (30 seconds)\n */\n reactivePollingFallback?: number\n}\n\n/**\n * Consumer 門面類別(Facade),提供向後相容的公開 API。\n *\n * 內部委派給 StreamingConsumer 實作,所有事件都通過 passthrough。\n * 公開 API 與原始 Consumer 完全一致,不破壞現有使用者程式碼。\n *\n * @public\n */\nexport class Consumer extends EventEmitter {\n /** 內部 StreamingConsumer 實例 */\n private streaming: StreamingConsumer\n\n constructor(\n readonly queueManager: QueueManager,\n readonly options: ConsumerOptions\n ) {\n super()\n this.streaming = new StreamingConsumer(queueManager, options)\n this.forwardEvents()\n }\n\n /**\n * 將 StreamingConsumer 的所有事件轉發給 Consumer。\n */\n private forwardEvents(): void {\n const events = [\n 'job:started',\n 'job:processed',\n 'job:failed',\n 'job:retried',\n 'job:failed_permanently',\n 'max_requests_reached',\n 'error',\n ]\n\n for (const event of events) {\n this.streaming.on(event, (payload: unknown) => {\n this.emit(event, payload)\n })\n }\n }\n\n /**\n * Starts the consumer loop.\n */\n async start(): Promise<void> {\n return this.streaming.start()\n }\n\n /**\n * Gracefully stops the consumer.\n */\n async stop(): Promise<void> {\n return this.streaming.requestStop()\n }\n\n /**\n * Checks if the consumer is currently active.\n */\n isRunning(): boolean {\n return this.streaming.isRunning()\n }\n\n /**\n * Retrieves current operational statistics.\n */\n getStats(): ConsumerStats {\n return this.streaming.getStats()\n }\n\n /**\n * Resets the internal statistics counters.\n */\n resetStats(): void {\n this.streaming.resetStats()\n }\n}\n",
36
+ "import { EventEmitter } from 'node:events'\nimport type { ConsumerOptions } from '../Consumer'\nimport type { QueueManager } from '../QueueManager'\nimport { Worker } from '../Worker'\nimport { ConcurrencyGate } from './ConcurrencyGate'\nimport { GroupSequencer } from './GroupSequencer'\nimport { HeartbeatManager } from './HeartbeatManager'\nimport { JobExecutor } from './JobExecutor'\nimport { jobSourceGenerator } from './JobSourceGenerator'\nimport type { ConsumerStats } from './types'\n\n/**\n * StreamingConsumer 是 Consumer 管線的核心實作。\n *\n * 組合以下元件,提供高效能、可測試的 job 消費管線:\n * - JobSourceGenerator:抓取 job 的 Async Generator\n * - ConcurrencyGate:Promise-based Semaphore,取代 busy-wait\n * - GroupSequencer:確保相同 groupId 的 job 依序執行\n * - JobExecutor:完整的 job 執行生命週期\n * - HeartbeatManager:定時心跳與監控日誌\n *\n * 主管線採用 `for await...of` 模式,\n * 完全消除原始 Consumer 中的 `setTimeout(50)` busy-wait。\n *\n * @example\n * ```typescript\n * const streaming = new StreamingConsumer(queueManager, options)\n * streaming.on('job:processed', (payload) => console.log('Done:', payload.job.id))\n *\n * await streaming.start()\n * ```\n */\nexport class StreamingConsumer extends EventEmitter {\n private running = false\n private stopRequested = false\n private readonly workerId: string\n private readonly stats: ConsumerStats = {\n processed: 0,\n failed: 0,\n retried: 0,\n active: 0,\n }\n\n private gate: ConcurrencyGate | null = null\n private sequencer: GroupSequencer | null = null\n private heartbeat: HeartbeatManager | null = null\n private abortController: AbortController | null = null\n\n constructor(\n private readonly queueManager: QueueManager,\n private readonly options: ConsumerOptions\n ) {\n super()\n this.workerId = `worker-${crypto.randomUUID()}`\n }\n\n /**\n * 啟動主消費管線。\n *\n * 初始化所有元件,然後進入 `for await...of` 管線迴圈:\n * 1. 從 jobSourceGenerator 取得 FetchResult\n * 2. 對每個 job,acquire ConcurrencyGate\n * 3. 透過 GroupSequencer 確保 group 序列\n * 4. 由 JobExecutor 執行 job\n * 5. release ConcurrencyGate\n *\n * @throws {Error} 如果 consumer 已在執行中\n */\n async start(): Promise<void> {\n if (this.running) {\n throw new Error('Consumer is already running')\n }\n\n this.running = true\n this.stopRequested = false\n this.abortController = new AbortController()\n\n const concurrency = this.options.concurrency ?? 1\n const batchSize = this.options.batchSize ?? 1\n const useBlocking = this.options.useBlocking ?? true\n const blockingTimeout = this.options.blockingTimeout ?? 5\n const keepAlive = this.options.keepAlive ?? true\n const minPollInterval = this.options.minPollInterval ?? 100\n const maxPollInterval = this.options.maxPollInterval ?? 5000\n const backoffMultiplier = this.options.backoffMultiplier ?? 1.5\n const connectionName = this.options.connection ?? this.queueManager.getDefaultConnection()\n\n // 初始化元件\n this.gate = new ConcurrencyGate(concurrency)\n this.sequencer = new GroupSequencer()\n\n // 初始化心跳管理器(若啟用監控)\n if (this.options.monitor) {\n const monitorOptions = typeof this.options.monitor === 'object' ? this.options.monitor : {}\n\n this.heartbeat = new HeartbeatManager(\n this.queueManager,\n {\n workerId: this.workerId,\n queues: this.options.queues,\n connectionName,\n interval: monitorOptions.interval,\n extraInfo: monitorOptions.extraInfo,\n prefix: monitorOptions.prefix,\n },\n () => this.getStats()\n )\n this.heartbeat.start()\n await this.heartbeat.publishLog(\n 'info',\n `Consumer started on [${this.options.queues.join(', ')}] with concurrency ${concurrency}`\n )\n }\n\n // 建立 JobExecutor\n const executor = new JobExecutor(this.queueManager, this, this.stats, this.heartbeat, {\n debug: this.options.debug ?? false,\n workerId: this.workerId,\n workerOptions: this.options.workerOptions,\n monitor: this.options.monitor,\n maxRequests: this.options.maxRequests,\n onEvent: this.options.onEvent,\n })\n\n // 建立 Worker\n const worker = new Worker(this.options.workerOptions)\n\n this.log('Started', {\n queues: this.options.queues,\n connection: this.options.connection,\n workerId: this.workerId,\n concurrency,\n batchSize,\n })\n\n // 建立 job 來源 generator\n const jobSource = jobSourceGenerator(\n this.queueManager,\n {\n queues: this.options.queues,\n connection: this.options.connection,\n batchSize,\n useBlocking,\n blockingTimeout,\n keepAlive,\n minPollInterval,\n maxPollInterval,\n backoffMultiplier,\n rateLimits: this.options.rateLimits,\n getCapacity: () => this.gate?.available ?? 0,\n },\n this.abortController.signal\n )\n\n try {\n // 主管線迴圈\n for await (const fetchResult of jobSource) {\n if (this.stopRequested) {\n break\n }\n\n for (const job of fetchResult.jobs) {\n if (this.stopRequested) {\n break\n }\n\n // 等待並發許可(Promise-based,不 busy-wait)\n await this.gate.acquire()\n // 更新 active 計數\n this.stats.active++\n\n // 非同步執行(不 await),確保並發\n this.sequencer\n .run(this.options.groupJobsSequential !== false ? job.groupId : undefined, async () => {\n const result = await executor.execute(job, worker)\n if (result.shouldStop) {\n this.stopRequested = true\n // 通知 generator 停止\n this.abortController?.abort()\n }\n })\n .finally(() => {\n this.stats.active--\n this.gate?.release()\n })\n }\n }\n\n // 等待所有正在執行的 job 完成\n await this.waitForAllJobsToComplete()\n } finally {\n this.cleanup()\n }\n }\n\n /**\n * 請求優雅停止。\n *\n * 設定 stopRequested 旗標,並中止 generator,\n * 等待目前執行中的 job 完成後停止。\n *\n * @returns 等待完全停止的 Promise\n */\n async requestStop(): Promise<void> {\n this.log('Stopping...')\n this.stopRequested = true\n this.abortController?.abort()\n\n // 等待 running 變為 false\n while (this.running) {\n await new Promise((resolve) => setTimeout(resolve, 100))\n }\n }\n\n /**\n * 檢查是否仍有 job 在執行中。\n */\n isActive(): boolean {\n return this.stats.active > 0\n }\n\n /**\n * 取得目前的統計資料快照。\n */\n getStats(): ConsumerStats {\n return { ...this.stats }\n }\n\n /**\n * 重置統計計數器。\n */\n resetStats(): void {\n this.stats.processed = 0\n this.stats.failed = 0\n this.stats.retried = 0\n // active 不重置,因為它反映即時狀態\n }\n\n /**\n * Consumer 是否正在執行中。\n */\n isRunning(): boolean {\n return this.running\n }\n\n /**\n * 等待所有正在執行的 job 完成。\n */\n private async waitForAllJobsToComplete(): Promise<void> {\n while (this.stats.active > 0) {\n await new Promise((resolve) => setTimeout(resolve, 10))\n }\n }\n\n /**\n * 清理所有資源。\n */\n private cleanup(): void {\n this.running = false\n this.sequencer?.destroy()\n this.sequencer = null\n this.heartbeat?.stop()\n\n if (this.options.monitor && this.heartbeat) {\n this.heartbeat.publishLog('info', 'Consumer stopped').catch(() => {\n // 靜默忽略\n })\n }\n\n this.heartbeat = null\n this.gate = null\n this.abortController = null\n this.log('Stopped')\n }\n\n /**\n * 輸出 debug 日誌(僅在 debug=true 時)。\n */\n private log(message: string, data?: unknown): void {\n if (!this.options.debug) {\n return\n }\n\n const timestamp = new Date().toISOString()\n const prefix = `[StreamingConsumer:${this.workerId}] [${timestamp}]`\n if (data) {\n // biome-ignore lint/suspicious/noConsole: debug 模式下允許輸出\n console.log(prefix, message, data)\n } else {\n // biome-ignore lint/suspicious/noConsole: debug 模式下允許輸出\n console.log(prefix, message)\n }\n }\n}\n",
37
+ "/**\n * Sandboxed Worker Implementation.\n *\n * Executes jobs in isolated Worker Threads to provide context isolation,\n * error containment, and resource limits.\n *\n * @public\n */\n\nimport { resolve } from 'node:path'\nimport { Worker as ThreadWorker } from 'node:worker_threads'\nimport type { SerializedJob } from '../types'\n\n/**\n * Configuration options for the Sandboxed Worker.\n */\nexport interface SandboxedWorkerConfig {\n /**\n * Maximum execution time for a job in milliseconds.\n *\n * Jobs exceeding this duration will be forcefully terminated.\n * @default 30000 (30 seconds)\n */\n maxExecutionTime?: number\n\n /**\n * Maximum memory limit for the worker in MB.\n *\n * If the worker exceeds this limit, it will be terminated and restarted.\n * Note: Relies on `resourceLimits` which may vary by platform.\n * @default undefined (unlimited)\n */\n maxMemory?: number\n\n /**\n * Whether to isolate contexts for each job.\n *\n * If `true`, a new Worker Thread is created for every job execution.\n * If `false`, the Worker Thread is reused across multiple jobs.\n * @default false\n */\n isolateContexts?: boolean\n\n /**\n * Idle timeout for the Worker Thread in milliseconds.\n *\n * The worker will be terminated if it remains idle for this duration to save resources.\n * @default 60000 (60 seconds)\n */\n idleTimeout?: number\n}\n\n/**\n * Internal state of the worker.\n */\nenum WorkerState {\n /** Worker is initializing or starting up. */\n INITIALIZING = 'initializing',\n /** Worker is ready to accept jobs. */\n READY = 'ready',\n /** Worker is currently executing a job. */\n BUSY = 'busy',\n /** Worker has been terminated or exited. */\n TERMINATED = 'terminated',\n}\n\n/**\n * Sandboxed Worker.\n *\n * Manages the lifecycle of a Node.js Worker Thread for job execution.\n * Provides features like:\n * - Context Isolation: Run code in a separate thread.\n * - Timeout Enforcement: Terminate hangs or long-running jobs.\n * - Memory Limits: Prevent OOM issues affecting the main process.\n * - Error Containment: Worker crashes do not crash the main application.\n *\n * @example\n * ```typescript\n * const worker = new SandboxedWorker({\n * maxExecutionTime: 30000,\n * maxMemory: 512,\n * isolateContexts: true\n * });\n *\n * await worker.execute(serializedJob);\n * await worker.terminate();\n * ```\n */\nexport class SandboxedWorker {\n private worker: ThreadWorker | null = null\n private state: WorkerState = WorkerState.INITIALIZING\n private config: Required<SandboxedWorkerConfig>\n private idleTimer: NodeJS.Timeout | null = null\n private executionTimer: NodeJS.Timeout | null = null\n\n /**\n * Creates a SandboxedWorker instance.\n *\n * @param config - Configuration options for the worker.\n */\n constructor(config: SandboxedWorkerConfig = {}) {\n this.config = {\n maxExecutionTime: config.maxExecutionTime ?? 30000,\n maxMemory: config.maxMemory ?? 0,\n isolateContexts: config.isolateContexts ?? false,\n idleTimeout: config.idleTimeout ?? 60000,\n }\n }\n\n /**\n * Initializes the Worker Thread.\n *\n * @returns The active Worker Thread instance.\n * @throws {Error} If worker initialization fails or times out.\n */\n private async initWorker(): Promise<ThreadWorker> {\n if (this.worker && this.state !== WorkerState.TERMINATED) {\n return this.worker\n }\n\n const fs = require('node:fs')\n let workerPath = resolve(__dirname, 'job-executor.js')\n\n // If running in development (TS), use the .ts executor if it exists\n if (!fs.existsSync(workerPath)) {\n const tsPath = resolve(__dirname, 'job-executor.ts')\n if (fs.existsSync(tsPath)) {\n workerPath = tsPath\n }\n }\n\n // Support Bun's native TS execution or ts-node/register\n const execArgv = process.execArgv.slice()\n if (workerPath.endsWith('.ts') && !process.env.BUN_BINARY_TARGET) {\n if (!execArgv.includes('--loader')) {\n execArgv.push('--loader', 'ts-node/esm')\n }\n }\n\n const resourceLimits: any = {}\n if (this.config.maxMemory > 0) {\n resourceLimits.maxOldGenerationSizeMb = this.config.maxMemory\n resourceLimits.maxYoungGenerationSizeMb = Math.min(this.config.maxMemory / 2, 128)\n }\n\n this.worker = new ThreadWorker(workerPath, {\n resourceLimits: Object.keys(resourceLimits).length > 0 ? resourceLimits : undefined,\n execArgv,\n })\n\n this.state = WorkerState.INITIALIZING\n\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error('Worker initialization timeout'))\n }, 5000)\n\n this.worker?.once('message', (message: any) => {\n clearTimeout(timeout)\n if (message.type === 'ready') {\n this.state = WorkerState.READY\n resolve()\n } else {\n reject(new Error('Unexpected worker message during initialization'))\n }\n })\n\n this.worker?.once('error', (error) => {\n clearTimeout(timeout)\n reject(error)\n })\n })\n\n this.worker.on('error', (error) => {\n console.error('[SandboxedWorker] Worker error:', error)\n this.state = WorkerState.TERMINATED\n })\n\n this.worker.on('exit', (code) => {\n if (code !== 0) {\n console.error(`[SandboxedWorker] Worker exited with code ${code}`)\n }\n this.state = WorkerState.TERMINATED\n })\n\n return this.worker\n }\n\n /**\n * Executes a job in the sandboxed environment.\n *\n * @param job - The serialized job data to execute.\n * @throws {Error} If execution fails, times out, or the worker crashes.\n */\n async execute(job: SerializedJob): Promise<void> {\n if (this.config.isolateContexts) {\n await this.terminate()\n }\n\n const worker = await this.initWorker()\n this.state = WorkerState.BUSY\n\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n this.idleTimer = null\n }\n\n try {\n await Promise.race([this.executeInWorker(worker, job), this.createTimeoutPromise()])\n } finally {\n this.state = WorkerState.READY\n\n if (this.executionTimer) {\n clearTimeout(this.executionTimer)\n this.executionTimer = null\n }\n\n if (!this.config.isolateContexts) {\n this.startIdleTimer()\n } else {\n await this.terminate()\n }\n }\n }\n\n /**\n * Internal method to send execution message to the worker thread.\n *\n * @param worker - The worker thread instance.\n * @param job - Job data.\n */\n private executeInWorker(worker: ThreadWorker, job: SerializedJob): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const messageHandler = (message: any) => {\n if (message.type === 'success') {\n cleanup()\n resolve()\n } else if (message.type === 'error') {\n cleanup()\n const error = new Error(message.error || 'Job execution failed')\n if (message.stack) {\n error.stack = message.stack\n }\n reject(error)\n }\n }\n\n const errorHandler = (error: Error) => {\n cleanup()\n reject(error)\n }\n\n const exitHandler = (code: number) => {\n cleanup()\n if (code !== 0) {\n reject(new Error(`Worker exited unexpectedly with code ${code}`))\n }\n }\n\n const cleanup = () => {\n worker.off('message', messageHandler)\n worker.off('error', errorHandler)\n worker.off('exit', exitHandler)\n }\n\n worker.on('message', messageHandler)\n worker.on('error', errorHandler)\n worker.on('exit', exitHandler)\n\n worker.postMessage({\n type: 'execute',\n job,\n })\n })\n }\n\n /**\n * Creates a promise that rejects after the configured timeout.\n */\n private createTimeoutPromise(): Promise<never> {\n return new Promise<never>((_, reject) => {\n this.executionTimer = setTimeout(() => {\n this.terminate().catch(console.error)\n reject(new Error(`Job execution timeout after ${this.config.maxExecutionTime}ms`))\n }, this.config.maxExecutionTime)\n })\n }\n\n /**\n * Starts the idle timer to auto-terminate the worker.\n */\n private startIdleTimer(): void {\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n }\n\n this.idleTimer = setTimeout(() => {\n this.terminate().catch(console.error)\n }, this.config.idleTimeout)\n }\n\n /**\n * Terminates the Worker Thread immediately.\n *\n * Stops any running job and releases resources.\n */\n async terminate(): Promise<void> {\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n this.idleTimer = null\n }\n\n if (this.executionTimer) {\n clearTimeout(this.executionTimer)\n this.executionTimer = null\n }\n\n if (this.worker) {\n const worker = this.worker\n this.worker = null\n this.state = WorkerState.TERMINATED\n\n try {\n await worker.terminate()\n } catch (error) {\n console.error('[SandboxedWorker] Error terminating worker:', error)\n }\n }\n }\n\n /**\n * Gets the current state of the worker.\n *\n * @returns The current `WorkerState`.\n */\n getState(): string {\n return this.state\n }\n\n /**\n * Checks if the worker is ready to accept a job.\n *\n * @returns `true` if ready, `false` otherwise.\n */\n isReady(): boolean {\n return this.state === WorkerState.READY\n }\n\n /**\n * Checks if the worker is currently executing a job.\n *\n * @returns `true` if busy, `false` otherwise.\n */\n isBusy(): boolean {\n return this.state === WorkerState.BUSY\n }\n}\n",
38
+ "import type { Job } from './Job'\nimport type { SerializedJob } from './types'\nimport { SandboxedWorker, type SandboxedWorkerConfig } from './workers/SandboxedWorker'\n\n/**\n * Configuration options for the Worker.\n *\n * Controls the execution behavior of jobs, including retry limits and timeouts.\n *\n * @example\n * ```typescript\n * const options: WorkerOptions = {\n * maxAttempts: 3,\n * timeout: 30\n * };\n * ```\n */\nexport interface WorkerOptions {\n /**\n * The maximum number of attempts for a job before it is marked as failed.\n *\n * This value serves as a default fallback if the job itself does not specify `maxAttempts`.\n */\n maxAttempts?: number\n\n /**\n * The maximum execution time for a job in seconds.\n *\n * If the job exceeds this duration, it will be timed out and marked as failed.\n */\n timeout?: number\n\n /**\n * Callback function triggered when a job permanently fails.\n *\n * This allows for custom error reporting or cleanup logic outside of the job class.\n */\n onFailed?: (job: Job, error: Error) => Promise<void>\n\n /**\n * Enable sandboxed execution using Worker Threads.\n *\n * When enabled, jobs are executed in isolated Worker Threads, providing:\n * - Context isolation: Each job runs in a separate execution environment\n * - Crash protection: Worker crashes don't affect the main thread\n * - Memory limits: Prevent memory leaks from affecting the main process\n * - Timeout enforcement: Jobs exceeding the timeout are forcefully terminated\n *\n * @default false\n */\n sandboxed?: boolean\n\n /**\n * Sandboxed worker configuration options.\n *\n * Only used when `sandboxed` is true.\n */\n sandboxConfig?: SandboxedWorkerConfig\n}\n\n/**\n * Executes background jobs.\n *\n * The Worker is responsible for running the `handle()` method of a job, managing its lifecycle,\n * enforcing timeouts, and handling retries or failures.\n *\n * Supports two execution modes:\n * - **Standard Mode** (default): Executes jobs directly in the current process\n * - **Sandboxed Mode**: Executes jobs in isolated Worker Threads for enhanced security and stability\n *\n * @example\n * ```typescript\n * // Standard mode\n * const worker = new Worker({\n * maxAttempts: 3,\n * timeout: 60\n * });\n *\n * // Sandboxed mode\n * const sandboxedWorker = new Worker({\n * maxAttempts: 3,\n * timeout: 60,\n * sandboxed: true,\n * sandboxConfig: {\n * maxExecutionTime: 30000,\n * maxMemory: 512,\n * isolateContexts: true\n * }\n * });\n *\n * await worker.process(job);\n * ```\n */\nexport class Worker {\n private sandboxedWorker?: SandboxedWorker\n\n constructor(private options: WorkerOptions = {}) {\n if (options.sandboxed) {\n this.sandboxedWorker = new SandboxedWorker(options.sandboxConfig)\n }\n }\n\n /**\n * Processes a single job instance.\n *\n * 1. Checks attempt counts.\n * 2. Enforces execution timeout (if configured).\n * 3. Runs `job.handle()` (either directly or in a sandboxed Worker Thread).\n * 4. Catches errors and invokes failure handlers if max attempts are reached.\n *\n * @param job - The job to process.\n * @throws {Error} If the job execution fails (to trigger retry logic in the consumer).\n */\n async process(job: Job): Promise<void> {\n const maxAttempts = job.maxAttempts ?? this.options.maxAttempts ?? 3\n const timeout = this.options.timeout\n\n // Ensure attempts is initialized\n if (!job.attempts) {\n job.attempts = 1\n }\n\n try {\n // Execute job (sandboxed or standard mode)\n if (this.options.sandboxed && this.sandboxedWorker) {\n await this.processSandboxed(job)\n } else {\n await this.processStandard(job, timeout)\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n\n // Check if this was the last attempt\n // Note: Consumer is responsible for incrementing attempts and re-queueing if needed.\n // Here we just check if we SHOULD have failed.\n if (job.attempts >= maxAttempts) {\n await this.handleFailure(job, err)\n }\n\n throw err\n }\n }\n\n /**\n * Processes a job in standard mode (directly in current process).\n *\n * @param job - The job to process.\n * @param timeout - Optional timeout in seconds.\n */\n private async processStandard(job: Job, timeout?: number): Promise<void> {\n if (timeout) {\n await Promise.race([\n job.handle(),\n new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error(`Job timeout after ${timeout} seconds`)),\n timeout * 1000\n )\n ),\n ])\n } else {\n await job.handle()\n }\n }\n\n /**\n * Processes a job in sandboxed mode (in Worker Thread).\n *\n * @param job - The job to process.\n */\n private async processSandboxed(job: Job): Promise<void> {\n if (!this.sandboxedWorker) {\n throw new Error('Sandboxed worker not initialized')\n }\n\n // Serialize Job to SerializedJob\n const serialized = this.serializeJob(job)\n\n // Execute in Worker Thread\n await this.sandboxedWorker.execute(serialized)\n }\n\n /**\n * Serializes a Job instance for Worker Thread execution.\n *\n * @param job - The job to serialize.\n * @returns Serialized job data.\n */\n private serializeJob(job: Job): SerializedJob {\n // Serialize Job to JSON\n // Note: This is a simplified version; real-world usage might require more complex serialization logic\n const data = JSON.stringify(job)\n\n return {\n id: job.id ?? `job-${Date.now()}-${Math.random()}`,\n type: 'json',\n data,\n createdAt: Date.now(),\n attempts: job.attempts,\n maxAttempts: job.maxAttempts,\n delaySeconds: job.delaySeconds,\n groupId: job.groupId,\n priority: job.priority,\n retryAfterSeconds: job.retryAfterSeconds,\n retryMultiplier: job.retryMultiplier,\n }\n }\n\n /**\n * Handles the permanent failure of a job.\n *\n * Invokes the job's `failed()` method and any global `onFailed` callback.\n *\n * @param job - The failed job.\n * @param error - The error that caused the failure.\n */\n private async handleFailure(job: Job, error: Error): Promise<void> {\n // Call job.failed()\n try {\n await job.failed(error)\n } catch (failedError) {\n console.error('[Worker] Error in job.failed():', failedError)\n }\n\n // Call onFailed callback\n if (this.options.onFailed) {\n try {\n await this.options.onFailed(job, error)\n } catch (callbackError) {\n console.error('[Worker] Error in onFailed callback:', callbackError)\n }\n }\n }\n\n /**\n * Terminates the sandboxed worker and releases resources.\n *\n * Should be called when the worker is no longer needed.\n * Only applicable when running in sandboxed mode.\n */\n async terminate(): Promise<void> {\n if (this.sandboxedWorker) {\n await this.sandboxedWorker.terminate()\n }\n }\n}\n",
39
+ "/**\n * Promise-based Semaphore,用於控制並發執行數量。\n *\n * 完全取代原始 Consumer 中的 `stats.active` + `setTimeout(50)` busy-wait 模式。\n * 使用 Promise 等待機制,當並發數達到上限時,後續的 acquire() 會被掛起,\n * 直到有其他任務 release() 後才會被喚醒,不會浪費 CPU 資源。\n *\n * @example\n * ```typescript\n * const gate = new ConcurrencyGate(5)\n *\n * await gate.acquire()\n * try {\n * await doWork()\n * } finally {\n * gate.release()\n * }\n * ```\n */\nexport class ConcurrencyGate {\n private active = 0\n /** 等待中的 resolve 函數佇列(FIFO) */\n private waiters: Array<() => void> = []\n\n constructor(private readonly limit: number) {\n if (limit < 0) {\n throw new Error(`ConcurrencyGate limit must be >= 0, got ${limit}`)\n }\n }\n\n /**\n * 取得並發許可。\n *\n * 若目前 active < limit,立即遞增 active 並回傳。\n * 否則等待直到有 release() 釋放許可後再獲取。\n */\n async acquire(): Promise<void> {\n if (this.active < this.limit) {\n this.active++\n return\n }\n\n // 等待 release() 喚醒\n await new Promise<void>((resolve) => {\n this.waiters.push(resolve)\n })\n // 被喚醒時 active 已由 release() 遞增\n }\n\n /**\n * 釋放並發許可。\n *\n * 遞減 active 計數,並喚醒下一個等待者(FIFO 順序)。\n */\n release(): void {\n if (this.active === 0) {\n // 防禦性檢查,不應發生但仍保護\n return\n }\n\n const next = this.waiters.shift()\n if (next) {\n // 有等待者:active 不變(從 limit 傳給下一個),直接喚醒\n next()\n } else {\n // 沒有等待者:直接遞減\n this.active--\n }\n }\n\n /**\n * 目前可立即取得的許可數量。\n */\n get available(): number {\n return Math.max(0, this.limit - this.active)\n }\n\n /**\n * 目前正在執行的任務數量。\n */\n get activeCount(): number {\n return this.active\n }\n\n /**\n * 目前等待中的任務數量。\n */\n get waitingCount(): number {\n return this.waiters.length\n }\n\n /**\n * 最大並發數量上限。\n */\n get concurrencyLimit(): number {\n return this.limit\n }\n}\n",
40
+ "import pLimit from 'p-limit'\n\n/**\n * 管理每個 groupId 的 FIFO 序列執行器。\n *\n * 確保相同 groupId 的 job 按照 FIFO 順序依序執行,\n * 不同 groupId 的 job 則可以並行執行。\n *\n * 使用 pLimit(1) 為每個 group 建立容量為 1 的限制器,\n * 確保同一 group 同時只有一個 job 在執行。\n *\n * @example\n * ```typescript\n * const sequencer = new GroupSequencer()\n *\n * // group1 的 job 依序執行\n * sequencer.run('group1', async () => await processJob(jobA))\n * sequencer.run('group1', async () => await processJob(jobB))\n *\n * // group2 與 group1 並行\n * sequencer.run('group2', async () => await processJob(jobC))\n *\n * // 無 group 的 job 直接執行\n * sequencer.run(undefined, async () => await processJob(jobD))\n * ```\n */\nexport class GroupSequencer {\n /** Group ID 到 pLimit limiter 的映射 */\n private limiters = new Map<string, ReturnType<typeof pLimit>>()\n /** Group ID 到最後使用時間(ms)的映射,用於 TTL 清理 */\n private lastUsed = new Map<string, number>()\n /** 定期清理計時器 */\n private cleanupTimer: ReturnType<typeof setInterval> | null = null\n /** Group limiter 存活時間(毫秒),超過且無任務時清理 */\n private static readonly TTL_MS = 60_000\n\n constructor() {\n // 啟動定期清理(每 60 秒)\n this.cleanupTimer = setInterval(() => {\n this.cleanup()\n }, GroupSequencer.TTL_MS)\n\n // 允許 timer 不阻止 process 退出\n if (this.cleanupTimer.unref) {\n this.cleanupTimer.unref()\n }\n }\n\n /**\n * 執行一個任務,確保相同 group 內的任務依序執行。\n *\n * @param groupId - 群組 ID,undefined 表示無群組(直接執行)\n * @param fn - 要執行的非同步任務\n * @returns 任務的 Promise\n */\n run<T>(groupId: string | undefined, fn: () => Promise<T>): Promise<T> {\n // 無 groupId,直接執行\n if (!groupId) {\n return fn()\n }\n\n // 取得或建立此 group 的 limiter\n let limiter = this.limiters.get(groupId)\n if (!limiter) {\n limiter = pLimit(1)\n this.limiters.set(groupId, limiter)\n }\n\n // 更新最後使用時間\n this.lastUsed.set(groupId, Date.now())\n\n // 透過 limiter 執行,確保 FIFO 序列\n return limiter(async () => {\n const result = await fn()\n // 更新最後使用時間(任務完成時)\n this.lastUsed.set(groupId, Date.now())\n return result\n })\n }\n\n /**\n * 清理超過 TTL 且沒有 active/pending 任務的 group limiters。\n *\n * 定期呼叫以避免記憶體洩漏。\n */\n cleanup(): void {\n const now = Date.now()\n const toDelete: string[] = []\n\n for (const [groupId, lastUsedTime] of this.lastUsed.entries()) {\n const limiter = this.limiters.get(groupId)\n if (!limiter) {\n toDelete.push(groupId)\n continue\n }\n\n // 超過 TTL 且無 active/pending 任務才清理\n if (\n now - lastUsedTime > GroupSequencer.TTL_MS &&\n limiter.activeCount === 0 &&\n limiter.pendingCount === 0\n ) {\n this.limiters.delete(groupId)\n toDelete.push(groupId)\n }\n }\n\n for (const groupId of toDelete) {\n this.lastUsed.delete(groupId)\n }\n }\n\n /**\n * 停止時完全清理所有 limiters 和計時器。\n */\n destroy(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer)\n this.cleanupTimer = null\n }\n this.limiters.clear()\n this.lastUsed.clear()\n }\n\n /**\n * 目前管理中的 group 數量(用於診斷)。\n */\n get groupCount(): number {\n return this.limiters.size\n }\n}\n",
41
+ "import type { QueueManager } from '../QueueManager'\nimport type { ConsumerStats } from './types'\n\n/**\n * HeartbeatManager 設定選項。\n */\nexport interface HeartbeatManagerOptions {\n /** Worker ID */\n workerId: string\n /** 要監控的佇列列表 */\n queues: string[]\n /** 連線名稱 */\n connectionName: string\n /** 心跳間隔(毫秒),預設 5000 */\n interval?: number\n /** 額外資訊,包含在心跳 payload 中 */\n extraInfo?: Record<string, unknown>\n /** 監控 key prefix */\n prefix?: string\n}\n\n/**\n * 管理 Consumer 的心跳與監控日誌。\n *\n * 定時向 driver 發送心跳信號(reportHeartbeat),\n * 並在支援時發送監控日誌(publishLog)。\n * 所有異常均被靜默捕獲,不影響主流程。\n *\n * @example\n * ```typescript\n * const heartbeat = new HeartbeatManager(queueManager, options, () => stats)\n * heartbeat.start()\n * // ... consumer running ...\n * heartbeat.stop()\n * ```\n */\nexport class HeartbeatManager {\n private timer: ReturnType<typeof setInterval> | null = null\n private readonly intervalMs: number\n\n constructor(\n private readonly queueManager: QueueManager,\n private readonly options: HeartbeatManagerOptions,\n /** getter 函數,每次心跳時取得最新統計 */\n private readonly getStats: () => ConsumerStats\n ) {\n this.intervalMs = options.interval ?? 5000\n }\n\n /**\n * 啟動心跳定時器。\n */\n start(): void {\n if (this.timer) {\n return\n }\n\n this.timer = setInterval(async () => {\n await this.sendHeartbeat()\n }, this.intervalMs)\n\n // 允許 timer 不阻止 process 退出\n if (this.timer.unref) {\n this.timer.unref()\n }\n }\n\n /**\n * 停止心跳定時器。\n */\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer)\n this.timer = null\n }\n }\n\n /**\n * 發送一次心跳。\n */\n async sendHeartbeat(): Promise<void> {\n try {\n const driver = this.queueManager.getDriver(this.options.connectionName)\n if (!driver.reportHeartbeat) {\n return\n }\n\n const os = require('node:os')\n const mem = process.memoryUsage()\n const stats = this.getStats()\n\n const metrics = {\n cpu: os.loadavg()[0],\n cores: os.cpus().length,\n ram: {\n rss: Math.floor(mem.rss / 1024 / 1024),\n heapUsed: Math.floor(mem.heapUsed / 1024 / 1024),\n total: Math.floor(os.totalmem() / 1024 / 1024),\n },\n stats,\n }\n\n await driver.reportHeartbeat(\n {\n id: this.options.workerId,\n status: 'online',\n hostname: os.hostname(),\n pid: process.pid,\n uptime: Math.floor(process.uptime()),\n last_ping: new Date().toISOString(),\n queues: this.options.queues,\n metrics,\n ...(this.options.extraInfo ?? {}),\n },\n this.options.prefix\n )\n } catch (_e) {\n // 靜默跳過,不影響 consumer 主流程\n }\n }\n\n /**\n * 發送監控日誌。\n *\n * @param level - 日誌等級(info, success, warning, error)\n * @param message - 日誌訊息\n * @param jobId - 相關的 job ID(可選)\n */\n async publishLog(level: string, message: string, jobId?: string): Promise<void> {\n try {\n const driver = this.queueManager.getDriver(this.options.connectionName)\n if (!driver.publishLog) {\n return\n }\n\n await driver.publishLog(\n {\n level,\n message,\n workerId: this.options.workerId,\n jobId,\n timestamp: new Date().toISOString(),\n },\n this.options.prefix\n )\n } catch (_e) {\n // 靜默跳過,監控日誌失敗不影響 consumer\n }\n }\n}\n",
42
+ "import type { EventEmitter } from 'node:events'\nimport type { Job } from '../Job'\nimport type { QueueManager } from '../QueueManager'\nimport type { Worker } from '../Worker'\nimport type { HeartbeatManager } from './HeartbeatManager'\nimport type { ConsumerStats, ExecutionResult, ExecutorOptions } from './types'\n\n/**\n * JobExecutor 負責完整的 Job 執行生命週期。\n *\n * 從原始 Consumer.handleJob() 提取,封裝以下邏輯:\n * - 發射生命週期事件(job:started, job:processed, job:failed 等)\n * - 呼叫 worker.process(job)\n * - 成功後呼叫 queueManager.complete()\n * - 失敗後執行重試邏輯(指數退避 + re-push)\n * - 超出 maxAttempts 後發射 job:failed_permanently 並移入 DLQ\n * - maxRequests 達到時設定 shouldStop = true\n *\n * 所有異常均被捕獲,不拋出(確保管線繼續執行)。\n *\n * @example\n * ```typescript\n * const executor = new JobExecutor(queueManager, emitter, stats, heartbeat, options)\n * const result = await executor.execute(job, worker)\n *\n * if (result.shouldStop) {\n * // 停止 consumer\n * }\n * ```\n */\nexport class JobExecutor {\n constructor(\n private readonly queueManager: QueueManager,\n private readonly emitter: EventEmitter,\n private readonly stats: ConsumerStats,\n private readonly heartbeat: HeartbeatManager | null,\n private readonly options: ExecutorOptions\n ) {}\n\n /**\n * 執行單一 Job 的完整生命週期。\n *\n * @param job - 要執行的 Job\n * @param worker - Worker 實例\n * @returns ExecutionResult,包含成功/失敗狀態、耗時、shouldStop 旗標\n */\n async execute(job: Job, worker: Worker): Promise<ExecutionResult> {\n const currentQueue = job.queueName ?? 'default'\n const startTime = Date.now()\n\n this.log(`Processing job ${job.id} from ${currentQueue}`)\n\n // 發射 job:started 事件\n this.emitter.emit('job:started', { job, queue: currentQueue })\n this.options.onEvent?.('job:started', { jobId: job.id, queue: currentQueue })\n\n if (this.heartbeat) {\n await this.heartbeat.publishLog('info', `Processing job: ${job.id}`, job.id)\n }\n\n try {\n await worker.process(job)\n\n const duration = Date.now() - startTime\n this.stats.processed++\n\n this.emitter.emit('job:processed', { job, duration, queue: currentQueue })\n this.options.onEvent?.('job:processed', { jobId: job.id, duration, queue: currentQueue })\n\n this.log(`Completed job ${job.id} in ${duration}ms`)\n\n if (this.heartbeat) {\n await this.heartbeat.publishLog('success', `Completed job: ${job.id}`, job.id)\n }\n\n // 完成後呼叫 complete(通知 driver 清理)\n await this.queueManager.complete(job).catch((err) => {\n // complete 失敗不影響主流程\n this.emitter.emit('error', err)\n })\n\n // 檢查是否達到 maxRequests\n const shouldStop = this.checkMaxRequests(job)\n\n return { success: true, duration, shouldStop }\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err))\n const duration = Date.now() - startTime\n\n this.stats.failed++\n this.emitter.emit('job:failed', { job, error, duration, queue: currentQueue })\n this.options.onEvent?.('job:failed', {\n jobId: job.id,\n error: error.message,\n duration,\n queue: currentQueue,\n })\n\n this.log(`Failed job ${job.id} in ${duration}ms`, { error: error.message })\n\n if (this.heartbeat) {\n await this.heartbeat.publishLog('error', `Job failed: ${job.id} - ${error.message}`, job.id)\n }\n\n // 重試邏輯\n const attempts = job.attempts ?? 1\n const maxAttempts = job.maxAttempts ?? this.options.workerOptions?.maxAttempts ?? 3\n\n if (attempts < maxAttempts) {\n await this.scheduleRetry(job, attempts, maxAttempts)\n } else {\n await this.handlePermanentFailure(job, error)\n }\n\n // 完成後呼叫 complete(通知 driver 清理)\n await this.queueManager.complete(job).catch((completeErr) => {\n this.emitter.emit('error', completeErr)\n })\n\n return { success: false, duration, shouldStop: false, error }\n }\n }\n\n /**\n * 安排 job 重試,使用指數退避策略。\n */\n private async scheduleRetry(job: Job, attempts: number, maxAttempts: number): Promise<void> {\n job.attempts = attempts + 1\n const delayMs = job.getRetryDelay(job.attempts)\n const delaySec = Math.ceil(delayMs / 1000)\n job.delay(delaySec)\n\n await this.queueManager.push(job)\n\n this.stats.retried++\n this.emitter.emit('job:retried', { job, attempt: job.attempts, delay: delaySec })\n\n this.log(`Retrying job ${job.id} in ${delaySec}s (Attempt ${job.attempts}/${maxAttempts})`)\n\n if (this.heartbeat) {\n await this.heartbeat.publishLog(\n 'warning',\n `Job retrying in ${delaySec}s (Attempt ${job.attempts}/${maxAttempts})`,\n job.id\n )\n }\n }\n\n /**\n * 處理永久失敗的 job,移入 DLQ 並發射事件。\n */\n private async handlePermanentFailure(job: Job, error: Error): Promise<void> {\n this.emitter.emit('job:failed_permanently', { job, error })\n this.options.onEvent?.('job:failed_permanently', { jobId: job.id, error: error.message })\n\n this.log(`Job ${job.id} failed permanently`)\n\n await this.queueManager.fail(job, error).catch((dlqErr) => {\n // DLQ 操作失敗不影響主流程\n this.emitter.emit('error', dlqErr)\n })\n }\n\n /**\n * 檢查是否達到 maxRequests,若達到則發射事件並回傳 shouldStop=true。\n */\n private checkMaxRequests(job: Job): boolean {\n if (!this.options.maxRequests) {\n return false\n }\n if (this.stats.processed < this.options.maxRequests) {\n return false\n }\n\n this.log(`Max requests reached: ${this.stats.processed}/${this.options.maxRequests}`)\n this.emitter.emit('max_requests_reached', {\n processed: this.stats.processed,\n maxRequests: this.options.maxRequests,\n })\n\n if (this.heartbeat) {\n this.heartbeat\n .publishLog('info', `Max requests reached: ${this.stats.processed}`, job.id)\n .catch(() => {\n // 靜默忽略\n })\n }\n\n return true\n }\n\n /**\n * 輸出 debug 日誌(僅在 debug=true 時)。\n */\n private log(message: string, data?: unknown): void {\n if (!this.options.debug) {\n return\n }\n\n const timestamp = new Date().toISOString()\n const prefix = `[JobExecutor:${this.options.workerId}] [${timestamp}]`\n if (data) {\n // biome-ignore lint/suspicious/noConsole: debug 模式下允許輸出\n console.log(prefix, message, data)\n } else {\n // biome-ignore lint/suspicious/noConsole: debug 模式下允許輸出\n console.log(prefix, message)\n }\n }\n}\n",
43
+ "import type { Job } from '../Job'\nimport type { QueueManager } from '../QueueManager'\nimport type { FetchResult, JobSourceOptions, StopSignal } from './types'\n\n/**\n * Async Generator,用於從佇列持續抓取 Job。\n *\n * 封裝所有抓取策略(blocking/batch/sequential),自適應 backoff,\n * 以及 rate limit 過濾邏輯。每次 yield 一個 FetchResult,\n * 包含本輪抓取的 job 列表和是否使用阻塞模式的資訊。\n *\n * 設計原則:\n * - blocking pop 已在 driver 層等待,不再額外 backoff\n * - 自適應退避:空佇列時指數增長,有 job 時重設\n * - rate limit:每輪抓取前過濾掉受限的佇列\n * - 中止信號:每次 yield 前檢查 signal.aborted\n *\n * @param queueManager - QueueManager 實例\n * @param options - 抓取策略選項\n * @param signal - 中止信號(AbortController.signal)\n *\n * @example\n * ```typescript\n * const source = jobSourceGenerator(queueManager, options, controller.signal)\n *\n * for await (const result of source) {\n * for (const job of result.jobs) {\n * await processJob(job)\n * }\n * }\n * ```\n */\nexport async function* jobSourceGenerator(\n queueManager: QueueManager,\n options: JobSourceOptions,\n signal: StopSignal\n): AsyncGenerator<FetchResult> {\n const {\n queues,\n connection,\n batchSize,\n useBlocking,\n blockingTimeout,\n keepAlive,\n minPollInterval,\n maxPollInterval,\n backoffMultiplier,\n rateLimits,\n getCapacity,\n } = options\n\n const connectionName = connection ?? queueManager.getDefaultConnection()\n let currentPollInterval = minPollInterval\n\n while (!signal.aborted) {\n // 檢查目前容量\n const capacity = getCapacity()\n if (capacity <= 0) {\n // 容量已滿,稍候再試(避免 tight loop)\n await sleep(10, signal)\n if (signal.aborted) {\n break\n }\n continue\n }\n\n // 過濾 rate-limited 佇列\n const eligibleQueues = await filterRateLimitedQueues(\n queueManager,\n connectionName,\n queues,\n rateLimits\n )\n\n if (eligibleQueues.length === 0) {\n // 所有佇列都被 rate limit,短暫等待(支援提前中止)\n await sleep(currentPollInterval, signal)\n currentPollInterval = Math.min(currentPollInterval * backoffMultiplier, maxPollInterval)\n if (signal.aborted) {\n break\n }\n yield { jobs: [], didBlock: false }\n continue\n }\n\n // 再次檢查中止信號\n if (signal.aborted) {\n break\n }\n\n // 抓取 job\n const { jobs, didBlock } = await fetchJobs(\n queueManager,\n connectionName,\n eligibleQueues,\n batchSize,\n capacity,\n useBlocking,\n blockingTimeout\n )\n\n if (jobs.length > 0) {\n // 有 job:重設 backoff\n currentPollInterval = minPollInterval\n yield { jobs, didBlock }\n continue\n }\n\n // 沒有 job\n if (!keepAlive) {\n // keepAlive=false 且佇列為空,終止 generator\n break\n }\n\n // 有 job 時才 yield,空結果僅在必要時 yield\n if (!didBlock) {\n // 自適應退避(支援提前中止)\n await sleep(currentPollInterval, signal)\n currentPollInterval = Math.min(currentPollInterval * backoffMultiplier, maxPollInterval)\n }\n // 若 didBlock,已在 driver 層等待過,直接繼續迴圈\n\n // 再次檢查中止信號再 yield\n if (!signal.aborted) {\n yield { jobs: [], didBlock }\n }\n }\n}\n\n/**\n * 過濾掉受 rate limit 限制的佇列,回傳允許處理的佇列名稱列表。\n */\nasync function filterRateLimitedQueues(\n queueManager: QueueManager,\n connectionName: string,\n queues: string[],\n rateLimits?: Record<string, { max: number; duration: number }>\n): Promise<string[]> {\n if (!rateLimits) {\n return queues\n }\n\n const eligible: string[] = []\n for (const queue of queues) {\n const limitConfig = rateLimits[queue]\n if (!limitConfig) {\n eligible.push(queue)\n continue\n }\n\n try {\n const driver = queueManager.getDriver(connectionName)\n if (driver.checkRateLimit) {\n const allowed = await driver.checkRateLimit(queue, limitConfig)\n if (allowed) {\n eligible.push(queue)\n }\n // 被 rate limit 的佇列直接略過\n } else {\n // driver 不支援 rate limit 檢查,視為允許\n eligible.push(queue)\n }\n } catch (_err) {\n // rate limit 檢查失敗時保守處理,允許佇列通過\n eligible.push(queue)\n }\n }\n\n return eligible\n}\n\n/**\n * 根據策略從佇列抓取 job。\n *\n * 支援三種策略:\n * 1. batch:batchSize > 1,使用 popMany\n * 2. blocking:batchSize = 1 且 useBlocking=true,使用 popBlocking\n * 3. sequential:batchSize = 1 且 useBlocking=false,依序 pop 各佇列\n */\nasync function fetchJobs(\n queueManager: QueueManager,\n connectionName: string,\n eligibleQueues: string[],\n batchSize: number,\n capacity: number,\n useBlocking: boolean,\n blockingTimeout: number\n): Promise<{ jobs: Job[]; didBlock: boolean }> {\n const driver = queueManager.getDriver(connectionName)\n\n // 策略 1:批次抓取\n if (batchSize > 1) {\n const actualBatchSize = Math.min(batchSize, capacity)\n for (const queue of eligibleQueues) {\n try {\n const fetched = await queueManager.popMany(queue, actualBatchSize, connectionName)\n if (fetched.length > 0) {\n return { jobs: fetched, didBlock: false }\n }\n } catch (_err) {\n // 單一佇列失敗不影響其他佇列\n }\n }\n return { jobs: [], didBlock: false }\n }\n\n // 策略 2:阻塞式 pop\n if (useBlocking && driver.popBlocking) {\n try {\n const job = await queueManager.popBlocking(eligibleQueues, blockingTimeout, connectionName)\n if (job) {\n return { jobs: [job], didBlock: true }\n }\n return { jobs: [], didBlock: true }\n } catch (_err) {\n return { jobs: [], didBlock: false }\n }\n }\n\n // 策略 3:依序非阻塞 pop\n for (const queue of eligibleQueues) {\n try {\n const job = await queueManager.pop(queue, connectionName)\n if (job) {\n return { jobs: [job], didBlock: false }\n }\n } catch (_err) {\n // 單一佇列失敗不影響其他佇列\n }\n }\n return { jobs: [], didBlock: false }\n}\n\n/**\n * 非同步睡眠工具函數,支援提前中止。\n *\n * 若 signal 在睡眠期間被中止,Promise 會立即 resolve(不拋出錯誤)。\n */\nfunction sleep(ms: number, signal?: StopSignal): Promise<void> {\n return new Promise((resolve) => {\n if (signal?.aborted) {\n resolve()\n return\n }\n const timer = setTimeout(resolve, ms)\n // 若 signal 支援 addEventListener(原生 AbortSignal),監聽中止事件\n if (signal && 'addEventListener' in signal) {\n ;(signal as AbortSignal).addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n resolve()\n },\n { once: true }\n )\n }\n })\n}\n",
44
+ "import type { Job } from '../Job'\nimport type { QueueManager } from '../QueueManager'\nimport type { ConsumerStrategy } from './ConsumerStrategy'\n\n/**\n * PollingStrategy implements pull-based job consumption.\n *\n * Continuously polls queues at adaptive intervals, backing off when empty\n * and resetting when jobs are found.\n *\n * Characteristics:\n * - Simple and reliable\n * - Predictable polling intervals\n * - Higher latency and resource usage vs reactive\n * - No external dependencies (works with any driver)\n *\n * @public\n */\nexport class PollingStrategy implements ConsumerStrategy {\n private running = false\n\n constructor(\n private queueManager: QueueManager,\n private queues: string[],\n private connectionName: string,\n private options: {\n minPollInterval: number\n maxPollInterval: number\n backoffMultiplier: number\n batchSize: number\n useBlocking: boolean\n blockingTimeout: number\n concurrency: number\n stats: { active: number }\n debug: boolean\n log: (message: string, data?: unknown) => void\n }\n ) {}\n\n async start(): Promise<void> {\n if (this.running) {\n throw new Error('PollingStrategy is already running')\n }\n this.running = true\n this.options.log('[PollingStrategy] Started')\n }\n\n async stop(): Promise<void> {\n if (!this.running) {\n return\n }\n this.options.log('[PollingStrategy] Stopping...')\n this.running = false\n this.options.log('[PollingStrategy] Stopped')\n }\n\n isRunning(): boolean {\n return this.running\n }\n\n async fetchJobs(): Promise<Job[]> {\n if (!this.running) {\n return []\n }\n\n const capacity = this.options.concurrency - this.options.stats.active\n if (capacity <= 0) {\n await new Promise((resolve) => setTimeout(resolve, 50))\n return []\n }\n\n const currentBatchSize = Math.min(this.options.batchSize, capacity)\n const jobs: Job[] = []\n\n try {\n const driver = this.queueManager.getDriver(this.connectionName)\n\n if (currentBatchSize > 1) {\n // Batch fetch\n for (const queue of this.queues) {\n const fetched = await this.queueManager.popMany(\n queue,\n currentBatchSize,\n this.connectionName\n )\n if (fetched.length > 0) {\n jobs.push(...fetched)\n break\n }\n }\n } else {\n // Single fetch\n if (this.options.useBlocking && driver.popBlocking) {\n const job = await this.queueManager.popBlocking(\n this.queues,\n this.options.blockingTimeout,\n this.connectionName\n )\n if (job) {\n jobs.push(job)\n }\n } else {\n // Sequential non-blocking pop\n for (const queue of this.queues) {\n const job = await this.queueManager.pop(queue, this.connectionName)\n if (job) {\n jobs.push(job)\n break\n }\n }\n }\n }\n } catch (error) {\n console.error('[PollingStrategy] Error fetching jobs:', error)\n }\n\n return jobs\n }\n}\n",
45
+ "import type { Job } from '../Job'\nimport type { QueueManager } from '../QueueManager'\nimport type { ConsumerStrategy } from './ConsumerStrategy'\n\n/**\n * ReactiveStrategy implements push-based job consumption.\n *\n * Listens for queue notifications and pulls jobs reactively when they arrive.\n * Implements drain-loop pattern with optional polling fallback.\n *\n * Characteristics:\n * - Low latency (immediate job pickup)\n * - Efficient resource usage (no continuous polling)\n * - Requires driver support for onNotify()\n * - Includes polling fallback to prevent starvation\n *\n * @public\n */\nexport class ReactiveStrategy implements ConsumerStrategy {\n private running = false\n private lastNotificationTime = Date.now()\n private fallbackPollingTimer: ReturnType<typeof setTimeout> | null = null\n\n constructor(\n private queueManager: QueueManager,\n private queues: string[],\n private connectionName: string,\n private options: {\n concurrency: number\n batchSize: number\n stats: { active: number }\n reactivePollingFallback: number\n debug: boolean\n log: (message: string, data?: unknown) => void\n }\n ) {}\n\n async start(): Promise<void> {\n if (this.running) {\n throw new Error('ReactiveStrategy is already running')\n }\n\n this.running = true\n this.lastNotificationTime = Date.now()\n\n this.options.log('[ReactiveStrategy] Starting')\n\n const driver = this.queueManager.getDriver(this.connectionName)\n\n // Enable notifications\n try {\n if (driver.enableNotifications) {\n await driver.enableNotifications()\n }\n\n // Register notification listener\n if (driver.onNotify) {\n await driver.onNotify(this.queues, async () => {\n this.lastNotificationTime = Date.now()\n })\n }\n } catch (error) {\n this.options.log('[ReactiveStrategy] Failed to enable notifications:', error)\n this.running = false\n throw error\n }\n\n this.options.log('[ReactiveStrategy] Started')\n\n // Start fallback polling\n this.startFallbackPolling()\n }\n\n async stop(): Promise<void> {\n if (!this.running) {\n return\n }\n\n this.options.log('[ReactiveStrategy] Stopping...')\n\n // Stop fallback polling\n if (this.fallbackPollingTimer) {\n clearTimeout(this.fallbackPollingTimer)\n this.fallbackPollingTimer = null\n }\n\n // Disable notifications\n const driver = this.queueManager.getDriver(this.connectionName)\n if (driver.disableNotifications) {\n try {\n await driver.disableNotifications()\n } catch (error) {\n this.options.log('[ReactiveStrategy] Error disabling notifications:', error)\n }\n }\n\n this.running = false\n this.options.log('[ReactiveStrategy] Stopped')\n }\n\n isRunning(): boolean {\n return this.running\n }\n\n async fetchJobs(): Promise<Job[]> {\n if (!this.running) {\n return []\n }\n\n const capacity = this.options.concurrency - this.options.stats.active\n if (capacity <= 0) {\n return []\n }\n\n const currentBatchSize = Math.min(this.options.batchSize, capacity)\n const jobs: Job[] = []\n\n try {\n // Drain available jobs from the queues\n for (const queue of this.queues) {\n if (currentBatchSize > 1) {\n const fetched = await this.queueManager.popMany(\n queue,\n currentBatchSize,\n this.connectionName\n )\n if (fetched.length > 0) {\n jobs.push(...fetched)\n if (jobs.length >= currentBatchSize) {\n break\n }\n }\n } else {\n const job = await this.queueManager.pop(queue, this.connectionName)\n if (job) {\n jobs.push(job)\n break\n }\n }\n }\n } catch (error) {\n console.error('[ReactiveStrategy] Error fetching jobs:', error)\n }\n\n return jobs\n }\n\n private startFallbackPolling(): void {\n const checkFallback = async () => {\n if (!this.running) {\n return\n }\n\n const timeSinceLastNotification = Date.now() - this.lastNotificationTime\n\n // Check if we need fallback polling\n if (timeSinceLastNotification > this.options.reactivePollingFallback) {\n this.options.log('[ReactiveStrategy] Fallback polling triggered')\n\n // Do a fallback poll check\n await this.fetchJobs()\n this.lastNotificationTime = Date.now()\n }\n\n // Check again after interval\n if (this.running) {\n this.fallbackPollingTimer = setTimeout(\n checkFallback,\n Math.min(this.options.reactivePollingFallback / 2, 5000)\n )\n }\n }\n\n checkFallback()\n }\n}\n",
46
+ "/**\n * @gravito/stream\n *\n * Lightweight, high-performance queue system inspired by Laravel while keeping Gravito's core values.\n * Supports multiple storage drivers, embedded/standalone consumer modes, and multiple job serialization strategies.\n *\n * @example\n * ```typescript\n * import { OrbitStream, Job } from '@gravito/stream'\n *\n * // Create a Job\n * class SendEmail extends Job {\n * async handle() {\n * // handle logic\n * }\n * }\n *\n * // Push a Job\n * await queue.push(new SendEmail())\n * ```\n */\n\nexport { BatchConsumer, type BatchConsumerOptions } from './BatchConsumer'\nexport type { ConsumerOptions } from './Consumer'\nexport { Consumer } from './Consumer'\n\n// Consumer strategies\nexport type { ConsumerStrategy } from './consumer/ConsumerStrategy'\nexport { PollingStrategy } from './consumer/PollingStrategy'\nexport { ReactiveStrategy } from './consumer/ReactiveStrategy'\n\nexport {\n decodeBinaryJobFrame,\n encodeBinaryJobFrame,\n Flags as BinaryJobFrameFlags,\n isGravitoJobFrame,\n MAGIC as BINARY_JOB_FRAME_MAGIC,\n VERSION as BINARY_JOB_FRAME_VERSION,\n} from './drivers/BinaryJobFrame'\n// Driver config types\nexport type { BullMQDriverConfig } from './drivers/BullMQDriver'\nexport { BullMQDriver } from './drivers/BullMQDriver'\nexport type { DatabaseDriverConfig } from './drivers/DatabaseDriver'\nexport { DatabaseDriver } from './drivers/DatabaseDriver'\nexport type { GrpcDriverConfig } from './drivers/GrpcDriver'\nexport { GrpcDriver } from './drivers/GrpcDriver'\nexport type { KafkaDriverConfig } from './drivers/KafkaDriver'\nexport { KafkaDriver } from './drivers/KafkaDriver'\nexport { MemoryDriver } from './drivers/MemoryDriver'\n// Drivers\nexport type { QueueDriver } from './drivers/QueueDriver'\nexport type { RabbitMQDriverConfig } from './drivers/RabbitMQDriver'\nexport { RabbitMQDriver } from './drivers/RabbitMQDriver'\nexport type { RedisClient, RedisDriverConfig } from './drivers/RedisDriver'\nexport { RedisDriver } from './drivers/RedisDriver'\nexport type { SQSDriverConfig } from './drivers/SQSDriver'\nexport { SQSDriver } from './drivers/SQSDriver'\n\n// Core classes\nexport { Job } from './Job'\nexport type { LockOptions } from './locks/DistributedLock'\nexport { DistributedLock } from './locks/DistributedLock'\nexport type { OrbitStreamOptions } from './OrbitStream'\nexport { OrbitStream } from './OrbitStream'\nexport { BufferedPersistence } from './persistence/BufferedPersistence'\nexport {\n BunBufferedPersistence,\n type BunBufferedPersistenceOptions,\n createBufferedPersistence,\n} from './persistence/BunBufferedPersistence'\nexport { MySQLPersistence } from './persistence/MySQLPersistence'\nexport { SQLitePersistence } from './persistence/SQLitePersistence'\n// Core interfaces & types\nexport type { Queueable } from './Queueable'\nexport { QueueManager } from './QueueManager'\nexport type { ScheduledJobConfig, SchedulerOptions } from './Scheduler'\nexport { Scheduler } from './Scheduler'\nexport {\n type RetryStrategy,\n StreamEventBackend,\n type StreamEventBackendConfig,\n} from './StreamEventBackend'\nexport { SystemEventJob } from './SystemEventJob'\nexport { BinarySerializer } from './serializers/BinarySerializer'\nexport { CborNativeSerializer } from './serializers/CborNativeSerializer'\nexport { ClassNameSerializer } from './serializers/ClassNameSerializer'\n// Serializers\nexport type { JobSerializer } from './serializers/JobSerializer'\nexport { JsonlSerializer } from './serializers/JsonlSerializer'\nexport { JsonSerializer } from './serializers/JsonSerializer'\nexport type {\n PersistenceAdapter,\n QueueConfig,\n QueueConnectionConfig,\n SerializedJob,\n TopicOptions,\n} from './types'\n// Types\nexport type { WorkerOptions } from './Worker'\nexport { Worker } from './Worker'\n\n// Workers (Sandboxed execution)\nexport {\n SandboxedWorker,\n type SandboxedWorkerConfig,\n WorkerPool,\n type WorkerPoolConfig,\n type WorkerPoolStats,\n} from './workers'\n",
47
+ "import path from 'node:path'\nimport * as grpc from '@grpc/grpc-js'\nimport * as protoLoader from '@grpc/proto-loader'\nimport type { GrpcDriverConfig, JobPushOptions, QueueStats, SerializedJob } from '../types'\nimport type { QueueDriver } from './QueueDriver'\n\nexport type { GrpcDriverConfig } from '../types'\n\nexport class GrpcDriver implements QueueDriver {\n private client: grpc.Client\n\n constructor(config: GrpcDriverConfig) {\n const protoPath = config.protoPath || path.resolve(__dirname, '../../proto/queue.proto')\n\n // Fallback for bundled environments where __dirname might not be reliable\n // or when running from different contexts.\n // Ideally, the user provides the protoPath if standard resolution fails.\n\n const packageDefinition = protoLoader.loadSync(protoPath, {\n keepCase: true,\n longs: String,\n enums: String,\n defaults: true,\n oneofs: true,\n })\n\n const packageName = config.packageName || 'stream'\n const serviceName = config.serviceName || 'QueueService'\n\n const pkg = packageDefinition[packageName] as any\n if (!pkg) {\n throw new Error(`Package '${packageName}' not found in proto definition at ${protoPath}`)\n }\n\n const Service = pkg[serviceName]\n if (!Service) {\n throw new Error(`Service '${serviceName}' not found in package '${packageName}'`)\n }\n\n const credentials = this.getCredentials(config)\n this.client = new Service(config.url, credentials)\n }\n\n private getCredentials(config: GrpcDriverConfig): grpc.ChannelCredentials {\n if (config.credentials) {\n if (config.credentials.rootCerts) {\n return grpc.credentials.createSsl(\n config.credentials.rootCerts,\n config.credentials.privateKey,\n config.credentials.certChain\n )\n }\n }\n return grpc.credentials.createInsecure()\n }\n\n async push(queue: string, job: SerializedJob, options?: JobPushOptions): Promise<void> {\n const req = {\n queue,\n job: this.toProtoJob(job),\n options: {\n groupId: options?.groupId,\n priority: String(options?.priority || ''),\n },\n }\n\n return new Promise((resolve, reject) => {\n ;(this.client as any).Push(req, (err: any, response: any) => {\n if (err) {\n return reject(err)\n }\n if (!response.success) {\n return reject(new Error(response.message || 'Unknown gRPC error'))\n }\n resolve()\n })\n })\n }\n\n async pop(queue: string): Promise<SerializedJob | null> {\n return new Promise((resolve, reject) => {\n ;(this.client as any).Pull({ queue }, (err: any, response: any) => {\n if (err) {\n return reject(err)\n }\n if (!response.job || !response.job.id) {\n return resolve(null)\n }\n resolve(this.fromProtoJob(response.job))\n })\n })\n }\n\n async size(queue: string): Promise<number> {\n return new Promise((resolve, reject) => {\n ;(this.client as any).Size({ queue }, (err: any, response: any) => {\n if (err) {\n return reject(err)\n }\n resolve(response.size || 0)\n })\n })\n }\n\n async clear(queue: string): Promise<void> {\n return new Promise((resolve, reject) => {\n ;(this.client as any).Clear({ queue }, (err: any) => {\n if (err) {\n return reject(err)\n }\n resolve()\n })\n })\n }\n\n async acknowledge(messageId: string): Promise<void> {\n // Note: The generic interface implies acknowledge is by messageId.\n // But my proto design for AcknowledgeRequest takes (queue, jobId).\n // I might need to adapt. For now, assuming messageId is sufficient or I need queue context.\n // But QueueDriver.acknowledge only passes messageId.\n // Issue: gRPC usually needs context.\n // If the driver is strictly proxying, it might need to know the queue.\n // However, typically `messageId` in distributed systems is unique globally.\n\n // Workaround: Send messageId as jobId and empty queue if the server implementation can handle it,\n // or change the Proto to only take stored JobID.\n\n // Let's assume the server only needs ID.\n return new Promise((resolve, reject) => {\n ;(this.client as any).Acknowledge({ jobId: messageId }, (err: any) => {\n if (err) {\n return reject(err)\n }\n resolve()\n })\n })\n }\n\n async stats(queue: string): Promise<QueueStats> {\n return new Promise((resolve, reject) => {\n ;(this.client as any).Stats({ queue }, (err: any, response: any) => {\n if (err) {\n return reject(err)\n }\n resolve({\n queue: response.queue,\n size: response.size,\n delayed: response.delayed,\n failed: response.failed,\n reserved: response.reserved,\n })\n })\n })\n }\n\n private toProtoJob(job: SerializedJob): any {\n return {\n ...job,\n priority: job.priority ? String(job.priority) : undefined,\n createdAt: String(job.createdAt), // Long as string\n failedAt: job.failedAt ? String(job.failedAt) : undefined,\n }\n }\n\n private fromProtoJob(protoJob: any): SerializedJob {\n return {\n id: protoJob.id,\n type: protoJob.type,\n data: protoJob.data,\n className: protoJob.className,\n createdAt: Number(protoJob.createdAt),\n delaySeconds: protoJob.delaySeconds,\n attempts: protoJob.attempts,\n maxAttempts: protoJob.maxAttempts,\n groupId: protoJob.groupId,\n priority: protoJob.priority,\n failedAt: protoJob.failedAt ? Number(protoJob.failedAt) : undefined,\n error: protoJob.error,\n retryAfterSeconds: protoJob.retryAfterSeconds,\n retryMultiplier: protoJob.retryMultiplier,\n }\n }\n}\n",
48
+ "import type { QueueStats, SerializedJob } from '../types'\nimport type { QueueDriver } from './QueueDriver'\n\n/**\n * Configuration options for the MemoryDriver.\n */\nexport interface MemoryDriverConfig {\n /**\n * The maximum number of jobs allowed in a single queue.\n *\n * @default Infinity\n */\n maxSize?: number\n}\n\n/**\n * In-memory queue driver.\n *\n * Stores jobs in a local JavaScript Map. Ideal for development, testing, and simple\n * use cases where persistence across restarts is not required.\n * It supports basic delay handling but data is volatile.\n *\n * @public\n * @example\n * ```typescript\n * const driver = new MemoryDriver({ maxSize: 1000 });\n * await driver.push('default', job);\n * ```\n */\nexport class MemoryDriver implements QueueDriver {\n private queues = new Map<string, SerializedJob[]>()\n private maxSize: number\n\n constructor(config: MemoryDriverConfig = {}) {\n this.maxSize = config.maxSize ?? Infinity\n }\n\n /**\n * Pushes a job to the in-memory queue.\n *\n * @param queue - The queue name.\n * @param job - The serialized job.\n * @throws {Error} If the queue has reached `maxSize`.\n */\n async push(queue: string, job: SerializedJob): Promise<void> {\n if (!this.queues.has(queue)) {\n this.queues.set(queue, [])\n }\n\n const q = this.queues.get(queue)!\n if (q.length >= this.maxSize) {\n throw new Error(`[MemoryDriver] Queue '${queue}' is full (max size: ${this.maxSize})`)\n }\n\n q.push(job)\n }\n\n /**\n * Pops the next available job from the queue.\n *\n * Respects `delaySeconds` by checking the job's `createdAt` timestamp.\n *\n * @param queue - The queue name.\n * @returns The job or `null`.\n */\n async pop(queue: string): Promise<SerializedJob | null> {\n const queueJobs = this.queues.get(queue)\n if (!queueJobs || queueJobs.length === 0) {\n return null\n }\n\n // Respect delayed jobs\n const now = Date.now()\n const availableIndex = queueJobs.findIndex(\n (job) => !job.delaySeconds || now >= job.createdAt + job.delaySeconds * 1000\n )\n\n if (availableIndex === -1) {\n return null\n }\n\n return queueJobs.splice(availableIndex, 1)[0]!\n }\n\n /**\n * Returns the number of jobs in the queue.\n *\n * @param queue - The queue name.\n */\n async size(queue: string): Promise<number> {\n return this.queues.get(queue)?.length ?? 0\n }\n\n /**\n * Clears all jobs from the queue.\n *\n * @param queue - The queue name.\n */\n async clear(queue: string): Promise<void> {\n this.queues.delete(queue)\n }\n\n /**\n * Moves a job to the failed (DLQ) list.\n *\n * In MemoryDriver, this simply pushes to a `failed:{queue}` list.\n *\n * @param queue - The original queue name.\n * @param job - The failed job.\n */\n async fail(queue: string, job: SerializedJob): Promise<void> {\n const failedQueue = `failed:${queue}`\n if (!this.queues.has(failedQueue)) {\n this.queues.set(failedQueue, [])\n }\n this.queues.get(failedQueue)?.push(job)\n }\n\n /**\n * Retrieves statistics for the queue.\n *\n * Calculates pending, delayed, and failed counts by iterating through the list.\n *\n * @param queue - The queue name.\n */\n async stats(queue: string): Promise<QueueStats> {\n const jobs = this.queues.get(queue) || []\n const now = Date.now()\n\n let pending = 0\n let delayed = 0\n\n for (const job of jobs) {\n const isDelayed = job.delaySeconds && now < job.createdAt + job.delaySeconds * 1000\n if (isDelayed) {\n delayed++\n } else {\n pending++\n }\n }\n\n return {\n queue,\n size: pending,\n delayed,\n failed: this.queues.get(`failed:${queue}`)?.length || 0,\n }\n }\n\n /**\n * Pushes multiple jobs to the queue.\n *\n * @param queue - The queue name.\n * @param jobs - Array of jobs.\n */\n async pushMany(queue: string, jobs: SerializedJob[]): Promise<void> {\n if (!this.queues.has(queue)) {\n this.queues.set(queue, [])\n }\n this.queues.get(queue)?.push(...jobs)\n }\n\n /**\n * Pops multiple jobs from the queue.\n *\n * @param queue - The queue name.\n * @param count - Max jobs to pop.\n */\n async popMany(queue: string, count: number): Promise<SerializedJob[]> {\n const results: SerializedJob[] = []\n for (let i = 0; i < count; i++) {\n const job = await this.pop(queue)\n if (job) {\n results.push(job)\n } else {\n break\n }\n }\n return results\n }\n\n /**\n * Lists all active queues in memory.\n */\n async getQueues(): Promise<string[]> {\n return Array.from(this.queues.keys())\n .filter((q) => !q.startsWith('failed:'))\n .sort()\n }\n\n /**\n * Stub: MemoryDriver doesn't support reactive notifications.\n */\n async enableNotifications(): Promise<void> {\n // No-op for in-memory driver\n }\n\n /**\n * Stub: MemoryDriver doesn't support reactive notifications.\n */\n async disableNotifications(): Promise<void> {\n // No-op for in-memory driver\n }\n\n /**\n * Stub: MemoryDriver doesn't support reactive notifications.\n */\n async onNotify(\n _queues: string | string[],\n _callback: (queue: string) => Promise<void>\n ): Promise<void> {\n // No-op for in-memory driver\n }\n}\n",
49
+ "import type { Queueable } from './Queueable'\n\n/**\n * Abstract base class for all background jobs.\n *\n * This class serves as the foundation for creating queueable tasks. It implements the `Queueable`\n * interface for fluent configuration and provides the core structure for defining execution logic (`handle`)\n * and failure handling (`failed`).\n *\n * Subclasses must implement the `handle` method.\n *\n * @public\n * @example\n * ```typescript\n * export class SendEmailJob extends Job {\n * constructor(private email: string, private subject: string) {\n * super();\n * }\n *\n * async handle(): Promise<void> {\n * await emailService.send(this.email, this.subject);\n * }\n * }\n *\n * // Usage\n * await queue.push(new SendEmailJob('user@example.com', 'Welcome'))\n * .onQueue('emails')\n * .delay(60);\n * ```\n */\nexport abstract class Job implements Queueable {\n /**\n * Unique identifier for the job instance.\n *\n * Assigned automatically when the job is pushed to the queue.\n */\n id?: string\n\n /**\n * The name of the queue where this job will be processed.\n */\n queueName?: string\n\n /**\n * The name of the connection used to transport this job.\n */\n connectionName?: string\n\n /**\n * Delay in seconds before the job becomes available for processing.\n */\n delaySeconds?: number\n\n /**\n * The current attempt number (starts at 1).\n */\n attempts?: number\n\n /**\n * The maximum number of retry attempts allowed.\n *\n * Can be overridden by the worker configuration or per-job using `maxAttempts`.\n */\n maxAttempts?: number\n\n /**\n * Group ID for sequential processing.\n *\n * Jobs with the same `groupId` will be processed in strict order (FIFO)\n * if the consumer supports it.\n */\n groupId?: string\n\n /**\n * Priority level of the job.\n */\n priority?: string | number\n\n /**\n * Initial delay in seconds before the first retry attempt.\n *\n * Used for exponential backoff calculation.\n */\n retryAfterSeconds?: number\n\n /**\n * Multiplier applied to the retry delay for each subsequent attempt.\n *\n * Used for exponential backoff calculation.\n */\n retryMultiplier?: number\n\n /**\n * Sets the target queue for the job.\n *\n * @param queue - The name of the target queue.\n * @returns The job instance for chaining.\n *\n * @example\n * ```typescript\n * job.onQueue('billing');\n * ```\n */\n onQueue(queue: string): this {\n this.queueName = queue\n return this\n }\n\n /**\n * Sets the target connection for the job.\n *\n * @param connection - The name of the connection (e.g., 'redis').\n * @returns The job instance for chaining.\n *\n * @example\n * ```typescript\n * job.onConnection('sqs-primary');\n * ```\n */\n onConnection(connection: string): this {\n this.connectionName = connection\n return this\n }\n\n /**\n * Sets the priority of the job.\n *\n * @param priority - The priority level (e.g., 'high', 10).\n * @returns The job instance for chaining.\n *\n * @example\n * ```typescript\n * job.withPriority('high');\n * ```\n */\n withPriority(priority: string | number): this {\n this.priority = priority\n return this\n }\n\n /**\n * Delays the job execution.\n *\n * @param delay - Delay in seconds.\n * @returns The job instance for chaining.\n *\n * @example\n * ```typescript\n * job.delay(60); // Run after 1 minute\n * ```\n */\n delay(delay: number): this {\n this.delaySeconds = delay\n return this\n }\n\n /**\n * Configures the exponential backoff strategy for retries.\n *\n * @param seconds - Initial delay in seconds before the first retry.\n * @param multiplier - Factor by which the delay increases for each subsequent attempt (default: 2).\n * @returns The job instance for chaining.\n *\n * @example\n * ```typescript\n * // Wait 5s, then 10s, then 20s...\n * job.backoff(5, 2);\n * ```\n */\n backoff(seconds: number, multiplier = 2): this {\n this.retryAfterSeconds = seconds\n this.retryMultiplier = multiplier\n return this\n }\n\n /**\n * Calculates the delay for the next retry attempt based on the backoff strategy.\n *\n * Uses the formula: `initialDelay * multiplier^(attempt - 1)`, capped at 1 hour.\n *\n * @param attempt - The current attempt number (1-based).\n * @returns The calculated delay in milliseconds.\n *\n * @example\n * ```typescript\n * const nextDelay = job.getRetryDelay(2);\n * ```\n */\n getRetryDelay(attempt: number): number {\n const initialDelay = (this.retryAfterSeconds ?? 1) * 1000\n const multiplier = this.retryMultiplier ?? 2\n // Exponential backoff: initial * multiplier^(attempt-1)\n // capped at 1 hour for safety\n return Math.min(initialDelay * multiplier ** (attempt - 1), 3600000)\n }\n\n /**\n * Contains the main business logic of the job.\n *\n * This method is called by the worker to process the job.\n * Implementations should be idempotent if possible.\n *\n * @throws {Error} If the job fails and should be retried.\n */\n abstract handle(): Promise<void>\n\n /**\n * Optional handler for when the job has permanently failed.\n *\n * Called when the job has exhausted all retry attempts.\n * Useful for cleaning up resources, sending alerts, or logging.\n *\n * @param _error - The error that caused the final failure.\n *\n * @example\n * ```typescript\n * async failed(error: Error) {\n * await notifyAdmin(`Job failed: ${error.message}`);\n * }\n * ```\n */\n async failed(_error: Error): Promise<void> {\n // No-op by default (override in subclasses if needed)\n }\n}\n",
50
+ "import type { Job } from '../Job'\nimport type { SerializedJob } from '../types'\nimport type { JobSerializer } from './JobSerializer'\n\n/**\n * Cached Serializer Decorator.\n *\n * Wraps another serializer to cache the results of serialization for the same Job instance.\n * Useful when the same job object is enqueued multiple times (e.g., fan-out or testing),\n * avoiding redundant serialization overhead.\n *\n * Uses `WeakMap` to associate cached payloads with Job object references without causing memory leaks.\n *\n * @public\n * @example\n * ```typescript\n * const serializer = new CachedSerializer(new JsonSerializer());\n * ```\n */\nexport class CachedSerializer implements JobSerializer {\n private cache = new WeakMap<Job, SerializedJob>()\n\n /**\n * @param delegate - The underlying serializer to use.\n */\n constructor(private delegate: JobSerializer) {}\n\n /**\n * Serializes the job, returning a cached result if available.\n *\n * @param job - The job to serialize.\n */\n serialize(job: Job): SerializedJob {\n if (this.cache.has(job)) {\n return this.cache.get(job)!\n }\n\n const serialized = this.delegate.serialize(job)\n this.cache.set(job, serialized)\n return serialized\n }\n\n /**\n * Deserializes a job.\n *\n * Caching is not applied here as deserialization always produces new instances.\n */\n deserialize(serialized: SerializedJob): Job {\n return this.delegate.deserialize(serialized)\n }\n}\n",
51
+ "import type { Job } from '../Job'\nimport type { SerializedJob } from '../types'\nimport type { JobSerializer } from './JobSerializer'\n\n/**\n * Class Name Serializer (Laravel-style).\n *\n * Serializes jobs by storing their class name along with their properties.\n * During deserialization, it looks up the registered class constructor and creates a new instance,\n * populating it with the stored properties.\n *\n * This is the recommended serializer for most use cases as it preserves the behavior (methods)\n * of the job class.\n *\n * @public\n * @example\n * ```typescript\n * const serializer = new ClassNameSerializer();\n * serializer.register(SendEmailJob);\n *\n * const serialized = serializer.serialize(new SendEmailJob('foo@bar.com'));\n * const job = serializer.deserialize(serialized); // instanceof SendEmailJob\n * ```\n */\nexport class ClassNameSerializer implements JobSerializer {\n /**\n * Registry of job classes, mapped by class name.\n */\n private jobClasses = new Map<string, new (...args: unknown[]) => Job>()\n\n /**\n * Registers a Job class for serialization.\n *\n * @param jobClass - The job class constructor.\n */\n register(jobClass: new (...args: unknown[]) => Job): void {\n this.jobClasses.set(jobClass.name, jobClass)\n }\n\n /**\n * Registers multiple Job classes at once.\n *\n * @param jobClasses - An array of job class constructors.\n */\n registerMany(jobClasses: Array<new (...args: unknown[]) => Job>): void {\n for (const jobClass of jobClasses) {\n this.register(jobClass)\n }\n }\n\n /**\n * Serializes a Job instance.\n *\n * Captures the class name and all enumerable properties.\n *\n * @param job - The job to serialize.\n */\n serialize(job: Job): SerializedJob {\n const id = job.id || `${Date.now()}-${crypto.randomUUID()}`\n const className = job.constructor.name\n\n // Extract properties (exclude methods)\n const properties: Record<string, unknown> = {}\n for (const key in job) {\n if (\n Object.hasOwn(job, key) &&\n typeof (job as unknown as Record<string, unknown>)[key] !== 'function'\n ) {\n properties[key] = (job as unknown as Record<string, unknown>)[key]\n }\n }\n\n return {\n id,\n type: 'class',\n className,\n data: JSON.stringify(properties),\n createdAt: Date.now(),\n ...(job.delaySeconds !== undefined ? { delaySeconds: job.delaySeconds } : {}),\n attempts: job.attempts ?? 0,\n ...(job.maxAttempts !== undefined ? { maxAttempts: job.maxAttempts } : {}),\n ...(job.groupId ? { groupId: job.groupId } : {}),\n ...(job.retryAfterSeconds !== undefined ? { retryAfterSeconds: job.retryAfterSeconds } : {}),\n ...(job.retryMultiplier !== undefined ? { retryMultiplier: job.retryMultiplier } : {}),\n ...(job.priority !== undefined ? { priority: job.priority } : {}),\n }\n }\n\n /**\n * Deserializes a Job instance.\n *\n * Instantiates the class matching `className` and assigns properties.\n *\n * @param serialized - The serialized job.\n * @throws {Error} If the job class is not registered.\n */\n deserialize(serialized: SerializedJob): Job {\n if (serialized.type !== 'class') {\n throw new Error('Invalid serialization type: expected \"class\"')\n }\n\n if (!serialized.className) {\n throw new Error('Missing className in serialized job')\n }\n\n const JobClass = this.jobClasses.get(serialized.className)\n if (!JobClass) {\n throw new Error(\n `Job class \"${serialized.className}\" is not registered. Please register it using serializer.register().`\n )\n }\n\n const dataStr =\n typeof serialized.data === 'string'\n ? serialized.data\n : Buffer.from(serialized.data).toString('utf8')\n const properties = JSON.parse(dataStr)\n const job = new JobClass()\n\n // Restore properties\n if (properties) {\n Object.assign(job, properties)\n }\n\n // Restore metadata\n job.id = serialized.id\n\n // Restore Queueable fields\n if (serialized.delaySeconds !== undefined) {\n job.delaySeconds = serialized.delaySeconds\n }\n if (serialized.attempts !== undefined) {\n job.attempts = serialized.attempts\n }\n if (serialized.maxAttempts !== undefined) {\n job.maxAttempts = serialized.maxAttempts\n }\n if (serialized.groupId !== undefined) {\n job.groupId = serialized.groupId\n }\n if (serialized.retryAfterSeconds !== undefined) {\n job.retryAfterSeconds = serialized.retryAfterSeconds\n }\n if (serialized.retryMultiplier !== undefined) {\n job.retryMultiplier = serialized.retryMultiplier\n }\n if (serialized.priority !== undefined) {\n job.priority = serialized.priority\n }\n\n return job\n }\n}\n",
52
+ "import type { Job } from '../Job'\nimport type { SerializedJob } from '../types'\nimport type { JobSerializer } from './JobSerializer'\n\n/**\n * JSON Serializer.\n *\n * Serializes jobs to standard JSON. This is the simplest serializer but has limitations:\n * it cannot restore class instances (methods are lost) or handle complex types like Maps/Sets.\n * Deserialized jobs will be plain objects that must be manually handled or cast.\n *\n * @public\n * @example\n * ```typescript\n * const serializer = new JsonSerializer();\n * ```\n */\nexport class JsonSerializer implements JobSerializer {\n /**\n * Serializes a job to a JSON object.\n */\n serialize(job: Job): SerializedJob {\n const id = job.id || `${Date.now()}-${crypto.randomUUID()}`\n\n // Extract properties (exclude methods)\n const properties: Record<string, unknown> = {}\n for (const key in job) {\n if (\n Object.hasOwn(job, key) &&\n typeof (job as unknown as Record<string, unknown>)[key] !== 'function'\n ) {\n properties[key] = (job as unknown as Record<string, unknown>)[key]\n }\n }\n\n return {\n id,\n type: 'json',\n data: JSON.stringify(properties),\n createdAt: Date.now(),\n ...(job.delaySeconds !== undefined ? { delaySeconds: job.delaySeconds } : {}),\n attempts: job.attempts ?? 0,\n ...(job.maxAttempts !== undefined ? { maxAttempts: job.maxAttempts } : {}),\n ...(job.groupId ? { groupId: job.groupId } : {}),\n ...(job.priority ? { priority: job.priority } : {}),\n }\n }\n\n /**\n * Deserializes a JSON object into a basic Job-like object.\n *\n * Note: The result is NOT an instance of the original Job class.\n */\n deserialize(serialized: SerializedJob): Job {\n if (serialized.type !== 'json') {\n throw new Error('Invalid serialization type: expected \"json\"')\n }\n\n const dataStr =\n typeof serialized.data === 'string'\n ? serialized.data\n : Buffer.from(serialized.data).toString('utf8')\n const properties = JSON.parse(dataStr)\n // Only restores properties, not class instances.\n const job = Object.create({}) as Record<string, any>\n Object.assign(job, properties)\n\n job.id = serialized.id\n if (serialized.groupId) {\n job.groupId = serialized.groupId\n }\n if (serialized.priority) {\n job.priority = serialized.priority\n }\n if (serialized.delaySeconds !== undefined) {\n job.delaySeconds = serialized.delaySeconds\n }\n if (serialized.attempts !== undefined) {\n job.attempts = serialized.attempts\n }\n\n return job as Job\n }\n}\n",
53
+ "import { MemoryDriver } from './drivers/MemoryDriver'\nimport type { QueueDriver } from './drivers/QueueDriver'\nimport type { Job } from './Job'\nimport type { Queueable } from './Queueable'\nimport type { Scheduler } from './Scheduler'\nimport { CachedSerializer } from './serializers/CachedSerializer'\nimport { ClassNameSerializer } from './serializers/ClassNameSerializer'\nimport type { JobSerializer } from './serializers/JobSerializer'\nimport { JsonSerializer } from './serializers/JsonSerializer'\nimport type {\n JobPushOptions,\n PersistenceAdapter,\n QueueConfig,\n QueueConnectionConfig,\n QueueStats,\n SerializedJob,\n} from './types'\n\n/**\n * The central manager for queue operations.\n *\n * This class manages multiple queue connections and drivers, exposing a unified API for pushing,\n * popping, and managing jobs. It handles connection pooling, serialization, persistence,\n * and driver lazy-loading.\n *\n * @public\n * @example\n * ```typescript\n * const manager = new QueueManager({\n * default: 'redis',\n * connections: {\n * redis: { driver: 'redis', client: redisClient }\n * }\n * });\n *\n * await manager.push(new SendEmailJob('hello@example.com'));\n * ```\n */\nexport class QueueManager {\n private drivers = new Map<string, QueueDriver>()\n private serializers = new Map<string, JobSerializer>()\n private defaultConnection: string\n private defaultSerializer: JobSerializer\n private persistence?: QueueConfig['persistence']\n private scheduler?: Scheduler\n private debug: boolean\n\n constructor(config: QueueConfig = {}) {\n this.persistence = config.persistence\n this.defaultConnection = config.default ?? 'default'\n this.debug = config.debug ?? false\n\n // Wrap persistence adapter if buffering is configured\n if (this.persistence && (this.persistence.bufferSize || this.persistence.flushInterval)) {\n const { BufferedPersistence } = require('./persistence/BufferedPersistence')\n this.persistence.adapter = new BufferedPersistence(this.persistence.adapter, {\n maxBufferSize: this.persistence.bufferSize,\n flushInterval: this.persistence.flushInterval,\n })\n }\n\n // Initialize default serializer\n const serializerType = config.defaultSerializer ?? 'class'\n if (serializerType === 'class') {\n this.defaultSerializer = new ClassNameSerializer()\n } else if (serializerType === 'msgpack') {\n const { MessagePackSerializer } = require('./serializers/MessagePackSerializer')\n this.defaultSerializer = new MessagePackSerializer()\n } else {\n this.defaultSerializer = new JsonSerializer()\n }\n\n // Wrap with CachedSerializer if enabled\n if (config.useSerializationCache) {\n this.defaultSerializer = new CachedSerializer(this.defaultSerializer)\n }\n\n // Initialize default connection (MemoryDriver)\n if (!this.drivers.has('default')) {\n this.drivers.set('default', new MemoryDriver())\n }\n\n // Initialize additional connections\n if (config.connections) {\n for (const [name, connectionConfig] of Object.entries(config.connections)) {\n this.registerConnection(name, connectionConfig)\n }\n }\n }\n\n /**\n * Log debug message.\n */\n private log(message: string, data?: unknown): void {\n if (this.debug) {\n const timestamp = new Date().toISOString()\n const prefix = `[QueueManager] [${timestamp}]`\n if (data) {\n console.log(prefix, message, data)\n } else {\n console.log(prefix, message)\n }\n }\n }\n\n /**\n * Registers a new queue connection with the manager.\n *\n * Dynamically loads the required driver implementation based on the configuration.\n *\n * @param name - The name of the connection (e.g., 'primary').\n * @param config - The configuration object for the driver.\n * @throws {Error} If the driver type is missing required dependencies or unsupported.\n *\n * @example\n * ```typescript\n * manager.registerConnection('analytics', { driver: 'sqs', client: sqs });\n * ```\n */\n registerConnection(name: string, config: QueueConnectionConfig): void {\n const driverType = config.driver\n\n switch (driverType) {\n case 'memory':\n this.drivers.set(name, new MemoryDriver())\n break\n\n case 'database': {\n // Lazy-load DatabaseDriver\n const { DatabaseDriver } = require('./drivers/DatabaseDriver')\n if (!config.dbService) {\n throw new Error(\n '[QueueManager] DatabaseDriver requires dbService. Please provide a database service that implements DatabaseService interface.'\n )\n }\n this.drivers.set(\n name,\n new DatabaseDriver({\n dbService: config.dbService,\n table: config.table,\n })\n )\n break\n }\n\n case 'redis': {\n // Lazy-load RedisDriver\n const { RedisDriver } = require('./drivers/RedisDriver')\n if (!config.client) {\n throw new Error(\n '[QueueManager] RedisDriver requires client. Please provide Redis client in connection config.'\n )\n }\n this.drivers.set(\n name,\n new RedisDriver({\n client: config.client,\n prefix: config.prefix,\n })\n )\n break\n }\n\n case 'kafka': {\n // Lazy-load KafkaDriver\n const { KafkaDriver } = require('./drivers/KafkaDriver')\n if (!config.client) {\n throw new Error(\n '[QueueManager] KafkaDriver requires client. Please provide Kafka client in connection config.'\n )\n }\n this.drivers.set(\n name,\n new KafkaDriver({\n client: config.client,\n consumerGroupId: config.consumerGroupId,\n })\n )\n break\n }\n\n case 'sqs': {\n // Lazy-load SQSDriver\n const { SQSDriver } = require('./drivers/SQSDriver')\n if (!config.client) {\n throw new Error(\n '[QueueManager] SQSDriver requires client. Please provide SQS client in connection config.'\n )\n }\n this.drivers.set(\n name,\n new SQSDriver({\n client: config.client,\n queueUrlPrefix: config.queueUrlPrefix,\n visibilityTimeout: config.visibilityTimeout,\n waitTimeSeconds: config.waitTimeSeconds,\n })\n )\n break\n }\n\n case 'rabbitmq': {\n // Lazy-load RabbitMQDriver\n const { RabbitMQDriver } = require('./drivers/RabbitMQDriver')\n if (!config.client) {\n throw new Error(\n '[QueueManager] RabbitMQDriver requires client. Please provide RabbitMQ connection/channel in connection config.'\n )\n }\n this.drivers.set(\n name,\n new RabbitMQDriver({\n client: config.client,\n exchange: config.exchange,\n exchangeType: config.exchangeType,\n })\n )\n break\n }\n\n case 'bullmq': {\n // Lazy-load BullMQDriver\n const { BullMQDriver } = require('./drivers/BullMQDriver')\n if (!config.queue) {\n throw new Error(\n '[QueueManager] BullMQDriver requires queue. Please provide Bull Queue instance in connection config.'\n )\n }\n this.drivers.set(\n name,\n new BullMQDriver({\n queue: config.queue,\n worker: config.worker,\n prefix: config.prefix,\n debug: config.debug,\n })\n )\n break\n }\n\n default:\n throw new Error(\n `Driver \"${driverType}\" is not supported. Supported drivers: memory, database, redis, kafka, sqs, rabbitmq, bullmq`\n )\n }\n }\n\n /**\n * Retrieves the driver instance for a specific connection.\n *\n * @param connection - The name of the connection.\n * @returns The configured QueueDriver instance.\n * @throws {Error} If the connection has not been registered.\n *\n * @example\n * ```typescript\n * const driver = manager.getDriver('redis');\n * ```\n */\n getDriver(connection: string): QueueDriver {\n const driver = this.drivers.get(connection)\n if (!driver) {\n throw new Error(`Connection \"${connection}\" not found`)\n }\n return driver\n }\n\n /**\n * Gets the name of the default connection.\n *\n * @returns The default connection name.\n */\n getDefaultConnection(): string {\n return this.defaultConnection\n }\n\n /**\n * Retrieves a serializer instance by type.\n *\n * @param type - The serializer type (e.g., 'json', 'class'). If omitted, returns the default serializer.\n * @returns The JobSerializer instance.\n * @throws {Error} If the requested serializer type is not found.\n */\n getSerializer(type?: string): JobSerializer {\n if (type) {\n const serializer = this.serializers.get(type)\n if (!serializer) {\n throw new Error(`Serializer \"${type}\" not found`)\n }\n return serializer\n }\n return this.defaultSerializer\n }\n\n /**\n * Registers Job classes for the `ClassNameSerializer`.\n *\n * This is required when using 'class' serialization to allow proper hydration of job instances\n * upon deserialization.\n *\n * @param jobClasses - An array of Job class constructors.\n *\n * @example\n * ```typescript\n * manager.registerJobClasses([SendEmailJob, ProcessOrderJob]);\n * ```\n */\n registerJobClasses(jobClasses: Array<new (...args: unknown[]) => Job>): void {\n if (this.defaultSerializer instanceof ClassNameSerializer) {\n this.defaultSerializer.registerMany(jobClasses)\n }\n }\n\n /**\n * Pushes a single job to the queue.\n *\n * Serializes the job, selects the appropriate driver based on job configuration,\n * and dispatches it. Also handles audit logging if persistence is enabled.\n *\n * @template T - The type of the job (extends Job).\n * @param job - The job instance to enqueue.\n * @param options - Optional overrides for push behavior (priority, delay, etc.).\n * @returns The same job instance (for chaining).\n *\n * @example\n * ```typescript\n * await manager.push(new SendEmailJob('user@example.com'));\n * ```\n */\n async push<T extends Job & Queueable>(job: T, options?: JobPushOptions): Promise<T> {\n const connection = job.connectionName ?? this.defaultConnection\n const queue = job.queueName ?? 'default'\n const driver = this.getDriver(connection)\n const serializer = this.getSerializer()\n\n // Serialize job\n const serialized = serializer.serialize(job)\n\n // Push to queue\n const pushOptions = { ...options }\n if (job.priority) {\n pushOptions.priority = job.priority\n }\n await driver.push(queue, serialized, pushOptions)\n\n this.log(`Pushed job to ${queue} (${connection})`, {\n id: serialized.id,\n job: serialized.className ?? 'json',\n options: pushOptions,\n })\n\n // Auto-archive (Audit Mode) - Fire and forget\n if (this.persistence?.archiveEnqueued) {\n this.persistence.adapter.archive(queue, serialized, 'waiting').catch((err) => {\n console.error('[QueueManager] Persistence archive failed (waiting):', err)\n })\n }\n\n return job\n }\n\n /**\n * Pushes multiple jobs to the queue in a batch.\n *\n * Optimizes network requests by batching jobs where possible. Groups jobs by connection\n * and queue to maximize throughput.\n *\n * @template T - The type of the jobs.\n * @param jobs - An array of job instances to enqueue.\n * @param options - Configuration for batch size and concurrency.\n * @returns A promise that resolves when all jobs have been pushed.\n *\n * @example\n * ```typescript\n * await manager.pushMany(jobs, { batchSize: 500, concurrency: 5 });\n * ```\n */\n async pushMany<T extends Job & Queueable>(\n jobs: T[],\n options: {\n batchSize?: number\n concurrency?: number\n } = {}\n ): Promise<void> {\n if (jobs.length === 0) {\n return\n }\n\n const batchSize = options.batchSize ?? 100\n const concurrency = options.concurrency ?? 1\n\n // Group by connection and queue\n const groups = new Map<string, SerializedJob[]>()\n const serializer = this.getSerializer()\n\n for (const job of jobs) {\n const connection = job.connectionName ?? this.defaultConnection\n const queue = job.queueName ?? 'default'\n const key = `${connection}:${queue}`\n const serialized = serializer.serialize(job)\n\n if (!groups.has(key)) {\n groups.set(key, [])\n }\n groups.get(key)?.push(serialized)\n }\n\n // Helper to process a batch\n const processBatch = async (\n driver: QueueDriver,\n queue: string,\n batch: SerializedJob[]\n ): Promise<void> => {\n if (driver.pushMany) {\n await driver.pushMany(queue, batch)\n } else {\n // Fallback: push one-by-one\n for (const job of batch) {\n await driver.push(queue, job)\n }\n }\n }\n\n // Process each group\n for (const [key, serializedJobs] of groups.entries()) {\n const [connection, queue] = key.split(':')\n if (!connection || !queue) {\n continue\n }\n const driver = this.getDriver(connection)\n\n this.log(`Pushing ${serializedJobs.length} jobs to ${queue} (${connection})`)\n\n // Chunk jobs\n const chunks: SerializedJob[][] = []\n for (let i = 0; i < serializedJobs.length; i += batchSize) {\n chunks.push(serializedJobs.slice(i, i + batchSize))\n }\n\n // Process chunks with concurrency\n if (concurrency > 1) {\n const activePromises: Promise<void>[] = []\n for (const chunk of chunks) {\n const promise = processBatch(driver, queue, chunk)\n activePromises.push(promise)\n\n if (activePromises.length >= concurrency) {\n await Promise.race(activePromises)\n // Clean up finished promises? simpler to just await all if we don't need strict pool\n // Actually Promise.race just tells us ONE finished. We need to remove it.\n // A simple way is using p-limit style, or just Promise.all for blocks of N.\n // For simplicity and robustness, let's use blocks of N (Promise.all).\n // It's slightly less efficient than a sliding window but much simpler to implement without external deps.\n }\n }\n // Wait for remaining (This logic is flawed for true concurrency pool.\n // Let's use simple chunking for now: process 'concurrency' chunks at a time).\n\n for (let i = 0; i < chunks.length; i += concurrency) {\n const batchPromises = chunks\n .slice(i, i + concurrency)\n .map((chunk) => processBatch(driver, queue, chunk))\n await Promise.all(batchPromises)\n }\n } else {\n // Serial\n for (const chunk of chunks) {\n await processBatch(driver, queue, chunk)\n }\n }\n }\n }\n\n /**\n * Pops a single job from the queue.\n *\n * Retrieves the next available job from the specified queue.\n *\n * @param queue - The queue name (default: 'default').\n * @param connection - The connection name (defaults to default connection).\n * @returns A Job instance if found, or `null` if the queue is empty.\n *\n * @example\n * ```typescript\n * const job = await manager.pop('priority-queue');\n * if (job) await job.handle();\n * ```\n */\n async pop(queue = 'default', connection: string = this.defaultConnection): Promise<Job | null> {\n const driver = this.getDriver(connection)\n const serializer = this.getSerializer()\n\n const serialized = await driver.pop(queue)\n if (!serialized) {\n return null\n }\n\n this.log(`Popped job from ${queue} (${connection})`, { id: serialized.id })\n\n try {\n return serializer.deserialize(serialized)\n } catch (error) {\n // Deserialization failure: log and continue\n console.error('[QueueManager] Failed to deserialize job:', error)\n return null\n }\n }\n\n /**\n * Pops multiple jobs from the queue efficiently.\n *\n * Attempts to retrieve a batch of jobs from the driver. If the driver does not support\n * batching, it falls back to sequential popping.\n *\n * @param queue - The queue name (default: 'default').\n * @param count - The maximum number of jobs to retrieve (default: 10).\n * @param connection - The connection name.\n * @returns An array of Job instances.\n *\n * @example\n * ```typescript\n * const jobs = await manager.popMany('default', 50);\n * ```\n */\n async popMany(\n queue = 'default',\n count = 10,\n connection: string = this.defaultConnection\n ): Promise<Job[]> {\n const driver = this.getDriver(connection)\n const serializer = this.getSerializer()\n const results: Job[] = []\n\n if (driver.popMany) {\n const serializedJobs = await driver.popMany(queue, count)\n if (serializedJobs.length > 0) {\n this.log(`Popped ${serializedJobs.length} jobs from ${queue} (${connection})`)\n }\n for (const serialized of serializedJobs) {\n try {\n results.push(serializer.deserialize(serialized))\n } catch (error) {\n console.error('[QueueManager] Failed to deserialize job:', error)\n }\n }\n } else {\n // Fallback: pop one-by-one\n for (let i = 0; i < count; i++) {\n const job = await this.pop(queue, connection)\n if (job) {\n results.push(job)\n } else {\n break\n }\n }\n }\n\n return results\n }\n\n /**\n * Retrieves the current size of a queue.\n *\n * @param queue - The queue name (default: 'default').\n * @param connection - The connection name.\n * @returns The number of waiting jobs.\n *\n * @example\n * ```typescript\n * const count = await manager.size('emails');\n * ```\n */\n async size(queue = 'default', connection: string = this.defaultConnection): Promise<number> {\n const driver = this.getDriver(connection)\n return driver.size(queue)\n }\n\n /**\n * Pops a job from the queue with blocking (wait) behavior.\n *\n * Waits for a job to become available for the specified timeout duration.\n * Useful for reducing polling loop frequency.\n *\n * @param queues - A queue name or array of queue names to listen to.\n * @param timeout - Timeout in seconds (0 = block indefinitely).\n * @param connection - The connection name.\n * @returns A Job instance if found, or `null` if timed out.\n *\n * @example\n * ```typescript\n * // Wait up to 30 seconds for a job\n * const job = await manager.popBlocking('default', 30);\n * ```\n */\n async popBlocking(\n queues: string | string[] = 'default',\n timeout = 0,\n connection: string = this.defaultConnection\n ): Promise<Job | null> {\n const driver = this.getDriver(connection)\n const serializer = this.getSerializer()\n\n if (!driver.popBlocking) {\n const q = Array.isArray(queues) ? queues[0]! : queues\n return this.pop(q, connection)\n }\n\n const serialized = await driver.popBlocking(queues, timeout)\n if (!serialized) {\n return null\n }\n\n this.log(\n `Popped job (blocking) from ${Array.isArray(queues) ? queues.join(',') : queues} (${connection})`,\n { id: serialized.id }\n )\n\n try {\n return serializer.deserialize(serialized)\n } catch (error) {\n console.error('[QueueManager] Failed to deserialize job:', error)\n return null\n }\n }\n\n /**\n * Removes all jobs from a specific queue.\n *\n * @param queue - The queue name to purge.\n * @param connection - The connection name.\n *\n * @example\n * ```typescript\n * await manager.clear('test-queue');\n * ```\n */\n async clear(queue = 'default', connection: string = this.defaultConnection): Promise<void> {\n const driver = this.getDriver(connection)\n await driver.clear(queue)\n }\n\n /**\n * Retrieves comprehensive statistics for a queue.\n *\n * Includes counts for pending, processing, delayed, and failed jobs.\n *\n * @param queue - The queue name.\n * @param connection - The connection name.\n * @returns A QueueStats object.\n *\n * @example\n * ```typescript\n * const stats = await manager.stats('default');\n * console.log(stats.size, stats.failed);\n * ```\n */\n async stats(queue = 'default', connection: string = this.defaultConnection): Promise<QueueStats> {\n const driver = this.getDriver(connection)\n if (driver.stats) {\n return await driver.stats(queue)\n }\n\n // Fallback: minimal stats\n return {\n queue,\n size: await driver.size(queue),\n }\n }\n\n /**\n * Marks a job as successfully completed.\n *\n * Removes the job from the processing state and optionally archives it.\n *\n * @param job - The job instance that finished.\n *\n * @example\n * ```typescript\n * await manager.complete(job);\n * ```\n */\n async complete<T extends Job & Queueable>(job: T): Promise<void> {\n const connection = job.connectionName ?? this.defaultConnection\n const queue = job.queueName ?? 'default'\n const driver = this.getDriver(connection)\n const serializer = this.getSerializer()\n\n if (driver.complete) {\n const serialized = serializer.serialize(job)\n await driver.complete(queue, serialized)\n\n this.log(`Completed job ${job.id} in ${queue}`)\n\n // Auto-archive\n if (this.persistence?.archiveCompleted) {\n await this.persistence.adapter.archive(queue, serialized, 'completed').catch((err) => {\n console.error('[QueueManager] Persistence archive failed (completed):', err)\n })\n }\n }\n }\n\n /**\n * Marks a job as failed.\n *\n * Moves the job to the failed state (Dead Letter Queue) and optionally archives it.\n * This is typically called after max retry attempts are exhausted.\n *\n * @param job - The job instance that failed.\n * @param error - The error that caused the failure.\n *\n * @example\n * ```typescript\n * await manager.fail(job, new Error('Something went wrong'));\n * ```\n */\n async fail<T extends Job & Queueable>(job: T, error: Error): Promise<void> {\n const connection = job.connectionName ?? this.defaultConnection\n const queue = job.queueName ?? 'default'\n const driver = this.getDriver(connection)\n const serializer = this.getSerializer()\n\n if (driver.fail) {\n const serialized = serializer.serialize(job)\n serialized.error = error.message\n serialized.failedAt = Date.now()\n await driver.fail(queue, serialized)\n\n this.log(`Failed job ${job.id} in ${queue}`, { error: error.message })\n\n // Auto-archive\n if (this.persistence?.archiveFailed) {\n await this.persistence.adapter.archive(queue, serialized, 'failed').catch((err) => {\n console.error('[QueueManager] Persistence archive failed (failed):', err)\n })\n }\n }\n }\n\n /**\n * Retrieves the configured persistence adapter.\n *\n * @returns The PersistenceAdapter instance, or undefined if not configured.\n */\n getPersistence(): PersistenceAdapter | undefined {\n return this.persistence?.adapter\n }\n\n /**\n * Gets the Scheduler instance associated with this manager.\n *\n * The Scheduler handles delayed jobs and periodic tasks.\n *\n * @returns The Scheduler instance.\n */\n getScheduler(): Scheduler {\n if (!this.scheduler) {\n const { Scheduler } = require('./Scheduler')\n this.scheduler = new Scheduler(this)\n }\n return this.scheduler!\n }\n\n /**\n * Retrieves failed jobs from the Dead Letter Queue.\n *\n * @param queue - The queue name.\n * @param start - The starting index (pagination).\n * @param end - The ending index (pagination).\n * @param connection - The connection name.\n * @returns An array of serialized jobs.\n *\n * @example\n * ```typescript\n * const failedJobs = await manager.getFailed('default', 0, 10);\n * ```\n */\n async getFailed(\n queue: string,\n start = 0,\n end = -1,\n connection: string = this.defaultConnection\n ): Promise<SerializedJob[]> {\n const driver = this.getDriver(connection)\n if (driver.getFailed) {\n return driver.getFailed(queue, start, end)\n }\n return []\n }\n\n /**\n * Retries failed jobs from the Dead Letter Queue.\n *\n * Moves jobs from the failed state back to the active queue for re-processing.\n *\n * @param queue - The queue name.\n * @param count - The number of jobs to retry.\n * @param connection - The connection name.\n * @returns The number of jobs successfully retried.\n *\n * @example\n * ```typescript\n * await manager.retryFailed('default', 5);\n * ```\n */\n async retryFailed(\n queue: string,\n count = 1,\n connection: string = this.defaultConnection\n ): Promise<number> {\n const driver = this.getDriver(connection)\n if (driver.retryFailed) {\n return driver.retryFailed(queue, count)\n }\n return 0\n }\n\n /**\n * Clears all failed jobs from the Dead Letter Queue.\n *\n * @param queue - The queue name.\n * @param connection - The connection name.\n *\n * @example\n * ```typescript\n * await manager.clearFailed('default');\n * ```\n */\n async clearFailed(queue: string, connection: string = this.defaultConnection): Promise<void> {\n const driver = this.getDriver(connection)\n if (driver.clearFailed) {\n await driver.clearFailed(queue)\n }\n }\n\n /**\n * Retrieves high-level statistics across all registered connections and queues.\n *\n * Iterates through all drivers and collects metadata to provide a comprehensive\n * snapshot of the entire queue system's health.\n *\n * @returns A promise resolving to a GlobalStats object.\n */\n async getGlobalStats(): Promise<import('./types').GlobalStats> {\n const stats: import('./types').GlobalStats = {\n connections: {},\n totalSize: 0,\n totalFailed: 0,\n timestamp: Date.now(),\n }\n\n for (const [name, driver] of this.drivers.entries()) {\n const queueNames = driver.getQueues ? await driver.getQueues() : ['default']\n const connectionStats: QueueStats[] = []\n\n for (const queue of queueNames) {\n const qStats = await this.stats(queue, name)\n connectionStats.push(qStats)\n stats.totalSize += qStats.size\n stats.totalFailed += qStats.failed ?? 0\n }\n\n stats.connections[name] = connectionStats\n }\n\n return stats\n }\n}\n",
54
+ "import { app } from '@gravito/core'\nimport { Job } from './Job'\n\n/**\n * SystemEventJob - Internal job for processing Gravito async hooks.\n *\n * @internal\n */\nexport class SystemEventJob extends Job {\n /**\n * Optional failure callback for DLQ handling.\n */\n private onFailedCallback?: (error: Error, attempt: number) => Promise<void>\n\n constructor(\n public readonly hook: string,\n public readonly args: unknown,\n public readonly options: Record<string, any> = {}\n ) {\n super()\n\n // Apply options to job configuration\n if (options.queue) {\n this.onQueue(options.queue)\n }\n if (options.priority) {\n this.withPriority(options.priority)\n }\n if (options.delay) {\n this.delay(options.delay)\n }\n if (options.retryAfter) {\n this.backoff(options.retryAfter, options.retryMultiplier)\n }\n // options.connection handling depends on Job implementation, keeping it if it was there?\n // Original line 18: if (options.connection) this.onConnection(options.connection)\n if (options.connection) {\n this.onConnection(options.connection)\n }\n }\n\n /**\n * Set failure callback for DLQ handling.\n *\n * @param callback - Called when job fails permanently\n * @returns Self for chaining\n */\n onFailed(callback: (error: Error, attempt: number) => Promise<void>): this {\n this.onFailedCallback = callback\n return this\n }\n\n /**\n * Execute the hook listeners in the worker process.\n */\n async handle(): Promise<void> {\n const core = app()\n if (core?.hooks) {\n // Use doActionSync to execute listeners in the worker process\n // and avoid infinite recursion if asyncByDefault is true.\n await core.hooks.doActionSync(this.hook, this.args)\n }\n }\n\n /**\n * Called when job fails permanently after all retries.\n *\n * This method is invoked by the worker when job exhausts all retry attempts.\n */\n async failed(error: Error, attempt = 1): Promise<void> {\n if (this.onFailedCallback) {\n try {\n await this.onFailedCallback(error, attempt)\n } catch (callbackError) {\n console.error('[SystemEventJob] Failed callback error:', callbackError)\n }\n }\n }\n}\n",
55
+ "import type { EventBackend, EventTask } from '@gravito/core'\nimport type { QueueManager } from './QueueManager'\nimport { SystemEventJob } from './SystemEventJob'\nimport type { JobPushOptions } from './types'\n\n/**\n * Retry strategy for events.\n *\n * - 'bull': Use Bull Queue's built-in retry mechanism\n * - 'core': Use EventPriorityQueue's retry logic (not implemented in Stream backend)\n * - 'hybrid': Bull retries + Core DLQ fallback (future phase)\n */\nexport type RetryStrategy = 'bull' | 'core' | 'hybrid'\n\n/**\n * Configuration for StreamEventBackend.\n */\nexport interface StreamEventBackendConfig {\n /**\n * Retry strategy to use.\n * @default 'bull'\n */\n retryStrategy?: RetryStrategy\n\n /**\n * Whether to integrate with CircuitBreaker.\n * @default false\n */\n circuitBreakerIntegration?: boolean\n\n /**\n * Optional DLQ (Dead Letter Queue) handler for failed events.\n */\n dlqHandler?: {\n handle(event: EventTask, error: Error, attempt: number): Promise<void>\n }\n\n /**\n * CircuitBreaker getter (injected from core)\n */\n getCircuitBreaker?: (hook: string) => any\n}\n\n/**\n * Event backend implementation using Gravito Stream (Bull Queue).\n *\n * Provides persistent, distributed event processing with:\n * - Bull Queue persistence (Redis-backed)\n * - Configurable retry strategies\n * - Optional CircuitBreaker integration\n * - DLQ support for failed events\n *\n * @example\n * ```typescript\n * const queueManager = new QueueManager({\n * default: 'bullmq',\n * connections: {\n * bullmq: {\n * driver: 'bullmq',\n * queue: new Queue('gravito-events', { connection: redis })\n * }\n * }\n * })\n *\n * const backend = new StreamEventBackend(queueManager, {\n * retryStrategy: 'bull',\n * circuitBreakerIntegration: true\n * })\n * ```\n */\nexport class StreamEventBackend implements EventBackend {\n private config: StreamEventBackendConfig\n\n constructor(\n private queueManager: QueueManager,\n config?: StreamEventBackendConfig\n ) {\n this.config = {\n retryStrategy: 'bull',\n circuitBreakerIntegration: false,\n ...config,\n }\n }\n\n /**\n * Build Job Push Options from EventOptions.\n *\n * Maps EventOptions to Bull Queue JobPushOptions with retry strategy applied.\n */\n private buildJobOptions(task: EventTask): JobPushOptions {\n const options: JobPushOptions = {}\n\n // Map priority if present\n if (task.options?.priority) {\n options.priority = task.options.priority\n }\n\n // Map group ID for FIFO processing (if provided in options as any)\n const taskOptionsAny = task.options as any\n if (taskOptionsAny?.groupId) {\n options.groupId = taskOptionsAny.groupId\n }\n\n return options\n }\n\n /**\n * Enqueue an event task to the stream queue.\n *\n * Applies retry strategy and CircuitBreaker checks based on configuration.\n * Supports DLQ routing for failed events.\n */\n async enqueue(task: EventTask): Promise<void> {\n // CircuitBreaker state check (before queuing)\n if (this.config.circuitBreakerIntegration && this.config.getCircuitBreaker) {\n const breaker = this.config.getCircuitBreaker(task.hook)\n if (breaker?.getState?.() === 'OPEN') {\n throw new Error(`Circuit breaker OPEN for event: ${task.hook}`)\n }\n }\n\n // Create job with options\n const job = new SystemEventJob(task.hook, task.args, task.options)\n\n // Apply retry strategy configuration to job\n this.applyRetryStrategy(job, task)\n\n // Setup DLQ failure callback\n if (this.config.dlqHandler) {\n job.onFailed(async (error: Error, attempt: number) => {\n await this.handleJobFailure(task, error, attempt)\n })\n }\n\n // Push to queue\n const options = this.buildJobOptions(task)\n await this.queueManager.push(job, options)\n }\n\n /**\n * Apply retry strategy to the job based on configuration.\n */\n private applyRetryStrategy(job: SystemEventJob, task: EventTask): void {\n const strategy = this.config.retryStrategy ?? 'bull'\n const taskOptionsAny = task.options as any\n\n if (strategy === 'bull' || strategy === 'hybrid') {\n // Let Bull Queue handle retries with exponential backoff\n job.maxAttempts = taskOptionsAny?.maxAttempts ?? 3\n job.retryAfterSeconds = taskOptionsAny?.retryAfter ?? 5\n job.retryMultiplier = taskOptionsAny?.retryMultiplier ?? 2\n }\n\n // For 'core' and 'hybrid', we'd use EventPriorityQueue retry logic\n // (future implementation in Phase 5)\n }\n\n /**\n * Handle job failure and route to DLQ if configured.\n *\n * Called when a job exhausts all retry attempts.\n */\n async handleJobFailure(task: EventTask, error: Error, attempt: number): Promise<void> {\n if (this.config.dlqHandler) {\n try {\n await this.config.dlqHandler.handle(task, error, attempt)\n } catch (dlqError) {\n console.error('[StreamEventBackend] Failed to handle DLQ:', dlqError)\n }\n }\n }\n\n /**\n * Record a job failure for CircuitBreaker state management.\n *\n * Called when a job fails, regardless of retry status.\n */\n recordJobFailure(task: EventTask, error: Error): void {\n if (this.config.circuitBreakerIntegration && this.config.getCircuitBreaker) {\n const breaker = this.config.getCircuitBreaker(task.hook)\n if (breaker?.recordFailure) {\n breaker.recordFailure(error)\n }\n }\n }\n\n /**\n * Record a job success for CircuitBreaker state management.\n *\n * Called when a job completes successfully.\n */\n recordJobSuccess(task: EventTask): void {\n if (this.config.circuitBreakerIntegration && this.config.getCircuitBreaker) {\n const breaker = this.config.getCircuitBreaker(task.hook)\n if (breaker?.recordSuccess) {\n breaker.recordSuccess()\n }\n }\n }\n\n /**\n * Get the retry strategy configuration.\n */\n getRetryStrategy(): RetryStrategy {\n return this.config.retryStrategy ?? 'bull'\n }\n\n /**\n * Check if CircuitBreaker integration is enabled.\n */\n isCircuitBreakerEnabled(): boolean {\n return this.config.circuitBreakerIntegration ?? false\n }\n\n /**\n * Get the DLQ handler, if configured.\n */\n getDLQHandler(): StreamEventBackendConfig['dlqHandler'] | undefined {\n return this.config.dlqHandler\n }\n}\n",
56
+ "import type { GravitoContext, GravitoNext, GravitoOrbit, PlanetCore } from '@gravito/core'\nimport type { ConsumerOptions } from './Consumer'\nimport { Consumer } from './Consumer'\nimport { QueueManager } from './QueueManager'\nimport { StreamEventBackend } from './StreamEventBackend'\nimport type { QueueConfig } from './types'\n\n/**\n * Configuration options for the OrbitStream extension.\n *\n * Extends the standard `QueueConfig` with specific options for integration into\n * the Gravito lifecycle, such as auto-starting workers in development environments.\n *\n * @public\n * @example\n * ```typescript\n * const options: OrbitStreamOptions = {\n * default: 'redis',\n * autoStartWorker: true\n * };\n * ```\n */\nexport interface OrbitStreamOptions extends QueueConfig {\n /**\n * Automatically start an embedded worker process.\n *\n * If set to `true`, a background worker will be spawned within the main process.\n * This is recommended for development or simple deployments but should be\n * avoided in high-scale production to keep web servers stateless.\n */\n autoStartWorker?: boolean\n\n /**\n * Configuration options for the embedded worker.\n *\n * Only used if `autoStartWorker` is true. Defines concurrency, polling intervals, etc.\n */\n workerOptions?: ConsumerOptions\n\n /**\n * Configuration for the Stream Monitoring Dashboard API.\n *\n * If enabled, registers API routes for monitoring queue health and job history.\n *\n * @default false\n */\n dashboard?:\n | boolean\n | {\n /**\n * Base path for the dashboard API routes.\n * @default '/_flux'\n */\n path?: string\n }\n}\n\n/**\n * The Queue Orbit (Plugin) for Gravito Framework.\n *\n * This class acts as the integration layer between the `@gravito/stream` package\n * and the Gravito core system (`PlanetCore`). It registers the `QueueManager`\n * service, injects it into the request context, and manages the lifecycle of\n * embedded workers.\n *\n * @public\n * @example\n * ```typescript\n * const stream = OrbitStream.configure({\n * default: 'redis',\n * connections: {\n * redis: { driver: 'redis', client: redis }\n * }\n * });\n *\n * await PlanetCore.boot({ orbits: [stream] });\n * ```\n */\nexport class OrbitStream implements GravitoOrbit {\n private queueManager?: QueueManager\n private consumer?: Consumer\n private core?: PlanetCore\n\n constructor(private options: OrbitStreamOptions = {}) {}\n\n /**\n * Factory method for creating and configuring an OrbitStream instance.\n *\n * Provides a fluent way to instantiate the orbit during application bootstrap.\n *\n * @param options - Configuration options.\n * @returns A new OrbitStream instance.\n *\n * @example\n * ```typescript\n * const orbit = OrbitStream.configure({ default: 'memory' });\n * ```\n */\n static configure(options: OrbitStreamOptions): OrbitStream {\n return new OrbitStream(options)\n }\n\n /**\n * Installs the Queue system into the Gravito PlanetCore.\n *\n * This lifecycle method:\n * 1. Initializes the `QueueManager`.\n * 2. Registers the `queue` service in the dependency injection container.\n * 3. Sets up a global middleware to inject `QueueManager` into the request context (`c.get('queue')`).\n * 4. Automatically detects and registers database connections if available in the context.\n * 5. Starts the embedded worker if configured.\n *\n * @param core - The PlanetCore instance.\n */\n install(core: PlanetCore): void {\n this.core = core\n // Create QueueManager.\n this.queueManager = new QueueManager(this.options)\n\n // Register in core container for global access (CLI, Jobs)\n core.container.instance('queue', this.queueManager)\n\n // Inject queue service into Context.\n core.adapter.use('*', async (c: GravitoContext, next: GravitoNext) => {\n // Resolve dbService dynamically for database connections\n if (this.queueManager && this.options.connections) {\n for (const [name, config] of Object.entries(this.options.connections)) {\n if (\n (config as { driver: string }).driver === 'database' &&\n !(config as { dbService?: unknown }).dbService\n ) {\n try {\n // Try to get dbService from Context\n const dbService = c.get('db')\n if (dbService) {\n // Check whether the driver is already registered\n try {\n this.queueManager.getDriver(name)\n } catch {\n // Not registered yet: register now\n this.queueManager.registerConnection(name, {\n ...config,\n dbService,\n })\n }\n }\n } catch {\n // db service not present: ignore (OrbitDB may not be installed)\n }\n }\n }\n }\n\n c.set('queue', this.queueManager!)\n return await next()\n })\n\n core.logger.info('[OrbitStream] Installed')\n\n // Replace default event backend with Stream backend\n if (this.queueManager) {\n const backend = new StreamEventBackend(this.queueManager)\n core.hooks.setBackend(backend)\n core.logger.info('[OrbitStream] HookManager backend switched to StreamEventBackend')\n }\n\n if (this.options.dashboard) {\n const { DashboardProvider } = require('./DashboardProvider')\n const dashboard = new DashboardProvider(this.queueManager)\n const path =\n typeof this.options.dashboard === 'object' ? this.options.dashboard.path : '/_flux'\n dashboard.registerRoutes(core, path)\n core.logger.info(`[OrbitStream] Dashboard API registered at ${path}`)\n }\n\n // Auto-start embedded worker in development (optional)\n if (\n this.options.autoStartWorker &&\n process.env.NODE_ENV === 'development' &&\n this.options.workerOptions\n ) {\n this.startWorker(this.options.workerOptions)\n }\n }\n\n /**\n * Starts the embedded worker process.\n *\n * Launches a `Consumer` instance to process jobs in the background.\n * Throws an error if `QueueManager` is not initialized or if a worker is already running.\n *\n * @param options - Consumer configuration options.\n * @throws {Error} If QueueManager is missing or worker is already active.\n *\n * @example\n * ```typescript\n * orbit.startWorker({ queues: ['default'] });\n * ```\n */\n startWorker(options: ConsumerOptions): void {\n if (!this.queueManager) {\n throw new Error('QueueManager not initialized. Call install() first.')\n }\n\n if (this.consumer?.isRunning()) {\n throw new Error('Worker is already running')\n }\n\n const consumerOptions: ConsumerOptions = {\n ...options,\n onEvent: (event, payload) => {\n const signal = this.core?.container.make('signal') as any\n if (signal && typeof signal.emit === 'function') {\n signal.emit(`stream:${event}`, payload)\n }\n },\n }\n\n this.consumer = new Consumer(this.queueManager, consumerOptions)\n this.consumer.start().catch((error: unknown) => {\n console.error('[OrbitStream] Worker error:', error)\n })\n }\n\n /**\n * Stops the embedded worker process.\n *\n * Gracefully shuts down the consumer, waiting for active jobs to complete.\n *\n * @returns A promise that resolves when the worker has stopped.\n *\n * @example\n * ```typescript\n * await orbit.stopWorker();\n * ```\n */\n async stopWorker(): Promise<void> {\n if (this.consumer) {\n await this.consumer.stop()\n }\n }\n\n /**\n * Retrieves the underlying QueueManager instance.\n *\n * @returns The active QueueManager, or undefined if not installed.\n *\n * @example\n * ```typescript\n * const manager = orbit.getQueueManager();\n * ```\n */\n getQueueManager(): QueueManager | undefined {\n return this.queueManager\n }\n}\n\n// Module augmentation for GravitoVariables (new abstraction)\ndeclare module '@gravito/core' {\n interface GravitoVariables {\n /** Queue manager for job processing */\n queue?: QueueManager\n /** Database service (from orbit-db) */\n db?: unknown\n }\n}\n",
57
+ "import type { PersistenceAdapter, SerializedJob } from '../types'\n\n// ──────────────────────────────────────────────────────────────────────────────\n// CBOR 輕量編碼工具(不依賴外部模組,直接嵌入)\n// 遵循 RFC 7049,僅實作 archive 所需的子集\n// ──────────────────────────────────────────────────────────────────────────────\n\n/**\n * 將數字長度寫入 CBOR 標頭\n */\nfunction writeCborHeader(major: number, length: number): Uint8Array {\n const majorBits = major << 5\n if (length < 24) {\n return new Uint8Array([majorBits | length])\n }\n if (length < 0x100) {\n return new Uint8Array([majorBits | 24, length])\n }\n if (length < 0x10000) {\n return new Uint8Array([majorBits | 25, length >> 8, length & 0xff])\n }\n const bytes = new Uint8Array(5)\n bytes[0] = majorBits | 26\n bytes[1] = (length >> 24) & 0xff\n bytes[2] = (length >> 16) & 0xff\n bytes[3] = (length >> 8) & 0xff\n bytes[4] = length & 0xff\n return bytes\n}\n\n/**\n * 簡易 CBOR 編碼器\n * 支援 string / number / boolean / null / undefined / Date / Uint8Array / object / array\n */\nfunction cborEncodeValue(value: unknown): Uint8Array {\n // null / undefined → CBOR null (0xf6)\n if (value === null || value === undefined) {\n return new Uint8Array([0xf6])\n }\n\n // boolean\n if (typeof value === 'boolean') {\n return new Uint8Array([value ? 0xf5 : 0xf4])\n }\n\n // number\n if (typeof value === 'number') {\n if (Number.isInteger(value) && value >= 0 && value <= 0xffffffff) {\n // 正整數 major type 0\n return writeCborHeader(0, value)\n }\n if (Number.isInteger(value) && value < 0 && value >= -0x100000000) {\n // 負整數 major type 1\n return writeCborHeader(1, -1 - value)\n }\n // 浮點數 → IEEE 754 double(major type 7, additional 27)\n const buf = new Uint8Array(9)\n const view = new DataView(buf.buffer)\n buf[0] = 0xfb\n view.setFloat64(1, value, false)\n return buf\n }\n\n // string → major type 3\n if (typeof value === 'string') {\n const encoded = new TextEncoder().encode(value)\n const header = writeCborHeader(3, encoded.length)\n const result = new Uint8Array(header.length + encoded.length)\n result.set(header)\n result.set(encoded, header.length)\n return result\n }\n\n // Uint8Array / ArrayBuffer → major type 2(bytes)\n if (value instanceof Uint8Array) {\n const header = writeCborHeader(2, value.length)\n const result = new Uint8Array(header.length + value.length)\n result.set(header)\n result.set(value, header.length)\n return result\n }\n\n if (value instanceof ArrayBuffer) {\n return cborEncodeValue(new Uint8Array(value))\n }\n\n // Date → 轉為時間戳(毫秒整數)\n if (value instanceof Date) {\n return cborEncodeValue(value.getTime())\n }\n\n // Array → major type 4\n if (Array.isArray(value)) {\n const parts: Uint8Array[] = [writeCborHeader(4, value.length)]\n for (const item of value) {\n parts.push(cborEncodeValue(item))\n }\n return concatBytes(parts)\n }\n\n // Object → major type 5(map)\n if (typeof value === 'object') {\n const obj = value as Record<string, unknown>\n const keys = Object.keys(obj)\n const parts: Uint8Array[] = [writeCborHeader(5, keys.length)]\n for (const key of keys) {\n parts.push(cborEncodeValue(key))\n parts.push(cborEncodeValue(obj[key]))\n }\n return concatBytes(parts)\n }\n\n // 其他(function 等)→ CBOR null\n return new Uint8Array([0xf6])\n}\n\n/**\n * 合併多個 Uint8Array\n */\nfunction concatBytes(arrays: Uint8Array[]): Uint8Array {\n let total = 0\n for (const arr of arrays) {\n total += arr.length\n }\n const result = new Uint8Array(total)\n let offset = 0\n for (const arr of arrays) {\n result.set(arr, offset)\n offset += arr.length\n }\n return result\n}\n\n// ──────────────────────────────────────────────────────────────────────────────\n// CBOR 解碼器(簡易版,對應上述編碼器)\n// ──────────────────────────────────────────────────────────────────────────────\n\n/**\n * 解碼器狀態\n */\ninterface DecoderState {\n bytes: Uint8Array\n view: DataView\n pos: number\n}\n\nfunction cborReadHeader(state: DecoderState): { major: number; info: number; value: number } {\n const byte = state.bytes[state.pos++]\n const major = byte >> 5\n const info = byte & 0x1f\n\n if (info < 24) {\n return { major, info, value: info }\n }\n if (info === 24) {\n return { major, info, value: state.bytes[state.pos++] }\n }\n if (info === 25) {\n const v = state.view.getUint16(state.pos, false)\n state.pos += 2\n return { major, info, value: v }\n }\n if (info === 26) {\n const v = state.view.getUint32(state.pos, false)\n state.pos += 4\n return { major, info, value: v }\n }\n // info === 27 → uint64(這裡只用低 32 位元,夠用於本模組場景)\n const hi = state.view.getUint32(state.pos, false)\n const lo = state.view.getUint32(state.pos + 4, false)\n state.pos += 8\n return { major, info, value: hi * 0x100000000 + lo }\n}\n\nfunction cborDecodeValue(state: DecoderState): unknown {\n const byte = state.bytes[state.pos]\n const major = byte >> 5\n const info = byte & 0x1f\n\n // major type 7:特殊值\n if (major === 7) {\n state.pos++\n if (info === 20) {\n return false // false\n }\n if (info === 21) {\n return true // true\n }\n if (info === 22) {\n return null // null\n }\n if (info === 23) {\n return undefined\n }\n if (info === 27) {\n // IEEE 754 double\n const v = state.view.getFloat64(state.pos, false)\n state.pos += 8\n return v\n }\n return null\n }\n\n const header = cborReadHeader(state)\n\n // major type 0:正整數\n if (header.major === 0) {\n return header.value\n }\n\n // major type 1:負整數\n if (header.major === 1) {\n return -1 - header.value\n }\n\n // major type 2:bytes\n if (header.major === 2) {\n const bytes = state.bytes.slice(state.pos, state.pos + header.value)\n state.pos += header.value\n return bytes\n }\n\n // major type 3:string\n if (header.major === 3) {\n const bytes = state.bytes.slice(state.pos, state.pos + header.value)\n state.pos += header.value\n return new TextDecoder().decode(bytes)\n }\n\n // major type 4:array\n if (header.major === 4) {\n const arr: unknown[] = []\n for (let i = 0; i < header.value; i++) {\n arr.push(cborDecodeValue(state))\n }\n return arr\n }\n\n // major type 5:map\n if (header.major === 5) {\n const obj: Record<string, unknown> = {}\n for (let i = 0; i < header.value; i++) {\n const key = cborDecodeValue(state) as string\n obj[key] = cborDecodeValue(state)\n }\n return obj\n }\n\n throw new Error(`不支援的 CBOR major type: ${header.major}`)\n}\n\n/**\n * 編碼單筆 archive 項目為 CBOR 格式\n */\nfunction encodeArchiveEntry(queue: string, job: SerializedJob, status: string): Uint8Array {\n const entry: Record<string, unknown> = {\n queue,\n status,\n id: job.id,\n type: job.type,\n data: job.data,\n createdAt: job.createdAt,\n }\n // 選擇性欄位(只序列化有值的,減少 payload 大小)\n if (job.className !== undefined) {\n entry.className = job.className\n }\n if (job.delaySeconds !== undefined) {\n entry.delaySeconds = job.delaySeconds\n }\n if (job.attempts !== undefined) {\n entry.attempts = job.attempts\n }\n if (job.maxAttempts !== undefined) {\n entry.maxAttempts = job.maxAttempts\n }\n if (job.groupId !== undefined) {\n entry.groupId = job.groupId\n }\n if (job.retryAfterSeconds !== undefined) {\n entry.retryAfterSeconds = job.retryAfterSeconds\n }\n if (job.retryMultiplier !== undefined) {\n entry.retryMultiplier = job.retryMultiplier\n }\n if (job.error !== undefined) {\n entry.error = job.error\n }\n if (job.failedAt !== undefined) {\n entry.failedAt = job.failedAt\n }\n if (job.priority !== undefined) {\n entry.priority = job.priority\n }\n\n return cborEncodeValue(entry) as Uint8Array\n}\n\n/**\n * 確保 Uint8Array 有標準的 .buffer 屬性可供 DataView 使用\n * Bun 某些 API 回傳的 Uint8Array 可能沒有標準 ArrayBuffer\n */\nfunction ensureBuffer(bytes: Uint8Array): { buf: ArrayBuffer; offset: number } {\n if (bytes.buffer && bytes.buffer instanceof ArrayBuffer) {\n return { buf: bytes.buffer, offset: bytes.byteOffset }\n }\n // 複製到新的 ArrayBuffer\n const copy = new Uint8Array(bytes.length)\n for (let i = 0; i < bytes.length; i++) {\n copy[i] = bytes[i]\n }\n return { buf: copy.buffer, offset: 0 }\n}\n\n/**\n * 解碼 CBOR bytes 為 archive 項目\n */\nfunction decodeArchiveEntry(bytes: Uint8Array): {\n queue: string\n job: SerializedJob\n status: string\n} {\n const { buf, offset } = ensureBuffer(bytes)\n const state: DecoderState = {\n bytes,\n view: new DataView(buf, offset, bytes.byteLength),\n pos: 0,\n }\n const obj = cborDecodeValue(state) as Record<string, unknown>\n\n return {\n queue: obj.queue as string,\n status: obj.status as string,\n job: {\n id: obj.id as string,\n type: obj.type as SerializedJob['type'],\n data: obj.data as string | Uint8Array,\n createdAt: obj.createdAt as number,\n ...(obj.className !== undefined ? { className: obj.className as string } : {}),\n ...(obj.delaySeconds !== undefined ? { delaySeconds: obj.delaySeconds as number } : {}),\n ...(obj.attempts !== undefined ? { attempts: obj.attempts as number } : {}),\n ...(obj.maxAttempts !== undefined ? { maxAttempts: obj.maxAttempts as number } : {}),\n ...(obj.groupId !== undefined ? { groupId: obj.groupId as string } : {}),\n ...(obj.retryAfterSeconds !== undefined\n ? { retryAfterSeconds: obj.retryAfterSeconds as number }\n : {}),\n ...(obj.retryMultiplier !== undefined\n ? { retryMultiplier: obj.retryMultiplier as number }\n : {}),\n ...(obj.error !== undefined ? { error: obj.error as string } : {}),\n ...(obj.failedAt !== undefined ? { failedAt: obj.failedAt as number } : {}),\n ...(obj.priority !== undefined ? { priority: obj.priority as string | number } : {}),\n },\n }\n}\n\n/**\n * 編碼單筆 log 項目為 CBOR 格式\n */\nfunction encodeLogEntry(log: {\n level: string\n message: string\n workerId: string\n queue?: string\n timestamp: Date\n}): Uint8Array {\n const entry: Record<string, unknown> = {\n level: log.level,\n message: log.message,\n workerId: log.workerId,\n timestamp: log.timestamp.getTime(),\n }\n if (log.queue !== undefined) {\n entry.queue = log.queue\n }\n return cborEncodeValue(entry) as Uint8Array\n}\n\n/**\n * 解碼 CBOR bytes 為 log 項目\n */\nfunction decodeLogEntry(bytes: Uint8Array): {\n level: string\n message: string\n workerId: string\n queue?: string\n timestamp: Date\n} {\n const { buf, offset } = ensureBuffer(bytes)\n const state: DecoderState = {\n bytes,\n view: new DataView(buf, offset, bytes.byteLength),\n pos: 0,\n }\n const obj = cborDecodeValue(state) as Record<string, unknown>\n\n return {\n level: obj.level as string,\n message: obj.message as string,\n workerId: obj.workerId as string,\n timestamp: new Date(obj.timestamp as number),\n ...(obj.queue !== undefined ? { queue: obj.queue as string } : {}),\n }\n}\n\n// ──────────────────────────────────────────────────────────────────────────────\n// 長度前綴序列化:每個記錄前附加 4 byte(大端序)長度,方便批次解碼\n// ──────────────────────────────────────────────────────────────────────────────\n\n/**\n * 將 Uint8Array 封裝為「長度前綴 frame」\n * [4 bytes length][N bytes payload]\n */\nfunction framePack(payload: Uint8Array): Uint8Array {\n const frame = new Uint8Array(4 + payload.length)\n const view = new DataView(frame.buffer)\n view.setUint32(0, payload.length, false)\n frame.set(payload, 4)\n return frame\n}\n\n/**\n * 將一段含多個長度前綴 frame 的 Uint8Array 拆解為各個 payload\n *\n * 使用逐 byte 讀取而非 DataView 建立,避免 Bun ArrayBufferSink.end()\n * 回傳的 Uint8Array 可能沒有標準 .buffer 屬性的問題。\n */\nfunction frameUnpackAll(data: Uint8Array): Uint8Array[] {\n const results: Uint8Array[] = []\n let pos = 0\n\n while (pos < data.length) {\n if (pos + 4 > data.length) {\n break\n }\n\n // 手動讀取 4 bytes 大端序長度(避免 DataView 相容性問題)\n const len = (data[pos] << 24) | (data[pos + 1] << 16) | (data[pos + 2] << 8) | data[pos + 3]\n pos += 4\n\n // 防衛:確保長度合理(正整數且不超出邊界)\n if (len < 0 || pos + len > data.length) {\n break\n }\n\n // 複製 payload bytes(確保獨立的 Uint8Array)\n const payload = new Uint8Array(len)\n for (let i = 0; i < len; i++) {\n payload[i] = data[pos + i]\n }\n results.push(payload)\n pos += len\n }\n\n return results\n}\n\n// ──────────────────────────────────────────────────────────────────────────────\n// 型別定義\n// ──────────────────────────────────────────────────────────────────────────────\n\n/**\n * BunBufferedPersistence 設定選項\n */\nexport interface BunBufferedPersistenceOptions {\n /**\n * 觸發自動 flush 的緩衝筆數上限(預設 50)\n */\n maxBufferSize?: number\n\n /**\n * 定時 flush 的間隔(毫秒,預設 5000)\n */\n flushInterval?: number\n\n /**\n * ArrayBufferSink 的初始容量(bytes,預設 65536)\n */\n sinkCapacity?: number\n}\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Bun.ArrayBufferSink 型別宣告(bun-types 未必完整匯出,手動補齊)\n// ──────────────────────────────────────────────────────────────────────────────\n\ninterface BunArrayBufferSink {\n start(options?: { highWaterMark?: number; stream?: boolean; asUint8Array?: boolean }): void\n write(chunk: string | ArrayBufferView | ArrayBuffer): number\n /** flush() 在非 stream 模式下只回傳已寫入 byte 數(number),不回傳資料 */\n flush(): number\n /** end() 關閉 sink 並回傳所有緩衝資料,之後可再次呼叫 start() 重用 */\n end(): Uint8Array | ArrayBuffer\n}\n\n/**\n * 偵測目前是否在 Bun 環境執行\n */\nfunction isBunRuntime(): boolean {\n return (\n typeof globalThis !== 'undefined' &&\n typeof (globalThis as Record<string, unknown>).Bun !== 'undefined'\n )\n}\n\n// ──────────────────────────────────────────────────────────────────────────────\n// BunBufferedPersistence\n// ──────────────────────────────────────────────────────────────────────────────\n\n/**\n * 使用 Bun ArrayBufferSink 的高效緩衝持久化裝飾器\n *\n * 在 Bun 環境下,使用 Bun 原生的 ArrayBufferSink 作為記憶體緩衝區,\n * 以 CBOR 格式直接寫入二進制資料(零字串轉換開銷),\n * 並透過背壓控制避免無限增長。\n *\n * 在非 Bun 環境(Node.js 等)則回退到簡單的陣列緩衝機制,\n * 與原始 BufferedPersistence 行為等效。\n *\n * @public\n * @example\n * ```typescript\n * const mysqlAdapter = new MySQLPersistence(db)\n * const buffered = new BunBufferedPersistence(mysqlAdapter, {\n * maxBufferSize: 100,\n * flushInterval: 1000,\n * })\n * await buffered.archive('email', job, 'completed')\n * await buffered.flush()\n * ```\n */\nexport class BunBufferedPersistence implements PersistenceAdapter {\n // ── Bun 模式(ArrayBufferSink)────────────────────────────────────────────\n private jobSink: BunArrayBufferSink | null = null\n private logSink: BunArrayBufferSink | null = null\n\n // ── 共用計數器 ──────────────────────────────────────────────────────────────\n private jobPendingCount = 0\n private logPendingCount = 0\n\n // ── 背壓控制:確保同時只有一個 flush 在執行 ─────────────────────────────────\n private flushing = false\n private flushPromise: Promise<void> | null = null\n\n // ── Node.js 回退:使用簡單陣列 ──────────────────────────────────────────────\n private jobBuffer: Array<{ queue: string; job: SerializedJob; status: string }> = []\n private logBuffer: Array<{\n level: string\n message: string\n workerId: string\n queue?: string\n timestamp: Date\n }> = []\n\n // ── 定時 flush ──────────────────────────────────────────────────────────────\n private flushTimer: ReturnType<typeof setTimeout> | null = null\n\n // ── 設定 ───────────────────────────────────────────────────────────────────\n private readonly maxBufferSize: number\n private readonly flushInterval: number\n private readonly useBun: boolean\n private readonly sinkCapacity: number\n\n constructor(\n private readonly adapter: PersistenceAdapter,\n options: BunBufferedPersistenceOptions = {}\n ) {\n this.maxBufferSize = options.maxBufferSize ?? 50\n this.flushInterval = options.flushInterval ?? 5000\n this.sinkCapacity = options.sinkCapacity ?? 65536\n this.useBun = isBunRuntime()\n\n if (this.useBun) {\n this.initSinks()\n }\n }\n\n /**\n * 初始化 Bun ArrayBufferSink(Bun 模式專用)\n * 可重複呼叫(flush 後重建 sink)\n */\n private initSinks(): void {\n const BunGlobal = (globalThis as Record<string, unknown>).Bun as {\n ArrayBufferSink: new () => BunArrayBufferSink\n }\n\n this.jobSink = new BunGlobal.ArrayBufferSink()\n this.jobSink.start({ highWaterMark: this.sinkCapacity, asUint8Array: true })\n\n this.logSink = new BunGlobal.ArrayBufferSink()\n this.logSink.start({ highWaterMark: this.sinkCapacity, asUint8Array: true })\n }\n\n /**\n * 緩衝一筆 job archive 請求\n *\n * @param queue - 隊列名稱\n * @param job - 序列化的 job 資料\n * @param status - job 最終狀態\n */\n async archive(\n queue: string,\n job: SerializedJob,\n status: 'completed' | 'failed' | 'waiting' | string\n ): Promise<void> {\n // 背壓:如果正在 flush 就等待完成\n if (this.flushing && this.flushPromise) {\n await this.flushPromise\n }\n\n if (this.useBun && this.jobSink) {\n // Bun 模式:CBOR 編碼後寫入 sink(帶長度前綴方便批次解碼)\n const encoded = encodeArchiveEntry(queue, job, status)\n const frame = framePack(encoded)\n this.jobSink.write(frame)\n } else {\n // Node.js 回退:寫入陣列\n this.jobBuffer.push({ queue, job, status })\n }\n\n this.jobPendingCount++\n\n if (this.jobPendingCount >= this.maxBufferSize) {\n // 達到上限,立即 flush(catch 錯誤避免 unhandled rejection)\n this.flush().catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : String(err)\n process.stderr.write(`[BunBufferedPersistence] Auto-flush 失敗 (jobs): ${msg}\\n`)\n })\n } else {\n this.ensureFlushTimer()\n }\n }\n\n /**\n * 緩衝一筆 log archive 請求\n */\n async archiveLog(log: {\n level: string\n message: string\n workerId: string\n queue?: string\n timestamp: Date\n }): Promise<void> {\n if (this.flushing && this.flushPromise) {\n await this.flushPromise\n }\n\n if (this.useBun && this.logSink) {\n const encoded = encodeLogEntry(log)\n const frame = framePack(encoded)\n this.logSink.write(frame)\n } else {\n this.logBuffer.push(log)\n }\n\n this.logPendingCount++\n\n if (this.logPendingCount >= this.maxBufferSize) {\n this.flush().catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : String(err)\n process.stderr.write(`[BunBufferedPersistence] Auto-flush 失敗 (logs): ${msg}\\n`)\n })\n } else {\n this.ensureFlushTimer()\n }\n }\n\n /**\n * 批次 archive 多個 job(直接委派,不走緩衝)\n */\n async archiveMany(\n jobs: Array<{\n queue: string\n job: SerializedJob\n status: 'completed' | 'failed' | 'waiting' | string\n }>\n ): Promise<void> {\n if (this.adapter.archiveMany) {\n return this.adapter.archiveMany(jobs)\n }\n for (const item of jobs) {\n await this.adapter.archive(item.queue, item.job, item.status)\n }\n }\n\n /**\n * 批次 archive 多個 log(直接委派,不走緩衝)\n */\n async archiveLogMany(\n logs: Array<{\n level: string\n message: string\n workerId: string\n queue?: string\n timestamp: Date\n }>\n ): Promise<void> {\n if (this.adapter.archiveLogMany) {\n return this.adapter.archiveLogMany(logs)\n }\n for (const log of logs) {\n await this.adapter.archiveLog(log)\n }\n }\n\n /**\n * 將緩衝區的所有資料批次寫入底層 adapter\n *\n * 具備互斥鎖語意:同時只有一個 flush 在執行。\n * 背壓控制:archive() 和 archiveLog() 在 flush 進行中時會等待。\n */\n async flush(): Promise<void> {\n // 雙重檢查:若已在 flush 中,等待完成即可\n if (this.flushing) {\n return this.flushPromise ?? Promise.resolve()\n }\n\n this.flushing = true\n this.flushPromise = this._doFlush().finally(() => {\n this.flushing = false\n this.flushPromise = null\n })\n\n return this.flushPromise\n }\n\n /**\n * 實際執行 flush 的內部方法\n */\n private async _doFlush(): Promise<void> {\n // 清除定時器\n if (this.flushTimer) {\n clearTimeout(this.flushTimer)\n this.flushTimer = null\n }\n\n const jobCount = this.jobPendingCount\n const logCount = this.logPendingCount\n\n // 重置計數器(先重置,讓後續 archive 可以繼續寫入)\n this.jobPendingCount = 0\n this.logPendingCount = 0\n\n const promises: Promise<void>[] = []\n\n // ── Bun 模式:用 end() 取出所有資料,然後重建 sink ──────────────────────────\n // 說明:Bun.ArrayBufferSink.flush() 在非 stream 模式只回傳 byte 數(number),\n // 必須使用 end() 才能取得實際二進制資料。end() 後可再次 start() 重用。\n let rawJobs: Uint8Array | null = null\n let rawLogs: Uint8Array | null = null\n\n if (this.useBun) {\n if (jobCount > 0 && this.jobSink) {\n rawJobs = this.jobSink.end() as Uint8Array\n }\n if (logCount > 0 && this.logSink) {\n rawLogs = this.logSink.end() as Uint8Array\n }\n // 重建 sink,讓 flush 後的 archive 可以繼續寫入\n this.initSinks()\n }\n\n // ── 處理 job 緩衝 ─────────────────────────────────────────────────────────\n if (jobCount > 0) {\n let jobs: Array<{ queue: string; job: SerializedJob; status: string }>\n\n if (this.useBun && rawJobs) {\n // Bun 模式:從 sink end() 取出二進制資料後解碼\n const frames = frameUnpackAll(rawJobs)\n jobs = frames.map((frame) => decodeArchiveEntry(frame))\n } else {\n // Node.js 回退:取出陣列並清空\n jobs = this.jobBuffer\n this.jobBuffer = []\n }\n\n if (jobs.length > 0) {\n if (this.adapter.archiveMany) {\n promises.push(this.adapter.archiveMany(jobs))\n } else {\n promises.push(\n (async () => {\n for (const item of jobs) {\n await this.adapter.archive(item.queue, item.job, item.status)\n }\n })()\n )\n }\n }\n }\n\n // ── 處理 log 緩衝 ─────────────────────────────────────────────────────────\n if (logCount > 0) {\n let logs: Array<{\n level: string\n message: string\n workerId: string\n queue?: string\n timestamp: Date\n }>\n\n if (this.useBun && rawLogs) {\n const frames = frameUnpackAll(rawLogs)\n logs = frames.map((frame) => decodeLogEntry(frame))\n } else {\n logs = this.logBuffer\n this.logBuffer = []\n }\n\n if (logs.length > 0) {\n if (this.adapter.archiveLogMany) {\n promises.push(this.adapter.archiveLogMany(logs))\n } else {\n promises.push(\n (async () => {\n for (const log of logs) {\n await this.adapter.archiveLog(log)\n }\n })()\n )\n }\n }\n }\n\n await Promise.all(promises)\n }\n\n // ── 讀取操作:直接委派底層 adapter ──────────────────────────────────────────\n\n async find(queue: string, id: string): Promise<SerializedJob | null> {\n return this.adapter.find(queue, id)\n }\n\n async list(\n queue: string,\n options?: {\n limit?: number\n offset?: number\n status?: 'completed' | 'failed' | 'waiting' | string\n jobId?: string\n startTime?: Date\n endTime?: Date\n }\n ): Promise<SerializedJob[]> {\n return this.adapter.list(queue, options)\n }\n\n async count(\n queue: string,\n options?: {\n status?: 'completed' | 'failed' | 'waiting' | string\n jobId?: string\n startTime?: Date\n endTime?: Date\n }\n ): Promise<number> {\n return this.adapter.count(queue, options)\n }\n\n async cleanup(days: number): Promise<number> {\n return this.adapter.cleanup(days)\n }\n\n async listLogs(options?: {\n limit?: number\n offset?: number\n level?: string\n workerId?: string\n queue?: string\n search?: string\n startTime?: Date\n endTime?: Date\n }): Promise<unknown[]> {\n return this.adapter.listLogs(options)\n }\n\n async countLogs(options?: {\n level?: string\n workerId?: string\n queue?: string\n search?: string\n startTime?: Date\n endTime?: Date\n }): Promise<number> {\n return this.adapter.countLogs(options)\n }\n\n // ── 內部工具 ──────────────────────────────────────────────────────────────\n\n /**\n * 確保定時 flush 計時器正在執行\n */\n private ensureFlushTimer(): void {\n if (this.flushTimer) {\n return\n }\n\n this.flushTimer = setTimeout(() => {\n this.flush().catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : String(err)\n process.stderr.write(`[BunBufferedPersistence] 定時 flush 失敗: ${msg}\\n`)\n })\n }, this.flushInterval)\n }\n\n /**\n * 取得目前緩衝中的 job 筆數(供測試與監控使用)\n */\n get pendingJobCount(): number {\n return this.jobPendingCount\n }\n\n /**\n * 取得目前緩衝中的 log 筆數(供測試與監控使用)\n */\n get pendingLogCount(): number {\n return this.logPendingCount\n }\n\n /**\n * 目前是否正在執行 flush\n */\n get isFlushing(): boolean {\n return this.flushing\n }\n}\n\n// ──────────────────────────────────────────────────────────────────────────────\n// 工廠函數:自動選擇最佳實作\n// ──────────────────────────────────────────────────────────────────────────────\n\n/**\n * 建立最佳的 BufferedPersistence 實例\n *\n * 在 Bun 環境自動使用 BunBufferedPersistence(ArrayBufferSink 加速),\n * 在 Node.js 環境回退到一般陣列緩衝行為。\n *\n * 兩者皆實作相同的 `PersistenceAdapter` 介面,可互換使用。\n *\n * @example\n * ```typescript\n * const adapter = createBufferedPersistence(mysqlAdapter, { maxBufferSize: 100 })\n * ```\n */\nexport function createBufferedPersistence(\n adapter: PersistenceAdapter,\n options?: BunBufferedPersistenceOptions\n): BunBufferedPersistence {\n return new BunBufferedPersistence(adapter, options)\n}\n",
58
+ "import type { ConnectionContract } from '@gravito/atlas'\nimport { DB, Schema } from '@gravito/atlas'\nimport type { JobRow, PersistenceAdapter, SerializedJob } from '../types'\n\n/**\n * MySQL Persistence Adapter.\n *\n * Implements the `PersistenceAdapter` interface for MySQL databases.\n * Stores job history and logs in relational tables for long-term retention and auditing.\n *\n * @public\n * @example\n * ```typescript\n * const persistence = new MySQLPersistence(dbConnection);\n * ```\n */\nexport class MySQLPersistence implements PersistenceAdapter {\n /**\n * @param db - An Atlas DB instance or compatible QueryBuilder.\n * @param table - The name of the table to store archived jobs.\n * @param logsTable - The name of the table to store system logs.\n * @param options - Buffering options (Deprecated: Use BufferedPersistence wrapper instead).\n */\n constructor(\n private db: ConnectionContract,\n private table = 'flux_job_archive',\n private logsTable = 'flux_system_logs',\n _options: { maxBufferSize?: number; flushInterval?: number } = {}\n ) {}\n\n /**\n * Archives a single job.\n */\n async archive(\n queue: string,\n job: SerializedJob,\n status: 'completed' | 'failed' | 'waiting' | string\n ): Promise<void> {\n await this.archiveMany([{ queue, job, status }])\n }\n\n /**\n * Archives multiple jobs in a batch.\n */\n async archiveMany(\n jobs: Array<{\n queue: string\n job: SerializedJob\n status: 'completed' | 'failed' | 'waiting' | string\n }>\n ): Promise<void> {\n if (jobs.length === 0) {\n return\n }\n\n const batchSize = 500\n for (let i = 0; i < jobs.length; i += batchSize) {\n const chunk = jobs.slice(i, i + batchSize)\n try {\n const records = chunk.map((item) => ({\n job_id: item.job.id,\n queue: item.queue,\n status: item.status,\n payload: JSON.stringify(item.job),\n error: item.job.error || null,\n created_at: new Date(item.job.createdAt),\n archived_at: new Date(),\n }))\n\n await this.db.table(this.table).insert(records)\n } catch (err: unknown) {\n console.error(`[MySQLPersistence] Failed to archive ${chunk.length} jobs:`, err)\n }\n }\n }\n\n /**\n * No-op. Use BufferedPersistence if flushing is needed.\n */\n async flush(): Promise<void> {\n // No-op: Buffering removed. Use BufferedPersistence if buffering is needed.\n }\n\n /**\n * Finds an archived job by ID.\n */\n async find(queue: string, id: string): Promise<SerializedJob | null> {\n const row = await this.db.table(this.table).where('queue', queue).where('job_id', id).first()\n\n if (!row) {\n return null\n }\n\n try {\n const job = typeof row.payload === 'string' ? JSON.parse(row.payload) : row.payload\n return job\n } catch (_e) {\n return null\n }\n }\n\n /**\n * List jobs from the archive.\n */\n async list(\n queue: string,\n options: {\n limit?: number\n offset?: number\n status?: 'completed' | 'failed' | 'waiting' | string\n jobId?: string\n startTime?: Date\n endTime?: Date\n } = {}\n ): Promise<SerializedJob[]> {\n let query = this.db.table(this.table).where('queue', queue)\n\n if (options.status) {\n query = query.where('status', options.status)\n }\n\n if (options.jobId) {\n query = query.where('job_id', options.jobId)\n }\n\n if (options.startTime) {\n query = query.where('archived_at', '>=', options.startTime)\n }\n\n if (options.endTime) {\n query = query.where('archived_at', '<=', options.endTime)\n }\n\n const rows = await query\n .orderBy('archived_at', 'desc')\n .limit(options.limit ?? 50)\n .offset(options.offset ?? 0)\n .get()\n\n return (rows as unknown as JobRow[])\n .map((r) => {\n try {\n const job = typeof r.payload === 'string' ? JSON.parse(r.payload) : r.payload\n return { ...job, _status: r.status, _archivedAt: r.archived_at }\n } catch (_e) {\n return null\n }\n })\n .filter(\n (item): item is SerializedJob & { _status: string; _archivedAt: Date | string } => !!item\n )\n }\n\n /**\n * Search jobs from the archive.\n *\n * @param query - Search string (matches ID, payload, or error).\n * @param options - Filter options.\n */\n async search(\n query: string,\n options: { limit?: number; offset?: number; queue?: string } = {}\n ): Promise<SerializedJob[]> {\n let q = this.db.table(this.table)\n\n if (options.queue) {\n q = q.where('queue', options.queue)\n }\n\n const rows = await q\n .where((sub: any) => {\n sub\n .where('job_id', 'like', `%${query}%`)\n .orWhere('payload', 'like', `%${query}%`)\n .orWhere('error', 'like', `%${query}%`)\n })\n .orderBy('archived_at', 'desc')\n .limit(options.limit ?? 50)\n .offset(options.offset ?? 0)\n .get()\n\n return (rows as unknown as JobRow[])\n .map((r) => {\n try {\n const job = typeof r.payload === 'string' ? JSON.parse(r.payload) : r.payload\n return { ...job, _status: r.status, _archivedAt: r.archived_at }\n } catch (_e) {\n return null\n }\n })\n .filter(\n (item): item is SerializedJob & { _status: string; _archivedAt: Date | string } => !!item\n )\n }\n\n /**\n * Archive a system log message.\n */\n async archiveLog(log: {\n level: string\n message: string\n workerId: string\n queue?: string\n timestamp: Date\n }): Promise<void> {\n await this.archiveLogMany([log])\n }\n\n /**\n * Archive multiple log messages.\n */\n async archiveLogMany(\n logs: Array<{\n level: string\n message: string\n workerId: string\n queue?: string\n timestamp: Date\n }>\n ): Promise<void> {\n if (logs.length === 0) {\n return\n }\n\n try {\n const records = logs.map((log) => ({\n level: log.level,\n message: log.message,\n worker_id: log.workerId,\n queue: log.queue || null,\n timestamp: log.timestamp,\n }))\n\n await this.db.table(this.logsTable).insert(records)\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err))\n console.error(`[MySQLPersistence] Failed to archive ${logs.length} logs:`, error.message)\n }\n }\n\n /**\n * List system logs from the archive.\n */\n async listLogs(\n options: {\n limit?: number\n offset?: number\n level?: string\n workerId?: string\n queue?: string\n search?: string\n startTime?: Date\n endTime?: Date\n } = {}\n ): Promise<any[]> {\n let query = this.db.table(this.logsTable)\n\n if (options.level) {\n query = query.where('level', options.level)\n }\n if (options.workerId) {\n query = query.where('worker_id', options.workerId)\n }\n if (options.queue) {\n query = query.where('queue', options.queue)\n }\n if (options.search) {\n query = query.where('message', 'like', `%${options.search}%`)\n }\n\n if (options.startTime) {\n query = query.where('timestamp', '>=', options.startTime)\n }\n\n if (options.endTime) {\n query = query.where('timestamp', '<=', options.endTime)\n }\n\n return await query\n .orderBy('timestamp', 'desc')\n .limit(options.limit ?? 50)\n .offset(options.offset ?? 0)\n .get()\n }\n\n /**\n * Count system logs in the archive.\n */\n async countLogs(\n options: {\n level?: string\n workerId?: string\n queue?: string\n search?: string\n startTime?: Date\n endTime?: Date\n } = {}\n ): Promise<number> {\n let query = this.db.table(this.logsTable)\n\n if (options.level) {\n query = query.where('level', options.level)\n }\n if (options.workerId) {\n query = query.where('worker_id', options.workerId)\n }\n if (options.queue) {\n query = query.where('queue', options.queue)\n }\n if (options.search) {\n query = query.where('message', 'like', `%${options.search}%`)\n }\n\n if (options.startTime) {\n query = query.where('timestamp', '>=', options.startTime)\n }\n\n if (options.endTime) {\n query = query.where('timestamp', '<=', options.endTime)\n }\n\n const result = await query.count()\n return Number(result) || 0\n }\n\n /**\n * Remove old records from the archive.\n */\n async cleanup(days: number): Promise<number> {\n const threshold = new Date()\n threshold.setDate(threshold.getDate() - days)\n\n const [jobsDeleted, logsDeleted] = await Promise.all([\n this.db.table(this.table).where('archived_at', '<', threshold).delete(),\n this.db.table(this.logsTable).where('timestamp', '<', threshold).delete(),\n ])\n\n return (Number(jobsDeleted) || 0) + (Number(logsDeleted) || 0)\n }\n\n /**\n * Count jobs in the archive.\n */\n async count(\n queue: string,\n options: {\n status?: 'completed' | 'failed' | 'waiting' | string\n jobId?: string\n startTime?: Date\n endTime?: Date\n } = {}\n ): Promise<number> {\n let query = this.db.table(this.table).where('queue', queue)\n\n if (options.status) {\n query = query.where('status', options.status)\n }\n\n if (options.jobId) {\n query = query.where('job_id', options.jobId)\n }\n\n if (options.startTime) {\n query = query.where('archived_at', '>=', options.startTime)\n }\n\n if (options.endTime) {\n query = query.where('archived_at', '<=', options.endTime)\n }\n\n const result = await query.count()\n return Number(result) || 0\n }\n\n /**\n * Helper to create necessary tables if they don't exist.\n */\n async setupTable(): Promise<void> {\n await Promise.all([this.setupJobsTable(), this.setupLogsTable()])\n }\n\n private async setupJobsTable(): Promise<void> {\n const exists = await Schema.hasTable(this.table)\n if (exists) {\n return\n }\n\n await Schema.create(this.table, (table) => {\n table.id()\n table.string('job_id', 64)\n table.string('queue', 128)\n table.string('status', 20)\n table.json('payload')\n table.text('error').nullable()\n table.timestamp('created_at').nullable()\n table.timestamp('archived_at').default(DB.raw('CURRENT_TIMESTAMP'))\n\n table.index(['queue', 'archived_at'])\n table.index(['queue', 'job_id'])\n table.index(['status', 'archived_at'])\n table.index(['archived_at'])\n })\n console.log(`[MySQLPersistence] Created jobs archive table: ${this.table}`)\n }\n\n private async setupLogsTable(): Promise<void> {\n const exists = await Schema.hasTable(this.logsTable)\n if (exists) {\n return\n }\n\n await Schema.create(this.logsTable, (table) => {\n table.id()\n table.string('level', 20)\n table.text('message')\n table.string('worker_id', 128)\n table.string('queue', 128).nullable()\n table.timestamp('timestamp').default(DB.raw('CURRENT_TIMESTAMP'))\n\n table.index(['worker_id'])\n table.index(['queue'])\n table.index(['level'])\n table.index(['timestamp'])\n })\n console.log(`[MySQLPersistence] Created logs archive table: ${this.logsTable}`)\n }\n}\n",
59
+ "import type { ConnectionContract } from '@gravito/atlas'\nimport { Schema } from '@gravito/atlas'\nimport type { JobRow, PersistenceAdapter, SerializedJob } from '../types'\n\n/**\n * SQLite Persistence Adapter.\n *\n * Archives jobs into a local SQLite database for zero-config persistence.\n * Uses transactions to optimize write performance for batches.\n *\n * @public\n * @example\n * ```typescript\n * const persistence = new SQLitePersistence(db);\n * ```\n */\nexport class SQLitePersistence implements PersistenceAdapter {\n /**\n * @param db - An Atlas DB instance (SQLite driver).\n * @param table - The name of the table to store archived jobs.\n * @param logsTable - The name of the table to store system logs.\n * @param options - Buffering options (Deprecated: Use BufferedPersistence wrapper instead).\n */\n constructor(\n private db: ConnectionContract,\n private table = 'flux_job_archive',\n private logsTable = 'flux_system_logs',\n _options: { maxBufferSize?: number; flushInterval?: number } = {}\n ) {}\n\n /**\n * Archives a single job.\n */\n async archive(\n queue: string,\n job: SerializedJob,\n status: 'completed' | 'failed' | 'waiting' | string\n ): Promise<void> {\n await this.archiveMany([{ queue, job, status }])\n }\n\n /**\n * Archives multiple jobs in a batch.\n *\n * Optimized for SQLite by wrapping chunks in transactions.\n */\n async archiveMany(\n jobs: Array<{\n queue: string\n job: SerializedJob\n status: 'completed' | 'failed' | 'waiting' | string\n }>\n ): Promise<void> {\n if (jobs.length === 0) {\n return\n }\n\n const batchSize = 200\n for (let i = 0; i < jobs.length; i += batchSize) {\n const chunk = jobs.slice(i, i + batchSize)\n try {\n const records = chunk.map((item) => ({\n job_id: item.job.id,\n queue: item.queue,\n status: item.status,\n payload: JSON.stringify(item.job),\n error: item.job.error || null,\n created_at: new Date(item.job.createdAt),\n archived_at: new Date(),\n }))\n\n // For SQLite, wrapping in a transaction significantly improves performance\n if (typeof (this.db as any).transaction === 'function') {\n await (this.db as any).transaction(async (trx: any) => {\n await trx.table(this.table).insert(records)\n })\n } else {\n await this.db.table(this.table).insert(records)\n }\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err))\n console.error(`[SQLitePersistence] Failed to archive ${chunk.length} jobs:`, error.message)\n }\n }\n }\n\n /**\n * No-op. Use BufferedPersistence if flushing is needed.\n */\n async flush(): Promise<void> {\n // No-op: Buffering removed. Use BufferedPersistence if buffering is needed.\n }\n\n /**\n * Finds an archived job by ID.\n */\n async find(queue: string, id: string): Promise<SerializedJob | null> {\n const row = await this.db.table(this.table).where('queue', queue).where('job_id', id).first()\n\n if (!row) {\n return null\n }\n\n try {\n const job = typeof row.payload === 'string' ? JSON.parse(row.payload) : row.payload\n return job\n } catch (_e) {\n return null\n }\n }\n\n /**\n * List jobs from the archive.\n */\n async list(\n queue: string,\n options: {\n limit?: number\n offset?: number\n status?: 'completed' | 'failed' | 'waiting' | string | string[]\n jobId?: string\n startTime?: Date\n endTime?: Date\n } = {}\n ): Promise<SerializedJob[]> {\n let query = this.db.table(this.table).where('queue', queue)\n\n if (options.status) {\n if (Array.isArray(options.status)) {\n query = query.whereIn('status', options.status)\n } else {\n query = query.where('status', options.status)\n }\n }\n\n if (options.jobId) {\n query = query.where('job_id', options.jobId)\n }\n\n if (options.startTime) {\n query = query.where('archived_at', '>=', options.startTime)\n }\n\n if (options.endTime) {\n query = query.where('archived_at', '<=', options.endTime)\n }\n\n const rows = await query\n .orderBy('archived_at', 'desc')\n .limit(options.limit ?? 50)\n .offset(options.offset ?? 0)\n .get()\n\n return (rows as unknown as JobRow[])\n .map((r) => {\n try {\n const job = typeof r.payload === 'string' ? JSON.parse(r.payload) : r.payload\n return { ...job, _status: r.status, _archivedAt: r.archived_at }\n } catch (_e) {\n return null\n }\n })\n .filter(\n (item): item is SerializedJob & { _status: string; _archivedAt: Date | string } => !!item\n )\n }\n\n /**\n * Search jobs from the archive.\n */\n async search(\n query: string,\n options: { limit?: number; offset?: number; queue?: string } = {}\n ): Promise<SerializedJob[]> {\n let q = this.db.table(this.table)\n\n if (options.queue) {\n q = q.where('queue', options.queue)\n }\n\n const rows = await q\n .where((sub: any) => {\n sub\n .where('job_id', 'like', `%${query}%`)\n .orWhere('payload', 'like', `%${query}%`)\n .orWhere('error', 'like', `%${query}%`)\n })\n .orderBy('archived_at', 'desc')\n .limit(options.limit ?? 50)\n .offset(options.offset ?? 0)\n .get()\n\n return (rows as unknown as JobRow[])\n .map((r) => {\n try {\n const job = typeof r.payload === 'string' ? JSON.parse(r.payload) : r.payload\n return { ...job, _status: r.status, _archivedAt: r.archived_at }\n } catch (_e) {\n return null\n }\n })\n .filter(\n (item): item is SerializedJob & { _status: string; _archivedAt: Date | string } => !!item\n )\n }\n\n /**\n * Archive a system log message (buffered).\n */\n async archiveLog(log: {\n level: string\n message: string\n workerId: string\n queue?: string\n timestamp: Date\n }): Promise<void> {\n await this.archiveLogMany([log])\n }\n\n /**\n * Archive multiple log messages (direct batch write).\n */\n async archiveLogMany(\n logs: Array<{\n level: string\n message: string\n workerId: string\n queue?: string\n timestamp: Date\n }>\n ): Promise<void> {\n if (logs.length === 0) {\n return\n }\n\n try {\n const records = logs.map((log) => ({\n level: log.level,\n message: log.message,\n worker_id: log.workerId,\n queue: log.queue || null,\n timestamp: log.timestamp,\n }))\n\n await this.db.table(this.logsTable).insert(records)\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err))\n console.error(`[SQLitePersistence] Failed to archive ${logs.length} logs:`, error.message)\n }\n }\n\n /**\n * List system logs from the archive.\n */\n async listLogs(\n options: {\n limit?: number\n offset?: number\n level?: string\n workerId?: string\n queue?: string\n search?: string\n startTime?: Date\n endTime?: Date\n } = {}\n ): Promise<any[]> {\n let query = this.db.table(this.logsTable)\n\n if (options.level) {\n query = query.where('level', options.level)\n }\n if (options.workerId) {\n query = query.where('worker_id', options.workerId)\n }\n if (options.queue) {\n query = query.where('queue', options.queue)\n }\n if (options.search) {\n query = query.where('message', 'like', `%${options.search}%`)\n }\n\n if (options.startTime) {\n query = query.where('timestamp', '>=', options.startTime)\n }\n\n if (options.endTime) {\n query = query.where('timestamp', '<=', options.endTime)\n }\n\n return await query\n .orderBy('timestamp', 'desc')\n .limit(options.limit ?? 50)\n .offset(options.offset ?? 0)\n .get()\n }\n\n /**\n * Count system logs in the archive.\n */\n async countLogs(\n options: {\n level?: string\n workerId?: string\n queue?: string\n search?: string\n startTime?: Date\n endTime?: Date\n } = {}\n ): Promise<number> {\n let query = this.db.table(this.logsTable)\n\n if (options.level) {\n query = query.where('level', options.level)\n }\n if (options.workerId) {\n query = query.where('worker_id', options.workerId)\n }\n if (options.queue) {\n query = query.where('queue', options.queue)\n }\n if (options.search) {\n query = query.where('message', 'like', `%${options.search}%`)\n }\n\n if (options.startTime) {\n query = query.where('timestamp', '>=', options.startTime)\n }\n\n if (options.endTime) {\n query = query.where('timestamp', '<=', options.endTime)\n }\n\n const result = await query.count()\n return Number(result) || 0\n }\n\n /**\n * Remove old records from the archive.\n */\n async cleanup(days: number): Promise<number> {\n const threshold = new Date()\n threshold.setDate(threshold.getDate() - days)\n\n const [jobsDeleted, logsDeleted] = await Promise.all([\n this.db.table(this.table).where('archived_at', '<', threshold).delete(),\n this.db.table(this.logsTable).where('timestamp', '<', threshold).delete(),\n ])\n\n return (Number(jobsDeleted) || 0) + (Number(logsDeleted) || 0)\n }\n\n /**\n * Count jobs in the archive.\n */\n async count(\n queue: string,\n options: {\n status?: 'completed' | 'failed' | 'waiting' | string | string[]\n jobId?: string\n startTime?: Date\n endTime?: Date\n } = {}\n ): Promise<number> {\n let query = this.db.table(this.table).where('queue', queue)\n\n if (options.status) {\n if (Array.isArray(options.status)) {\n query = query.whereIn('status', options.status)\n } else {\n query = query.where('status', options.status)\n }\n }\n\n if (options.jobId) {\n query = query.where('job_id', options.jobId)\n }\n\n if (options.startTime) {\n query = query.where('archived_at', '>=', options.startTime)\n }\n\n if (options.endTime) {\n query = query.where('archived_at', '<=', options.endTime)\n }\n\n const result = await query.count()\n return Number(result) || 0\n }\n\n /**\n * Setup table for SQLite.\n */\n async setupTable(): Promise<void> {\n await Promise.all([this.setupJobsTable(), this.setupLogsTable()])\n }\n\n private async setupJobsTable(): Promise<void> {\n const exists = await Schema.hasTable(this.table)\n if (exists) {\n return\n }\n\n await Schema.create(this.table, (table) => {\n table.id()\n table.string('job_id', 64)\n table.string('queue', 128)\n table.string('status', 20)\n table.text('payload')\n table.text('error').nullable()\n table.timestamp('created_at').nullable()\n table.timestamp('archived_at').nullable()\n\n table.index(['queue', 'archived_at'])\n table.index(['archived_at'])\n })\n console.log(`[SQLitePersistence] Created jobs archive table: ${this.table}`)\n }\n\n private async setupLogsTable(): Promise<void> {\n const exists = await Schema.hasTable(this.logsTable)\n if (exists) {\n return\n }\n\n await Schema.create(this.logsTable, (table) => {\n table.id()\n table.string('level', 20)\n table.text('message')\n table.string('worker_id', 128)\n table.string('queue', 128).nullable()\n table.timestamp('timestamp')\n\n table.index(['worker_id'])\n table.index(['queue'])\n table.index(['level'])\n table.index(['timestamp'])\n })\n console.log(`[SQLitePersistence] Created logs archive table: ${this.logsTable}`)\n }\n}\n",
60
+ "import type { CborAccelerator, NativeAcceleratorStatus } from '@gravito/core/ffi'\nimport { NativeAccelerator } from '@gravito/core/ffi'\nimport type { Job } from '../Job'\nimport type { SerializedJob } from '../types'\nimport type { JobSerializer } from './JobSerializer'\n\n/**\n * 原生 CBOR 序列化器\n *\n * 使用 @gravito/core 的 NativeAccelerator 進行 CBOR 編碼/解碼,\n * 自動選擇最佳的加速器實現(Native FFI 或 JavaScript Fallback)。\n *\n * 與現有 BinarySerializer 完全相容(type 為 'binary'),\n * 可作為直接替代品使用。\n *\n * @public\n * @example\n * ```typescript\n * const serializer = new CborNativeSerializer()\n * const serialized = serializer.serialize(job)\n * const deserialized = serializer.deserialize(serialized)\n * ```\n */\nexport class CborNativeSerializer implements JobSerializer {\n private readonly accelerator: CborAccelerator\n\n constructor() {\n this.accelerator = NativeAccelerator.getCborAccelerator()\n }\n\n /**\n * 取得當前使用的 CBOR 後端資訊\n * 可用於診斷和監控\n */\n static getBackendInfo(): NativeAcceleratorStatus {\n return NativeAccelerator.getStatus()\n }\n\n /**\n * 將 Job 序列化為 CBOR 二進制格式\n *\n * @param job - 要序列化的 Job 實例\n * @returns SerializedJob,data 為 Uint8Array\n */\n serialize(job: Job): SerializedJob {\n const id = job.id || `${Date.now()}-${crypto.randomUUID()}`\n\n // 萃取屬性(排除 function 和 undefined)\n const properties: Record<string, unknown> = {}\n for (const key in job) {\n if (Object.hasOwn(job, key)) {\n const value = (job as unknown as Record<string, unknown>)[key]\n if (typeof value !== 'function' && value !== undefined) {\n properties[key] = value\n }\n }\n }\n\n // 使用 NativeAccelerator 的 CBOR 編碼\n const encoded = this.accelerator.encode(properties)\n\n return {\n id,\n type: 'binary',\n data: encoded,\n createdAt: Date.now(),\n ...(job.delaySeconds !== undefined ? { delaySeconds: job.delaySeconds } : {}),\n attempts: job.attempts ?? 0,\n ...(job.maxAttempts !== undefined ? { maxAttempts: job.maxAttempts } : {}),\n ...(job.groupId ? { groupId: job.groupId } : {}),\n ...(job.priority !== undefined && job.priority !== '' ? { priority: job.priority } : {}),\n ...(job.retryAfterSeconds !== undefined ? { retryAfterSeconds: job.retryAfterSeconds } : {}),\n ...(job.retryMultiplier !== undefined ? { retryMultiplier: job.retryMultiplier } : {}),\n }\n }\n\n /**\n * 反序列化 CBOR 二進制資料為 Job\n *\n * 支援三種資料格式:\n * - Uint8Array(原生 CBOR 二進制)\n * - Base64 string(來自 Redis / 網路傳輸)\n * - ArrayBuffer(來自 Worker Transferable)\n *\n * @param serialized - 序列化的 Job 資料\n * @returns 還原的 Job 實例\n */\n deserialize(serialized: SerializedJob): Job {\n if (serialized.type !== 'binary') {\n throw new TypeError(`Expected binary type, got ${serialized.type}`)\n }\n\n const bytes = this.resolveBytes(serialized.data)\n\n // 使用 NativeAccelerator 的 CBOR 解碼\n let properties: Record<string, unknown>\n try {\n properties = this.accelerator.decode(bytes)\n } catch (err) {\n throw new Error(\n `Failed to decode CBOR data: ${err instanceof Error ? err.message : String(err)}`\n )\n }\n\n const job = Object.create({}) as Record<string, any>\n if (properties) {\n Object.assign(job, properties)\n }\n\n // 從 SerializedJob 還原 metadata\n job.id = serialized.id\n if (serialized.groupId) {\n job.groupId = serialized.groupId\n }\n if (serialized.priority !== undefined) {\n job.priority = serialized.priority\n }\n if (serialized.delaySeconds !== undefined) {\n job.delaySeconds = serialized.delaySeconds\n }\n if (serialized.attempts !== undefined) {\n job.attempts = serialized.attempts\n }\n if (serialized.maxAttempts !== undefined) {\n job.maxAttempts = serialized.maxAttempts\n }\n if (serialized.retryAfterSeconds !== undefined) {\n job.retryAfterSeconds = serialized.retryAfterSeconds\n }\n if (serialized.retryMultiplier !== undefined) {\n job.retryMultiplier = serialized.retryMultiplier\n }\n\n return job as Job\n }\n\n /**\n * 將各種格式的 data 轉換為 Uint8Array\n *\n * @param data - Uint8Array、Base64 string 或 ArrayBuffer\n * @returns Uint8Array\n */\n private resolveBytes(data: unknown): Uint8Array {\n if (data instanceof Uint8Array) {\n return data\n }\n\n if (typeof data === 'string') {\n try {\n return new Uint8Array(Buffer.from(data, 'base64'))\n } catch (err) {\n throw new Error(\n `Failed to decode Base64 data: ${err instanceof Error ? err.message : String(err)}`\n )\n }\n }\n\n if (data instanceof ArrayBuffer) {\n return new Uint8Array(data)\n }\n\n throw new TypeError(`Invalid data type for binary deserialization: ${typeof data}`)\n }\n}\n",
61
+ "import type { NativeAcceleratorStatus } from '@gravito/core/ffi'\nimport type { Job } from '../Job'\nimport type { SerializedJob } from '../types'\nimport { CborNativeSerializer } from './CborNativeSerializer'\nimport type { JobSerializer } from './JobSerializer'\n\n/**\n * Binary Serializer using CBOR.\n *\n * 委派給 CborNativeSerializer,使用 @gravito/core 的 NativeAccelerator\n * 進行 CBOR 編碼/解碼。自動選擇最佳後端(Native FFI 或 JavaScript Fallback)。\n *\n * 此類別保留為向後相容的入口點,新程式碼建議直接使用 CborNativeSerializer。\n *\n * @public\n * @example\n * ```typescript\n * const serializer = new BinarySerializer()\n * const serialized = serializer.serialize(job)\n * const deserialized = serializer.deserialize(serialized)\n * ```\n */\nexport class BinarySerializer implements JobSerializer {\n private readonly delegate: CborNativeSerializer\n\n constructor() {\n this.delegate = new CborNativeSerializer()\n }\n\n /**\n * 取得當前使用的 CBOR 後端資訊\n * 可用於診斷和監控\n */\n static getBackendInfo(): NativeAcceleratorStatus {\n return CborNativeSerializer.getBackendInfo()\n }\n\n /**\n * 將 Job 序列化為 CBOR 二進制格式\n */\n serialize(job: Job): SerializedJob {\n return this.delegate.serialize(job)\n }\n\n /**\n * 反序列化 CBOR 二進制資料為 Job\n *\n * 支援三種資料格式:\n * - Uint8Array(原生 CBOR 二進制)\n * - Base64 string(來自 Redis / 網路傳輸)\n * - ArrayBuffer(來自 Worker Transferable)\n */\n deserialize(serialized: SerializedJob): Job {\n return this.delegate.deserialize(serialized)\n }\n}\n",
62
+ "import type { Job } from '../Job'\nimport type { SerializedJob } from '../types'\nimport type { JobSerializer } from './JobSerializer'\n\n/**\n * 判斷目前是否在 Bun 執行環境中。\n */\nconst isBun = typeof globalThis.Bun !== 'undefined'\n\n/**\n * JSONL (JSON Lines) Serializer。\n *\n * 使用 JSONL 格式序列化 Job,每個 Job 佔一行。\n * 在 Bun 環境中利用原生 `Bun.JSONL.parse()` 和 `Bun.JSONL.parseChunk()`\n * 以獲得最佳的批量與流式處理性能;在非 Bun 環境中降級為逐行 JSON 解析。\n *\n * **使用情境**:\n * - 日誌串流與稽核場景\n * - 大量 Job 匯出 / 匯入\n * - 與外部工具(如 jq、logstash)整合\n *\n * @public\n * @example\n * ```typescript\n * const serializer = new JsonlSerializer()\n *\n * // 單一 Job\n * const serialized = serializer.serialize(job)\n * const restored = serializer.deserialize(serialized)\n *\n * // 批量 JSONL 字串\n * const jsonl = serializer.serializeMany(jobs)\n * const restored = serializer.deserializeMany(jsonl)\n *\n * // 流式處理(Generator)\n * for (const job of serializer.deserializeStream(jsonlChunk)) {\n * await queue.push(job)\n * }\n * ```\n */\nexport class JsonlSerializer implements JobSerializer {\n /**\n * 從 Job 提取可序列化屬性(排除函式)。\n */\n private extractProperties(job: Job): Record<string, unknown> {\n const properties: Record<string, unknown> = {}\n for (const key in job) {\n if (\n Object.hasOwn(job, key) &&\n typeof (job as unknown as Record<string, unknown>)[key] !== 'function'\n ) {\n properties[key] = (job as unknown as Record<string, unknown>)[key]\n }\n }\n return properties\n }\n\n /**\n * 將 SerializedJob 的 metadata 還原至 job 物件上。\n */\n private restoreMetadata(job: Record<string, any>, serialized: SerializedJob): void {\n job.id = serialized.id\n if (serialized.groupId) {\n job.groupId = serialized.groupId\n }\n if (serialized.priority) {\n job.priority = serialized.priority\n }\n if (serialized.delaySeconds !== undefined) {\n job.delaySeconds = serialized.delaySeconds\n }\n if (serialized.attempts !== undefined) {\n job.attempts = serialized.attempts\n }\n if (serialized.maxAttempts !== undefined) {\n job.maxAttempts = serialized.maxAttempts\n }\n if (serialized.retryAfterSeconds !== undefined) {\n job.retryAfterSeconds = serialized.retryAfterSeconds\n }\n if (serialized.retryMultiplier !== undefined) {\n job.retryMultiplier = serialized.retryMultiplier\n }\n }\n\n /**\n * 序列化單一 Job 為 SerializedJob。\n *\n * data 欄位使用 JSON 字串,type 標記為 'jsonl'。\n */\n serialize(job: Job): SerializedJob {\n const id = job.id || `${Date.now()}-${crypto.randomUUID()}`\n const properties = this.extractProperties(job)\n\n return {\n id,\n type: 'jsonl',\n data: JSON.stringify(properties),\n createdAt: Date.now(),\n ...(job.delaySeconds !== undefined ? { delaySeconds: job.delaySeconds } : {}),\n attempts: job.attempts ?? 0,\n ...(job.maxAttempts !== undefined ? { maxAttempts: job.maxAttempts } : {}),\n ...(job.groupId ? { groupId: job.groupId } : {}),\n ...(job.priority ? { priority: job.priority } : {}),\n ...(job.retryAfterSeconds !== undefined ? { retryAfterSeconds: job.retryAfterSeconds } : {}),\n ...(job.retryMultiplier !== undefined ? { retryMultiplier: job.retryMultiplier } : {}),\n }\n }\n\n /**\n * 反序列化單一 SerializedJob 為 Job 物件。\n */\n deserialize(serialized: SerializedJob): Job {\n if (serialized.type !== 'jsonl') {\n throw new Error(`Invalid serialization type: expected \"jsonl\", got \"${serialized.type}\"`)\n }\n\n const dataStr =\n typeof serialized.data === 'string'\n ? serialized.data\n : Buffer.from(serialized.data).toString('utf8')\n\n let properties: Record<string, unknown>\n try {\n properties = JSON.parse(dataStr)\n } catch (err) {\n throw new Error(\n `JsonlSerializer: failed to parse JSON data: ${err instanceof Error ? err.message : String(err)}`\n )\n }\n\n const job = Object.create({}) as Record<string, any>\n Object.assign(job, properties)\n this.restoreMetadata(job, serialized)\n\n return job as unknown as Job\n }\n\n /**\n * 批量序列化多個 Job 為 JSONL 字串(每個 SerializedJob 佔一行)。\n *\n * @param jobs - 要序列化的 Job 陣列\n * @returns 換行符分隔的 JSONL 字串\n */\n serializeMany(jobs: Job[]): string {\n return jobs.map((job) => JSON.stringify(this.serialize(job))).join('\\n')\n }\n\n /**\n * 批量反序列化 JSONL 字串為 Job 陣列。\n *\n * 在 Bun 環境中使用 `Bun.JSONL.parse()` 以獲得最佳性能;\n * 非 Bun 環境則降級為逐行 `JSON.parse()`。\n *\n * @param jsonlStr - JSONL 格式字串(每行一個 SerializedJob)\n * @returns 還原後的 Job 陣列\n */\n deserializeMany(jsonlStr: string): Job[] {\n let parsed: SerializedJob[]\n\n if (isBun) {\n // 使用 Bun 原生 JSONL 解析器以獲得最佳性能\n parsed = (globalThis.Bun as any).JSONL.parse(jsonlStr) as SerializedJob[]\n } else {\n // 降級:逐行解析\n parsed = jsonlStr\n .split('\\n')\n .filter((line) => line.trim().length > 0)\n .map((line) => {\n try {\n return JSON.parse(line) as SerializedJob\n } catch (err) {\n throw new Error(\n `JsonlSerializer: failed to parse JSONL line: ${err instanceof Error ? err.message : String(err)}`\n )\n }\n })\n }\n\n return parsed.map((serialized) => this.deserialize(serialized))\n }\n\n /**\n * 以 Generator 流式處理 JSONL 資料塊,逐一產出 Job。\n *\n * 適合處理大型串流或分批送達的 JSONL 資料,避免一次性將所有資料載入記憶體。\n * 在 Bun 環境中使用 `Bun.JSONL.parseChunk()` 以支援增量解析;\n * 非 Bun 環境則降級為按行切割後逐行解析。\n *\n * @param chunk - JSONL 資料塊(可能包含多行,或為不完整的單行)\n * @yields 每次產出一個還原後的 Job\n *\n * @example\n * ```typescript\n * const serializer = new JsonlSerializer()\n * for (const job of serializer.deserializeStream(bigJsonlChunk)) {\n * await processJob(job)\n * }\n * ```\n */\n *deserializeStream(chunk: string): Generator<Job> {\n if (isBun) {\n // 使用 Bun 原生 JSONL 增量解析器\n const items = (globalThis.Bun as any).JSONL.parseChunk(chunk) as SerializedJob[]\n for (const serialized of items) {\n yield this.deserialize(serialized)\n }\n } else {\n // 降級:按行切割後逐行解析\n const lines = chunk.split('\\n')\n for (const line of lines) {\n const trimmed = line.trim()\n if (trimmed.length === 0) {\n continue\n }\n let serialized: SerializedJob\n try {\n serialized = JSON.parse(trimmed) as SerializedJob\n } catch (err) {\n throw new Error(\n `JsonlSerializer: failed to parse JSONL chunk line: ${err instanceof Error ? err.message : String(err)}`\n )\n }\n yield this.deserialize(serialized)\n }\n }\n }\n}\n",
63
+ "/**\n * Binary Worker Protocol - Worker 執行緒二進制傳輸協定\n *\n * 實作 JSON + TextEncoder/TextDecoder + ArrayBuffer Transfer 方案,\n * 讓 Main Thread 與 Worker Thread 之間以零拷貝方式傳遞 Job 資料。\n *\n * 設計原則:\n * - 不依賴 CBOR 或外部函式庫,使用 Bun 原生優化的 TextEncoder/TextDecoder\n * - ArrayBuffer Transfer 確保零拷貝語意(transfer 後原 buffer 失效)\n * - 呼叫端須自行保留 job 物件引用,以支援潛在的重試機制\n *\n * @module workers/BinaryWorkerProtocol\n */\n\nimport type { SerializedJob } from '../types'\n\n// ─── 協定常數 ─────────────────────────────────────────────────────────────────\n\n/**\n * Binary Protocol 版本號,未來可用於版本協商。\n */\nexport const BINARY_PROTOCOL_VERSION = 1\n\n// ─── 型別定義 ─────────────────────────────────────────────────────────────────\n\n/**\n * 使用 Binary Protocol 傳送給 Worker 的訊息格式。\n */\nexport interface BinaryWorkerMessage {\n /**\n * 訊息類型識別符,固定為 'execute-binary'。\n */\n type: 'execute-binary'\n\n /**\n * 以 ArrayBuffer 格式包裝的序列化 Job 資料。\n *\n * 注意:此 buffer 在 postMessage transfer 後即失效(零拷貝語意)。\n * Main Thread 應保留原始 job 物件以支援重試,而非依賴此 buffer。\n */\n buffer: ArrayBuffer\n}\n\n// ─── 編碼函式 ──────────────────────────────────────────────────────────────────\n\n/**\n * 將 SerializedJob 編碼為可傳輸的 ArrayBuffer。\n *\n * 編碼流程:\n * 1. JSON.stringify(job) — 序列化為 JSON 字串\n * 2. TextEncoder.encode(json) — 轉換為 UTF-8 Uint8Array\n * 3. 取出底層 ArrayBuffer 並以 slice 建立獨立副本,確保 buffer 邊界正確\n *\n * @param job - 要傳輸的已序列化 Job 物件\n * @returns 包含 Job 資料的 ArrayBuffer(可作為 transfer list 傳遞給 postMessage)\n * @throws {Error} 若 job 序列化失敗\n *\n * @example\n * ```typescript\n * const buffer = encodeJobForTransfer(job)\n * worker.postMessage({ type: 'execute-binary', buffer }, [buffer])\n * // buffer 在此之後失效,請勿再使用\n * ```\n */\nexport function encodeJobForTransfer(job: SerializedJob): ArrayBuffer {\n // 步驟 1:JSON 序列化\n // undefined 欄位在 JSON.stringify 中會被忽略,這是預期行為\n const jsonStr = JSON.stringify(job)\n\n // 步驟 2:UTF-8 編碼\n const encoder = new TextEncoder()\n const encoded = encoder.encode(jsonStr)\n\n // 步驟 3:取出 ArrayBuffer\n // 注意:TextEncoder.encode() 可能回傳共用 buffer 的 Uint8Array,\n // 使用 slice() 確保取得獨立的 ArrayBuffer,避免 transfer 後影響其他資料\n return encoded.buffer.slice(encoded.byteOffset, encoded.byteOffset + encoded.byteLength)\n}\n\n// ─── 解碼函式 ──────────────────────────────────────────────────────────────────\n\n/**\n * 從 ArrayBuffer 解碼 SerializedJob。\n *\n * 解碼流程:\n * 1. new Uint8Array(buffer) — 建立 buffer 的視圖\n * 2. TextDecoder.decode(view) — 從 UTF-8 還原 JSON 字串\n * 3. JSON.parse(json) — 還原為 SerializedJob 物件\n *\n * @param buffer - 由 encodeJobForTransfer 產生的 ArrayBuffer\n * @returns 還原的 SerializedJob 物件\n * @throws {Error} 若 buffer 為空、JSON 解析失敗或結果不符合 SerializedJob 結構\n *\n * @example\n * ```typescript\n * self.onmessage = async (event) => {\n * if (event.data.type === 'execute-binary') {\n * const job = decodeJobFromTransfer(event.data.buffer)\n * await executeJob(job)\n * }\n * }\n * ```\n */\nexport function decodeJobFromTransfer(buffer: ArrayBuffer): SerializedJob {\n // 防禦性檢查:buffer 不應為空\n if (buffer.byteLength === 0) {\n throw new Error('BinaryWorkerProtocol: 收到空的 ArrayBuffer,無法解碼 Job 資料')\n }\n\n // 步驟 1:建立 Uint8Array 視圖\n const view = new Uint8Array(buffer)\n\n // 步驟 2:UTF-8 解碼\n const decoder = new TextDecoder('utf-8')\n const jsonStr = decoder.decode(view)\n\n // 步驟 3:JSON 解析\n let parsed: unknown\n try {\n parsed = JSON.parse(jsonStr)\n } catch (cause) {\n throw new Error(\n `BinaryWorkerProtocol: JSON 解析失敗 - ${cause instanceof Error ? cause.message : String(cause)}`\n )\n }\n\n // 步驟 4:基本結構驗證(確保必要欄位存在)\n if (!isValidSerializedJob(parsed)) {\n throw new Error(\n 'BinaryWorkerProtocol: 解碼結果不符合 SerializedJob 結構(缺少必要欄位 id、type 或 data)'\n )\n }\n\n return parsed\n}\n\n// ─── 輔助函式 ──────────────────────────────────────────────────────────────────\n\n/**\n * 型別守衛:驗證物件是否符合 SerializedJob 的必要欄位結構。\n *\n * 只檢查必要欄位(id、type、data、createdAt),\n * 可選欄位(className、delaySeconds 等)不做驗證。\n *\n * @param value - 待驗證的未知值\n * @returns 若符合 SerializedJob 必要結構則回傳 true\n */\nfunction isValidSerializedJob(value: unknown): value is SerializedJob {\n if (typeof value !== 'object' || value === null) {\n return false\n }\n\n const obj = value as Record<string, unknown>\n\n // 必要欄位:id(字串)\n if (typeof obj.id !== 'string' || obj.id.length === 0) {\n return false\n }\n\n // 必要欄位:type(限定值)\n if (obj.type !== 'json' && obj.type !== 'class' && obj.type !== 'msgpack') {\n return false\n }\n\n // 必要欄位:data(字串,允許空字串)\n if (typeof obj.data !== 'string') {\n return false\n }\n\n // 必要欄位:createdAt(數字)\n if (typeof obj.createdAt !== 'number') {\n return false\n }\n\n return true\n}\n",
64
+ "/**\n * Bun Worker Implementation.\n *\n * Executes jobs in isolated Bun Worker Threads to provide context isolation,\n * error containment, and leverages Bun's performance optimizations.\n *\n * Key advantages over Node.js Worker Threads:\n * - Native TypeScript support (no compilation needed)\n * - 2-241x faster message passing for common patterns\n * - Memory-efficient with `smol` mode\n * - Built-in module preloading\n *\n * @public\n */\n\nimport { resolve } from 'node:path'\nimport type { SerializedJob } from '../types'\nimport { encodeJobForTransfer } from './BinaryWorkerProtocol'\n\n/**\n * Configuration options for the Bun Worker.\n */\nexport interface BunWorkerConfig {\n /**\n * Maximum execution time for a job in milliseconds.\n *\n * Jobs exceeding this duration will be forcefully terminated.\n * @default 30000 (30 seconds)\n */\n maxExecutionTime?: number\n\n /**\n * Maximum memory limit for the worker in MB.\n *\n * Note: Bun's memory management differs from Node.js.\n * This is advisory and may not be strictly enforced.\n * @default undefined (unlimited)\n */\n maxMemory?: number\n\n /**\n * Whether to isolate contexts for each job.\n *\n * If `true`, a new Worker is created for every job execution.\n * If `false`, the Worker is reused across multiple jobs.\n * @default false\n */\n isolateContexts?: boolean\n\n /**\n * Idle timeout for the Worker in milliseconds.\n *\n * The worker will be terminated if it remains idle for this duration to save resources.\n * @default 60000 (60 seconds)\n */\n idleTimeout?: number\n\n /**\n * Enable Bun's memory-saving mode with minimal performance tradeoff.\n *\n * Reduces memory footprint by approximately 20-30% per worker.\n * @default false\n */\n smol?: boolean\n\n /**\n * Modules to preload before worker starts.\n *\n * Useful for large libraries or frequently used dependencies.\n * Can be a single path or array of paths.\n * @default undefined\n */\n preload?: string | string[]\n\n /**\n * Enable debugging for this worker (opens inspector port).\n *\n * Useful for debugging worker code.\n * @default undefined\n */\n inspectPort?: number\n}\n\n/**\n * Internal state of the worker.\n */\nenum WorkerState {\n /** Worker is initializing or starting up. */\n INITIALIZING = 'initializing',\n /** Worker is ready to accept jobs. */\n READY = 'ready',\n /** Worker is currently executing a job. */\n BUSY = 'busy',\n /** Worker has been terminated or exited. */\n TERMINATED = 'terminated',\n}\n\n/**\n * Response message format from worker.\n */\ninterface WorkerResponse {\n type: 'success' | 'error' | 'ready'\n error?: string\n stack?: string\n}\n\n/**\n * Bun Worker.\n *\n * Manages the lifecycle of a Bun Worker Thread for job execution.\n * Provides features like:\n * - Context Isolation: Run code in a separate thread.\n * - Timeout Enforcement: Terminate hangs or long-running jobs.\n * - Memory Optimization: Native support for memory-efficient mode (`smol`).\n * - Error Containment: Worker crashes do not crash the main application.\n * - Performance: Leverages Bun's optimized message passing.\n *\n * @example\n * ```typescript\n * const worker = new BunWorker({\n * maxExecutionTime: 30000,\n * maxMemory: 512,\n * isolateContexts: true,\n * smol: true\n * });\n *\n * await worker.execute(serializedJob);\n * await worker.terminate();\n * ```\n */\nexport class BunWorker {\n private worker: Worker | null = null\n private state: WorkerState = WorkerState.INITIALIZING\n private config: {\n maxExecutionTime: number\n maxMemory: number\n isolateContexts: boolean\n idleTimeout: number\n smol: boolean\n preload?: string | string[]\n inspectPort?: number\n }\n private idleTimer: NodeJS.Timeout | null = null\n private executionTimer: NodeJS.Timeout | null = null\n\n /**\n * Creates a BunWorker instance.\n *\n * @param config - Configuration options for the worker.\n */\n constructor(config: BunWorkerConfig = {}) {\n this.config = {\n maxExecutionTime: config.maxExecutionTime ?? 30000,\n maxMemory: config.maxMemory ?? 0,\n isolateContexts: config.isolateContexts ?? false,\n idleTimeout: config.idleTimeout ?? 60000,\n smol: config.smol ?? false,\n preload: config.preload ?? undefined,\n inspectPort: config.inspectPort ?? undefined,\n }\n }\n\n /**\n * Initializes the Bun Worker.\n *\n * @returns The active Worker instance.\n * @throws {Error} If worker initialization fails or times out.\n */\n private async initWorker(): Promise<Worker> {\n if (this.worker && this.state !== WorkerState.TERMINATED) {\n return this.worker\n }\n\n const workerPath = resolve(__dirname, 'bun-job-executor.ts')\n\n // Build worker options with Bun-specific features\n const workerOptions: Record<string, any> = {}\n\n // Enable memory-efficient mode if requested\n if (this.config.smol) {\n workerOptions.smol = true\n }\n\n // Add preload modules if specified\n if (this.config.preload) {\n const preloadModules = Array.isArray(this.config.preload)\n ? this.config.preload\n : [this.config.preload]\n workerOptions.preload = preloadModules\n }\n\n // Enable debugging if inspector port specified\n if (this.config.inspectPort && this.config.inspectPort > 0) {\n workerOptions.inspectPort = this.config.inspectPort\n }\n\n // Create the worker\n this.worker = new Worker(workerPath, workerOptions)\n this.state = WorkerState.INITIALIZING\n\n // Wait for worker to be ready\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error('Bun Worker initialization timeout'))\n }, 5000)\n\n const messageHandler = (event: MessageEvent<WorkerResponse>) => {\n const message = event.data\n clearTimeout(timeout)\n\n if (message.type === 'ready') {\n cleanup()\n this.state = WorkerState.READY\n resolve()\n } else {\n cleanup()\n reject(new Error('Unexpected worker message during initialization'))\n }\n }\n\n const errorHandler = (event: ErrorEvent) => {\n clearTimeout(timeout)\n cleanup()\n reject(new Error(event.message || 'Worker initialization error'))\n }\n\n const cleanup = () => {\n if (this.worker) {\n this.worker.removeEventListener('message', messageHandler)\n this.worker.removeEventListener('error', errorHandler)\n }\n }\n\n if (this.worker) {\n this.worker.addEventListener('message', messageHandler)\n this.worker.addEventListener('error', errorHandler)\n }\n })\n\n // Set up error handler for runtime errors\n if (this.worker) {\n this.worker.addEventListener('error', (event: ErrorEvent) => {\n console.error('[BunWorker] Worker error:', event.message)\n this.state = WorkerState.TERMINATED\n })\n\n // Bun workers trigger 'close' event instead of 'exit'\n this.worker.addEventListener('close', () => {\n this.state = WorkerState.TERMINATED\n })\n }\n\n return this.worker\n }\n\n /**\n * Executes a job in the isolated Bun worker.\n *\n * @param job - The serialized job data to execute.\n * @throws {Error} If execution fails, times out, or the worker crashes.\n */\n async execute(job: SerializedJob): Promise<void> {\n if (this.config.isolateContexts) {\n await this.terminate()\n }\n\n const worker = await this.initWorker()\n this.state = WorkerState.BUSY\n\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n this.idleTimer = null\n }\n\n try {\n await Promise.race([this.executeInWorker(worker, job), this.createTimeoutPromise()])\n } finally {\n this.state = WorkerState.READY\n\n if (this.executionTimer) {\n clearTimeout(this.executionTimer)\n this.executionTimer = null\n }\n\n if (!this.config.isolateContexts) {\n this.startIdleTimer()\n } else {\n await this.terminate()\n }\n }\n }\n\n /**\n * Internal method to send execution message to the worker thread.\n *\n * 使用 Binary Protocol(ArrayBuffer Transfer)傳遞 Job 資料:\n * 1. 將 job 編碼為 ArrayBuffer(JSON + TextEncoder)\n * 2. 透過 postMessage transfer list 零拷貝傳遞給 Worker\n * 3. 注意:buffer transfer 後即失效,但 job 引用仍有效(支援重試)\n *\n * @param worker - The worker instance.\n * @param job - Job data(保留此引用以支援潛在重試,不依賴已 transfer 的 buffer)\n */\n private executeInWorker(worker: Worker, job: SerializedJob): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const messageHandler = (event: MessageEvent<WorkerResponse>) => {\n const message = event.data\n\n if (message.type === 'success') {\n cleanup()\n resolve()\n } else if (message.type === 'error') {\n cleanup()\n const error = new Error(message.error || 'Job execution failed')\n if (message.stack) {\n error.stack = message.stack\n }\n reject(error)\n }\n }\n\n const errorHandler = (event: ErrorEvent) => {\n cleanup()\n reject(new Error(event.message || 'Worker error'))\n }\n\n const cleanup = () => {\n worker.removeEventListener('message', messageHandler as EventListener)\n worker.removeEventListener('error', errorHandler as EventListener)\n }\n\n worker.addEventListener('message', messageHandler as EventListener)\n worker.addEventListener('error', errorHandler as EventListener)\n\n // 將 job 編碼為 ArrayBuffer 並以零拷貝方式 transfer 給 Worker\n // job 物件本身保留在 Main Thread 側,不受 transfer 影響\n const buffer = encodeJobForTransfer(job)\n worker.postMessage({ type: 'execute-binary', buffer }, [buffer])\n })\n }\n\n /**\n * Creates a promise that rejects after the configured timeout.\n */\n private createTimeoutPromise(): Promise<never> {\n return new Promise<never>((_, reject) => {\n this.executionTimer = setTimeout(() => {\n this.terminate().catch(console.error)\n reject(new Error(`Job execution timeout after ${this.config.maxExecutionTime}ms`))\n }, this.config.maxExecutionTime)\n })\n }\n\n /**\n * Starts the idle timer to auto-terminate the worker.\n */\n private startIdleTimer(): void {\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n }\n\n this.idleTimer = setTimeout(() => {\n this.terminate().catch(console.error)\n }, this.config.idleTimeout)\n }\n\n /**\n * Terminates the Worker immediately.\n *\n * Stops any running job and releases resources.\n */\n async terminate(): Promise<void> {\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n this.idleTimer = null\n }\n\n if (this.executionTimer) {\n clearTimeout(this.executionTimer)\n this.executionTimer = null\n }\n\n if (this.worker) {\n const worker = this.worker\n this.worker = null\n this.state = WorkerState.TERMINATED\n\n try {\n // Bun workers have terminate() method\n if (typeof worker.terminate === 'function') {\n await worker.terminate()\n }\n } catch (error) {\n console.error('[BunWorker] Error terminating worker:', error)\n }\n }\n }\n\n /**\n * Gets the current state of the worker.\n *\n * @returns The current `WorkerState`.\n */\n getState(): string {\n return this.state\n }\n\n /**\n * Checks if the worker is ready to accept a job.\n *\n * @returns `true` if ready, `false` otherwise.\n */\n isReady(): boolean {\n return this.state === WorkerState.READY\n }\n\n /**\n * Checks if the worker is currently executing a job.\n *\n * @returns `true` if busy, `false` otherwise.\n */\n isBusy(): boolean {\n return this.state === WorkerState.BUSY\n }\n\n /**\n * Unreferences the worker, allowing the process to exit even if worker is running.\n *\n * Bun-specific optimization for background workers.\n */\n unref(): void {\n if (this.worker && typeof (this.worker as any).unref === 'function') {\n ;(this.worker as any).unref()\n }\n }\n\n /**\n * Re-references the worker, preventing process exit while worker is running.\n *\n * Bun-specific optimization for background workers.\n */\n ref(): void {\n if (this.worker && typeof (this.worker as any).ref === 'function') {\n ;(this.worker as any).ref()\n }\n }\n}\n",
65
+ "/**\n * Worker Factory Implementation.\n *\n * Provides runtime-aware worker creation with automatic environment detection.\n * Abstracts differences between Bun Workers and Node.js Worker Threads,\n * allowing transparent switching based on the runtime environment.\n *\n * @public\n */\n\nimport { BunWorker, type BunWorkerConfig } from './BunWorker'\nimport { SandboxedWorker, type SandboxedWorkerConfig } from './SandboxedWorker'\n\n/**\n * Union type for worker configuration.\n * Accepts both Bun and Node.js specific configs.\n */\nexport type WorkerConfig = BunWorkerConfig | SandboxedWorkerConfig\n\n/**\n * Union type for worker instances.\n */\nexport type Worker = BunWorker | SandboxedWorker\n\n/**\n * Runtime environment type.\n */\nexport type RuntimeEnvironment = 'bun' | 'node' | 'auto'\n\n/**\n * Worker Factory Interface.\n *\n * Defines the contract for creating workers in different runtime environments.\n */\nexport interface IWorkerFactory {\n /**\n * Create a worker appropriate for the current runtime.\n *\n * @param config - Configuration for the worker.\n * @returns A worker instance (BunWorker or SandboxedWorker).\n */\n create(config: WorkerConfig): BunWorker | SandboxedWorker\n\n /**\n * Get the detected runtime environment.\n *\n * @returns The runtime environment ('bun' or 'node').\n */\n getRuntime(): 'bun' | 'node'\n\n /**\n * Check if running in Bun environment.\n *\n * @returns `true` if running on Bun, `false` otherwise.\n */\n isBun(): boolean\n\n /**\n * Check if running in Node.js environment.\n *\n * @returns `true` if running on Node.js, `false` otherwise.\n */\n isNode(): boolean\n}\n\n/**\n * Runtime-aware Worker Factory.\n *\n * Automatically detects the runtime environment (Bun or Node.js) and creates\n * the appropriate worker type. Provides a unified interface that abstracts\n * away runtime-specific details.\n *\n * @example\n * ```typescript\n * // Automatic detection\n * const factory = new RuntimeAwareWorkerFactory()\n * const worker = factory.create({ maxExecutionTime: 30000 })\n *\n * // Force specific runtime (testing/development)\n * const bunFactory = new RuntimeAwareWorkerFactory('bun')\n * const nodeFactory = new RuntimeAwareWorkerFactory('node')\n * ```\n */\nexport class RuntimeAwareWorkerFactory implements IWorkerFactory {\n private runtime: 'bun' | 'node'\n\n /**\n * Creates a RuntimeAwareWorkerFactory instance.\n *\n * @param runtimeOverride - Optional override for runtime detection.\n * - `'auto'` or undefined: Automatically detect (default)\n * - `'bun'`: Force Bun runtime\n * - `'node'`: Force Node.js runtime\n */\n constructor(runtimeOverride?: RuntimeEnvironment) {\n if (runtimeOverride === 'bun') {\n this.runtime = 'bun'\n } else if (runtimeOverride === 'node') {\n this.runtime = 'node'\n } else {\n // Auto-detect\n this.runtime = this.detectRuntime()\n }\n }\n\n /**\n * Automatically detects the runtime environment.\n *\n * Detection strategy:\n * 1. Check for Bun global object\n * 2. Fall back to Node.js\n *\n * @returns The detected runtime ('bun' or 'node').\n */\n private detectRuntime(): 'bun' | 'node' {\n // Check for Bun global\n if (typeof Bun !== 'undefined' && Bun.isMainThread) {\n return 'bun'\n }\n\n // Fall back to Node.js\n return 'node'\n }\n\n /**\n * Creates a worker appropriate for the current runtime.\n *\n * @param config - Configuration for the worker.\n * @returns A BunWorker if running on Bun, SandboxedWorker otherwise.\n */\n create(config: WorkerConfig): BunWorker | SandboxedWorker {\n if (this.runtime === 'bun') {\n return new BunWorker(config as BunWorkerConfig)\n }\n\n return new SandboxedWorker(config as SandboxedWorkerConfig)\n }\n\n /**\n * Gets the detected runtime environment.\n *\n * @returns The runtime ('bun' or 'node').\n */\n getRuntime(): 'bun' | 'node' {\n return this.runtime\n }\n\n /**\n * Checks if running in Bun environment.\n *\n * @returns `true` if running on Bun, `false` otherwise.\n */\n isBun(): boolean {\n return this.runtime === 'bun'\n }\n\n /**\n * Checks if running in Node.js environment.\n *\n * @returns `true` if running on Node.js, `false` otherwise.\n */\n isNode(): boolean {\n return this.runtime === 'node'\n }\n}\n\n/**\n * Helper function to create a default factory with optional runtime override.\n *\n * @param runtimeOverride - Optional runtime override.\n * @returns A new RuntimeAwareWorkerFactory instance.\n */\nexport function createWorkerFactory(\n runtimeOverride?: RuntimeEnvironment\n): RuntimeAwareWorkerFactory {\n return new RuntimeAwareWorkerFactory(runtimeOverride)\n}\n",
66
+ "/**\n * Worker Pool Implementation.\n *\n * Manages a pool of Sandboxed Workers to provide concurrency control,\n * worker reuse, load balancing, and health monitoring.\n *\n * @public\n */\n\nimport type { SerializedJob } from '../types'\nimport type { SandboxedWorker, SandboxedWorkerConfig } from './SandboxedWorker'\nimport {\n type IWorkerFactory,\n RuntimeAwareWorkerFactory,\n type RuntimeEnvironment,\n type WorkerConfig,\n} from './WorkerFactory'\n\n/**\n * Configuration options for the Worker Pool.\n */\nexport interface WorkerPoolConfig extends SandboxedWorkerConfig {\n /**\n * The maximum number of workers allowed in the pool.\n *\n * @default 4\n */\n poolSize?: number\n\n /**\n * The minimum number of workers to keep alive.\n *\n * The pool will pre-warm and maintain at least this many ready workers.\n * @default 0\n */\n minWorkers?: number\n\n /**\n * Interval for performing health checks in milliseconds.\n *\n * Periodically scans for and removes terminated or unhealthy workers.\n * @default 30000 (30 seconds)\n */\n healthCheckInterval?: number\n\n /**\n * Custom worker factory for creating workers.\n *\n * If not provided, RuntimeAwareWorkerFactory will be used with the runtime option.\n * @default undefined\n */\n factory?: IWorkerFactory\n\n /**\n * Runtime environment to use for worker creation.\n *\n * - `'auto'` or undefined: Automatically detect (Bun or Node.js)\n * - `'bun'`: Force Bun runtime\n * - `'node'`: Force Node.js runtime\n * - `'bun'`/`'node'`: Only used if factory is not provided\n *\n * @default 'auto'\n */\n runtime?: RuntimeEnvironment\n}\n\n/**\n * Runtime statistics for the Worker Pool.\n */\nexport interface WorkerPoolStats {\n /** Total number of workers (ready + busy). */\n total: number\n /** Number of idle workers ready for new jobs. */\n ready: number\n /** Number of workers currently executing jobs. */\n busy: number\n /** Number of workers in terminated state awaiting cleanup. */\n terminated: number\n /** Number of jobs waiting in the queue. */\n pending: number\n /** Total number of successfully completed jobs. */\n completed: number\n /** Total number of failed jobs. */\n failed: number\n}\n\n/**\n * Worker Pool.\n *\n * Orchestrates multiple `SandboxedWorker` or `BunWorker` instances to execute jobs concurrently.\n * Automatically selects the best worker implementation based on the runtime environment.\n *\n * Key features:\n * - **Concurrency Control**: Limits the number of simultaneous job executions (`poolSize`).\n * - **Queueing**: Queues jobs when all workers are busy.\n * - **Lifecycle Management**: Automatically creates, reuses, and terminates workers.\n * - **Health Monitoring**: Periodically cleans up dead workers and maintains `minWorkers`.\n * - **Runtime-Aware**: Automatically uses BunWorker on Bun, SandboxedWorker on Node.js.\n *\n * @example\n * ```typescript\n * // Auto-detection (uses best available runtime)\n * const pool = new WorkerPool({\n * poolSize: 8,\n * minWorkers: 2,\n * maxExecutionTime: 30000\n * });\n *\n * // Force specific runtime\n * const bunPool = new WorkerPool({\n * runtime: 'bun',\n * poolSize: 8\n * });\n *\n * await pool.execute(job);\n * await pool.shutdown();\n * ```\n */\nexport class WorkerPool {\n private workers: Array<SandboxedWorker | any> = []\n private factory: IWorkerFactory\n private config: Required<Omit<WorkerPoolConfig, 'factory' | 'runtime'>> & {\n factory: IWorkerFactory\n runtime: RuntimeEnvironment\n }\n private queue: Array<{\n job: SerializedJob\n resolve: () => void\n reject: (error: Error) => void\n }> = []\n private healthCheckTimer: NodeJS.Timeout | null = null\n private stats = {\n completed: 0,\n failed: 0,\n }\n\n /**\n * Creates a WorkerPool instance.\n *\n * @param config - Configuration options for the pool.\n */\n constructor(config: WorkerPoolConfig = {}) {\n // Initialize factory\n this.factory = config.factory ?? new RuntimeAwareWorkerFactory(config.runtime ?? 'auto')\n\n this.config = {\n poolSize: config.poolSize ?? 4,\n minWorkers: config.minWorkers ?? 0,\n healthCheckInterval: config.healthCheckInterval ?? 30000,\n maxExecutionTime: config.maxExecutionTime ?? 30000,\n maxMemory: config.maxMemory ?? 0,\n isolateContexts: config.isolateContexts ?? false,\n idleTimeout: config.idleTimeout ?? 60000,\n factory: this.factory,\n runtime: config.runtime ?? 'auto',\n }\n\n this.warmUp()\n this.startHealthCheck()\n }\n\n /**\n * Pre-warms the pool by creating the minimum number of workers.\n */\n private warmUp(): void {\n const targetCount = Math.min(this.config.minWorkers, this.config.poolSize)\n for (let i = 0; i < targetCount; i++) {\n this.createWorker()\n }\n }\n\n /**\n * Creates a new Worker (BunWorker or SandboxedWorker) and adds it to the pool.\n *\n * Uses the configured factory to create the appropriate worker type\n * based on the runtime environment.\n *\n * @returns The newly created worker.\n */\n private createWorker(): SandboxedWorker | any {\n const config: WorkerConfig = {\n maxExecutionTime: this.config.maxExecutionTime,\n maxMemory: this.config.maxMemory,\n isolateContexts: this.config.isolateContexts,\n idleTimeout: this.config.idleTimeout,\n }\n\n const worker = this.factory.create(config)\n\n this.workers.push(worker)\n return worker\n }\n\n /**\n * Retrieves an available worker from the pool.\n *\n * Priorities:\n * 1. Reuse an existing ready worker.\n * 2. Create a new worker if the pool is not full.\n * 3. Return `null` if the pool is saturated.\n *\n * @returns An available worker or `null`.\n */\n private getAvailableWorker(): SandboxedWorker | null {\n const readyWorker = this.workers.find((w) => w.isReady())\n if (readyWorker) {\n return readyWorker\n }\n\n if (this.workers.length < this.config.poolSize) {\n return this.createWorker()\n }\n\n return null\n }\n\n /**\n * Executes a job using the worker pool.\n *\n * If a worker is available, the job starts immediately.\n * Otherwise, it is added to the pending queue.\n *\n * @param job - The serialized job data.\n * @throws {Error} If execution fails.\n */\n async execute(job: SerializedJob): Promise<void> {\n const worker = this.getAvailableWorker()\n\n if (worker) {\n try {\n await worker.execute(job)\n this.stats.completed++\n } catch (error) {\n this.stats.failed++\n throw error\n } finally {\n this.processQueue()\n }\n } else {\n return new Promise<void>((resolve, reject) => {\n this.queue.push({ job, resolve, reject })\n })\n }\n }\n\n /**\n * Processes the next job in the queue if a worker is available.\n */\n private processQueue(): void {\n if (this.queue.length === 0) {\n return\n }\n\n const worker = this.getAvailableWorker()\n if (!worker) {\n return\n }\n\n const item = this.queue.shift()\n if (!item) {\n return\n }\n\n worker\n .execute(item.job)\n .then(() => {\n this.stats.completed++\n item.resolve()\n })\n .catch((error) => {\n this.stats.failed++\n item.reject(error)\n })\n .finally(() => {\n this.processQueue()\n })\n }\n\n /**\n * Starts the periodic health check.\n */\n private startHealthCheck(): void {\n if (this.healthCheckTimer) {\n return\n }\n\n this.healthCheckTimer = setInterval(() => {\n this.performHealthCheck()\n }, this.config.healthCheckInterval)\n }\n\n /**\n * Performs a health check on the pool.\n *\n * Removes terminated workers and ensures `minWorkers` are available.\n */\n private performHealthCheck(): void {\n this.workers = this.workers.filter((worker) => {\n if (worker.getState() === 'terminated') {\n worker.terminate().catch(console.error)\n return false\n }\n return true\n })\n\n const activeWorkers = this.workers.length\n if (activeWorkers < this.config.minWorkers) {\n const needed = this.config.minWorkers - activeWorkers\n for (let i = 0; i < needed; i++) {\n this.createWorker()\n }\n }\n }\n\n /**\n * Gets the current statistics of the worker pool.\n *\n * @returns Snapshot of pool statistics.\n */\n getStats(): WorkerPoolStats {\n let ready = 0\n let busy = 0\n let terminated = 0\n\n for (const worker of this.workers) {\n const state = worker.getState()\n if (state === 'ready') {\n ready++\n } else if (state === 'busy') {\n busy++\n } else if (state === 'terminated') {\n terminated++\n }\n }\n\n return {\n total: this.workers.length,\n ready,\n busy,\n terminated,\n pending: this.queue.length,\n completed: this.stats.completed,\n failed: this.stats.failed,\n }\n }\n\n /**\n * Shuts down the worker pool.\n *\n * Terminates all workers and rejects any pending jobs.\n */\n async shutdown(): Promise<void> {\n if (this.healthCheckTimer) {\n clearInterval(this.healthCheckTimer)\n this.healthCheckTimer = null\n }\n\n for (const item of this.queue) {\n item.reject(new Error('Worker pool is shutting down'))\n }\n this.queue = []\n\n await Promise.all(this.workers.map((worker) => worker.terminate().catch(console.error)))\n\n this.workers = []\n }\n\n /**\n * Waits for all active and pending jobs to complete.\n *\n * @param timeout - Maximum wait time in milliseconds. 0 for infinite.\n * @throws {Error} If the timeout is reached.\n */\n async waitForCompletion(timeout = 0): Promise<void> {\n const startTime = Date.now()\n\n return new Promise<void>((resolve, reject) => {\n const checkCompletion = () => {\n const stats = this.getStats()\n const isComplete = stats.busy === 0 && stats.pending === 0\n\n if (isComplete) {\n resolve()\n return\n }\n\n if (timeout > 0 && Date.now() - startTime > timeout) {\n reject(new Error('Wait for completion timeout'))\n return\n }\n\n setTimeout(checkCompletion, 100)\n }\n\n checkCompletion()\n })\n }\n}\n"
67
+ ],
68
+ "mappings": "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",
69
+ "debugId": "D40AD59BE0C7115864756E2164756E21",
70
+ "names": []
71
+ }