@cloudnux/local-cloud-provider 0.19.0 → 0.21.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/dev-console-plugin/plugin.ts","../../src/queue-plugin/plugin.ts","../../src/queue-plugin/core.ts","../../src/queue-plugin/persistence.ts","../../src/queue-plugin/processing.ts","../../src/queue-plugin/decorator.ts","../../src/queue-plugin/routes.ts","../../src/schedule-plugin/plugin.ts","../../src/schedule-plugin/cron-utils.ts","../../src/schedule-plugin/utils.ts","../../src/schedule-plugin/core.ts","../../src/schedule-plugin/jobs.ts","../../src/schedule-plugin/persistence.ts","../../src/schedule-plugin/processing.ts","../../src/schedule-plugin/decorator.ts","../../src/schedule-plugin/routes.ts","../../src/websocket-plugin/plugin.ts","../../src/dev-console-plugin/route-registry.ts"],"sourcesContent":["import path from \"path\";\nimport { FastifyInstance } from \"fastify\";\nimport fastifyStatic from \"@fastify/static\";\nimport fsPlugin from \"fastify-plugin\";\nimport { createRequire } from 'module';\nconst require = createRequire(import.meta.url);\n\nimport { WebSocketConnectionGoneError } from \"@cloudnux/core-cloud-provider\";\n\nimport \"../logger/types\";\n\nimport \"../queue-plugin\";\nimport \"../schedule-plugin\";\nimport \"../websocket-plugin\";\n\nimport { routeRegistry } from \"./route-registry\";\n\ninterface LogEntry {\n id: string;\n timestamp: Date;\n levelName: string;\n message: string;\n meta?: Record<string, unknown>;\n module: string;\n reqId: string;\n}\n\nclass LogStore {\n private logs: LogEntry[] = [];\n private maxLogs = 1000;\n private listeners: ((log: LogEntry) => void)[] = [];\n\n addLog(entry: LogEntry) {\n this.logs.unshift(entry);\n if (this.logs.length > this.maxLogs) {\n this.logs = this.logs.slice(0, this.maxLogs);\n }\n this.listeners.forEach(listener => listener(entry));\n }\n\n getLogs(limit = 100) {\n return this.logs.slice(0, limit);\n }\n\n clear() {\n this.logs = [];\n }\n\n subscribe(listener: (log: LogEntry) => void) {\n this.listeners.push(listener);\n return () => {\n this.listeners = this.listeners.filter(l => l !== listener);\n };\n }\n}\n\nconst logStore = new LogStore();\n\ninterface HttpHistoryEntry {\n id: string;\n method: string;\n routeUrl: string;\n url: string;\n statusCode: number;\n duration: number;\n reqId: string;\n requestHeaders: Record<string, unknown>;\n requestBody?: unknown;\n timestamp: Date;\n}\n\n// Records every real request that hits a module route (matched by url\n// prefix, same \"/api\" convention routeRegistry uses), not just the ones\n// fired from the console's own \"Test Route\" panel - so RouteDetailView can\n// show traffic that actually happened, keyed by the route's method+template\n// since that's all the frontend has to ask for.\nclass HttpHistoryStore {\n private entries: Map<string, HttpHistoryEntry[]> = new Map();\n private readonly maxPerRoute = 50;\n\n add(entry: HttpHistoryEntry) {\n const key = `${entry.method} ${entry.routeUrl}`;\n const existing = this.entries.get(key) ?? [];\n existing.unshift(entry);\n if (existing.length > this.maxPerRoute) {\n existing.length = this.maxPerRoute;\n }\n this.entries.set(key, existing);\n }\n\n get(method: string, routeUrl: string) {\n return this.entries.get(`${method.toUpperCase()} ${routeUrl}`) ?? [];\n }\n\n clear() {\n this.entries.clear();\n }\n}\n\nconst httpHistoryStore = new HttpHistoryStore();\n\nexport interface DevConsolePluginOptions {\n prefix?: string;\n enableUI?: boolean;\n}\n\nasync function devConsolePluginFunction(\n fastify: FastifyInstance,\n options: DevConsolePluginOptions = {}\n) {\n const { prefix = 'console', enableUI = true } = options;\n\n // Read off `fastify.logging` (decorated once by router/index.ts on the shared\n // FastifyInstance), not a direct `../logger` import - dev-console-plugin is its\n // own separately-bundled tsup entry, so a direct import would get its own\n // disconnected copy of the logger's listeners Set and never see logs published\n // from queue-plugin/schedule-plugin/websocket-plugin's bundles.\n const unsubscribe = fastify.logging.subscribeToLogs((entry) => {\n logStore.addLog({\n id: Date.now().toString() + Math.random().toString(36).slice(2, 9),\n timestamp: new Date(entry.time),\n levelName: entry.levelName,\n message: entry.msg,\n meta: entry.meta,\n module: entry.module,\n reqId: entry.reqId,\n });\n });\n\n // Unsubscribe and clear log store on plugin teardown\n fastify.addHook('onClose', (_instance, done) => {\n unsubscribe();\n logStore.clear();\n httpHistoryStore.clear();\n done();\n });\n\n // Register route discovery hook for all routes\n fastify.addHook('onRoute', (routeOptions) => {\n if (routeOptions.prefix === \"/api\") {\n routeRegistry.register(routeOptions);\n }\n });\n\n // Stamp a start time on every request so onResponse below can compute\n // duration - registered fastify-plugin-wide (like onRoute above), so it\n // sees traffic regardless of whether it was triggered from the console UI.\n fastify.addHook('onRequest', (request, _reply, done) => {\n (request as any)._historyStart = Date.now();\n done();\n });\n\n fastify.addHook('onResponse', (request, reply, done) => {\n const routeUrl = request.routeOptions.url;\n if (routeUrl?.startsWith('/api')) {\n const start = (request as any)._historyStart as number | undefined;\n httpHistoryStore.add({\n id: Date.now().toString() + Math.random().toString(36).slice(2, 9),\n method: request.method,\n routeUrl,\n url: request.url,\n statusCode: reply.statusCode,\n duration: start ? Date.now() - start : 0,\n reqId: request.id,\n requestHeaders: request.headers,\n requestBody: request.body,\n timestamp: new Date(),\n });\n }\n done();\n });\n\n // API endpoints\n fastify.get(`/${prefix}/routes`, async () => {\n return { routes: routeRegistry.getAll() };\n });\n\n fastify.get(`/${prefix}/routes/:method`, async (request) => {\n const { method } = request.params as { method: string };\n return { routes: routeRegistry.getByMethod(method) };\n });\n\n // Real requests that hit a given route (method + url template), captured\n // by the onResponse hook above - not just clicks from \"Test Route\".\n fastify.get(`/${prefix}/routes/history`, async (request, reply) => {\n const { method, url } = request.query as { method?: string; url?: string };\n\n if (!method || !url) {\n return reply.status(400).send({ error: 'method and url query params are required' });\n }\n\n return { history: httpHistoryStore.get(method, url) };\n });\n\n fastify.get(`/${prefix}/registry/stats`, async () => {\n return {\n totalRoutes: routeRegistry.count(),\n registeredAt: new Date()\n };\n });\n\n // Modules endpoints - group resources by module\n fastify.get(`/${prefix}/modules`, async (_, reply) => {\n const queueManager = fastify.queues;\n const schedulerManager = fastify.scheduler;\n const wsManager = fastify.websockets;\n\n if (!queueManager || !schedulerManager || !wsManager) {\n return reply.status(503).send({ error: 'Services not available' });\n }\n\n // Get all routes and filter HTTP routes by prefix\n const allRoutes = routeRegistry.getAll();\n const httpRoutes = allRoutes;\n\n // Get all modules from routes, queues, schedules, and websockets\n const moduleSet = new Set<string>();\n\n httpRoutes.forEach(route => {\n if (route.module) moduleSet.add(route.module);\n });\n\n const allQueueNames = queueManager.listQueues();\n const allJobNames = schedulerManager.listJobs();\n\n allQueueNames.forEach(queueName => {\n const queueStats = queueManager.getQueueStats(queueName);\n if (queueStats?.module) moduleSet.add(queueStats.module);\n });\n\n allJobNames.forEach(jobName => {\n const jobStats = schedulerManager.getJobStats(jobName);\n if (jobStats?.job.module) moduleSet.add(jobStats.job.module);\n });\n\n wsManager.getRegisteredPaths().forEach(p => {\n if (p.module) moduleSet.add(p.module);\n });\n\n // Create module objects\n const modules = Array.from(moduleSet).map(moduleName => {\n // Get routes for this module\n const moduleRoutes = httpRoutes.filter(route => route.module === moduleName);\n\n // Get queues for this module\n const moduleQueueNames = queueManager.listQueues(moduleName);\n const moduleQueues = moduleQueueNames.map(name => {\n const stats = queueManager.getQueueStats(name);\n return {\n name,\n stats: stats ? {\n incoming: stats.incoming.length,\n processing: stats.processing.length,\n dlq: stats.dlq.length\n } : null\n };\n });\n\n // Get schedules for this module\n const moduleJobNames = schedulerManager.listJobs(moduleName);\n const moduleSchedules = moduleJobNames.map(name => {\n const jobStats = schedulerManager.getJobStats(name);\n return {\n name,\n enabled: jobStats?.job.enabled || false,\n isRunning: jobStats?.isRunning || false,\n cronExpression: jobStats?.job.cronExpression,\n timezone: jobStats?.job.timezone\n };\n });\n\n // Get websockets for this module\n const moduleWebSockets = wsManager\n ? wsManager.getRegisteredPaths(moduleName).map(p => ({\n path: p.path,\n connectionCount: wsManager.getConnections(p.path).length\n }))\n : [];\n\n return {\n name: moduleName,\n routes: moduleRoutes,\n queues: moduleQueues,\n schedules: moduleSchedules,\n websockets: moduleWebSockets\n };\n });\n\n return { modules };\n });\n\n // Queues endpoints - access via decorator\n fastify.get(`/${prefix}/queues`, async (_, reply) => {\n const queueManager = fastify.queues;\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n const queueNames = queueManager.listQueues();\n const queues = queueNames.map(name => {\n const stats = queueManager.getQueueStats(name);\n return {\n name,\n stats: stats ? {\n incoming: stats.incoming.length,\n processing: stats.processing.length,\n dlq: stats.dlq.length\n } : null\n };\n });\n\n return { queues };\n });\n\n fastify.get(`/${prefix}/queues/:queueName`, async (request, reply) => {\n const { queueName } = request.params as { queueName: string };\n const queueManager = fastify.queues;\n\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n const queueStats = queueManager.getQueueStats(queueName);\n if (!queueStats) {\n return reply.status(404).send({ error: 'Queue not found' });\n }\n\n const config = queueManager.getConfig();\n\n return {\n name: queueName,\n stats: {\n incoming: queueStats.incoming.length,\n processing: queueStats.processing.length,\n dlq: queueStats.dlq.length,\n configuration: config\n },\n messages: {\n incoming: queueStats.incoming,\n processing: queueStats.processing,\n dlq: queueStats.dlq\n }\n };\n });\n\n // Messages that already finished processing (completed or DLQ'd) -\n // covers listener invocations triggered by real traffic, not just\n // messages enqueued from the console's own form.\n fastify.get(`/${prefix}/queues/:queueName/history`, async (request, reply) => {\n const { queueName } = request.params as { queueName: string };\n const queueManager = fastify.queues;\n\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n if (!queueManager.getQueueStats(queueName)) {\n return reply.status(404).send({ error: 'Queue not found' });\n }\n\n return { history: queueManager.getMessageHistory(queueName) };\n });\n\n // Queue action endpoints\n fastify.get(`/${prefix}/queues/:queueName/process-dlq`, async (request, reply) => {\n const { queueName } = request.params as { queueName: string };\n const queueManager = fastify.queues;\n\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n try {\n const result = await queueManager.processDlq(queueName);\n return reply.status(200).send(result);\n } catch (error) {\n return reply.status(500).send({\n message: 'Failed to process DLQ',\n error\n });\n }\n });\n\n fastify.get(`/${prefix}/queues/:queueName/purge-dlq`, async (request, reply) => {\n const { queueName } = request.params as { queueName: string };\n const queueManager = fastify.queues;\n\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n try {\n const result = await queueManager.purgeDlq(queueName);\n return reply.status(200).send(result);\n } catch (error) {\n return reply.status(500).send({\n message: 'Failed to purge DLQ',\n error\n });\n }\n });\n\n fastify.post(`/${prefix}/queues/:queueName/enqueue`, async (request, reply) => {\n const { queueName } = request.params as { queueName: string };\n const queueManager = fastify.queues;\n\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n try {\n const result = await queueManager.enqueueMessage(queueName, request.body, request.headers as Record<string, any>);\n return reply.status(200).send(result);\n } catch (error) {\n return reply.status(500).send({\n message: 'Failed to enqueue message',\n error\n });\n }\n });\n\n fastify.delete(`/${prefix}/queues/:queueName`, async (request, reply) => {\n const { queueName } = request.params as { queueName: string };\n const queueManager = fastify.queues;\n\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n try {\n await queueManager.removeQueue(queueName);\n return reply.status(200).send({\n status: 'success',\n message: `Queue ${queueName} removed successfully`\n });\n } catch (error) {\n return reply.status(500).send({\n message: 'Failed to remove queue',\n error\n });\n }\n });\n\n fastify.post(`/${prefix}/queues`, async (request, reply) => {\n const { queueName, module } = request.body as { queueName: string; module?: string };\n const queueManager = fastify.queues;\n\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n if (!queueName) {\n return reply.status(400).send({ error: 'Queue name is required' });\n }\n\n try {\n // Simple handler that logs messages\n const handler = async (message: any) => {\n console.log(`Processing message in ${queueName}:`, message);\n return undefined;\n };\n\n await queueManager.addQueue(queueName, handler, module);\n return reply.status(201).send({\n status: 'success',\n message: `Queue ${queueName} created successfully`,\n queueName\n });\n } catch (error) {\n return reply.status(500).send({\n message: 'Failed to create queue',\n error\n });\n }\n });\n\n // Schedules endpoints - access via decorator\n fastify.get(`/${prefix}/schedules`, async (_, reply) => {\n const schedulerManager = fastify.scheduler;\n if (!schedulerManager) {\n return reply.status(503).send({ error: 'Scheduler service not available' });\n }\n\n const jobNames = schedulerManager.listJobs();\n const jobs = jobNames.map(name => {\n const jobStats = schedulerManager.getJobStats(name);\n return {\n name,\n enabled: jobStats?.job.enabled || false,\n isRunning: jobStats?.isRunning || false,\n cronExpression: jobStats?.job.cronExpression,\n timezone: jobStats?.job.timezone\n };\n });\n\n return { schedules: jobs };\n });\n\n fastify.get(`/${prefix}/schedules/:jobName`, async (request, reply) => {\n const { jobName } = request.params as { jobName: string };\n const schedulerManager = (fastify as any).scheduler;\n\n if (!schedulerManager) {\n return reply.status(503).send({ error: 'Scheduler service not available' });\n }\n\n const jobStats = schedulerManager.getJobStats(jobName);\n if (!jobStats) {\n return reply.status(404).send({ error: 'Job not found' });\n }\n\n return {\n name: jobName,\n job: jobStats.job,\n isRunning: jobStats.isRunning,\n timerId: jobStats.timerId ? 'scheduled' : 'not_scheduled'\n };\n });\n\n // Every real execution of this job - tick-triggered or manually triggered,\n // from the console or otherwise - not just runs kicked off from this UI.\n fastify.get(`/${prefix}/schedules/:jobName/executions`, async (request, reply) => {\n const { jobName } = request.params as { jobName: string };\n const schedulerManager = fastify.scheduler;\n\n if (!schedulerManager) {\n return reply.status(503).send({ error: 'Scheduler service not available' });\n }\n\n if (!schedulerManager.getJobStats(jobName)) {\n return reply.status(404).send({ error: 'Job not found' });\n }\n\n return { executions: schedulerManager.getJobExecutionHistory(jobName) };\n });\n\n // Schedule action endpoints - use decorators\n fastify.post(`/${prefix}/schedules/:jobName/trigger`, async (request, reply) => {\n const { jobName } = request.params as { jobName: string };\n const schedulerManager = fastify.scheduler;\n\n if (!schedulerManager) {\n return reply.status(503).send({ error: 'Scheduler service not available' });\n }\n\n try {\n await schedulerManager.triggerJob(jobName);\n return reply.status(200).send({\n status: 'success',\n message: `Schedule ${jobName} triggered successfully`\n });\n } catch {\n return reply.status(500).send({ error: 'Failed to trigger schedule' });\n }\n });\n\n fastify.put(`/${prefix}/schedules/:jobName/enable`, async (request, reply) => {\n const { jobName } = request.params as { jobName: string };\n const schedulerManager = fastify.scheduler;\n\n if (!schedulerManager) {\n return reply.status(503).send({ error: 'Scheduler service not available' });\n }\n\n try {\n await schedulerManager.enableJob(jobName);\n return reply.status(200).send({\n status: 'success',\n message: `Schedule ${jobName} enabled successfully`\n });\n } catch {\n return reply.status(500).send({ error: 'Failed to enable schedule' });\n }\n });\n\n fastify.put(`/${prefix}/schedules/:jobName/disable`, async (request, reply) => {\n const { jobName } = request.params as { jobName: string };\n const schedulerManager = fastify.scheduler;\n\n if (!schedulerManager) {\n return reply.status(503).send({ error: 'Scheduler service not available' });\n }\n\n try {\n await schedulerManager.disableJob(jobName);\n return reply.status(200).send({\n status: 'success',\n message: `Schedule ${jobName} disabled successfully`\n });\n } catch {\n return reply.status(500).send({ error: 'Failed to disable schedule' });\n }\n });\n\n // Logs endpoints\n fastify.get(`/${prefix}/logs`, async (request) => {\n const {\n limit = 100,\n level,\n module,\n reqId,\n } = request.query as {\n limit?: number;\n level?: string;\n module?: string;\n reqId?: string;\n };\n\n let logs = logStore.getLogs(Number(limit));\n\n if (level) {\n logs = logs.filter(log => log.levelName === level);\n }\n\n if (module) {\n logs = logs.filter(log => log.module === module);\n }\n\n if (reqId) {\n logs = logs.filter(log => log.reqId === reqId);\n }\n\n return { logs };\n });\n\n fastify.delete(`/${prefix}/logs`, async () => {\n logStore.clear();\n return { status: 'success', message: 'Logs cleared' };\n });\n\n // WebSocket endpoints\n fastify.get(`/${prefix}/websockets`, async (_, reply) => {\n const wsManager = fastify.websockets;\n if (!wsManager) {\n return reply.status(503).send({ error: 'WebSocket service not available' });\n }\n\n const connections = wsManager.getConnections();\n const pathSet = new Set(connections.map(c => c.path));\n const paths = Array.from(pathSet).map(p => ({\n path: p,\n connections: wsManager.getConnections(p).map(c => ({\n connectionId: c.connectionId,\n path: c.path,\n connectedAt: c.connectedAt,\n })),\n }));\n\n return { paths };\n });\n\n fastify.get(`/${prefix}/websockets/:path`, async (request, reply) => {\n const wsManager = fastify.websockets;\n if (!wsManager) {\n return reply.status(503).send({ error: 'WebSocket service not available' });\n }\n\n const { path: wsPath } = request.params as { path: string };\n const decodedPath = '/' + wsPath;\n const connections = wsManager.getConnections(decodedPath).map(c => ({\n connectionId: c.connectionId,\n path: c.path,\n connectedAt: c.connectedAt,\n }));\n\n return { path: decodedPath, connections };\n });\n\n fastify.post(`/${prefix}/websockets/:connectionId/send`, async (request, reply) => {\n const wsManager = fastify.websockets;\n if (!wsManager) {\n return reply.status(503).send({ error: 'WebSocket service not available' });\n }\n\n const { connectionId } = request.params as { connectionId: string };\n\n try {\n await wsManager.sendToClient(connectionId, request.body);\n return reply.status(200).send({ status: 'success', message: `Message sent to ${connectionId}` });\n } catch (error) {\n if (error instanceof WebSocketConnectionGoneError) {\n return reply.status(410).send({ error: error.message });\n }\n return reply.status(404).send({ error: (error as Error).message });\n }\n });\n\n // Server-Sent Events for real-time logs\n fastify.get(`/${prefix}/logs/stream`, async (request, reply) => {\n const { level, module, reqId } = request.query as {\n level?: string;\n module?: string;\n reqId?: string;\n };\n\n // Mirror the same filters the REST /logs endpoint applies - otherwise a\n // client viewing a filtered (e.g. module-scoped) log list gets every\n // other module's activity pushed into it live, which looks exactly like\n // cleared logs reappearing.\n const matchesFilters = (log: LogEntry) => {\n if (level && log.levelName !== level) return false;\n if (module && log.module !== module) return false;\n if (reqId && log.reqId !== reqId) return false;\n return true;\n };\n\n reply.type('text/event-stream');\n reply.header('Cache-Control', 'no-cache');\n reply.header('Connection', 'keep-alive');\n reply.header('Access-Control-Allow-Origin', '*');\n\n // Send initial logs\n const initialLogs = logStore.getLogs(50).filter(matchesFilters);\n reply.raw.write(`data: ${JSON.stringify({ type: 'initial', logs: initialLogs })}\\n\\n`);\n\n // Subscribe to new logs\n const unsubscribe = logStore.subscribe((log) => {\n if (matchesFilters(log)) {\n reply.raw.write(`data: ${JSON.stringify({ type: 'log', log })}\\n\\n`);\n }\n });\n\n // Cleanup on client disconnect\n request.raw.on('close', () => {\n unsubscribe();\n });\n });\n\n // Serve static UI files if enabled\n if (enableUI) {\n const devConsolePath = path.dirname(\n require.resolve('@cloudnux/dev-console/dist/index.html')\n );\n\n await fastify.register(fastifyStatic, {\n root: devConsolePath,\n decorateReply: true,\n prefix: `/${prefix}/`\n });\n\n // Serve dev-console SPA\n fastify.get(`/${prefix}`, async (_, reply) => {\n return reply.sendFile('index.html');\n });\n }\n}\n\nexport const devConsolePlugin = fsPlugin(devConsolePluginFunction, {\n name: 'dev-console-plugin'\n})","import { FastifyInstance, FastifyPluginAsync } from \"fastify\";\nimport fsPlugin from \"fastify-plugin\";\n\nimport { QueuePluginOptions, QueueRuntime } from \"./types\";\nimport { DEFAULT_CONFIG, mergeConfig } from \"./core\";\nimport { tick } from \"./processing\";\nimport { initializePersistence } from \"./persistence\";\nimport { createQueueManager } from \"./decorator\";\nimport { registerQueueRoutes } from \"./routes\";\n\nexport const queuesPlugin: FastifyPluginAsync<QueuePluginOptions> =\n fsPlugin(async (\n app: FastifyInstance,\n options: QueuePluginOptions\n ) => {\n const runtime: QueueRuntime = {\n config: mergeConfig(DEFAULT_CONFIG, options.config),\n queues: {},\n dirtyQueues: new Set<string>(),\n lastSavedAt: Date.now(),\n messageHistory: [],\n logging: app.logging,\n };\n\n // One timer for the entire plugin: every tickIntervalMs, check every\n // queue for batches/retries that are due, and save persistence if\n // its interval has elapsed. See processing.ts:tick.\n const tickIntervalId = setInterval(() => tick(runtime), runtime.config.tickIntervalMs);\n app.addHook('onClose', async () => clearInterval(tickIntervalId));\n\n app.decorate('queues', createQueueManager(runtime));\n registerQueueRoutes(app, options.prefix);\n\n await initializePersistence(runtime);\n });","import { EventHandler, QueueConfig, QueueMessage, QueueMessageHistoryEntry, QueueService, QueueSummary } from \"./types\";\n\nconst MAX_MESSAGE_HISTORY = 500;\n\n// default config\nexport const DEFAULT_CONFIG: QueueConfig = {\n batchSize: 10,\n batchWindowMs: 500,\n maxRetries: 3,\n parallel: true,\n maxConcurrent: 5,\n retryBackoff: true,\n tickIntervalMs: 50,\n persistence: {\n enabled: true,\n directory: './.develop/queue-data',\n saveInterval: 60000,\n saveOnShutdown: false\n }\n};\n\n// Pure function to merge configs\nexport const mergeConfig = (defaultConfig: QueueConfig, userConfig?: Partial<QueueConfig>): QueueConfig => ({\n ...defaultConfig,\n ...userConfig,\n persistence: {\n ...defaultConfig.persistence,\n ...(userConfig?.persistence || {})\n }\n});\n\n// Pure function to create a new queue service\nexport const createQueueService = (handler: EventHandler, module?: string): QueueService => ({\n handler,\n incoming: [],\n processing: [],\n dlq: [],\n processingBatch: false,\n module\n});\n\n// Pure function to create a queue message\nexport const createQueueMessage = (body: any, headers: Record<string, any>): QueueMessage => {\n const id = Date.now().toString() + Math.random().toString(36).substring(2, 7);\n const message: QueueMessage = {\n id,\n timestamp: new Date(),\n attempts: 0,\n payload: body,\n attributes: headers,\n };\n\n const delaySeconds = Number(headers?.['x-delay-seconds']);\n if (delaySeconds > 0) {\n message.nextAttempt = new Date(Date.now() + delaySeconds * 1000);\n }\n\n return message;\n};\n\n// Pure function to schedule a retry for a message\n// Puts a failed message back into `incoming` to wait out its backoff delay,\n// same as any delayed message - so the next batch dispatch picks it up\n// mixed in with whatever else is ready, instead of retrying it alone.\nexport const scheduleRetry = (queueService: QueueService, message: QueueMessage, delayMs: number): void => {\n removeFromProcessing(queueService, message.id);\n message.attempts += 1;\n message.nextAttempt = new Date(Date.now() + delayMs);\n queueService.incoming.push(message);\n};\n\n\n// Pure function to check whether a message is ready to be processed\nexport const isMessageReady = (message: QueueMessage, now: number = Date.now()): boolean => {\n return !message.nextAttempt || message.nextAttempt.getTime() <= now;\n};\n\n// Pure function to move ready messages from incoming to processing, leaving delayed messages in place\nexport const moveToProcessing = (queueService: QueueService, batchSize: number): QueueMessage[] => {\n const now = Date.now();\n const ready: QueueMessage[] = [];\n const remaining: QueueMessage[] = [];\n\n for (const message of queueService.incoming) {\n if (ready.length < batchSize && isMessageReady(message, now)) {\n ready.push(message);\n } else {\n remaining.push(message);\n }\n }\n\n queueService.incoming = remaining;\n return ready;\n};\n\n// Pure function to remove message from processing queue\nexport const removeFromProcessing = (queueService: QueueService, messageId: string): void => {\n queueService.processing = queueService.processing.filter(msg => msg.id !== messageId);\n};\n\n// Pure function to move message to DLQ\nexport const moveToDLQ = (queueService: QueueService, message: QueueMessage, error: string): void => {\n queueService.dlq.push({\n ...message,\n error,\n failedAt: new Date()\n });\n removeFromProcessing(queueService, message.id);\n};\n\n// Pure function to calculate backoff delay\nexport const calculateBackoffDelay = (attempts: number): number => {\n return Math.pow(2, attempts) * 100;\n};\n\n// Pure function to create queue summary\nexport const createQueueSummary = (queueService: QueueService, config: QueueConfig): QueueSummary => ({\n incoming: queueService.incoming.length,\n processing: queueService.processing.length,\n dlq: queueService.dlq.length,\n isProcessing: queueService.processingBatch,\n configuration: {\n batchSize: config.batchSize,\n batchWindowMs: config.batchWindowMs,\n parallel: config.parallel,\n maxConcurrent: config.maxConcurrent\n }\n});\n\n// Pure function to create dashboard summary\nexport const createDashboardSummary = (queues: Record<string, QueueService>, config: QueueConfig): Record<string, QueueSummary> => {\n return Object.entries(queues).reduce((summary, [queueName, queue]) => {\n summary[queueName] = createQueueSummary(queue, config);\n return summary;\n }, {} as Record<string, QueueSummary>);\n};\n\n// Pure function to move DLQ messages back to incoming\nexport const moveDLQToIncoming = (queueService: QueueService): number => {\n const dlqCount = queueService.dlq.length;\n\n if (dlqCount === 0) return 0;\n\n const movedMessages = queueService.dlq.map(message => ({\n ...message,\n attempts: 0,\n error: undefined,\n failedAt: undefined,\n reprocessed: true,\n originalId: message.id,\n id: Date.now().toString() + Math.random().toString(36).substring(2, 7)\n }));\n\n queueService.incoming.push(...movedMessages);\n queueService.dlq = [];\n\n return dlqCount;\n};\n\n// Pure function to purge DLQ\nexport const purgeDLQ = (queueService: QueueService): number => {\n const dlqCount = queueService.dlq.length;\n queueService.dlq = [];\n return dlqCount;\n};\n\n// Pure function to build a message-history record for a completed or\n// terminally-failed message. This is what powers the dev console's\n// per-queue history view for messages that already left incoming/processing/dlq.\nexport const createHistoryEntry = (\n queueName: string,\n message: QueueMessage,\n status: 'completed' | 'failed',\n error?: string\n): QueueMessageHistoryEntry => ({\n id: message.id,\n queueName,\n status,\n timestamp: message.timestamp,\n completedAt: new Date(),\n attempts: message.attempts,\n payload: message.payload,\n attributes: message.attributes,\n error,\n});\n\n// Appends to the bounded history log in place, mirroring schedule-plugin's\n// executionHistory cap so long-running processes don't grow this unbounded.\nexport const recordMessageHistory = (\n history: QueueMessageHistoryEntry[],\n entry: QueueMessageHistoryEntry\n): void => {\n history.push(entry);\n if (history.length > MAX_MESSAGE_HISTORY) {\n history.splice(0, history.length - MAX_MESSAGE_HISTORY);\n }\n};","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\n\nimport { QueueService, QueueRuntime, QueueMessage } from \"./types\";\n\nconst createQueueData = (queueService: QueueService) => ({\n incoming: queueService.incoming,\n processing: queueService.processing,\n dlq: queueService.dlq,\n savedAt: new Date()\n});\n\nconst restoreDates = (messages: QueueMessage[]): void => {\n messages.forEach((msg: QueueMessage) => {\n msg.timestamp = new Date(msg.timestamp);\n if (msg.nextAttempt) msg.nextAttempt = new Date(msg.nextAttempt);\n if (msg.failedAt) msg.failedAt = new Date(msg.failedAt);\n });\n};\n\nexport const saveQueueState = async (runtime: QueueRuntime, queueName: string, queueService: QueueService): Promise<void> => {\n try {\n const queueData = createQueueData(queueService);\n const now = Date.now();\n const queueFilePath = path.join(runtime.config.persistence.directory, `${queueName}.json`);\n const tempFilePath = path.join(runtime.config.persistence.directory, `${queueName}.${now}temp.json`);\n\n // Write to a temp file first, then rename - rename is atomic, so a\n // reader never sees a half-written file.\n await fs.writeFile(tempFilePath, JSON.stringify(queueData, null, 2), 'utf8');\n await fs.rename(tempFilePath, queueFilePath);\n\n runtime.logging.debug({ module: queueService.module }, `Queue state saved: ${queueName}`);\n } catch (error: any) {\n runtime.logging.error(\n { module: queueService.module, error: error?.message },\n `Failed to save queue state for ${queueName}`\n );\n }\n};\n\nexport const saveAllQueueStates = async (runtime: QueueRuntime): Promise<void> => {\n try {\n for (const [queueName, queueService] of Object.entries(runtime.queues)) {\n await saveQueueState(runtime, queueName, queueService);\n }\n runtime.logging.debug(`All queue states saved to ${runtime.config.persistence.directory}`);\n } catch (error: any) {\n runtime.logging.error({ error: error?.message }, `Failed to save all queue states`);\n }\n};\n\n// Only saves queues that changed since the last save (tracked via\n// runtime.dirtyQueues). Called from processing.ts's tick once\n// persistence.saveInterval has elapsed.\nexport const saveDirtyQueueStates = async (runtime: QueueRuntime): Promise<void> => {\n if (runtime.dirtyQueues.size === 0) return;\n\n try {\n const queueNames = [...runtime.dirtyQueues];\n runtime.dirtyQueues.clear();\n\n for (const queueName of queueNames) {\n if (runtime.queues[queueName]) {\n await saveQueueState(runtime, queueName, runtime.queues[queueName]);\n }\n }\n } catch (error: any) {\n runtime.logging.error({ error: error?.message }, `Failed to save dirty queue states`);\n }\n};\n\n// Called from addQueue, right after a queue is registered, to restore\n// whatever was on disk for it from a previous run.\nexport const loadQueueState = async (runtime: QueueRuntime, queueName: string): Promise<void> => {\n try {\n const queueService = runtime.queues[queueName];\n if (!queueService) {\n runtime.logging.warn(`Skipping load for non-existent queue: ${queueName}`);\n return;\n }\n\n const queueFilePath = path.join(runtime.config.persistence.directory, `${queueName}.json`);\n\n try {\n const data = await fs.readFile(queueFilePath, 'utf8');\n const queueData = JSON.parse(data);\n\n restoreDates(queueData.incoming);\n restoreDates(queueData.processing);\n restoreDates(queueData.dlq);\n\n queueService.incoming = queueData.incoming;\n queueService.dlq = queueData.dlq;\n queueService.processing = [];\n\n // Nothing is actually in flight right after a restart - anything\n // that was mid-handling goes back into the ready pool like any\n // other message (the tick's next batch picks it up), or straight\n // to the DLQ if it had already used up its retries before the\n // shutdown.\n for (const message of queueData.processing as QueueMessage[]) {\n if (message.attempts >= runtime.config.maxRetries) {\n queueService.dlq.push({ ...message, error: 'max retries exceeded before restart', failedAt: new Date() });\n } else {\n message.nextAttempt = new Date();\n queueService.incoming.push(message);\n }\n }\n\n runtime.logging.debug(\n { module: queueService.module },\n `Queue state loaded: ${queueName} (saved at ${queueData.savedAt})`\n );\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n runtime.logging.debug({ module: queueService.module }, `No saved state found for queue: ${queueName}`);\n } else {\n throw error;\n }\n }\n } catch (error: any) {\n runtime.logging.error({ error: error?.message }, `Failed to load queue state for ${queueName}`);\n }\n};\n\nexport const initializePersistence = async (runtime: QueueRuntime): Promise<void> => {\n try {\n await fs.mkdir(runtime.config.persistence.directory, { recursive: true });\n\n if (runtime.config.persistence.saveOnShutdown) {\n const shutdownHandler = async () => {\n runtime.logging.debug('Saving queue state before shutdown...');\n await saveAllQueueStates(runtime);\n process.exit(0);\n };\n\n process.on('SIGINT', shutdownHandler);\n process.on('SIGTERM', shutdownHandler);\n }\n\n runtime.logging.debug(`Queue persistence initialized: ${runtime.config.persistence.directory}`);\n } catch (error: any) {\n runtime.logging.error({ error: error?.message }, `Failed to initialize queue persistence`);\n }\n};","import { QueueMessage, QueueService, QueueRuntime } from \"./types\";\nimport {\n isMessageReady,\n moveToProcessing,\n removeFromProcessing,\n moveToDLQ,\n scheduleRetry,\n calculateBackoffDelay,\n createHistoryEntry,\n recordMessageHistory,\n} from \"./core\";\nimport { saveDirtyQueueStates } from \"./persistence\";\n\n// Sends one message through the user's handler. Success removes it from\n// `processing`; failure either schedules a retry or moves it to the DLQ.\n// Used for both freshly-batched messages and individually-retried ones.\n// Wrapped in runWithLogContext by processBatch, so every log call below\n// (and anything the user's handler itself logs) carries this message's\n// module/reqId without having to pass them through explicitly.\nconst processMessage = async (\n runtime: QueueRuntime,\n queueName: string,\n message: QueueMessage,\n queueService: QueueService\n): Promise<void> => {\n try {\n const result = await queueService.handler(message);\n if (result?.failureId) {\n handleFailure(runtime, queueName, message, queueService);\n } else {\n removeFromProcessing(queueService, message.id);\n recordMessageHistory(runtime.messageHistory, createHistoryEntry(queueName, message, 'completed'));\n runtime.logging.debug(`Successfully processed message ${message.id} in queue ${queueName}`);\n }\n } catch {\n handleFailure(runtime, queueName, message, queueService);\n }\n};\n\nconst handleFailure = (\n runtime: QueueRuntime,\n queueName: string,\n message: QueueMessage,\n queueService: QueueService\n): void => {\n runtime.logging.error(`Error processing message ${message.id} in queue ${queueName}: handler returned failure`);\n\n if (message.attempts >= runtime.config.maxRetries) {\n moveToDLQ(queueService, message, 'max retries exceeded');\n recordMessageHistory(runtime.messageHistory, createHistoryEntry(queueName, message, 'failed', 'max retries exceeded'));\n return;\n }\n\n const delayMs = runtime.config.retryBackoff ? calculateBackoffDelay(message.attempts + 1) : 0;\n scheduleRetry(queueService, message, delayMs);\n runtime.logging.debug(`Scheduling retry for message ${message.id} in ${delayMs}ms`);\n};\n\n// Pulls up to batchSize ready messages out of `incoming` and runs them\n// through processMessage concurrently. Guarded by `processingBatch` so the\n// tick never starts a second batch for a queue while one is still running.\nconst processBatch = async (\n runtime: QueueRuntime,\n queueName: string,\n queueService: QueueService\n): Promise<void> => {\n if (queueService.processingBatch) {\n return;\n }\n\n try {\n queueService.processingBatch = true;\n\n const messagesToProcess = moveToProcessing(queueService, runtime.config.batchSize);\n if (messagesToProcess.length === 0) {\n return;\n }\n\n queueService.processing.push(...messagesToProcess);\n\n await Promise.all(\n messagesToProcess.map(message => runtime.logging.runWithLogContext(\n { module: queueService.module, reqId: message.id },\n () => processMessage(runtime, queueName, message, queueService)\n ))\n );\n\n if (runtime.config.persistence.enabled) {\n runtime.dirtyQueues.add(queueName);\n }\n } finally {\n queueService.processingBatch = false;\n }\n};\n\nconst dispatchBatchIfDue = (\n runtime: QueueRuntime,\n queueName: string,\n queueService: QueueService,\n now: number\n): void => {\n if (queueService.processingBatch) {\n return;\n }\n const ready = queueService.incoming.filter(message => isMessageReady(message, now));\n if (ready.length === 0) {\n return;\n }\n\n const dueBySize = ready.length >= runtime.config.batchSize;\n const oldestReadyAge = now - Math.min(...ready.map(message => message.timestamp.getTime()));\n const dueByWindow = oldestReadyAge >= runtime.config.batchWindowMs;\n\n if (dueBySize || dueByWindow) {\n processBatch(runtime, queueName, queueService);\n }\n};\n\nconst maybeSavePersistence = (runtime: QueueRuntime, now: number): void => {\n if (!runtime.config.persistence.enabled) {\n return;\n }\n\n const saveInterval = runtime.config.persistence.saveInterval ?? 0;\n if (saveInterval > 0 && now - runtime.lastSavedAt >= saveInterval) {\n runtime.lastSavedAt = now;\n saveDirtyQueueStates(runtime);\n }\n};\n\n\n// The one timer for the whole plugin. Every tickIntervalMs: for every queue,\n// dispatch a batch if one is due (this is also how retried messages get\n// picked up - they wait in `incoming` like any delayed message); then save\n// persistence if its interval has elapsed.\nexport const tick = (runtime: QueueRuntime): void => {\n const now = Date.now();\n for (const [queueName, queueService] of Object.entries(runtime.queues)) {\n dispatchBatchIfDue(runtime, queueName, queueService, now);\n }\n maybeSavePersistence(runtime, now);\n};","import { QueueService, QueueManager, QueueRuntime, EventHandler } from \"./types\";\nimport {\n createQueueService,\n createQueueMessage,\n createDashboardSummary,\n createQueueSummary,\n moveDLQToIncoming,\n purgeDLQ,\n} from \"./core\";\nimport { loadQueueState, saveQueueState } from \"./persistence\";\n\nconst isValidQueueName = (queueName: string): boolean => {\n return typeof queueName === 'string' && queueName.length > 0 && /^[a-zA-Z0-9_-]+$/.test(queueName);\n};\n\nconst validateQueueName = (queueName: string): void => {\n if (!queueName || typeof queueName !== 'string') {\n throw new Error('Queue name must be a non-empty string');\n }\n\n if (!isValidQueueName(queueName)) {\n throw new Error('Queue name must contain only alphanumeric characters, hyphens, and underscores');\n }\n};\n\nconst validateHandler = (handler: any): void => {\n if (typeof handler !== 'function') {\n throw new Error('Handler must be a function');\n }\n};\n\nexport const addQueue = async (runtime: QueueRuntime, queueName: string, handler: EventHandler, module?: string): Promise<void> => {\n try {\n validateQueueName(queueName);\n validateHandler(handler);\n\n if (runtime.queues[queueName]) {\n runtime.logging.warn({ module }, `Queue already exists: ${queueName}.`);\n return;\n }\n\n runtime.queues[queueName] = createQueueService(handler, module);\n\n if (runtime.config.persistence.enabled) {\n await loadQueueState(runtime, queueName);\n }\n\n runtime.logging.info({ module }, `Queue added: ${queueName}`);\n } catch (error: any) {\n runtime.logging.error({ module, error: error.message }, `Failed to add queue ${queueName}`);\n throw error;\n }\n};\n\nexport const removeQueue = async (runtime: QueueRuntime, queueName: string): Promise<void> => {\n try {\n validateQueueName(queueName);\n\n const queueService = runtime.queues[queueName];\n if (!queueService) {\n throw new Error(`Queue '${queueName}' does not exist`);\n }\n\n const totalMessages = queueService.incoming.length + queueService.processing.length;\n if (totalMessages > 0) {\n runtime.logging.warn(\n { module: queueService.module },\n `Removing queue with ${totalMessages} pending messages: ${queueName}`\n );\n }\n\n if (runtime.config.persistence.enabled) {\n await saveQueueState(runtime, queueName, queueService);\n }\n\n delete runtime.queues[queueName];\n\n runtime.logging.info({ module: queueService.module }, `Queue removed: ${queueName}`);\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to remove queue ${queueName}`);\n throw error;\n }\n};\n\nexport const hasQueue = (runtime: QueueRuntime, queueName: string): boolean => {\n try {\n validateQueueName(queueName);\n return queueName in runtime.queues;\n } catch {\n return false;\n }\n};\n\nexport const listQueues = (runtime: QueueRuntime, module?: string): string[] => {\n return Object.keys(runtime.queues)\n .filter(queueName => !module || runtime.queues[queueName].module === module)\n .sort();\n};\n\nexport const getQueueStats = (runtime: QueueRuntime, queueName: string): QueueService | null => {\n try {\n validateQueueName(queueName);\n return runtime.queues[queueName] || null;\n } catch {\n return null;\n }\n};\n\nexport const getQueuesMap = (runtime: QueueRuntime): Record<string, QueueService> => {\n // Return a copy to prevent external modification\n return { ...runtime.queues };\n};\n\nexport const getDashboardSummary = (runtime: QueueRuntime) =>\n createDashboardSummary(runtime.queues, runtime.config);\n\nexport const getQueueSummary = (runtime: QueueRuntime, queueName: string) => {\n const queue = runtime.queues[queueName];\n if (!queue) {\n return null;\n }\n\n return {\n stats: createQueueSummary(queue, runtime.config),\n messages: {\n incoming: queue.incoming,\n processing: queue.processing,\n dlq: queue.dlq\n }\n };\n};\n\nexport const enqueueMessage = async (runtime: QueueRuntime, queueName: string, body: any, attributes: any) => {\n const queueService = runtime.queues[queueName];\n if (!queueService) {\n return null;\n }\n\n const message = createQueueMessage(body, attributes);\n queueService.incoming.push(message);\n\n if (runtime.config.persistence.enabled) {\n runtime.dirtyQueues.add(queueName);\n }\n\n return { id: message.id, queueName };\n};\n\nexport const processDlq = async (runtime: QueueRuntime, queueName: string) => {\n const queueService = runtime.queues[queueName];\n if (!queueService) {\n return null;\n }\n\n const processedCount = moveDLQToIncoming(queueService);\n if (processedCount === 0) {\n return { status: \"success\", message: \"No messages in DLQ to process\", processed: 0 };\n }\n\n runtime.logging.warn(\n { module: queueService.module },\n `Moving ${processedCount} messages from DLQ for ${queueName}`\n );\n\n if (runtime.config.persistence.enabled) {\n runtime.dirtyQueues.add(queueName);\n }\n\n return {\n status: \"success\",\n message: `Moved ${processedCount} messages from DLQ to processing queue`,\n processed: processedCount\n };\n};\n\nexport const purgeDlq = async (runtime: QueueRuntime, queueName: string) => {\n const queueService = runtime.queues[queueName];\n if (!queueService) {\n return null;\n }\n\n const purgedCount = purgeDLQ(queueService);\n if (purgedCount === 0) {\n return { status: \"success\", message: \"No messages in DLQ to purge\", purged: 0 };\n }\n\n runtime.logging.warn(\n { module: queueService.module },\n `Purging ${purgedCount} messages from DLQ for ${queueName}`\n );\n\n if (runtime.config.persistence.enabled) {\n runtime.dirtyQueues.add(queueName);\n }\n\n return {\n status: \"success\",\n message: `Purged ${purgedCount} messages from DLQ`,\n purged: purgedCount\n };\n};\n\nexport const getMessageHistory = (runtime: QueueRuntime, queueName: string, limit = 50) => {\n return runtime.messageHistory\n .filter(entry => entry.queueName === queueName)\n .slice(-limit)\n .reverse();\n};\n\n// The one place runtime gets bound into the public app.queues shape -\n// Fastify needs a plain object of methods with no runtime param, so this\n// wraps each plain function above with `runtime` pre-applied. Everything\n// above this line is a normal function you can call directly with an\n// explicit runtime, e.g. in tests.\nexport const createQueueManager = (runtime: QueueRuntime): QueueManager => ({\n addQueue: (queueName, handler, module) => addQueue(runtime, queueName, handler, module),\n removeQueue: (queueName) => removeQueue(runtime, queueName),\n hasQueue: (queueName) => hasQueue(runtime, queueName),\n listQueues: (module) => listQueues(runtime, module),\n getQueueStats: (queueName) => getQueueStats(runtime, queueName),\n getQueuesMap: () => getQueuesMap(runtime),\n getConfig: () => runtime.config,\n getDashboardSummary: () => getDashboardSummary(runtime),\n getQueueSummary: (queueName) => getQueueSummary(runtime, queueName),\n enqueueMessage: (queueName, body, attributes) => enqueueMessage(runtime, queueName, body, attributes),\n processDlq: (queueName) => processDlq(runtime, queueName),\n purgeDlq: (queueName) => purgeDlq(runtime, queueName),\n getMessageHistory: (queueName, limit) => getMessageHistory(runtime, queueName, limit),\n});","import { FastifyInstance, FastifyReply, FastifyRequest } from \"fastify\";\n\n// Function to register all routes\nexport const registerQueueRoutes = (\n app: FastifyInstance,\n prefix: string = \"\"\n): void => {\n app.get(`/${prefix}/dashboard`,\n async (_: FastifyRequest, reply: FastifyReply) => {\n const summary = app.queues.getDashboardSummary();\n return reply.status(200).send(summary);\n });\n\n app.get<{ Params: { queue: string } }>(`/${prefix}/:queue`,\n async (request: FastifyRequest<{ Params: { queue: string } }>, reply: FastifyReply) => {\n const queueName = request.params.queue;\n const summary = app.queues.getQueueSummary(queueName);\n if (summary === null) {\n return reply.status(404).send({ error: \"Queue not found\" });\n }\n return reply.status(200).send(summary);\n });\n\n app.post<{ Params: { queue: string }; Body: any }>(`/${prefix}/:queue`,\n async (request: FastifyRequest<{ Params: { queue: string }; Body: any }>, reply: FastifyReply) => {\n const queueName = request.params.queue;\n const result = await app.queues.enqueueMessage(queueName, request.body, request.headers as Record<string, any>);\n if (result === null) {\n return reply.status(404).send({ error: \"Queue not found\" });\n }\n return reply.status(200).send(result);\n });\n\n app.get<{ Params: { queue: string } }>(`/${prefix}/:queue/process-dlq`,\n async (request: FastifyRequest<{ Params: { queue: string } }>, reply: FastifyReply) => {\n const queueName = request.params.queue;\n const result = await app.queues.processDlq(queueName);\n if (result === null) {\n return reply.status(404).send(result);\n }\n return reply.status(200).send(result);\n });\n\n app.post<{ Params: { queue: string } }>(`/${prefix}/:queue/purge-dlq`,\n async (request: FastifyRequest<{ Params: { queue: string } }>, reply: FastifyReply) => {\n const queueName = request.params.queue;\n const result = await app.queues.purgeDlq(queueName);\n if (result === null) {\n return reply.status(404).send({ error: \"Queue not found\" });\n }\n return reply.status(200).send(result);\n });\n};","import { FastifyInstance, FastifyPluginAsync } from \"fastify\";\nimport fsPlugin from \"fastify-plugin\";\n\nimport { SchedulerPluginOptions, SchedulerRuntime } from \"./types\";\nimport { DEFAULT_CONFIG, mergeConfig } from \"./core\";\nimport { tick } from \"./processing\";\nimport { initializePersistence } from \"./persistence\";\nimport { createSchedulerManager } from \"./decorator\";\nimport { registerSchedulerRoutes } from \"./routes\";\n\nexport const schedulerPlugin: FastifyPluginAsync<SchedulerPluginOptions> =\n fsPlugin(async (\n app: FastifyInstance,\n options: SchedulerPluginOptions\n ) => {\n const runtime: SchedulerRuntime = {\n config: mergeConfig(DEFAULT_CONFIG, options.config),\n schedulers: {},\n executions: {},\n executionHistory: [],\n isShuttingDown: false,\n runningExecutions: 0,\n isDirty: false,\n lastCleanupTime: Date.now(),\n lastSavedAt: Date.now(),\n lastRestartTime: new Date(),\n logging: app.logging,\n };\n\n // One timer for the entire plugin: every tickIntervalMs, run any job\n // that's due, then clean up old execution history / save persistence\n // once their own intervals have elapsed. See processing.ts:tick.\n const tickIntervalId = setInterval(() => tick(runtime), runtime.config.tickIntervalMs);\n app.addHook('onClose', async () => {\n runtime.isShuttingDown = true;\n clearInterval(tickIntervalId);\n });\n\n app.decorate('scheduler', createSchedulerManager(runtime));\n registerSchedulerRoutes(app, options.prefix);\n\n if (runtime.config.persistence.enabled) {\n await initializePersistence(runtime);\n }\n });\n","import { parseExpression } from 'cron-parser';\n\n/**\n * Professional cron parser using cron-parser library\n * \n * Installation:\n * npm install cron-parser\n * npm install -D @types/cron-parser\n */\n\ninterface CronParseOptions {\n preserveNaturalTiming?: boolean;\n timezone?: string;\n utc?: boolean;\n currentDate?: Date;\n endDate?: Date;\n iterator?: boolean;\n}\n\ninterface CronParseResult {\n nextRun: Date;\n isValid: boolean;\n error?: string;\n pattern?: string;\n description?: string;\n}\n\n/**\n * Parse cron expression and get next execution time\n */\nexport function parseCronExpression(\n cronExpression: string,\n lastRun?: Date,\n options: CronParseOptions = {}\n): CronParseResult {\n const {\n preserveNaturalTiming = true,\n timezone,\n utc = false,\n currentDate\n } = options;\n\n try {\n // Validate and normalize cron expression\n const normalizedCron = normalizeCronExpression(cronExpression);\n\n const parseOptions: any = {\n tz: timezone,\n utc: utc,\n currentDate: currentDate ?? new Date()\n };\n\n // Use lastRun for baseline if preserving natural timing\n if (preserveNaturalTiming && lastRun) {\n parseOptions.currentDate = lastRun;\n }\n\n const interval = parseExpression(normalizedCron, parseOptions);\n let nextRun = interval.next().toDate();\n\n // Ensure next run is in the future\n const now = new Date();\n while (nextRun <= now) {\n nextRun = interval.next().toDate();\n }\n\n return {\n nextRun,\n isValid: true,\n pattern: normalizedCron,\n description: describeCronExpression(normalizedCron)\n };\n\n } catch (error: any) {\n // Fallback to a safe default (every hour) - the caller gets the\n // failure via `isValid`/`error` on the returned result, so it can\n // log with whatever module context it has; this module has none.\n const fallbackTime = new Date();\n fallbackTime.setHours(fallbackTime.getHours() + 1);\n fallbackTime.setMinutes(0);\n fallbackTime.setSeconds(0);\n fallbackTime.setMilliseconds(0);\n\n return {\n nextRun: fallbackTime,\n isValid: false,\n error: error.message,\n pattern: cronExpression\n };\n }\n}\n\n/**\n * Get multiple next execution times\n */\nexport function getNextExecutions(\n cronExpression: string,\n count: number = 5,\n options: CronParseOptions = {}\n): Date[] {\n try {\n const normalizedCron = normalizeCronExpression(cronExpression);\n const parseOptions: any = {\n tz: options.timezone,\n utc: options.utc ?? false,\n currentDate: options.currentDate ?? new Date()\n };\n\n const interval = parseExpression(normalizedCron, parseOptions);\n const executions: Date[] = [];\n\n for (let i = 0; i < count; i++) {\n executions.push(interval.next().toDate());\n }\n\n return executions;\n } catch {\n return [];\n }\n}\n\n/**\n * Validate if a cron expression is valid\n */\nexport function validateCronExpression(cronExpression: string): boolean {\n try {\n const normalized = normalizeCronExpression(cronExpression);\n parseExpression(normalized);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Normalize cron expressions to handle different formats\n */\nfunction normalizeCronExpression(cronExpression: string): string {\n const parts = cronExpression.trim().split(/\\s+/);\n\n // Handle different cron formats\n if (parts.length === 5) {\n // Standard 5-field format: minute hour day month dayOfWeek\n return cronExpression;\n } else if (parts.length === 6) {\n // 6-field format with seconds: second minute hour day month dayOfWeek\n return cronExpression;\n } else if (parts.length === 7) {\n // 7-field format with year: second minute hour day month dayOfWeek year\n return cronExpression;\n } else {\n throw new Error(`Invalid cron format: expected 5, 6, or 7 fields, got ${parts.length}`);\n }\n}\n\n/**\n * Provide human-readable description of cron expression\n */\nfunction describeCronExpression(cronExpression: string): string {\n const parts = cronExpression.split(' ');\n\n // Handle common patterns\n const patterns: Record<string, string> = {\n '*/5 * * * *': 'Every 5 minutes',\n '0 * * * *': 'Every hour at minute 0',\n '0 */2 * * *': 'Every 2 hours',\n '0 0 * * *': 'Daily at midnight',\n '0 6 * * *': 'Daily at 6:00 AM',\n '0 0 * * 0': 'Weekly on Sunday at midnight',\n '0 0 1 * *': 'Monthly on the 1st at midnight',\n '0 0 1 1 *': 'Yearly on January 1st at midnight'\n };\n\n if (patterns[cronExpression]) {\n return patterns[cronExpression];\n }\n\n // Basic description for other patterns\n if (parts.length >= 5) {\n const [minute, hour, day, month, dayOfWeek] = parts;\n\n let description = 'Runs ';\n\n if (minute.includes('*/')) {\n const interval = minute.split('*/')[1];\n description += `every ${interval} minutes`;\n } else if (minute === '*') {\n description += 'every minute';\n } else {\n description += `at minute ${minute}`;\n }\n\n if (hour.includes('*/')) {\n const interval = hour.split('*/')[1];\n description += `, every ${interval} hours`;\n } else if (hour !== '*') {\n description += `, at hour ${hour}`;\n }\n\n if (day !== '*') {\n description += `, on day ${day}`;\n }\n\n if (month !== '*') {\n description += `, in month ${month}`;\n }\n\n if (dayOfWeek !== '*') {\n const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\n const dayNames = dayOfWeek.split(',').map(d => days[parseInt(d)] || d).join(', ');\n description += `, on ${dayNames}`;\n }\n\n return description;\n }\n\n return 'Custom schedule';\n}\n\n/**\n * Calculate time until next execution\n */\nexport function timeUntilNextExecution(cronExpression: string, timezone?: string): number {\n const result = parseCronExpression(cronExpression, undefined, { timezone });\n if (!result.isValid) {\n return -1;\n }\n\n return result.nextRun.getTime() - Date.now();\n}\n\n/**\n * Check if a time matches a cron expression\n */\nexport function doesTimeMatchCron(cronExpression: string, date: Date, timezone?: string): boolean {\n try {\n const normalizedCron = normalizeCronExpression(cronExpression);\n const parseOptions: any = {\n tz: timezone,\n currentDate: date\n };\n\n const interval = parseExpression(normalizedCron, parseOptions);\n const nextExecution = interval.next().toDate();\n\n // Check if the date is very close to the next execution (within 1 minute)\n const timeDiff = Math.abs(nextExecution.getTime() - date.getTime());\n return timeDiff < 60000; // 1 minute tolerance\n } catch {\n return false;\n }\n}\n\n/**\n * Detect the type of scheduling expression\n */\nexport function detectExpressionType(expression: string | undefined): 'cron' | 'rate' | 'unknown' {\n if (!expression || typeof expression !== 'string') {\n return 'unknown';\n }\n const trimmedExpression = expression.trim();\n\n // Check for AWS rate expression pattern\n // Format: \"rate(value unit)\" where unit can be minute(s), hour(s), day(s)\n const ratePattern = /^rate\\(\\s*(\\d+)\\s+(minute|minutes|hour|hours|day|days)\\s*\\)$/i;\n if (ratePattern.test(trimmedExpression)) {\n return 'rate';\n }\n\n // Check for cron expression pattern\n // Should have 5, 6, or 7 space-separated fields\n const cronParts = trimmedExpression.split(/\\s+/);\n if (cronParts.length >= 5 && cronParts.length <= 7) {\n // Additional validation: check if parts contain valid cron characters\n const cronCharPattern = /^[\\d\\*\\-\\,\\/\\?\\#LW]+$/;\n const validCronParts = cronParts.every(part => cronCharPattern.test(part) || part === '*');\n\n if (validCronParts) {\n return 'cron';\n }\n }\n\n return 'unknown';\n}\n\n/**\n * Convert AWS rate expression to cron expression\n * \n * AWS Rate expressions format: rate(value unit)\n * Examples:\n * - rate(5 minutes) -> *\\/5 * * * *\n * - rate(1 hour) -> 0 * * * *\n * - rate(2 hours) -> 0 *\\/2 * * *\n * - rate(1 day) -> 0 0 * * *\n * - rate(7 days) -> 0 0 *\\/7 * *\n*/\nexport function convertRateToCron(rateExpression: string): {\n cronExpression: string;\n isValid: boolean;\n error?: string;\n originalRate: string;\n description: string;\n} {\n const trimmedExpression = rateExpression.trim();\n\n // Parse rate expression\n const ratePattern = /^rate\\(\\s*(\\d+)\\s+(minute|minutes|hour|hours|day|days)\\s*\\)$/i;\n const match = trimmedExpression.match(ratePattern);\n\n if (!match) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Invalid rate expression format. Expected: rate(value unit)',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n const value = parseInt(match[1]);\n const unit = match[2].toLowerCase();\n\n // Validate value\n if (value <= 0) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Rate value must be greater than 0',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n let cronExpression = '';\n let description = '';\n\n try {\n switch (unit) {\n case 'minute':\n case 'minutes':\n if (value > 59) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Minutes value cannot exceed 59. Use hours for longer intervals.',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n if (value === 1) {\n cronExpression = '* * * * *';\n description = 'Every minute';\n } else {\n cronExpression = `*/${value} * * * *`;\n description = `Every ${value} minutes`;\n }\n break;\n\n case 'hour':\n case 'hours':\n if (value > 23) {\n // For hours > 23, convert to days if evenly divisible by 24\n if (value % 24 === 0) {\n const days = value / 24;\n cronExpression = `0 0 */${days} * *`;\n description = `Every ${days} day${days > 1 ? 's' : ''}`;\n } else {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Hours value greater than 23 must be divisible by 24, or use days unit.',\n originalRate: rateExpression,\n description: ''\n };\n }\n } else if (value === 1) {\n cronExpression = '0 * * * *';\n description = 'Every hour';\n } else {\n cronExpression = `0 */${value} * * *`;\n description = `Every ${value} hours`;\n }\n break;\n\n case 'day':\n case 'days':\n if (value > 365) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Days value cannot exceed 365',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n if (value === 1) {\n cronExpression = '0 0 * * *';\n description = 'Every day (daily)';\n } else if (value === 7) {\n cronExpression = '0 0 * * 0';\n description = 'Every 7 days (weekly)';\n } else if (value <= 31) {\n cronExpression = `0 0 */${value} * *`;\n description = `Every ${value} days`;\n } else {\n // For large day intervals, we need to be more careful\n // This is an approximation since months have different lengths\n cronExpression = `0 0 */${value} * *`;\n description = `Every ${value} days (approximate)`;\n }\n break;\n\n default:\n return {\n cronExpression: '',\n isValid: false,\n error: `Unsupported time unit: ${unit}. Use minute(s), hour(s), or day(s).`,\n originalRate: rateExpression,\n description: ''\n };\n }\n\n // Validate the generated cron expression\n if (!validateCronExpression(cronExpression)) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Generated cron expression is invalid',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n return {\n cronExpression,\n isValid: true,\n originalRate: rateExpression,\n description\n };\n\n } catch (error: any) {\n return {\n cronExpression: '',\n isValid: false,\n error: `Conversion error: ${error.message}`,\n originalRate: rateExpression,\n description: ''\n };\n }\n}","import { ScheduledJob, SchedulerConfig } from \"./types\";\nimport { parseCronExpression } from \"./cron-utils\";\n\nexport const generateJobId = (): string =>\n `job_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\nexport const generateExecutionId = (): string =>\n `exec_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\nexport const calculateNextRun = (\n job: ScheduledJob,\n preserveNaturalTiming: boolean = true\n): Date => {\n const now = new Date();\n\n if (job.cronExpression) {\n const result = parseCronExpression(job.cronExpression, job.lastRun, {\n preserveNaturalTiming,\n timezone: job.timezone,\n currentDate: preserveNaturalTiming && job.lastRun ? job.lastRun : now\n });\n return result.nextRun;\n }\n\n if (job.intervalMs) {\n return new Date(now.getTime() + job.intervalMs);\n }\n\n if (job.delayMs) {\n return new Date(now.getTime() + job.delayMs);\n }\n\n // Default: 1 hour\n return new Date(now.getTime() + 3600000);\n};\n\nexport const calculateNextRunFromLastRun = (\n job: ScheduledJob,\n lastRun: Date | undefined,\n config: SchedulerConfig\n): Date => {\n const now = new Date();\n\n if (job.cronExpression) {\n const result = parseCronExpression(job.cronExpression, lastRun, {\n preserveNaturalTiming: config.restartBehavior.preserveNaturalTiming,\n timezone: job.timezone ?? config.cron.defaultTimezone\n });\n return result.nextRun;\n }\n\n if (job.intervalMs && lastRun) {\n let nextRun = new Date(lastRun.getTime() + job.intervalMs);\n\n if (config.restartBehavior.skipMissedRuns) {\n while (nextRun <= now) {\n nextRun = new Date(nextRun.getTime() + job.intervalMs);\n }\n } else {\n if (nextRun <= now) {\n nextRun = new Date(now.getTime() + job.intervalMs);\n }\n }\n\n return nextRun;\n }\n\n return calculateNextRun(job, config.restartBehavior.preserveNaturalTiming);\n};\n\nexport const hasJobDefinitionChanged = (currentJob: ScheduledJob, savedJob: any): boolean => (\n currentJob.cronExpression !== savedJob.cronExpression ||\n currentJob.intervalMs !== savedJob.intervalMs ||\n currentJob.delayMs !== savedJob.delayMs ||\n currentJob.maxRuns !== savedJob.maxRuns ||\n currentJob.timezone !== savedJob.timezone\n);\n\nexport const shouldSkipJob = (job: ScheduledJob): boolean => {\n if (!job.enabled) return true;\n if (job.maxRuns && job.runCount >= job.maxRuns) return true;\n return false;\n};\n\nexport const isJobReadyToRun = (job: ScheduledJob): boolean => {\n const now = new Date();\n return job.nextRun.getTime() <= now.getTime();\n};\n\nexport const getTimeUntilNextRun = (job: ScheduledJob): number =>\n Math.max(0, job.nextRun.getTime() - Date.now());","import { SchedulerConfig, SchedulerDashboardJob, SchedulerRuntime } from \"./types\";\nimport { getNextExecutions, parseCronExpression } from \"./cron-utils\";\nimport { getTimeUntilNextRun } from \"./utils\";\n\n// default config\nexport const DEFAULT_CONFIG: SchedulerConfig = {\n tickIntervalMs: 1000,\n persistence: {\n enabled: true,\n directory: './.develop/scheduler-data',\n saveInterval: 30000, // 30 seconds\n saveOnShutdown: false,\n },\n execution: {\n maxConcurrent: 5,\n defaultTimeout: 300000, // 5 minutes\n },\n cleanup: {\n maxExecutionHistory: 1000,\n cleanupInterval: 600000, // 10 minutes\n },\n restartBehavior: {\n preserveNaturalTiming: true,\n skipMissedRuns: true,\n maxTimingDrift: 60000, // 1 minute\n rapidRestartThreshold: 10000, // 10 seconds\n },\n cron: {\n defaultTimezone: undefined, // Use system timezone\n logCronDetails: true,\n },\n};\n\n// Pure function to merge configs\nexport const mergeConfig = (defaultConfig: SchedulerConfig, userConfig?: Partial<SchedulerConfig>): SchedulerConfig => ({\n ...defaultConfig,\n ...userConfig,\n persistence: { ...defaultConfig.persistence, ...userConfig?.persistence },\n execution: { ...defaultConfig.execution, ...userConfig?.execution },\n cleanup: { ...defaultConfig.cleanup, ...userConfig?.cleanup },\n restartBehavior: { ...defaultConfig.restartBehavior, ...userConfig?.restartBehavior },\n cron: { ...defaultConfig.cron, ...userConfig?.cron },\n});\n\n// Pure function to build the dashboard view of every job\nexport const createDashboardSummary = (runtime: SchedulerRuntime): { jobs: SchedulerDashboardJob[]; runningExecutions: number } => {\n const jobs = Object.values(runtime.schedulers).map((scheduler): SchedulerDashboardJob => {\n const upcomingExecutions = scheduler.job.cronExpression\n ? getNextExecutions(scheduler.job.cronExpression, 3, { timezone: scheduler.job.timezone })\n : [];\n\n const cronDescription = scheduler.job.cronExpression\n ? parseCronExpression(scheduler.job.cronExpression, undefined, { timezone: scheduler.job.timezone }).description\n : undefined;\n\n return {\n ...scheduler.job,\n isRunning: scheduler.isRunning,\n timeUntilNextRun: getTimeUntilNextRun(scheduler.job),\n upcomingExecutions,\n cronDescription,\n };\n });\n\n return { jobs, runningExecutions: runtime.runningExecutions };\n};\n\n// Pure function to build the executions view\nexport const createExecutionsSummary = (runtime: SchedulerRuntime) => ({\n executions: runtime.executionHistory.slice(-50), // Last 50 executions\n running: Object.values(runtime.executions).filter(e => e.status === 'running'),\n});\n","import { JobDefinition, JobExecution, JobHandler, ScheduledJob, SchedulerConfig, SchedulerService } from \"./types\";\nimport { detectExpressionType, convertRateToCron } from \"./cron-utils\";\nimport { generateExecutionId, generateJobId, calculateNextRun, calculateNextRunFromLastRun } from \"./utils\";\n\n// Pure function to validate a job definition before it's turned into a job.\n// A job needs exactly one timing source; only validate the cron expression\n// itself when one was actually given (intervalMs/delayMs-only jobs have no\n// cron expression to check).\nexport const validateJobDefinition = (jobDef: JobDefinition): void => {\n if (!jobDef.cronExpression && !jobDef.intervalMs && !jobDef.delayMs) {\n throw new Error(`Job ${jobDef.name} must specify a cronExpression, intervalMs, or delayMs`);\n }\n\n if (jobDef.cronExpression && detectExpressionType(jobDef.cronExpression) === \"unknown\") {\n throw new Error(`Invalid cron expression for job: ${jobDef.name}`);\n }\n};\n\n// Pure function to turn a job definition into a scheduled job\nexport const createJobFromDefinition = (jobDef: JobDefinition, config: SchedulerConfig): ScheduledJob => {\n validateJobDefinition(jobDef);\n\n const expressionType = detectExpressionType(jobDef.cronExpression);\n const cronExpression = expressionType === \"rate\"\n ? convertRateToCron(jobDef.cronExpression!).cronExpression\n : jobDef.cronExpression;\n\n const job: ScheduledJob = {\n id: generateJobId(),\n name: jobDef.name,\n cronExpression,\n intervalMs: jobDef.intervalMs,\n delayMs: jobDef.delayMs,\n nextRun: new Date(),\n enabled: jobDef.enabled ?? true,\n runCount: 0,\n maxRuns: jobDef.maxRuns,\n metadata: jobDef.metadata,\n createdAt: new Date(),\n timezone: jobDef.timezone,\n module: jobDef.module,\n };\n\n job.nextRun = calculateNextRun(job, config.restartBehavior.preserveNaturalTiming);\n return job;\n};\n\n// Pure function to create a scheduler service for a job\nexport const createSchedulerService = (job: ScheduledJob, handler: JobHandler): SchedulerService => ({\n job,\n handler,\n isRunning: false,\n});\n\n// Pure function to create a job execution record\nexport const createJobExecution = (jobId: string): JobExecution => ({\n id: generateExecutionId(),\n jobId,\n startTime: new Date(),\n status: 'running',\n});\n\n// Pure function to mark an execution as finished\nexport const completeExecution = (\n execution: JobExecution,\n result?: any,\n error?: string\n): JobExecution => ({\n ...execution,\n endTime: new Date(),\n status: error ? 'failed' : 'completed',\n result,\n error,\n});\n\n// Pure function to advance a job's run count/timing after an execution\nexport const updateJobAfterExecution = (\n job: ScheduledJob,\n execution: JobExecution,\n config: SchedulerConfig\n): ScheduledJob => {\n const updatedJob: ScheduledJob = {\n ...job,\n lastRun: execution.startTime,\n runCount: job.runCount + 1,\n };\n\n if (updatedJob.enabled) {\n updatedJob.nextRun = calculateNextRunFromLastRun(updatedJob, updatedJob.lastRun, config);\n }\n\n return updatedJob;\n};\n\n// Pure function to enable a job and recompute its next run\nexport const enableJob = (scheduler: SchedulerService): SchedulerService => ({\n ...scheduler,\n job: {\n ...scheduler.job,\n enabled: true,\n nextRun: calculateNextRun(scheduler.job),\n },\n});\n\n// Pure function to disable a job\nexport const disableJob = (scheduler: SchedulerService): SchedulerService => ({\n ...scheduler,\n job: { ...scheduler.job, enabled: false },\n});\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\n\nimport { JobExecution, ScheduledJob, SchedulerRuntime, SchedulerService } from \"./types\";\nimport { hasJobDefinitionChanged, calculateNextRunFromLastRun } from \"./utils\";\nimport { parseCronExpression } from \"./cron-utils\";\n\ninterface SchedulerStateData {\n jobs: ScheduledJob[];\n executions: JobExecution[];\n savedAt: Date;\n version: string;\n}\n\nconst stateFilePath = (directory: string): string => path.join(directory, 'scheduler-state.json');\n\nconst tempFilePath = (directory: string): string => path.join(directory, `scheduler-state.${Date.now()}.temp.json`);\n\nconst restoreExecutionHistory = (savedExecutions: JobExecution[]): JobExecution[] =>\n savedExecutions.map((exec) => ({\n ...exec,\n startTime: new Date(exec.startTime),\n endTime: exec.endTime ? new Date(exec.endTime) : undefined,\n }));\n\nconst readStateData = async (directory: string): Promise<SchedulerStateData | null> => {\n const data = await fs.readFile(stateFilePath(directory), 'utf8');\n return JSON.parse(data);\n};\n\nexport const saveSchedulerState = async (runtime: SchedulerRuntime): Promise<void> => {\n try {\n const stateData: SchedulerStateData = {\n jobs: Object.values(runtime.schedulers).map(s => s.job),\n executions: runtime.executionHistory.slice(-100),\n savedAt: new Date(),\n version: '1.0',\n };\n\n const file = stateFilePath(runtime.config.persistence.directory);\n const temp = tempFilePath(runtime.config.persistence.directory);\n\n // Write to a temp file first, then rename - rename is atomic, so a\n // reader never sees a half-written file.\n await fs.writeFile(temp, JSON.stringify(stateData, null, 2), 'utf8');\n await fs.rename(temp, file);\n\n runtime.logging.debug('Scheduler state saved');\n } catch (error: any) {\n runtime.logging.error({ error: error?.message }, 'Failed to save scheduler state');\n }\n};\n\n// Recalculates - or preserves - a restored job's nextRun depending on how\n// long ago the process restarted, so a quick redeploy doesn't lose timing\n// but a long outage doesn't fire a pile of catch-up runs.\nconst validateAndAdjustNextRun = (\n job: ScheduledJob,\n savedNextRun: Date | undefined,\n runtime: SchedulerRuntime\n): Date => {\n const { config, lastRestartTime, logging } = runtime;\n const now = new Date();\n\n if (!savedNextRun || savedNextRun <= now) {\n logging.debug({ module: job.module }, `Saved next run is in the past for ${job.name} - recalculating`);\n return calculateNextRunFromLastRun(job, job.lastRun, config);\n }\n\n const isRapidRestart = now.getTime() - lastRestartTime.getTime() < config.restartBehavior.rapidRestartThreshold;\n if (isRapidRestart) {\n logging.debug({ module: job.module }, `Rapid restart detected for ${job.name} - preserving saved timing`);\n return savedNextRun;\n }\n\n if (job.cronExpression || job.intervalMs) {\n const expectedNextRun = calculateNextRunFromLastRun(job, job.lastRun, config);\n const drift = Math.abs(savedNextRun.getTime() - expectedNextRun.getTime());\n if (drift > config.restartBehavior.maxTimingDrift) {\n logging.debug({ module: job.module }, `Adjusting timing for ${job.name} - drift of ${Math.round(drift / 1000)}s detected`);\n return expectedNextRun;\n }\n }\n\n return savedNextRun;\n};\n\n// Restores this job's saved run history (count, lastRun) and next-run\n// timing from the persisted state file. Mirrors queue-plugin's per-queue\n// loadQueueState: called from addJob right after the scheduler is\n// registered, not at plugin init - the saved file has nothing to match\n// against that early, since no jobs have been added yet.\nexport const loadJobState = async (runtime: SchedulerRuntime, scheduler: SchedulerService): Promise<SchedulerService> => {\n try {\n const stateData = await readStateData(runtime.config.persistence.directory);\n if (!stateData) {\n return scheduler;\n }\n\n const savedJob = stateData.jobs.find(job => job.name === scheduler.job.name);\n if (!savedJob) {\n return scheduler;\n }\n\n const definitionChanged = hasJobDefinitionChanged(scheduler.job, savedJob);\n const lastRun = savedJob.lastRun ? new Date(savedJob.lastRun) : undefined;\n\n const updatedJob: ScheduledJob = {\n ...scheduler.job,\n runCount: savedJob.runCount,\n lastRun,\n };\n\n if (definitionChanged) {\n runtime.logging.debug({ module: scheduler.job.module }, `Job definition changed: ${savedJob.name} - recalculating schedule`);\n updatedJob.nextRun = calculateNextRunFromLastRun(updatedJob, lastRun, runtime.config);\n } else {\n updatedJob.nextRun = validateAndAdjustNextRun(updatedJob, savedJob.nextRun ? new Date(savedJob.nextRun) : undefined, runtime);\n }\n\n if (runtime.config.cron.logCronDetails && updatedJob.cronExpression) {\n const result = parseCronExpression(updatedJob.cronExpression, updatedJob.lastRun, { timezone: updatedJob.timezone });\n runtime.logging.debug(\n { module: scheduler.job.module },\n `Job restored: ${savedJob.name} - ${result.description} - next: ${updatedJob.nextRun.toLocaleString()}`\n );\n } else {\n runtime.logging.debug({ module: scheduler.job.module }, `Job state restored: ${savedJob.name}`);\n }\n\n return { ...scheduler, job: updatedJob };\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n runtime.logging.debug('No saved scheduler state found - starting fresh');\n } else {\n runtime.logging.error({ error: error?.message }, `Failed to load job state for ${scheduler.job.name}`);\n }\n return scheduler;\n }\n};\n\n// Execution history isn't tied to any one job, so it's restored once at\n// plugin init (unlike per-job state, which loadJobState restores lazily as\n// each job is registered).\nexport const loadExecutionHistory = async (runtime: SchedulerRuntime): Promise<void> => {\n try {\n const stateData = await readStateData(runtime.config.persistence.directory);\n if (stateData?.executions) {\n runtime.executionHistory = restoreExecutionHistory(stateData.executions);\n }\n } catch (error: any) {\n if (error.code !== 'ENOENT') {\n runtime.logging.error({ error: error?.message }, 'Failed to load execution history');\n }\n }\n};\n\nexport const initializePersistence = async (runtime: SchedulerRuntime): Promise<void> => {\n try {\n await fs.mkdir(runtime.config.persistence.directory, { recursive: true });\n await loadExecutionHistory(runtime);\n\n if (runtime.config.persistence.saveOnShutdown) {\n const shutdownHandler = async () => {\n runtime.logging.debug('Saving scheduler state before shutdown...');\n await saveSchedulerState(runtime);\n process.exit(0);\n };\n\n process.on('SIGINT', shutdownHandler);\n process.on('SIGTERM', shutdownHandler);\n }\n\n runtime.logging.debug(`Scheduler persistence initialized: ${runtime.config.persistence.directory}`);\n } catch (error: any) {\n runtime.logging.error({ error: error?.message }, 'Failed to initialize scheduler persistence');\n }\n};\n","import { JobExecution, JobHandler, ScheduledJob, SchedulerRuntime, SchedulerService } from \"./types\";\nimport { completeExecution, createJobExecution, updateJobAfterExecution } from \"./jobs\";\nimport { isJobReadyToRun, shouldSkipJob } from \"./utils\";\nimport { saveSchedulerState } from \"./persistence\";\n\n// Pure function to check whether a job can run right now\nexport const canExecuteJob = (\n runtime: SchedulerRuntime,\n scheduler: SchedulerService\n): { canExecute: boolean; reason?: string } => {\n if (runtime.isShuttingDown) {\n return { canExecute: false, reason: 'System is shutting down' };\n }\n\n if (scheduler.isRunning) {\n return { canExecute: false, reason: 'Job is already running' };\n }\n\n if (shouldSkipJob(scheduler.job)) {\n const reason = !scheduler.job.enabled ? 'Job is disabled' : 'Job reached maximum runs';\n return { canExecute: false, reason };\n }\n\n if (runtime.runningExecutions >= runtime.config.execution.maxConcurrent) {\n return { canExecute: false, reason: 'Maximum concurrent executions reached' };\n }\n\n return { canExecute: true };\n};\n\nconst executeJobWithTimeout = async (\n handler: JobHandler,\n job: ScheduledJob,\n execution: JobExecution,\n timeoutMs: number\n): Promise<any> => {\n let timerId: NodeJS.Timeout;\n\n try {\n return await Promise.race([\n handler(job, execution),\n new Promise((_, reject) => {\n timerId = setTimeout(() => reject(new Error('Job execution timeout')), timeoutMs);\n }),\n ]);\n } finally {\n clearTimeout(timerId!);\n }\n};\n\n// Runs one job through its handler, recording the execution and advancing\n// its nextRun. Used by both the tick (once per due job) and triggerJob -\n// both go through the same path, wrapped in runWithLogContext by the\n// caller so every log call below carries the job's module/reqId.\nexport const executeJob = async (runtime: SchedulerRuntime, scheduler: SchedulerService): Promise<void> => {\n const execution = createJobExecution(scheduler.job.id);\n // Tracked in two places (the `executions` map and `executionHistory`)\n // but as a single shared reference - completeExecution below mutates\n // this same object via Object.assign so both views stay in sync,\n // instead of completeExecution's return value only updating one of them.\n runtime.executions[execution.id] = execution;\n runtime.executionHistory.push(execution);\n scheduler.isRunning = true;\n runtime.runningExecutions++;\n\n runtime.logging.info(`Executing job ${scheduler.job.name} (${execution.id})`);\n\n try {\n const result = await executeJobWithTimeout(\n scheduler.handler,\n scheduler.job,\n execution,\n runtime.config.execution.defaultTimeout\n );\n\n Object.assign(execution, completeExecution(execution, result));\n\n const duration = execution.endTime!.getTime() - execution.startTime.getTime();\n runtime.logging.debug(`Job completed in ${duration}ms`);\n } catch (error: any) {\n Object.assign(execution, completeExecution(execution, undefined, error.message));\n runtime.logging.error(`Job failed ${scheduler.job.name}: ${error.message}`);\n } finally {\n scheduler.isRunning = false;\n runtime.runningExecutions--;\n scheduler.job = updateJobAfterExecution(scheduler.job, execution, runtime.config);\n\n if (scheduler.job.maxRuns && scheduler.job.runCount >= scheduler.job.maxRuns) {\n runtime.logging.info(`Job ${scheduler.job.name} reached max runs (${scheduler.job.maxRuns})`);\n }\n\n if (runtime.config.persistence.enabled) {\n runtime.isDirty = true;\n }\n }\n};\n\nconst dispatchJobIfDue = (runtime: SchedulerRuntime, scheduler: SchedulerService): void => {\n if (!scheduler.job.enabled || !isJobReadyToRun(scheduler.job)) {\n return;\n }\n\n const { canExecute, reason } = canExecuteJob(runtime, scheduler);\n if (!canExecute) {\n // Not a permanent skip (except the maxRuns case, logged once above\n // instead) - e.g. at max concurrency, or another tick of the same\n // job already running. The job's nextRun hasn't moved, so the very\n // next tick simply tries again, instead of the old per-job timer\n // needing to be explicitly rescheduled with a delay. Logged at\n // debug to avoid spamming at tick frequency.\n if (reason === 'Maximum concurrent executions reached') {\n runtime.logging.debug({ module: scheduler.job.module }, `Delaying job ${scheduler.job.name} - ${reason}`);\n }\n return;\n }\n\n runtime.logging.runWithLogContext(\n { module: scheduler.job.module, reqId: scheduler.job.id },\n () => executeJob(runtime, scheduler)\n );\n};\n\nexport const cleanupExecutionHistory = (runtime: SchedulerRuntime): void => {\n const { maxExecutionHistory } = runtime.config.cleanup;\n if (runtime.executionHistory.length <= maxExecutionHistory) {\n return;\n }\n\n const removed = runtime.executionHistory.splice(0, runtime.executionHistory.length - maxExecutionHistory);\n runtime.logging.debug(`Cleaned up ${removed.length} old execution records`);\n};\n\nconst maybeCleanup = (runtime: SchedulerRuntime, now: number): void => {\n if (now - runtime.lastCleanupTime < runtime.config.cleanup.cleanupInterval) {\n return;\n }\n runtime.lastCleanupTime = now;\n cleanupExecutionHistory(runtime);\n};\n\nconst maybeSavePersistence = (runtime: SchedulerRuntime, now: number): void => {\n if (!runtime.config.persistence.enabled || !runtime.isDirty) {\n return;\n }\n\n const saveInterval = runtime.config.persistence.saveInterval ?? 0;\n if (saveInterval > 0 && now - runtime.lastSavedAt >= saveInterval) {\n runtime.lastSavedAt = now;\n runtime.isDirty = false;\n saveSchedulerState(runtime);\n }\n};\n\n// The one timer for the whole plugin. Every tickIntervalMs: run any job\n// whose nextRun has arrived (this is also how a manual triggerJob's\n// recurrence shows up - nothing schedules its own setTimeout anymore); then\n// clean up old execution history and save persistence if their intervals\n// have elapsed.\nexport const tick = (runtime: SchedulerRuntime): void => {\n const now = Date.now();\n for (const scheduler of Object.values(runtime.schedulers)) {\n dispatchJobIfDue(runtime, scheduler);\n }\n maybeCleanup(runtime, now);\n maybeSavePersistence(runtime, now);\n};\n","import { JobDefinition, JobHandler, SchedulerManager, SchedulerRuntime, SchedulerService } from \"./types\";\nimport { createJobFromDefinition, createSchedulerService, disableJob as disableJobData, enableJob as enableJobData } from \"./jobs\";\nimport { createDashboardSummary, createExecutionsSummary } from \"./core\";\nimport { getNextExecutions, parseCronExpression } from \"./cron-utils\";\nimport { loadJobState } from \"./persistence\";\nimport { executeJob } from \"./processing\";\n\nconst isValidJobName = (jobName: string): boolean => {\n return typeof jobName === 'string' && jobName.length > 0 && /^[a-zA-Z0-9_-]+$/.test(jobName);\n};\n\nconst validateJobName = (jobName: string): void => {\n if (!jobName || typeof jobName !== 'string') {\n throw new Error('Job name must be a non-empty string');\n }\n\n if (!isValidJobName(jobName)) {\n throw new Error('Job name must contain only alphanumeric characters, hyphens, and underscores');\n }\n};\n\nconst validateHandler = (handler: JobHandler): void => {\n if (typeof handler !== 'function') {\n throw new Error('Handler must be a function');\n }\n};\n\nconst findSchedulerByName = (runtime: SchedulerRuntime, jobName: string): SchedulerService | undefined =>\n Object.values(runtime.schedulers).find(scheduler => scheduler.job.name === jobName);\n\nexport const addJob = async (runtime: SchedulerRuntime, jobDefinition: JobDefinition): Promise<string> => {\n try {\n validateJobName(jobDefinition.name);\n validateHandler(jobDefinition.handler);\n\n const existing = findSchedulerByName(runtime, jobDefinition.name);\n if (existing) {\n runtime.logging.warn({ module: jobDefinition.module }, `Job already exists: ${jobDefinition.name}.`);\n return existing.job.id;\n }\n\n const job = createJobFromDefinition(jobDefinition, runtime.config);\n\n if (runtime.config.cron.logCronDetails && job.cronExpression) {\n const timezone = job.timezone ?? runtime.config.cron.defaultTimezone;\n const result = parseCronExpression(job.cronExpression, undefined, { timezone });\n runtime.logging.debug(\n { module: jobDefinition.module },\n `Job ${jobDefinition.name}: ${result.description} - Next: ${result.nextRun.toLocaleString()}`\n );\n\n const upcoming = getNextExecutions(job.cronExpression, 3, { timezone });\n runtime.logging.debug(\n { module: jobDefinition.module },\n `Upcoming: ${upcoming.map(d => d.toLocaleTimeString()).join(', ')}`\n );\n }\n\n let scheduler = createSchedulerService(job, jobDefinition.handler);\n\n if (runtime.config.persistence.enabled) {\n scheduler = await loadJobState(runtime, scheduler);\n }\n\n runtime.schedulers[scheduler.job.id] = scheduler;\n\n runtime.logging.info({ module: jobDefinition.module }, `Job added: ${jobDefinition.name} (${scheduler.job.id})`);\n\n return scheduler.job.id;\n } catch (error: any) {\n runtime.logging.error({ module: jobDefinition.module, error: error.message }, `Failed to add job ${jobDefinition.name}`);\n throw error;\n }\n};\n\nexport const removeJob = async (runtime: SchedulerRuntime, jobName: string): Promise<void> => {\n try {\n validateJobName(jobName);\n\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n throw new Error(`Job '${jobName}' does not exist`);\n }\n\n if (scheduler.isRunning) {\n runtime.logging.warn({ module: scheduler.job.module }, `Removing job that is currently running: ${jobName}`);\n }\n\n delete runtime.schedulers[scheduler.job.id];\n\n runtime.logging.info({ module: scheduler.job.module }, `Job removed: ${jobName}`);\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to remove job ${jobName}`);\n throw error;\n }\n};\n\nexport const hasJob = (runtime: SchedulerRuntime, jobName: string): boolean => {\n try {\n validateJobName(jobName);\n return !!findSchedulerByName(runtime, jobName);\n } catch {\n return false;\n }\n};\n\nexport const listJobs = (runtime: SchedulerRuntime, module?: string): string[] => {\n return Object.values(runtime.schedulers)\n .filter(scheduler => !module || scheduler.job.module === module)\n .map(scheduler => scheduler.job.name)\n .sort();\n};\n\nexport const getJobStats = (runtime: SchedulerRuntime, jobName: string): SchedulerService | null => {\n try {\n validateJobName(jobName);\n return findSchedulerByName(runtime, jobName) ?? null;\n } catch {\n return null;\n }\n};\n\nexport const getJobsMap = (runtime: SchedulerRuntime): Record<string, SchedulerService> => {\n // Return a copy to prevent external modification\n return { ...runtime.schedulers };\n};\n\nexport const enableJob = async (runtime: SchedulerRuntime, jobName: string): Promise<void> => {\n try {\n validateJobName(jobName);\n\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n throw new Error(`Job '${jobName}' does not exist`);\n }\n\n if (scheduler.job.enabled) {\n runtime.logging.debug({ module: scheduler.job.module }, `Job is already enabled: ${jobName}`);\n return;\n }\n\n runtime.schedulers[scheduler.job.id] = enableJobData(scheduler);\n runtime.logging.info({ module: scheduler.job.module }, `Job enabled: ${jobName}`);\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to enable job ${jobName}`);\n throw error;\n }\n};\n\nexport const disableJob = async (runtime: SchedulerRuntime, jobName: string): Promise<void> => {\n try {\n validateJobName(jobName);\n\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n throw new Error(`Job '${jobName}' does not exist`);\n }\n\n if (!scheduler.job.enabled) {\n runtime.logging.debug({ module: scheduler.job.module }, `Job is already disabled: ${jobName}`);\n return;\n }\n\n runtime.schedulers[scheduler.job.id] = disableJobData(scheduler);\n runtime.logging.info({ module: scheduler.job.module }, `Job disabled: ${jobName}`);\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to disable job ${jobName}`);\n throw error;\n }\n};\n\nexport const triggerJob = async (runtime: SchedulerRuntime, jobName: string): Promise<void> => {\n try {\n validateJobName(jobName);\n\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n throw new Error(`Job '${jobName}' does not exist`);\n }\n\n if (scheduler.isRunning) {\n throw new Error(`Job '${jobName}' is already running`);\n }\n\n runtime.logging.info({ module: scheduler.job.module }, `Job triggered: ${jobName}`);\n\n // Fire-and-forget, same as the tick's own dispatch - callers (e.g.\n // the trigger route) get an immediate response rather than waiting\n // out the job's full run.\n runtime.logging.runWithLogContext(\n { module: scheduler.job.module, reqId: scheduler.job.id },\n () => executeJob(runtime, scheduler)\n );\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to trigger job ${jobName}`);\n throw error;\n }\n};\n\nexport const getDashboardSummary = (runtime: SchedulerRuntime) => createDashboardSummary(runtime);\n\nexport const getExecutionsSummary = (runtime: SchedulerRuntime) => createExecutionsSummary(runtime);\n\n// Unlike getExecutionsSummary (last 50 across every job), this filters the\n// full executionHistory down to one job first - so a busy job elsewhere\n// can't push a quieter job's own runs out of view.\nexport const getJobExecutionHistory = (runtime: SchedulerRuntime, jobName: string, limit = 50) => {\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n return [];\n }\n\n return runtime.executionHistory\n .filter(execution => execution.jobId === scheduler.job.id)\n .slice(-limit)\n .reverse();\n};\n\n// The one place runtime gets bound into the public app.scheduler shape -\n// Fastify needs a plain object of methods with no runtime param, so this\n// wraps each plain function above with `runtime` pre-applied. Everything\n// above this line is a normal function you can call directly with an\n// explicit runtime, e.g. in tests.\nexport const createSchedulerManager = (runtime: SchedulerRuntime): SchedulerManager => ({\n addJob: (jobDefinition) => addJob(runtime, jobDefinition),\n removeJob: (jobName) => removeJob(runtime, jobName),\n hasJob: (jobName) => hasJob(runtime, jobName),\n listJobs: (module) => listJobs(runtime, module),\n getJobStats: (jobName) => getJobStats(runtime, jobName),\n getJobsMap: () => getJobsMap(runtime),\n getConfig: () => runtime.config,\n enableJob: (jobName) => enableJob(runtime, jobName),\n disableJob: (jobName) => disableJob(runtime, jobName),\n triggerJob: (jobName) => triggerJob(runtime, jobName),\n getDashboardSummary: () => getDashboardSummary(runtime),\n getExecutionsSummary: () => getExecutionsSummary(runtime),\n getJobExecutionHistory: (jobName, limit) => getJobExecutionHistory(runtime, jobName, limit),\n});\n","import { FastifyInstance, FastifyReply, FastifyRequest } from \"fastify\";\n\n// Function to register all routes\nexport const registerSchedulerRoutes = (\n app: FastifyInstance,\n prefix: string = \"schedule\"\n): void => {\n app.get(`/${prefix}/dashboard`,\n async (_: FastifyRequest, reply: FastifyReply) => {\n return reply.status(200).send(app.scheduler.getDashboardSummary());\n });\n\n app.get(`/${prefix}/executions`,\n async (_: FastifyRequest, reply: FastifyReply) => {\n return reply.status(200).send(app.scheduler.getExecutionsSummary());\n });\n\n app.post<{ Params: { jobName: string } }>(`/${prefix}/jobs/:jobName/trigger`,\n async (request: FastifyRequest<{ Params: { jobName: string } }>, reply: FastifyReply) => {\n try {\n await app.scheduler.triggerJob(request.params.jobName);\n return reply.status(200).send({ message: \"Job triggered successfully\" });\n } catch (error: any) {\n return reply.status(404).send({ error: error.message });\n }\n });\n\n app.put<{ Params: { jobName: string } }>(`/${prefix}/jobs/:jobName/enable`,\n async (request: FastifyRequest<{ Params: { jobName: string } }>, reply: FastifyReply) => {\n try {\n await app.scheduler.enableJob(request.params.jobName);\n return reply.status(200).send({ message: \"Job enabled successfully\" });\n } catch (error: any) {\n return reply.status(404).send({ error: error.message });\n }\n });\n\n app.put<{ Params: { jobName: string } }>(`/${prefix}/jobs/:jobName/disable`,\n async (request: FastifyRequest<{ Params: { jobName: string } }>, reply: FastifyReply) => {\n try {\n await app.scheduler.disableJob(request.params.jobName);\n return reply.status(200).send({ message: \"Job disabled successfully\" });\n } catch (error: any) {\n return reply.status(404).send({ error: error.message });\n }\n });\n};\n","import crypto from \"node:crypto\";\n\nimport { FastifyInstance, FastifyPluginAsync } from \"fastify\";\nimport fsPlugin from \"fastify-plugin\";\nimport websocketPlugin from \"@fastify/websocket\";\n\nimport \"../logger/types\";\nimport { WebSocketConnectionGoneError } from \"@cloudnux/core-cloud-provider\";\n\n\nimport {\n WebSocketPluginOptions,\n WebSocketConfig,\n WebSocketConnection,\n WebSocketRouteHandler,\n RegisteredWebSocketPath,\n} from \"./types\";\n\nconst DEFAULT_CONFIG: WebSocketConfig = {\n routeKeyField: \"action\",\n};\n\nfunction mergeConfig(\n defaults: WebSocketConfig,\n overrides?: Partial<WebSocketConfig>\n): WebSocketConfig {\n return { ...defaults, ...overrides };\n}\n\nexport const websocketsPlugin: FastifyPluginAsync<WebSocketPluginOptions> =\n fsPlugin(async (\n app: FastifyInstance,\n options: WebSocketPluginOptions\n ) => {\n const config = mergeConfig(DEFAULT_CONFIG, options.config);\n const connections = new Map<string, WebSocketConnection>();\n const handlers: WebSocketRouteHandler[] = [];\n const registeredPaths = new Set<string>();\n const pathModuleMap = new Map<string, string | undefined>();\n\n // Register @fastify/websocket\n await app.register(websocketPlugin);\n\n // Register WebSocket route for a path when first handler uses it\n function ensureRouteForPath(path: string) {\n if (registeredPaths.has(path)) return;\n registeredPaths.add(path);\n\n app.get(path, {\n websocket: true,\n preHandler: async (request, reply) => {\n const connectionId = crypto.randomUUID();\n (request as any)._wsConnectionId = connectionId;\n const reqId = `${request.id}:${connectionId}`;\n\n const connectHandlers = handlers.filter(h => h.path === path && h.event === \"connect\");\n for (const h of connectHandlers) {\n await app.logging.runWithLogContext(\n { module: h.module, reqId },\n () => h.handler(connectionId, \"connect\", null, request, reply)\n );\n }\n if (reply.statusCode !== 200)\n return reply; // Prevent WebSocket upgrade if preHandler set an error status\n },\n }, (socket, request) => {\n const connectionId = (request as any)._wsConnectionId ?? crypto.randomUUID();\n const reqId = `${request.id}:${connectionId}`;\n const connection: WebSocketConnection = {\n connectionId,\n socket,\n path,\n connectedAt: new Date(),\n };\n connections.set(connectionId, connection);\n\n // Filter handlers for this path at runtime so late-registered handlers are included\n const pathHandlers = () => handlers.filter(h => h.path === path);\n\n // Handle incoming messages\n socket.on(\"message\", (raw) => {\n const data = raw.toString();\n\n const currentHandlers = pathHandlers();\n\n // Try to parse and match a specific route handler\n let routeKey: string | undefined;\n try {\n const parsed = JSON.parse(data);\n routeKey = parsed?.[config.routeKeyField];\n } catch {\n // not JSON, no route key\n }\n\n let matched = false;\n if (routeKey) {\n const routeHandlers = currentHandlers.filter(\n h => h.event === \"message\" && h.route === routeKey\n );\n for (const h of routeHandlers) {\n matched = true;\n app.logging.runWithLogContext(\n { module: h.module, reqId },\n () => h.handler(connectionId, \"message\", data, request).catch((e) => app.logging.error(e))\n );\n }\n }\n\n // Fall back to default message handlers (no route)\n if (!matched) {\n const defaultHandlers = currentHandlers.filter(\n h => h.event === \"message\" && !h.route\n );\n for (const h of defaultHandlers) {\n app.logging.runWithLogContext(\n { module: h.module, reqId },\n () => h.handler(connectionId, \"message\", data, request).catch((e) => app.logging.error(e))\n );\n }\n }\n });\n\n // Handle disconnect\n socket.on(\"close\", () => {\n const disconnectHandlers = pathHandlers().filter(h => h.event === \"disconnect\");\n for (const h of disconnectHandlers) {\n app.logging.runWithLogContext(\n { module: h.module, reqId },\n () => h.handler(connectionId, \"disconnect\", null, request).catch((e) => app.logging.error(e))\n );\n }\n connections.delete(connectionId);\n });\n });\n }\n\n // Create manager with eager route registration\n const manager = {\n registerHandler(handler: WebSocketRouteHandler) {\n handlers.push(handler);\n if (!pathModuleMap.has(handler.path)) {\n pathModuleMap.set(handler.path, handler.module);\n }\n ensureRouteForPath(handler.path);\n },\n getConnections(path?: string): WebSocketConnection[] {\n const allConnections = Array.from(connections.values());\n if (path) {\n return allConnections.filter(c => c.path === path);\n }\n return allConnections;\n },\n getRegisteredPaths(module?: string): RegisteredWebSocketPath[] {\n const all: RegisteredWebSocketPath[] = Array.from(pathModuleMap.entries()).map(([path, mod]) => ({ path, module: mod }));\n if (module) {\n return all.filter(p => p.module === module);\n }\n return all;\n },\n async sendToClient(connectionId: string, data: any): Promise<void> {\n const connection = connections.get(connectionId);\n if (!connection) {\n throw new WebSocketConnectionGoneError(connectionId);\n }\n const payload = typeof data === \"string\" ? data : JSON.stringify(data);\n connection.socket.send(payload);\n },\n async disconnect(connectionId: string): Promise<void> {\n const connection = connections.get(connectionId);\n if (!connection) {\n throw new WebSocketConnectionGoneError(connectionId);\n }\n connection.socket.close();\n },\n };\n\n app.decorate('websockets', manager);\n });\n","export interface RouteInfo {\n method: string | string[]\n url: string\n handler: string\n registeredAt: Date,\n module?: string\n}\n\nclass RouteRegistry {\n private routes: RouteInfo[] = []\n\n private static readonly IGNORED_METHODS = new Set(['OPTIONS', 'HEAD'])\n\n register(routeOptions: any): void {\n const methods: string[] = Array.isArray(routeOptions.method)\n ? routeOptions.method\n : [routeOptions.method]\n\n if (methods.every(m => RouteRegistry.IGNORED_METHODS.has(m.toUpperCase()))) {\n return\n }\n\n const routeInfo: RouteInfo = {\n method: routeOptions.method,\n url: routeOptions.url,\n handler: routeOptions.handler?.name || 'anonymous',\n registeredAt: new Date(),\n module: routeOptions.config?.module\n }\n\n this.routes.push(routeInfo)\n }\n\n getAll(): RouteInfo[] {\n return [...this.routes]\n }\n\n getByMethod(method: string): RouteInfo[] {\n return this.routes.filter(route => {\n if (Array.isArray(route.method)) {\n return route.method.includes(method.toUpperCase())\n }\n return route.method.toUpperCase() === method.toUpperCase()\n })\n }\n\n clear(): void {\n this.routes = []\n }\n\n count(): number {\n return this.routes.length\n }\n}\n\nexport const routeRegistry = new RouteRegistry()"],"mappings":"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","names":["path","fsPlugin","WebSocketConnectionGoneError","tempFilePath","fsPlugin","DEFAULT_CONFIG","mergeConfig","createDashboardSummary","fs","path","initializePersistence","maybeSavePersistence","tick","validateHandler","enableJob","disableJob","getDashboardSummary","createDashboardSummary","fsPlugin","mergeConfig","DEFAULT_CONFIG","tick","initializePersistence","fsPlugin","DEFAULT_CONFIG","mergeConfig","fsPlugin","path","require","WebSocketConnectionGoneError","unsubscribe","path","fsPlugin"]}
1
+ {"version":3,"sources":["../../src/dev-console-plugin/plugin.ts","../../src/queue-plugin/plugin.ts","../../src/queue-plugin/core.ts","../../src/queue-plugin/persistence.ts","../../src/queue-plugin/processing.ts","../../src/queue-plugin/decorator.ts","../../src/queue-plugin/routes.ts","../../src/schedule-plugin/plugin.ts","../../src/schedule-plugin/cron-utils.ts","../../src/schedule-plugin/utils.ts","../../src/schedule-plugin/core.ts","../../src/schedule-plugin/jobs.ts","../../src/schedule-plugin/persistence.ts","../../src/schedule-plugin/processing.ts","../../src/schedule-plugin/decorator.ts","../../src/schedule-plugin/routes.ts","../../src/websocket-plugin/plugin.ts","../../src/dev-console-plugin/route-registry.ts","../../src/services/email.ts","../../../../../node_modules/lodash-es/_freeGlobal.js","../../../../../node_modules/lodash-es/_root.js","../../../../../node_modules/lodash-es/_Symbol.js","../../../../../node_modules/lodash-es/_getRawTag.js","../../../../../node_modules/lodash-es/_objectToString.js","../../../../../node_modules/lodash-es/_baseGetTag.js","../../../../../node_modules/lodash-es/isObjectLike.js","../../../../../node_modules/lodash-es/isSymbol.js","../../../../../node_modules/lodash-es/_arrayMap.js","../../../../../node_modules/lodash-es/isArray.js","../../../../../node_modules/lodash-es/_baseToString.js","../../../../../node_modules/lodash-es/_trimmedEndIndex.js","../../../../../node_modules/lodash-es/_baseTrim.js","../../../../../node_modules/lodash-es/isObject.js","../../../../../node_modules/lodash-es/isFunction.js","../../../../../node_modules/lodash-es/_coreJsData.js","../../../../../node_modules/lodash-es/_isMasked.js","../../../../../node_modules/lodash-es/_toSource.js","../../../../../node_modules/lodash-es/_baseIsNative.js","../../../../../node_modules/lodash-es/_getValue.js","../../../../../node_modules/lodash-es/_getNative.js","../../../../../node_modules/lodash-es/_baseFindIndex.js","../../../../../node_modules/lodash-es/_baseIsNaN.js","../../../../../node_modules/lodash-es/_strictIndexOf.js","../../../../../node_modules/lodash-es/_baseIndexOf.js","../../../../../node_modules/lodash-es/_isIndex.js","../../../../../node_modules/lodash-es/eq.js","../../../../../node_modules/lodash-es/isLength.js","../../../../../node_modules/lodash-es/_baseIsArguments.js","../../../../../node_modules/lodash-es/isArguments.js","../../../../../node_modules/lodash-es/_isKey.js","../../../../../node_modules/lodash-es/_nativeCreate.js","../../../../../node_modules/lodash-es/_hashClear.js","../../../../../node_modules/lodash-es/_hashDelete.js","../../../../../node_modules/lodash-es/_hashGet.js","../../../../../node_modules/lodash-es/_hashHas.js","../../../../../node_modules/lodash-es/_hashSet.js","../../../../../node_modules/lodash-es/_Hash.js","../../../../../node_modules/lodash-es/_listCacheClear.js","../../../../../node_modules/lodash-es/_assocIndexOf.js","../../../../../node_modules/lodash-es/_listCacheDelete.js","../../../../../node_modules/lodash-es/_listCacheGet.js","../../../../../node_modules/lodash-es/_listCacheHas.js","../../../../../node_modules/lodash-es/_listCacheSet.js","../../../../../node_modules/lodash-es/_ListCache.js","../../../../../node_modules/lodash-es/_Map.js","../../../../../node_modules/lodash-es/_mapCacheClear.js","../../../../../node_modules/lodash-es/_isKeyable.js","../../../../../node_modules/lodash-es/_getMapData.js","../../../../../node_modules/lodash-es/_mapCacheDelete.js","../../../../../node_modules/lodash-es/_mapCacheGet.js","../../../../../node_modules/lodash-es/_mapCacheHas.js","../../../../../node_modules/lodash-es/_mapCacheSet.js","../../../../../node_modules/lodash-es/_MapCache.js","../../../../../node_modules/lodash-es/memoize.js","../../../../../node_modules/lodash-es/_memoizeCapped.js","../../../../../node_modules/lodash-es/_stringToPath.js","../../../../../node_modules/lodash-es/toString.js","../../../../../node_modules/lodash-es/_castPath.js","../../../../../node_modules/lodash-es/_toKey.js","../../../../../node_modules/lodash-es/_baseSlice.js","../../../../../node_modules/lodash-es/_castSlice.js","../../../../../node_modules/lodash-es/_hasUnicode.js","../../../../../node_modules/lodash-es/_asciiToArray.js","../../../../../node_modules/lodash-es/_unicodeToArray.js","../../../../../node_modules/lodash-es/_stringToArray.js","../../../../../node_modules/lodash-es/_hasPath.js","../../../../../node_modules/lodash-es/_baseHas.js","../../../../../node_modules/lodash-es/has.js","../../../../../node_modules/lodash-es/_charsEndIndex.js","../../../../../node_modules/lodash-es/_charsStartIndex.js","../../../../../node_modules/lodash-es/trim.js","../../../../utils/src/config/env.ts"],"sourcesContent":["import path from \"path\";\nimport { FastifyInstance } from \"fastify\";\nimport fastifyStatic from \"@fastify/static\";\nimport fsPlugin from \"fastify-plugin\";\nimport { createRequire } from 'module';\nconst require = createRequire(import.meta.url);\n\nimport { WebSocketConnectionGoneError } from \"@cloudnux/core-cloud-provider\";\n\nimport \"../logger/types\";\n\nimport \"../queue-plugin\";\nimport \"../schedule-plugin\";\nimport \"../websocket-plugin\";\n\nimport { routeRegistry } from \"./route-registry\";\nimport { listEmailHistory, getEmailHistoryEntry, getEmailRaw, getEmailBody } from \"../services/email\";\n\ninterface LogEntry {\n id: string;\n timestamp: Date;\n levelName: string;\n message: string;\n meta?: Record<string, unknown>;\n module: string;\n reqId: string;\n}\n\nclass LogStore {\n private logs: LogEntry[] = [];\n private maxLogs = 1000;\n private listeners: ((log: LogEntry) => void)[] = [];\n\n addLog(entry: LogEntry) {\n this.logs.unshift(entry);\n if (this.logs.length > this.maxLogs) {\n this.logs = this.logs.slice(0, this.maxLogs);\n }\n this.listeners.forEach(listener => listener(entry));\n }\n\n getLogs(limit = 100) {\n return this.logs.slice(0, limit);\n }\n\n clear() {\n this.logs = [];\n }\n\n subscribe(listener: (log: LogEntry) => void) {\n this.listeners.push(listener);\n return () => {\n this.listeners = this.listeners.filter(l => l !== listener);\n };\n }\n}\n\nconst logStore = new LogStore();\n\ninterface HttpHistoryEntry {\n id: string;\n method: string;\n routeUrl: string;\n url: string;\n statusCode: number;\n duration: number;\n reqId: string;\n requestHeaders: Record<string, unknown>;\n requestBody?: unknown;\n timestamp: Date;\n}\n\n// Records every real request that hits a module route (matched by url\n// prefix, same \"/api\" convention routeRegistry uses), not just the ones\n// fired from the console's own \"Test Route\" panel - so RouteDetailView can\n// show traffic that actually happened, keyed by the route's method+template\n// since that's all the frontend has to ask for.\nclass HttpHistoryStore {\n private entries: Map<string, HttpHistoryEntry[]> = new Map();\n private readonly maxPerRoute = 50;\n\n add(entry: HttpHistoryEntry) {\n const key = `${entry.method} ${entry.routeUrl}`;\n const existing = this.entries.get(key) ?? [];\n existing.unshift(entry);\n if (existing.length > this.maxPerRoute) {\n existing.length = this.maxPerRoute;\n }\n this.entries.set(key, existing);\n }\n\n get(method: string, routeUrl: string) {\n return this.entries.get(`${method.toUpperCase()} ${routeUrl}`) ?? [];\n }\n\n clear() {\n this.entries.clear();\n }\n}\n\nconst httpHistoryStore = new HttpHistoryStore();\n\nexport interface DevConsolePluginOptions {\n prefix?: string;\n enableUI?: boolean;\n}\n\nasync function devConsolePluginFunction(\n fastify: FastifyInstance,\n options: DevConsolePluginOptions = {}\n) {\n const { prefix = 'console', enableUI = true } = options;\n\n // Read off `fastify.logging` (decorated once by router/index.ts on the shared\n // FastifyInstance), not a direct `../logger` import - dev-console-plugin is its\n // own separately-bundled tsup entry, so a direct import would get its own\n // disconnected copy of the logger's listeners Set and never see logs published\n // from queue-plugin/schedule-plugin/websocket-plugin's bundles.\n const unsubscribe = fastify.logging.subscribeToLogs((entry) => {\n logStore.addLog({\n id: Date.now().toString() + Math.random().toString(36).slice(2, 9),\n timestamp: new Date(entry.time),\n levelName: entry.levelName,\n message: entry.msg,\n meta: entry.meta,\n module: entry.module,\n reqId: entry.reqId,\n });\n });\n\n // Unsubscribe and clear log store on plugin teardown\n fastify.addHook('onClose', (_instance, done) => {\n unsubscribe();\n logStore.clear();\n httpHistoryStore.clear();\n done();\n });\n\n // Register route discovery hook for all routes\n fastify.addHook('onRoute', (routeOptions) => {\n if (routeOptions.prefix === \"/api\") {\n routeRegistry.register(routeOptions);\n }\n });\n\n // Stamp a start time on every request so onResponse below can compute\n // duration - registered fastify-plugin-wide (like onRoute above), so it\n // sees traffic regardless of whether it was triggered from the console UI.\n fastify.addHook('onRequest', (request, _reply, done) => {\n (request as any)._historyStart = Date.now();\n done();\n });\n\n fastify.addHook('onResponse', (request, reply, done) => {\n const routeUrl = request.routeOptions.url;\n if (routeUrl?.startsWith('/api')) {\n const start = (request as any)._historyStart as number | undefined;\n httpHistoryStore.add({\n id: Date.now().toString() + Math.random().toString(36).slice(2, 9),\n method: request.method,\n routeUrl,\n url: request.url,\n statusCode: reply.statusCode,\n duration: start ? Date.now() - start : 0,\n reqId: request.id,\n requestHeaders: request.headers,\n requestBody: request.body,\n timestamp: new Date(),\n });\n }\n done();\n });\n\n // API endpoints\n fastify.get(`/${prefix}/routes`, async () => {\n return { routes: routeRegistry.getAll() };\n });\n\n fastify.get(`/${prefix}/routes/:method`, async (request) => {\n const { method } = request.params as { method: string };\n return { routes: routeRegistry.getByMethod(method) };\n });\n\n // Real requests that hit a given route (method + url template), captured\n // by the onResponse hook above - not just clicks from \"Test Route\".\n fastify.get(`/${prefix}/routes/history`, async (request, reply) => {\n const { method, url } = request.query as { method?: string; url?: string };\n\n if (!method || !url) {\n return reply.status(400).send({ error: 'method and url query params are required' });\n }\n\n return { history: httpHistoryStore.get(method, url) };\n });\n\n fastify.get(`/${prefix}/registry/stats`, async () => {\n return {\n totalRoutes: routeRegistry.count(),\n registeredAt: new Date()\n };\n });\n\n // Modules endpoints - group resources by module\n fastify.get(`/${prefix}/modules`, async (_, reply) => {\n const queueManager = fastify.queues;\n const schedulerManager = fastify.scheduler;\n const wsManager = fastify.websockets;\n\n if (!queueManager || !schedulerManager || !wsManager) {\n return reply.status(503).send({ error: 'Services not available' });\n }\n\n // Get all routes and filter HTTP routes by prefix\n const allRoutes = routeRegistry.getAll();\n const httpRoutes = allRoutes;\n\n // Get all modules from routes, queues, schedules, and websockets\n const moduleSet = new Set<string>();\n\n httpRoutes.forEach(route => {\n if (route.module) moduleSet.add(route.module);\n });\n\n const allQueueNames = queueManager.listQueues();\n const allJobNames = schedulerManager.listJobs();\n\n allQueueNames.forEach(queueName => {\n const queueStats = queueManager.getQueueStats(queueName);\n if (queueStats?.module) moduleSet.add(queueStats.module);\n });\n\n allJobNames.forEach(jobName => {\n const jobStats = schedulerManager.getJobStats(jobName);\n if (jobStats?.job.module) moduleSet.add(jobStats.job.module);\n });\n\n wsManager.getRegisteredPaths().forEach(p => {\n if (p.module) moduleSet.add(p.module);\n });\n\n // Create module objects\n const modules = Array.from(moduleSet).map(moduleName => {\n // Get routes for this module\n const moduleRoutes = httpRoutes.filter(route => route.module === moduleName);\n\n // Get queues for this module\n const moduleQueueNames = queueManager.listQueues(moduleName);\n const moduleQueues = moduleQueueNames.map(name => {\n const stats = queueManager.getQueueStats(name);\n return {\n name,\n stats: stats ? {\n incoming: stats.incoming.length,\n processing: stats.processing.length,\n dlq: stats.dlq.length\n } : null\n };\n });\n\n // Get schedules for this module\n const moduleJobNames = schedulerManager.listJobs(moduleName);\n const moduleSchedules = moduleJobNames.map(name => {\n const jobStats = schedulerManager.getJobStats(name);\n return {\n name,\n enabled: jobStats?.job.enabled || false,\n isRunning: jobStats?.isRunning || false,\n cronExpression: jobStats?.job.cronExpression,\n timezone: jobStats?.job.timezone\n };\n });\n\n // Get websockets for this module\n const moduleWebSockets = wsManager\n ? wsManager.getRegisteredPaths(moduleName).map(p => ({\n path: p.path,\n connectionCount: wsManager.getConnections(p.path).length\n }))\n : [];\n\n return {\n name: moduleName,\n routes: moduleRoutes,\n queues: moduleQueues,\n schedules: moduleSchedules,\n websockets: moduleWebSockets\n };\n });\n\n return { modules };\n });\n\n // Queues endpoints - access via decorator\n fastify.get(`/${prefix}/queues`, async (_, reply) => {\n const queueManager = fastify.queues;\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n const queueNames = queueManager.listQueues();\n const queues = queueNames.map(name => {\n const stats = queueManager.getQueueStats(name);\n return {\n name,\n stats: stats ? {\n incoming: stats.incoming.length,\n processing: stats.processing.length,\n dlq: stats.dlq.length\n } : null\n };\n });\n\n return { queues };\n });\n\n fastify.get(`/${prefix}/queues/:queueName`, async (request, reply) => {\n const { queueName } = request.params as { queueName: string };\n const queueManager = fastify.queues;\n\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n const queueStats = queueManager.getQueueStats(queueName);\n if (!queueStats) {\n return reply.status(404).send({ error: 'Queue not found' });\n }\n\n const config = queueManager.getConfig();\n\n return {\n name: queueName,\n stats: {\n incoming: queueStats.incoming.length,\n processing: queueStats.processing.length,\n dlq: queueStats.dlq.length,\n configuration: config\n },\n messages: {\n incoming: queueStats.incoming,\n processing: queueStats.processing,\n dlq: queueStats.dlq\n }\n };\n });\n\n // Messages that already finished processing (completed or DLQ'd) -\n // covers listener invocations triggered by real traffic, not just\n // messages enqueued from the console's own form.\n fastify.get(`/${prefix}/queues/:queueName/history`, async (request, reply) => {\n const { queueName } = request.params as { queueName: string };\n const queueManager = fastify.queues;\n\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n if (!queueManager.getQueueStats(queueName)) {\n return reply.status(404).send({ error: 'Queue not found' });\n }\n\n return { history: queueManager.getMessageHistory(queueName) };\n });\n\n // Queue action endpoints\n fastify.get(`/${prefix}/queues/:queueName/process-dlq`, async (request, reply) => {\n const { queueName } = request.params as { queueName: string };\n const queueManager = fastify.queues;\n\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n try {\n const result = await queueManager.processDlq(queueName);\n return reply.status(200).send(result);\n } catch (error) {\n return reply.status(500).send({\n message: 'Failed to process DLQ',\n error\n });\n }\n });\n\n fastify.get(`/${prefix}/queues/:queueName/purge-dlq`, async (request, reply) => {\n const { queueName } = request.params as { queueName: string };\n const queueManager = fastify.queues;\n\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n try {\n const result = await queueManager.purgeDlq(queueName);\n return reply.status(200).send(result);\n } catch (error) {\n return reply.status(500).send({\n message: 'Failed to purge DLQ',\n error\n });\n }\n });\n\n fastify.post(`/${prefix}/queues/:queueName/enqueue`, async (request, reply) => {\n const { queueName } = request.params as { queueName: string };\n const queueManager = fastify.queues;\n\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n try {\n const result = await queueManager.enqueueMessage(queueName, request.body, request.headers as Record<string, any>);\n return reply.status(200).send(result);\n } catch (error) {\n return reply.status(500).send({\n message: 'Failed to enqueue message',\n error\n });\n }\n });\n\n fastify.delete(`/${prefix}/queues/:queueName`, async (request, reply) => {\n const { queueName } = request.params as { queueName: string };\n const queueManager = fastify.queues;\n\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n try {\n await queueManager.removeQueue(queueName);\n return reply.status(200).send({\n status: 'success',\n message: `Queue ${queueName} removed successfully`\n });\n } catch (error) {\n return reply.status(500).send({\n message: 'Failed to remove queue',\n error\n });\n }\n });\n\n fastify.post(`/${prefix}/queues`, async (request, reply) => {\n const { queueName, module } = request.body as { queueName: string; module?: string };\n const queueManager = fastify.queues;\n\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n if (!queueName) {\n return reply.status(400).send({ error: 'Queue name is required' });\n }\n\n try {\n // Simple handler that logs messages\n const handler = async (message: any) => {\n console.log(`Processing message in ${queueName}:`, message);\n return undefined;\n };\n\n await queueManager.addQueue(queueName, handler, module);\n return reply.status(201).send({\n status: 'success',\n message: `Queue ${queueName} created successfully`,\n queueName\n });\n } catch (error) {\n return reply.status(500).send({\n message: 'Failed to create queue',\n error\n });\n }\n });\n\n // Topics endpoints - a topic is a fan-out over queues (see\n // queue-plugin/decorator.ts), so subscriber stats are read the same way\n // a queue's own stats are, per subscriber queue name.\n const summarizeSubscribers = (subscriberQueues: string[]) =>\n subscriberQueues.map(queueName => {\n const stats = fastify.queues.getQueueStats(queueName);\n return {\n queueName,\n module: stats?.module,\n stats: stats ? {\n incoming: stats.incoming.length,\n processing: stats.processing.length,\n dlq: stats.dlq.length\n } : null\n };\n });\n\n fastify.get(`/${prefix}/topics`, async (_, reply) => {\n const queueManager = fastify.queues;\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n const topics = Object.entries(queueManager.listTopics()).map(([name, subscriberQueues]) => ({\n name,\n subscribers: summarizeSubscribers(subscriberQueues)\n }));\n\n return { topics };\n });\n\n fastify.get(`/${prefix}/topics/:topicName`, async (request, reply) => {\n const { topicName } = request.params as { topicName: string };\n const queueManager = fastify.queues;\n\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n const subscriberQueues = queueManager.listTopics()[topicName];\n if (!subscriberQueues) {\n return reply.status(404).send({ error: 'Topic not found' });\n }\n\n return {\n name: topicName,\n subscribers: summarizeSubscribers(subscriberQueues)\n };\n });\n\n fastify.post(`/${prefix}/topics/:topicName/publish`, async (request, reply) => {\n const { topicName } = request.params as { topicName: string };\n const queueManager = fastify.queues;\n\n if (!queueManager) {\n return reply.status(503).send({ error: 'Queue service not available' });\n }\n\n try {\n const results = await queueManager.publishTopic(topicName, request.body, request.headers as Record<string, any>);\n if (results === null) {\n return reply.status(404).send({ error: 'Topic not found' });\n }\n return reply.status(200).send({ topicName, results });\n } catch (error) {\n return reply.status(500).send({\n message: 'Failed to publish to topic',\n error\n });\n }\n });\n\n // Schedules endpoints - access via decorator\n fastify.get(`/${prefix}/schedules`, async (_, reply) => {\n const schedulerManager = fastify.scheduler;\n if (!schedulerManager) {\n return reply.status(503).send({ error: 'Scheduler service not available' });\n }\n\n const jobNames = schedulerManager.listJobs();\n const jobs = jobNames.map(name => {\n const jobStats = schedulerManager.getJobStats(name);\n return {\n name,\n enabled: jobStats?.job.enabled || false,\n isRunning: jobStats?.isRunning || false,\n cronExpression: jobStats?.job.cronExpression,\n timezone: jobStats?.job.timezone\n };\n });\n\n return { schedules: jobs };\n });\n\n fastify.get(`/${prefix}/schedules/:jobName`, async (request, reply) => {\n const { jobName } = request.params as { jobName: string };\n const schedulerManager = (fastify as any).scheduler;\n\n if (!schedulerManager) {\n return reply.status(503).send({ error: 'Scheduler service not available' });\n }\n\n const jobStats = schedulerManager.getJobStats(jobName);\n if (!jobStats) {\n return reply.status(404).send({ error: 'Job not found' });\n }\n\n return {\n name: jobName,\n job: jobStats.job,\n isRunning: jobStats.isRunning,\n timerId: jobStats.timerId ? 'scheduled' : 'not_scheduled'\n };\n });\n\n // Every real execution of this job - tick-triggered or manually triggered,\n // from the console or otherwise - not just runs kicked off from this UI.\n fastify.get(`/${prefix}/schedules/:jobName/executions`, async (request, reply) => {\n const { jobName } = request.params as { jobName: string };\n const schedulerManager = fastify.scheduler;\n\n if (!schedulerManager) {\n return reply.status(503).send({ error: 'Scheduler service not available' });\n }\n\n if (!schedulerManager.getJobStats(jobName)) {\n return reply.status(404).send({ error: 'Job not found' });\n }\n\n return { executions: schedulerManager.getJobExecutionHistory(jobName) };\n });\n\n // Schedule action endpoints - use decorators\n fastify.post(`/${prefix}/schedules/:jobName/trigger`, async (request, reply) => {\n const { jobName } = request.params as { jobName: string };\n const schedulerManager = fastify.scheduler;\n\n if (!schedulerManager) {\n return reply.status(503).send({ error: 'Scheduler service not available' });\n }\n\n try {\n await schedulerManager.triggerJob(jobName);\n return reply.status(200).send({\n status: 'success',\n message: `Schedule ${jobName} triggered successfully`\n });\n } catch {\n return reply.status(500).send({ error: 'Failed to trigger schedule' });\n }\n });\n\n fastify.put(`/${prefix}/schedules/:jobName/enable`, async (request, reply) => {\n const { jobName } = request.params as { jobName: string };\n const schedulerManager = fastify.scheduler;\n\n if (!schedulerManager) {\n return reply.status(503).send({ error: 'Scheduler service not available' });\n }\n\n try {\n await schedulerManager.enableJob(jobName);\n return reply.status(200).send({\n status: 'success',\n message: `Schedule ${jobName} enabled successfully`\n });\n } catch {\n return reply.status(500).send({ error: 'Failed to enable schedule' });\n }\n });\n\n fastify.put(`/${prefix}/schedules/:jobName/disable`, async (request, reply) => {\n const { jobName } = request.params as { jobName: string };\n const schedulerManager = fastify.scheduler;\n\n if (!schedulerManager) {\n return reply.status(503).send({ error: 'Scheduler service not available' });\n }\n\n try {\n await schedulerManager.disableJob(jobName);\n return reply.status(200).send({\n status: 'success',\n message: `Schedule ${jobName} disabled successfully`\n });\n } catch {\n return reply.status(500).send({ error: 'Failed to disable schedule' });\n }\n });\n\n // Logs endpoints\n fastify.get(`/${prefix}/logs`, async (request) => {\n const {\n limit = 100,\n level,\n module,\n reqId,\n } = request.query as {\n limit?: number;\n level?: string;\n module?: string;\n reqId?: string;\n };\n\n let logs = logStore.getLogs(Number(limit));\n\n if (level) {\n logs = logs.filter(log => log.levelName === level);\n }\n\n if (module) {\n logs = logs.filter(log => log.module === module);\n }\n\n if (reqId) {\n logs = logs.filter(log => log.reqId === reqId);\n }\n\n return { logs };\n });\n\n fastify.delete(`/${prefix}/logs`, async () => {\n logStore.clear();\n return { status: 'success', message: 'Logs cleared' };\n });\n\n // WebSocket endpoints\n fastify.get(`/${prefix}/websockets`, async (_, reply) => {\n const wsManager = fastify.websockets;\n if (!wsManager) {\n return reply.status(503).send({ error: 'WebSocket service not available' });\n }\n\n const connections = wsManager.getConnections();\n const pathSet = new Set(connections.map(c => c.path));\n const paths = Array.from(pathSet).map(p => ({\n path: p,\n connections: wsManager.getConnections(p).map(c => ({\n connectionId: c.connectionId,\n path: c.path,\n connectedAt: c.connectedAt,\n })),\n }));\n\n return { paths };\n });\n\n fastify.get(`/${prefix}/websockets/:path`, async (request, reply) => {\n const wsManager = fastify.websockets;\n if (!wsManager) {\n return reply.status(503).send({ error: 'WebSocket service not available' });\n }\n\n const { path: wsPath } = request.params as { path: string };\n const decodedPath = '/' + wsPath;\n const connections = wsManager.getConnections(decodedPath).map(c => ({\n connectionId: c.connectionId,\n path: c.path,\n connectedAt: c.connectedAt,\n }));\n\n return { path: decodedPath, connections };\n });\n\n fastify.post(`/${prefix}/websockets/:connectionId/send`, async (request, reply) => {\n const wsManager = fastify.websockets;\n if (!wsManager) {\n return reply.status(503).send({ error: 'WebSocket service not available' });\n }\n\n const { connectionId } = request.params as { connectionId: string };\n\n try {\n await wsManager.sendToClient(connectionId, request.body);\n return reply.status(200).send({ status: 'success', message: `Message sent to ${connectionId}` });\n } catch (error) {\n if (error instanceof WebSocketConnectionGoneError) {\n return reply.status(410).send({ error: error.message });\n }\n return reply.status(404).send({ error: (error as Error).message });\n }\n });\n\n // Emails endpoints - read straight off disk each request, since the\n // local email service keeps no in-memory history (the .eml/.json files\n // written to DEV_CLOUD_EMAIL_DIR are the only store).\n fastify.get(`/${prefix}/emails`, async (request) => {\n const { limit } = request.query as { limit?: string };\n return { emails: await listEmailHistory(limit ? Number(limit) : undefined) };\n });\n\n fastify.get(`/${prefix}/emails/:id`, async (request, reply) => {\n const { id } = request.params as { id: string };\n const email = await getEmailHistoryEntry(id);\n\n if (!email) {\n return reply.status(404).send({ error: 'Email not found' });\n }\n\n return { email };\n });\n\n fastify.get(`/${prefix}/emails/:id/raw`, async (request, reply) => {\n const { id } = request.params as { id: string };\n const raw = await getEmailRaw(id);\n\n if (!raw) {\n return reply.status(404).send({ error: 'Email not found' });\n }\n\n reply.type('message/rfc822');\n return raw;\n });\n\n fastify.get(`/${prefix}/emails/:id/body`, async (request, reply) => {\n const { id } = request.params as { id: string };\n const body = await getEmailBody(id);\n\n if (!body) {\n return reply.status(404).send({ error: 'Email not found' });\n }\n\n return { body };\n });\n\n // Server-Sent Events for real-time logs\n fastify.get(`/${prefix}/logs/stream`, async (request, reply) => {\n const { level, module, reqId } = request.query as {\n level?: string;\n module?: string;\n reqId?: string;\n };\n\n // Mirror the same filters the REST /logs endpoint applies - otherwise a\n // client viewing a filtered (e.g. module-scoped) log list gets every\n // other module's activity pushed into it live, which looks exactly like\n // cleared logs reappearing.\n const matchesFilters = (log: LogEntry) => {\n if (level && log.levelName !== level) return false;\n if (module && log.module !== module) return false;\n if (reqId && log.reqId !== reqId) return false;\n return true;\n };\n\n reply.type('text/event-stream');\n reply.header('Cache-Control', 'no-cache');\n reply.header('Connection', 'keep-alive');\n reply.header('Access-Control-Allow-Origin', '*');\n\n // Send initial logs\n const initialLogs = logStore.getLogs(50).filter(matchesFilters);\n reply.raw.write(`data: ${JSON.stringify({ type: 'initial', logs: initialLogs })}\\n\\n`);\n\n // Subscribe to new logs\n const unsubscribe = logStore.subscribe((log) => {\n if (matchesFilters(log)) {\n reply.raw.write(`data: ${JSON.stringify({ type: 'log', log })}\\n\\n`);\n }\n });\n\n // Cleanup on client disconnect\n request.raw.on('close', () => {\n unsubscribe();\n });\n });\n\n // Serve static UI files if enabled\n if (enableUI) {\n const devConsolePath = path.dirname(\n require.resolve('@cloudnux/dev-console/dist/index.html')\n );\n\n await fastify.register(fastifyStatic, {\n root: devConsolePath,\n decorateReply: true,\n prefix: `/${prefix}/`\n });\n\n // Serve dev-console SPA\n fastify.get(`/${prefix}`, async (_, reply) => {\n return reply.sendFile('index.html');\n });\n }\n}\n\nexport const devConsolePlugin = fsPlugin(devConsolePluginFunction, {\n name: 'dev-console-plugin'\n})","import { FastifyInstance, FastifyPluginAsync } from \"fastify\";\nimport fsPlugin from \"fastify-plugin\";\n\nimport { QueuePluginOptions, QueueRuntime } from \"./types\";\nimport { DEFAULT_CONFIG, mergeConfig } from \"./core\";\nimport { tick } from \"./processing\";\nimport { initializePersistence } from \"./persistence\";\nimport { createQueueManager } from \"./decorator\";\nimport { registerQueueRoutes } from \"./routes\";\n\nexport const queuesPlugin: FastifyPluginAsync<QueuePluginOptions> =\n fsPlugin(async (\n app: FastifyInstance,\n options: QueuePluginOptions\n ) => {\n const runtime: QueueRuntime = {\n config: mergeConfig(DEFAULT_CONFIG, options.config),\n queues: {},\n topics: {},\n dirtyQueues: new Set<string>(),\n lastSavedAt: Date.now(),\n messageHistory: [],\n logging: app.logging,\n };\n\n // One timer for the entire plugin: every tickIntervalMs, check every\n // queue for batches/retries that are due, and save persistence if\n // its interval has elapsed. See processing.ts:tick.\n const tickIntervalId = setInterval(() => tick(runtime), runtime.config.tickIntervalMs);\n app.addHook('onClose', async () => clearInterval(tickIntervalId));\n\n app.decorate('queues', createQueueManager(runtime));\n registerQueueRoutes(app, options.prefix);\n\n await initializePersistence(runtime);\n });","import { EventHandler, QueueConfig, QueueMessage, QueueMessageHistoryEntry, QueueService, QueueSummary } from \"./types\";\n\nconst MAX_MESSAGE_HISTORY = 500;\n\n// default config\nexport const DEFAULT_CONFIG: QueueConfig = {\n batchSize: 10,\n batchWindowMs: 500,\n maxRetries: 3,\n parallel: true,\n maxConcurrent: 5,\n retryBackoff: true,\n tickIntervalMs: 50,\n persistence: {\n enabled: true,\n directory: './.develop/.queue-data',\n saveInterval: 60000,\n saveOnShutdown: false\n }\n};\n\n// Pure function to merge configs\nexport const mergeConfig = (defaultConfig: QueueConfig, userConfig?: Partial<QueueConfig>): QueueConfig => ({\n ...defaultConfig,\n ...userConfig,\n persistence: {\n ...defaultConfig.persistence,\n ...(userConfig?.persistence || {})\n }\n});\n\n// Pure function to create a new queue service\nexport const createQueueService = (handler: EventHandler, module?: string): QueueService => ({\n handler,\n incoming: [],\n processing: [],\n dlq: [],\n processingBatch: false,\n module\n});\n\n// Pure function to create a queue message\nexport const createQueueMessage = (body: any, headers: Record<string, any>): QueueMessage => {\n const id = Date.now().toString() + Math.random().toString(36).substring(2, 7);\n const message: QueueMessage = {\n id,\n timestamp: new Date(),\n attempts: 0,\n payload: body,\n attributes: headers,\n };\n\n const delaySeconds = Number(headers?.['x-delay-seconds']);\n if (delaySeconds > 0) {\n message.nextAttempt = new Date(Date.now() + delaySeconds * 1000);\n }\n\n return message;\n};\n\n// Pure function to schedule a retry for a message\n// Puts a failed message back into `incoming` to wait out its backoff delay,\n// same as any delayed message - so the next batch dispatch picks it up\n// mixed in with whatever else is ready, instead of retrying it alone.\nexport const scheduleRetry = (queueService: QueueService, message: QueueMessage, delayMs: number): void => {\n removeFromProcessing(queueService, message.id);\n message.attempts += 1;\n message.nextAttempt = new Date(Date.now() + delayMs);\n queueService.incoming.push(message);\n};\n\n\n// Pure function to check whether a message is ready to be processed\nexport const isMessageReady = (message: QueueMessage, now: number = Date.now()): boolean => {\n return !message.nextAttempt || message.nextAttempt.getTime() <= now;\n};\n\n// Pure function to move ready messages from incoming to processing, leaving delayed messages in place\nexport const moveToProcessing = (queueService: QueueService, batchSize: number): QueueMessage[] => {\n const now = Date.now();\n const ready: QueueMessage[] = [];\n const remaining: QueueMessage[] = [];\n\n for (const message of queueService.incoming) {\n if (ready.length < batchSize && isMessageReady(message, now)) {\n ready.push(message);\n } else {\n remaining.push(message);\n }\n }\n\n queueService.incoming = remaining;\n return ready;\n};\n\n// Pure function to remove message from processing queue\nexport const removeFromProcessing = (queueService: QueueService, messageId: string): void => {\n queueService.processing = queueService.processing.filter(msg => msg.id !== messageId);\n};\n\n// Pure function to move message to DLQ\nexport const moveToDLQ = (queueService: QueueService, message: QueueMessage, error: string): void => {\n queueService.dlq.push({\n ...message,\n error,\n failedAt: new Date()\n });\n removeFromProcessing(queueService, message.id);\n};\n\n// Pure function to calculate backoff delay\nexport const calculateBackoffDelay = (attempts: number): number => {\n return Math.pow(2, attempts) * 100;\n};\n\n// Pure function to create queue summary\nexport const createQueueSummary = (queueService: QueueService, config: QueueConfig): QueueSummary => ({\n incoming: queueService.incoming.length,\n processing: queueService.processing.length,\n dlq: queueService.dlq.length,\n isProcessing: queueService.processingBatch,\n configuration: {\n batchSize: config.batchSize,\n batchWindowMs: config.batchWindowMs,\n parallel: config.parallel,\n maxConcurrent: config.maxConcurrent\n }\n});\n\n// Pure function to create dashboard summary\nexport const createDashboardSummary = (queues: Record<string, QueueService>, config: QueueConfig): Record<string, QueueSummary> => {\n return Object.entries(queues).reduce((summary, [queueName, queue]) => {\n summary[queueName] = createQueueSummary(queue, config);\n return summary;\n }, {} as Record<string, QueueSummary>);\n};\n\n// Pure function to move DLQ messages back to incoming\nexport const moveDLQToIncoming = (queueService: QueueService): number => {\n const dlqCount = queueService.dlq.length;\n\n if (dlqCount === 0) return 0;\n\n const movedMessages = queueService.dlq.map(message => ({\n ...message,\n attempts: 0,\n error: undefined,\n failedAt: undefined,\n reprocessed: true,\n originalId: message.id,\n id: Date.now().toString() + Math.random().toString(36).substring(2, 7)\n }));\n\n queueService.incoming.push(...movedMessages);\n queueService.dlq = [];\n\n return dlqCount;\n};\n\n// Pure function to purge DLQ\nexport const purgeDLQ = (queueService: QueueService): number => {\n const dlqCount = queueService.dlq.length;\n queueService.dlq = [];\n return dlqCount;\n};\n\n// Pure function to build a message-history record for a completed or\n// terminally-failed message. This is what powers the dev console's\n// per-queue history view for messages that already left incoming/processing/dlq.\nexport const createHistoryEntry = (\n queueName: string,\n message: QueueMessage,\n status: 'completed' | 'failed',\n error?: string\n): QueueMessageHistoryEntry => ({\n id: message.id,\n queueName,\n status,\n timestamp: message.timestamp,\n completedAt: new Date(),\n attempts: message.attempts,\n payload: message.payload,\n attributes: message.attributes,\n error,\n});\n\n// Appends to the bounded history log in place, mirroring schedule-plugin's\n// executionHistory cap so long-running processes don't grow this unbounded.\nexport const recordMessageHistory = (\n history: QueueMessageHistoryEntry[],\n entry: QueueMessageHistoryEntry\n): void => {\n history.push(entry);\n if (history.length > MAX_MESSAGE_HISTORY) {\n history.splice(0, history.length - MAX_MESSAGE_HISTORY);\n }\n};","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\n\nimport { QueueService, QueueRuntime, QueueMessage } from \"./types\";\n\nconst createQueueData = (queueService: QueueService) => ({\n incoming: queueService.incoming,\n processing: queueService.processing,\n dlq: queueService.dlq,\n savedAt: new Date()\n});\n\nconst restoreDates = (messages: QueueMessage[]): void => {\n messages.forEach((msg: QueueMessage) => {\n msg.timestamp = new Date(msg.timestamp);\n if (msg.nextAttempt) msg.nextAttempt = new Date(msg.nextAttempt);\n if (msg.failedAt) msg.failedAt = new Date(msg.failedAt);\n });\n};\n\nexport const saveQueueState = async (runtime: QueueRuntime, queueName: string, queueService: QueueService): Promise<void> => {\n try {\n const queueData = createQueueData(queueService);\n const now = Date.now();\n const queueFilePath = path.join(runtime.config.persistence.directory, `${queueName}.json`);\n const tempFilePath = path.join(runtime.config.persistence.directory, `${queueName}.${now}temp.json`);\n\n // Write to a temp file first, then rename - rename is atomic, so a\n // reader never sees a half-written file.\n await fs.writeFile(tempFilePath, JSON.stringify(queueData, null, 2), 'utf8');\n await fs.rename(tempFilePath, queueFilePath);\n\n runtime.logging.debug({ module: queueService.module }, `Queue state saved: ${queueName}`);\n } catch (error: any) {\n runtime.logging.error(\n { module: queueService.module, error: error?.message },\n `Failed to save queue state for ${queueName}`\n );\n }\n};\n\nexport const saveAllQueueStates = async (runtime: QueueRuntime): Promise<void> => {\n try {\n for (const [queueName, queueService] of Object.entries(runtime.queues)) {\n await saveQueueState(runtime, queueName, queueService);\n }\n runtime.logging.debug(`All queue states saved to ${runtime.config.persistence.directory}`);\n } catch (error: any) {\n runtime.logging.error({ error: error?.message }, `Failed to save all queue states`);\n }\n};\n\n// Only saves queues that changed since the last save (tracked via\n// runtime.dirtyQueues). Called from processing.ts's tick once\n// persistence.saveInterval has elapsed.\nexport const saveDirtyQueueStates = async (runtime: QueueRuntime): Promise<void> => {\n if (runtime.dirtyQueues.size === 0) return;\n\n try {\n const queueNames = [...runtime.dirtyQueues];\n runtime.dirtyQueues.clear();\n\n for (const queueName of queueNames) {\n if (runtime.queues[queueName]) {\n await saveQueueState(runtime, queueName, runtime.queues[queueName]);\n }\n }\n } catch (error: any) {\n runtime.logging.error({ error: error?.message }, `Failed to save dirty queue states`);\n }\n};\n\n// Called from addQueue, right after a queue is registered, to restore\n// whatever was on disk for it from a previous run.\nexport const loadQueueState = async (runtime: QueueRuntime, queueName: string): Promise<void> => {\n try {\n const queueService = runtime.queues[queueName];\n if (!queueService) {\n runtime.logging.warn(`Skipping load for non-existent queue: ${queueName}`);\n return;\n }\n\n const queueFilePath = path.join(runtime.config.persistence.directory, `${queueName}.json`);\n\n try {\n const data = await fs.readFile(queueFilePath, 'utf8');\n const queueData = JSON.parse(data);\n\n restoreDates(queueData.incoming);\n restoreDates(queueData.processing);\n restoreDates(queueData.dlq);\n\n queueService.incoming = queueData.incoming;\n queueService.dlq = queueData.dlq;\n queueService.processing = [];\n\n // Nothing is actually in flight right after a restart - anything\n // that was mid-handling goes back into the ready pool like any\n // other message (the tick's next batch picks it up), or straight\n // to the DLQ if it had already used up its retries before the\n // shutdown.\n for (const message of queueData.processing as QueueMessage[]) {\n if (message.attempts >= runtime.config.maxRetries) {\n queueService.dlq.push({ ...message, error: 'max retries exceeded before restart', failedAt: new Date() });\n } else {\n message.nextAttempt = new Date();\n queueService.incoming.push(message);\n }\n }\n\n runtime.logging.debug(\n { module: queueService.module },\n `Queue state loaded: ${queueName} (saved at ${queueData.savedAt})`\n );\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n runtime.logging.debug({ module: queueService.module }, `No saved state found for queue: ${queueName}`);\n } else {\n throw error;\n }\n }\n } catch (error: any) {\n runtime.logging.error({ error: error?.message }, `Failed to load queue state for ${queueName}`);\n }\n};\n\nexport const initializePersistence = async (runtime: QueueRuntime): Promise<void> => {\n try {\n await fs.mkdir(runtime.config.persistence.directory, { recursive: true });\n\n if (runtime.config.persistence.saveOnShutdown) {\n const shutdownHandler = async () => {\n runtime.logging.debug('Saving queue state before shutdown...');\n await saveAllQueueStates(runtime);\n process.exit(0);\n };\n\n process.on('SIGINT', shutdownHandler);\n process.on('SIGTERM', shutdownHandler);\n }\n\n runtime.logging.debug(`Queue persistence initialized: ${runtime.config.persistence.directory}`);\n } catch (error: any) {\n runtime.logging.error({ error: error?.message }, `Failed to initialize queue persistence`);\n }\n};","import { QueueMessage, QueueService, QueueRuntime } from \"./types\";\nimport {\n isMessageReady,\n moveToProcessing,\n removeFromProcessing,\n moveToDLQ,\n scheduleRetry,\n calculateBackoffDelay,\n createHistoryEntry,\n recordMessageHistory,\n} from \"./core\";\nimport { saveDirtyQueueStates } from \"./persistence\";\n\n// Sends one message through the user's handler. Success removes it from\n// `processing`; failure either schedules a retry or moves it to the DLQ.\n// Used for both freshly-batched messages and individually-retried ones.\n// Wrapped in runWithLogContext by processBatch, so every log call below\n// (and anything the user's handler itself logs) carries this message's\n// module/reqId without having to pass them through explicitly.\nconst processMessage = async (\n runtime: QueueRuntime,\n queueName: string,\n message: QueueMessage,\n queueService: QueueService\n): Promise<void> => {\n try {\n const result = await queueService.handler(message);\n if (result?.failureId) {\n handleFailure(runtime, queueName, message, queueService);\n } else {\n removeFromProcessing(queueService, message.id);\n recordMessageHistory(runtime.messageHistory, createHistoryEntry(queueName, message, 'completed'));\n runtime.logging.debug(`Successfully processed message ${message.id} in queue ${queueName}`);\n }\n } catch {\n handleFailure(runtime, queueName, message, queueService);\n }\n};\n\nconst handleFailure = (\n runtime: QueueRuntime,\n queueName: string,\n message: QueueMessage,\n queueService: QueueService\n): void => {\n runtime.logging.error(`Error processing message ${message.id} in queue ${queueName}: handler returned failure`);\n\n if (message.attempts >= runtime.config.maxRetries) {\n moveToDLQ(queueService, message, 'max retries exceeded');\n recordMessageHistory(runtime.messageHistory, createHistoryEntry(queueName, message, 'failed', 'max retries exceeded'));\n return;\n }\n\n const delayMs = runtime.config.retryBackoff ? calculateBackoffDelay(message.attempts + 1) : 0;\n scheduleRetry(queueService, message, delayMs);\n runtime.logging.debug(`Scheduling retry for message ${message.id} in ${delayMs}ms`);\n};\n\n// Pulls up to batchSize ready messages out of `incoming` and runs them\n// through processMessage concurrently. Guarded by `processingBatch` so the\n// tick never starts a second batch for a queue while one is still running.\nconst processBatch = async (\n runtime: QueueRuntime,\n queueName: string,\n queueService: QueueService\n): Promise<void> => {\n if (queueService.processingBatch) {\n return;\n }\n\n try {\n queueService.processingBatch = true;\n\n const messagesToProcess = moveToProcessing(queueService, runtime.config.batchSize);\n if (messagesToProcess.length === 0) {\n return;\n }\n\n queueService.processing.push(...messagesToProcess);\n\n await Promise.all(\n messagesToProcess.map(message => runtime.logging.runWithLogContext(\n { module: queueService.module, reqId: message.id },\n () => processMessage(runtime, queueName, message, queueService)\n ))\n );\n\n if (runtime.config.persistence.enabled) {\n runtime.dirtyQueues.add(queueName);\n }\n } finally {\n queueService.processingBatch = false;\n }\n};\n\nconst dispatchBatchIfDue = (\n runtime: QueueRuntime,\n queueName: string,\n queueService: QueueService,\n now: number\n): void => {\n if (queueService.processingBatch) {\n return;\n }\n const ready = queueService.incoming.filter(message => isMessageReady(message, now));\n if (ready.length === 0) {\n return;\n }\n\n const dueBySize = ready.length >= runtime.config.batchSize;\n const oldestReadyAge = now - Math.min(...ready.map(message => message.timestamp.getTime()));\n const dueByWindow = oldestReadyAge >= runtime.config.batchWindowMs;\n\n if (dueBySize || dueByWindow) {\n processBatch(runtime, queueName, queueService);\n }\n};\n\nconst maybeSavePersistence = (runtime: QueueRuntime, now: number): void => {\n if (!runtime.config.persistence.enabled) {\n return;\n }\n\n const saveInterval = runtime.config.persistence.saveInterval ?? 0;\n if (saveInterval > 0 && now - runtime.lastSavedAt >= saveInterval) {\n runtime.lastSavedAt = now;\n saveDirtyQueueStates(runtime);\n }\n};\n\n\n// The one timer for the whole plugin. Every tickIntervalMs: for every queue,\n// dispatch a batch if one is due (this is also how retried messages get\n// picked up - they wait in `incoming` like any delayed message); then save\n// persistence if its interval has elapsed.\nexport const tick = (runtime: QueueRuntime): void => {\n const now = Date.now();\n for (const [queueName, queueService] of Object.entries(runtime.queues)) {\n dispatchBatchIfDue(runtime, queueName, queueService, now);\n }\n maybeSavePersistence(runtime, now);\n};","import { QueueService, QueueManager, QueueRuntime, EventHandler } from \"./types\";\nimport {\n createQueueService,\n createQueueMessage,\n createDashboardSummary,\n createQueueSummary,\n moveDLQToIncoming,\n purgeDLQ,\n} from \"./core\";\nimport { loadQueueState, saveQueueState } from \"./persistence\";\n\nconst isValidQueueName = (queueName: string): boolean => {\n return typeof queueName === 'string' && queueName.length > 0 && /^[a-zA-Z0-9_-]+$/.test(queueName);\n};\n\nconst validateQueueName = (queueName: string): void => {\n if (!queueName || typeof queueName !== 'string') {\n throw new Error('Queue name must be a non-empty string');\n }\n\n if (!isValidQueueName(queueName)) {\n throw new Error('Queue name must contain only alphanumeric characters, hyphens, and underscores');\n }\n};\n\nconst validateHandler = (handler: any): void => {\n if (typeof handler !== 'function') {\n throw new Error('Handler must be a function');\n }\n};\n\nexport const addQueue = async (runtime: QueueRuntime, queueName: string, handler: EventHandler, module?: string): Promise<void> => {\n try {\n validateQueueName(queueName);\n validateHandler(handler);\n\n if (runtime.queues[queueName]) {\n runtime.logging.warn({ module }, `Queue already exists: ${queueName}.`);\n return;\n }\n\n runtime.queues[queueName] = createQueueService(handler, module);\n\n if (runtime.config.persistence.enabled) {\n await loadQueueState(runtime, queueName);\n }\n\n runtime.logging.info({ module }, `Queue added: ${queueName}`);\n } catch (error: any) {\n runtime.logging.error({ module, error: error.message }, `Failed to add queue ${queueName}`);\n throw error;\n }\n};\n\nexport const removeQueue = async (runtime: QueueRuntime, queueName: string): Promise<void> => {\n try {\n validateQueueName(queueName);\n\n const queueService = runtime.queues[queueName];\n if (!queueService) {\n throw new Error(`Queue '${queueName}' does not exist`);\n }\n\n const totalMessages = queueService.incoming.length + queueService.processing.length;\n if (totalMessages > 0) {\n runtime.logging.warn(\n { module: queueService.module },\n `Removing queue with ${totalMessages} pending messages: ${queueName}`\n );\n }\n\n if (runtime.config.persistence.enabled) {\n await saveQueueState(runtime, queueName, queueService);\n }\n\n delete runtime.queues[queueName];\n\n runtime.logging.info({ module: queueService.module }, `Queue removed: ${queueName}`);\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to remove queue ${queueName}`);\n throw error;\n }\n};\n\nexport const hasQueue = (runtime: QueueRuntime, queueName: string): boolean => {\n try {\n validateQueueName(queueName);\n return queueName in runtime.queues;\n } catch {\n return false;\n }\n};\n\nexport const listQueues = (runtime: QueueRuntime, module?: string): string[] => {\n return Object.keys(runtime.queues)\n .filter(queueName => !module || runtime.queues[queueName].module === module)\n .sort();\n};\n\nexport const getQueueStats = (runtime: QueueRuntime, queueName: string): QueueService | null => {\n try {\n validateQueueName(queueName);\n return runtime.queues[queueName] || null;\n } catch {\n return null;\n }\n};\n\nexport const getQueuesMap = (runtime: QueueRuntime): Record<string, QueueService> => {\n // Return a copy to prevent external modification\n return { ...runtime.queues };\n};\n\nexport const getDashboardSummary = (runtime: QueueRuntime) =>\n createDashboardSummary(runtime.queues, runtime.config);\n\nexport const getQueueSummary = (runtime: QueueRuntime, queueName: string) => {\n const queue = runtime.queues[queueName];\n if (!queue) {\n return null;\n }\n\n return {\n stats: createQueueSummary(queue, runtime.config),\n messages: {\n incoming: queue.incoming,\n processing: queue.processing,\n dlq: queue.dlq\n }\n };\n};\n\nexport const enqueueMessage = async (runtime: QueueRuntime, queueName: string, body: any, attributes: any) => {\n const queueService = runtime.queues[queueName];\n if (!queueService) {\n return null;\n }\n\n const message = createQueueMessage(body, attributes);\n queueService.incoming.push(message);\n\n if (runtime.config.persistence.enabled) {\n runtime.dirtyQueues.add(queueName);\n }\n\n return { id: message.id, queueName };\n};\n\nexport const processDlq = async (runtime: QueueRuntime, queueName: string) => {\n const queueService = runtime.queues[queueName];\n if (!queueService) {\n return null;\n }\n\n const processedCount = moveDLQToIncoming(queueService);\n if (processedCount === 0) {\n return { status: \"success\", message: \"No messages in DLQ to process\", processed: 0 };\n }\n\n runtime.logging.warn(\n { module: queueService.module },\n `Moving ${processedCount} messages from DLQ for ${queueName}`\n );\n\n if (runtime.config.persistence.enabled) {\n runtime.dirtyQueues.add(queueName);\n }\n\n return {\n status: \"success\",\n message: `Moved ${processedCount} messages from DLQ to processing queue`,\n processed: processedCount\n };\n};\n\nexport const purgeDlq = async (runtime: QueueRuntime, queueName: string) => {\n const queueService = runtime.queues[queueName];\n if (!queueService) {\n return null;\n }\n\n const purgedCount = purgeDLQ(queueService);\n if (purgedCount === 0) {\n return { status: \"success\", message: \"No messages in DLQ to purge\", purged: 0 };\n }\n\n runtime.logging.warn(\n { module: queueService.module },\n `Purging ${purgedCount} messages from DLQ for ${queueName}`\n );\n\n if (runtime.config.persistence.enabled) {\n runtime.dirtyQueues.add(queueName);\n }\n\n return {\n status: \"success\",\n message: `Purged ${purgedCount} messages from DLQ`,\n purged: purgedCount\n };\n};\n\nexport const getMessageHistory = (runtime: QueueRuntime, queueName: string, limit = 50) => {\n return runtime.messageHistory\n .filter(entry => entry.queueName === queueName)\n .slice(-limit)\n .reverse();\n};\n\nexport const subscribeTopic = (runtime: QueueRuntime, topicName: string, queueName: string): void => {\n const subscribers = runtime.topics[topicName] ?? (runtime.topics[topicName] = []);\n if (!subscribers.includes(queueName)) {\n subscribers.push(queueName);\n }\n\n runtime.logging.info({ topicName, queueName }, `Subscribed queue '${queueName}' to topic '${topicName}'`);\n};\n\n// Fans a published message out to every queue subscribed to the topic, reusing\n// enqueueMessage so each subscriber gets its own independent backlog/DLQ/retries.\nexport const publishTopic = async (runtime: QueueRuntime, topicName: string, body: any, attributes: any) => {\n const subscribers = runtime.topics[topicName];\n if (!subscribers || subscribers.length === 0) {\n return null;\n }\n\n const results = await Promise.all(\n subscribers.map(queueName => enqueueMessage(runtime, queueName, body, attributes))\n );\n\n return results.filter((result): result is { id: string; queueName: string } => result !== null);\n};\n\nexport const listTopics = (runtime: QueueRuntime): Record<string, string[]> => {\n // Return a copy to prevent external modification\n return Object.fromEntries(Object.entries(runtime.topics).map(([name, queues]) => [name, [...queues]]));\n};\n\n// The one place runtime gets bound into the public app.queues shape -\n// Fastify needs a plain object of methods with no runtime param, so this\n// wraps each plain function above with `runtime` pre-applied. Everything\n// above this line is a normal function you can call directly with an\n// explicit runtime, e.g. in tests.\nexport const createQueueManager = (runtime: QueueRuntime): QueueManager => ({\n addQueue: (queueName, handler, module) => addQueue(runtime, queueName, handler, module),\n removeQueue: (queueName) => removeQueue(runtime, queueName),\n hasQueue: (queueName) => hasQueue(runtime, queueName),\n listQueues: (module) => listQueues(runtime, module),\n getQueueStats: (queueName) => getQueueStats(runtime, queueName),\n getQueuesMap: () => getQueuesMap(runtime),\n getConfig: () => runtime.config,\n getDashboardSummary: () => getDashboardSummary(runtime),\n getQueueSummary: (queueName) => getQueueSummary(runtime, queueName),\n enqueueMessage: (queueName, body, attributes) => enqueueMessage(runtime, queueName, body, attributes),\n processDlq: (queueName) => processDlq(runtime, queueName),\n purgeDlq: (queueName) => purgeDlq(runtime, queueName),\n getMessageHistory: (queueName, limit) => getMessageHistory(runtime, queueName, limit),\n subscribeTopic: (topicName, queueName) => subscribeTopic(runtime, topicName, queueName),\n publishTopic: (topicName, body, attributes) => publishTopic(runtime, topicName, body, attributes),\n listTopics: () => listTopics(runtime),\n});","import { FastifyInstance, FastifyReply, FastifyRequest } from \"fastify\";\n\n// Function to register all routes\nexport const registerQueueRoutes = (\n app: FastifyInstance,\n prefix: string = \"\"\n): void => {\n app.get(`/${prefix}/dashboard`,\n async (_: FastifyRequest, reply: FastifyReply) => {\n const summary = app.queues.getDashboardSummary();\n return reply.status(200).send(summary);\n });\n\n app.get<{ Params: { queue: string } }>(`/${prefix}/:queue`,\n async (request: FastifyRequest<{ Params: { queue: string } }>, reply: FastifyReply) => {\n const queueName = request.params.queue;\n const summary = app.queues.getQueueSummary(queueName);\n if (summary === null) {\n return reply.status(404).send({ error: \"Queue not found\" });\n }\n return reply.status(200).send(summary);\n });\n\n app.post<{ Params: { queue: string }; Body: any }>(`/${prefix}/:queue`,\n async (request: FastifyRequest<{ Params: { queue: string }; Body: any }>, reply: FastifyReply) => {\n const queueName = request.params.queue;\n const result = await app.queues.enqueueMessage(queueName, request.body, request.headers as Record<string, any>);\n if (result === null) {\n return reply.status(404).send({ error: \"Queue not found\" });\n }\n return reply.status(200).send(result);\n });\n\n // Topic publish: fans the message out to every queue subscribed to the\n // topic (see queue-plugin/decorator.ts:publishTopic). Registered as its\n // own static path segment, so it never collides with POST /:queue.\n app.post<{ Params: { topic: string }; Body: any }>(`/${prefix}/topics/:topic`,\n async (request: FastifyRequest<{ Params: { topic: string }; Body: any }>, reply: FastifyReply) => {\n const topicName = request.params.topic;\n const results = await app.queues.publishTopic(topicName, request.body, request.headers as Record<string, any>);\n if (results === null) {\n return reply.status(404).send({ error: \"Topic not found\" });\n }\n return reply.status(200).send({ topicName, results });\n });\n\n app.get<{ Params: { queue: string } }>(`/${prefix}/:queue/process-dlq`,\n async (request: FastifyRequest<{ Params: { queue: string } }>, reply: FastifyReply) => {\n const queueName = request.params.queue;\n const result = await app.queues.processDlq(queueName);\n if (result === null) {\n return reply.status(404).send(result);\n }\n return reply.status(200).send(result);\n });\n\n app.post<{ Params: { queue: string } }>(`/${prefix}/:queue/purge-dlq`,\n async (request: FastifyRequest<{ Params: { queue: string } }>, reply: FastifyReply) => {\n const queueName = request.params.queue;\n const result = await app.queues.purgeDlq(queueName);\n if (result === null) {\n return reply.status(404).send({ error: \"Queue not found\" });\n }\n return reply.status(200).send(result);\n });\n};","import { FastifyInstance, FastifyPluginAsync } from \"fastify\";\nimport fsPlugin from \"fastify-plugin\";\n\nimport { SchedulerPluginOptions, SchedulerRuntime } from \"./types\";\nimport { DEFAULT_CONFIG, mergeConfig } from \"./core\";\nimport { tick } from \"./processing\";\nimport { initializePersistence } from \"./persistence\";\nimport { createSchedulerManager } from \"./decorator\";\nimport { registerSchedulerRoutes } from \"./routes\";\n\nexport const schedulerPlugin: FastifyPluginAsync<SchedulerPluginOptions> =\n fsPlugin(async (\n app: FastifyInstance,\n options: SchedulerPluginOptions\n ) => {\n const runtime: SchedulerRuntime = {\n config: mergeConfig(DEFAULT_CONFIG, options.config),\n schedulers: {},\n executions: {},\n executionHistory: [],\n isShuttingDown: false,\n runningExecutions: 0,\n isDirty: false,\n lastCleanupTime: Date.now(),\n lastSavedAt: Date.now(),\n lastRestartTime: new Date(),\n logging: app.logging,\n };\n\n // One timer for the entire plugin: every tickIntervalMs, run any job\n // that's due, then clean up old execution history / save persistence\n // once their own intervals have elapsed. See processing.ts:tick.\n const tickIntervalId = setInterval(() => tick(runtime), runtime.config.tickIntervalMs);\n app.addHook('onClose', async () => {\n runtime.isShuttingDown = true;\n clearInterval(tickIntervalId);\n });\n\n app.decorate('scheduler', createSchedulerManager(runtime));\n registerSchedulerRoutes(app, options.prefix);\n\n if (runtime.config.persistence.enabled) {\n await initializePersistence(runtime);\n }\n });\n","import { parseExpression } from 'cron-parser';\n\n/**\n * Professional cron parser using cron-parser library\n * \n * Installation:\n * npm install cron-parser\n * npm install -D @types/cron-parser\n */\n\ninterface CronParseOptions {\n preserveNaturalTiming?: boolean;\n timezone?: string;\n utc?: boolean;\n currentDate?: Date;\n endDate?: Date;\n iterator?: boolean;\n}\n\ninterface CronParseResult {\n nextRun: Date;\n isValid: boolean;\n error?: string;\n pattern?: string;\n description?: string;\n}\n\n/**\n * Parse cron expression and get next execution time\n */\nexport function parseCronExpression(\n cronExpression: string,\n lastRun?: Date,\n options: CronParseOptions = {}\n): CronParseResult {\n const {\n preserveNaturalTiming = true,\n timezone,\n utc = false,\n currentDate\n } = options;\n\n try {\n // Validate and normalize cron expression\n const normalizedCron = normalizeCronExpression(cronExpression);\n\n const parseOptions: any = {\n tz: timezone,\n utc: utc,\n currentDate: currentDate ?? new Date()\n };\n\n // Use lastRun for baseline if preserving natural timing\n if (preserveNaturalTiming && lastRun) {\n parseOptions.currentDate = lastRun;\n }\n\n const interval = parseExpression(normalizedCron, parseOptions);\n let nextRun = interval.next().toDate();\n\n // Ensure next run is in the future\n const now = new Date();\n while (nextRun <= now) {\n nextRun = interval.next().toDate();\n }\n\n return {\n nextRun,\n isValid: true,\n pattern: normalizedCron,\n description: describeCronExpression(normalizedCron)\n };\n\n } catch (error: any) {\n // Fallback to a safe default (every hour) - the caller gets the\n // failure via `isValid`/`error` on the returned result, so it can\n // log with whatever module context it has; this module has none.\n const fallbackTime = new Date();\n fallbackTime.setHours(fallbackTime.getHours() + 1);\n fallbackTime.setMinutes(0);\n fallbackTime.setSeconds(0);\n fallbackTime.setMilliseconds(0);\n\n return {\n nextRun: fallbackTime,\n isValid: false,\n error: error.message,\n pattern: cronExpression\n };\n }\n}\n\n/**\n * Get multiple next execution times\n */\nexport function getNextExecutions(\n cronExpression: string,\n count: number = 5,\n options: CronParseOptions = {}\n): Date[] {\n try {\n const normalizedCron = normalizeCronExpression(cronExpression);\n const parseOptions: any = {\n tz: options.timezone,\n utc: options.utc ?? false,\n currentDate: options.currentDate ?? new Date()\n };\n\n const interval = parseExpression(normalizedCron, parseOptions);\n const executions: Date[] = [];\n\n for (let i = 0; i < count; i++) {\n executions.push(interval.next().toDate());\n }\n\n return executions;\n } catch {\n return [];\n }\n}\n\n/**\n * Validate if a cron expression is valid\n */\nexport function validateCronExpression(cronExpression: string): boolean {\n try {\n const normalized = normalizeCronExpression(cronExpression);\n parseExpression(normalized);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Normalize cron expressions to handle different formats\n */\nfunction normalizeCronExpression(cronExpression: string): string {\n const parts = cronExpression.trim().split(/\\s+/);\n\n // Handle different cron formats\n if (parts.length === 5) {\n // Standard 5-field format: minute hour day month dayOfWeek\n return cronExpression;\n } else if (parts.length === 6) {\n // 6-field format with seconds: second minute hour day month dayOfWeek\n return cronExpression;\n } else if (parts.length === 7) {\n // 7-field format with year: second minute hour day month dayOfWeek year\n return cronExpression;\n } else {\n throw new Error(`Invalid cron format: expected 5, 6, or 7 fields, got ${parts.length}`);\n }\n}\n\n/**\n * Provide human-readable description of cron expression\n */\nfunction describeCronExpression(cronExpression: string): string {\n const parts = cronExpression.split(' ');\n\n // Handle common patterns\n const patterns: Record<string, string> = {\n '*/5 * * * *': 'Every 5 minutes',\n '0 * * * *': 'Every hour at minute 0',\n '0 */2 * * *': 'Every 2 hours',\n '0 0 * * *': 'Daily at midnight',\n '0 6 * * *': 'Daily at 6:00 AM',\n '0 0 * * 0': 'Weekly on Sunday at midnight',\n '0 0 1 * *': 'Monthly on the 1st at midnight',\n '0 0 1 1 *': 'Yearly on January 1st at midnight'\n };\n\n if (patterns[cronExpression]) {\n return patterns[cronExpression];\n }\n\n // Basic description for other patterns\n if (parts.length >= 5) {\n const [minute, hour, day, month, dayOfWeek] = parts;\n\n let description = 'Runs ';\n\n if (minute.includes('*/')) {\n const interval = minute.split('*/')[1];\n description += `every ${interval} minutes`;\n } else if (minute === '*') {\n description += 'every minute';\n } else {\n description += `at minute ${minute}`;\n }\n\n if (hour.includes('*/')) {\n const interval = hour.split('*/')[1];\n description += `, every ${interval} hours`;\n } else if (hour !== '*') {\n description += `, at hour ${hour}`;\n }\n\n if (day !== '*') {\n description += `, on day ${day}`;\n }\n\n if (month !== '*') {\n description += `, in month ${month}`;\n }\n\n if (dayOfWeek !== '*') {\n const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\n const dayNames = dayOfWeek.split(',').map(d => days[parseInt(d)] || d).join(', ');\n description += `, on ${dayNames}`;\n }\n\n return description;\n }\n\n return 'Custom schedule';\n}\n\n/**\n * Calculate time until next execution\n */\nexport function timeUntilNextExecution(cronExpression: string, timezone?: string): number {\n const result = parseCronExpression(cronExpression, undefined, { timezone });\n if (!result.isValid) {\n return -1;\n }\n\n return result.nextRun.getTime() - Date.now();\n}\n\n/**\n * Check if a time matches a cron expression\n */\nexport function doesTimeMatchCron(cronExpression: string, date: Date, timezone?: string): boolean {\n try {\n const normalizedCron = normalizeCronExpression(cronExpression);\n const parseOptions: any = {\n tz: timezone,\n currentDate: date\n };\n\n const interval = parseExpression(normalizedCron, parseOptions);\n const nextExecution = interval.next().toDate();\n\n // Check if the date is very close to the next execution (within 1 minute)\n const timeDiff = Math.abs(nextExecution.getTime() - date.getTime());\n return timeDiff < 60000; // 1 minute tolerance\n } catch {\n return false;\n }\n}\n\n/**\n * Detect the type of scheduling expression\n */\nexport function detectExpressionType(expression: string | undefined): 'cron' | 'rate' | 'unknown' {\n if (!expression || typeof expression !== 'string') {\n return 'unknown';\n }\n const trimmedExpression = expression.trim();\n\n // Check for AWS rate expression pattern\n // Format: \"rate(value unit)\" where unit can be minute(s), hour(s), day(s)\n const ratePattern = /^rate\\(\\s*(\\d+)\\s+(minute|minutes|hour|hours|day|days)\\s*\\)$/i;\n if (ratePattern.test(trimmedExpression)) {\n return 'rate';\n }\n\n // Check for cron expression pattern\n // Should have 5, 6, or 7 space-separated fields\n const cronParts = trimmedExpression.split(/\\s+/);\n if (cronParts.length >= 5 && cronParts.length <= 7) {\n // Additional validation: check if parts contain valid cron characters\n const cronCharPattern = /^[\\d\\*\\-\\,\\/\\?\\#LW]+$/;\n const validCronParts = cronParts.every(part => cronCharPattern.test(part) || part === '*');\n\n if (validCronParts) {\n return 'cron';\n }\n }\n\n return 'unknown';\n}\n\n/**\n * Convert AWS rate expression to cron expression\n * \n * AWS Rate expressions format: rate(value unit)\n * Examples:\n * - rate(5 minutes) -> *\\/5 * * * *\n * - rate(1 hour) -> 0 * * * *\n * - rate(2 hours) -> 0 *\\/2 * * *\n * - rate(1 day) -> 0 0 * * *\n * - rate(7 days) -> 0 0 *\\/7 * *\n*/\nexport function convertRateToCron(rateExpression: string): {\n cronExpression: string;\n isValid: boolean;\n error?: string;\n originalRate: string;\n description: string;\n} {\n const trimmedExpression = rateExpression.trim();\n\n // Parse rate expression\n const ratePattern = /^rate\\(\\s*(\\d+)\\s+(minute|minutes|hour|hours|day|days)\\s*\\)$/i;\n const match = trimmedExpression.match(ratePattern);\n\n if (!match) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Invalid rate expression format. Expected: rate(value unit)',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n const value = parseInt(match[1]);\n const unit = match[2].toLowerCase();\n\n // Validate value\n if (value <= 0) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Rate value must be greater than 0',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n let cronExpression = '';\n let description = '';\n\n try {\n switch (unit) {\n case 'minute':\n case 'minutes':\n if (value > 59) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Minutes value cannot exceed 59. Use hours for longer intervals.',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n if (value === 1) {\n cronExpression = '* * * * *';\n description = 'Every minute';\n } else {\n cronExpression = `*/${value} * * * *`;\n description = `Every ${value} minutes`;\n }\n break;\n\n case 'hour':\n case 'hours':\n if (value > 23) {\n // For hours > 23, convert to days if evenly divisible by 24\n if (value % 24 === 0) {\n const days = value / 24;\n cronExpression = `0 0 */${days} * *`;\n description = `Every ${days} day${days > 1 ? 's' : ''}`;\n } else {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Hours value greater than 23 must be divisible by 24, or use days unit.',\n originalRate: rateExpression,\n description: ''\n };\n }\n } else if (value === 1) {\n cronExpression = '0 * * * *';\n description = 'Every hour';\n } else {\n cronExpression = `0 */${value} * * *`;\n description = `Every ${value} hours`;\n }\n break;\n\n case 'day':\n case 'days':\n if (value > 365) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Days value cannot exceed 365',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n if (value === 1) {\n cronExpression = '0 0 * * *';\n description = 'Every day (daily)';\n } else if (value === 7) {\n cronExpression = '0 0 * * 0';\n description = 'Every 7 days (weekly)';\n } else if (value <= 31) {\n cronExpression = `0 0 */${value} * *`;\n description = `Every ${value} days`;\n } else {\n // For large day intervals, we need to be more careful\n // This is an approximation since months have different lengths\n cronExpression = `0 0 */${value} * *`;\n description = `Every ${value} days (approximate)`;\n }\n break;\n\n default:\n return {\n cronExpression: '',\n isValid: false,\n error: `Unsupported time unit: ${unit}. Use minute(s), hour(s), or day(s).`,\n originalRate: rateExpression,\n description: ''\n };\n }\n\n // Validate the generated cron expression\n if (!validateCronExpression(cronExpression)) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Generated cron expression is invalid',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n return {\n cronExpression,\n isValid: true,\n originalRate: rateExpression,\n description\n };\n\n } catch (error: any) {\n return {\n cronExpression: '',\n isValid: false,\n error: `Conversion error: ${error.message}`,\n originalRate: rateExpression,\n description: ''\n };\n }\n}","import { ScheduledJob, SchedulerConfig } from \"./types\";\nimport { parseCronExpression } from \"./cron-utils\";\n\nexport const generateJobId = (): string =>\n `job_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\nexport const generateExecutionId = (): string =>\n `exec_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\nexport const calculateNextRun = (\n job: ScheduledJob,\n preserveNaturalTiming: boolean = true\n): Date => {\n const now = new Date();\n\n if (job.cronExpression) {\n const result = parseCronExpression(job.cronExpression, job.lastRun, {\n preserveNaturalTiming,\n timezone: job.timezone,\n currentDate: preserveNaturalTiming && job.lastRun ? job.lastRun : now\n });\n return result.nextRun;\n }\n\n if (job.intervalMs) {\n return new Date(now.getTime() + job.intervalMs);\n }\n\n if (job.delayMs) {\n return new Date(now.getTime() + job.delayMs);\n }\n\n // Default: 1 hour\n return new Date(now.getTime() + 3600000);\n};\n\nexport const calculateNextRunFromLastRun = (\n job: ScheduledJob,\n lastRun: Date | undefined,\n config: SchedulerConfig\n): Date => {\n const now = new Date();\n\n if (job.cronExpression) {\n const result = parseCronExpression(job.cronExpression, lastRun, {\n preserveNaturalTiming: config.restartBehavior.preserveNaturalTiming,\n timezone: job.timezone ?? config.cron.defaultTimezone\n });\n return result.nextRun;\n }\n\n if (job.intervalMs && lastRun) {\n let nextRun = new Date(lastRun.getTime() + job.intervalMs);\n\n if (config.restartBehavior.skipMissedRuns) {\n while (nextRun <= now) {\n nextRun = new Date(nextRun.getTime() + job.intervalMs);\n }\n } else {\n if (nextRun <= now) {\n nextRun = new Date(now.getTime() + job.intervalMs);\n }\n }\n\n return nextRun;\n }\n\n return calculateNextRun(job, config.restartBehavior.preserveNaturalTiming);\n};\n\nexport const hasJobDefinitionChanged = (currentJob: ScheduledJob, savedJob: any): boolean => (\n currentJob.cronExpression !== savedJob.cronExpression ||\n currentJob.intervalMs !== savedJob.intervalMs ||\n currentJob.delayMs !== savedJob.delayMs ||\n currentJob.maxRuns !== savedJob.maxRuns ||\n currentJob.timezone !== savedJob.timezone\n);\n\nexport const shouldSkipJob = (job: ScheduledJob): boolean => {\n if (!job.enabled) return true;\n if (job.maxRuns && job.runCount >= job.maxRuns) return true;\n return false;\n};\n\nexport const isJobReadyToRun = (job: ScheduledJob): boolean => {\n const now = new Date();\n return job.nextRun.getTime() <= now.getTime();\n};\n\nexport const getTimeUntilNextRun = (job: ScheduledJob): number =>\n Math.max(0, job.nextRun.getTime() - Date.now());","import { SchedulerConfig, SchedulerDashboardJob, SchedulerRuntime } from \"./types\";\nimport { getNextExecutions, parseCronExpression } from \"./cron-utils\";\nimport { getTimeUntilNextRun } from \"./utils\";\n\n// default config\nexport const DEFAULT_CONFIG: SchedulerConfig = {\n tickIntervalMs: 1000,\n persistence: {\n enabled: true,\n directory: './.develop/.scheduler-data',\n saveInterval: 30000, // 30 seconds\n saveOnShutdown: false,\n },\n execution: {\n maxConcurrent: 5,\n defaultTimeout: 300000, // 5 minutes\n },\n cleanup: {\n maxExecutionHistory: 1000,\n cleanupInterval: 600000, // 10 minutes\n },\n restartBehavior: {\n preserveNaturalTiming: true,\n skipMissedRuns: true,\n maxTimingDrift: 60000, // 1 minute\n rapidRestartThreshold: 10000, // 10 seconds\n },\n cron: {\n defaultTimezone: undefined, // Use system timezone\n logCronDetails: true,\n },\n};\n\n// Pure function to merge configs\nexport const mergeConfig = (defaultConfig: SchedulerConfig, userConfig?: Partial<SchedulerConfig>): SchedulerConfig => ({\n ...defaultConfig,\n ...userConfig,\n persistence: { ...defaultConfig.persistence, ...userConfig?.persistence },\n execution: { ...defaultConfig.execution, ...userConfig?.execution },\n cleanup: { ...defaultConfig.cleanup, ...userConfig?.cleanup },\n restartBehavior: { ...defaultConfig.restartBehavior, ...userConfig?.restartBehavior },\n cron: { ...defaultConfig.cron, ...userConfig?.cron },\n});\n\n// Pure function to build the dashboard view of every job\nexport const createDashboardSummary = (runtime: SchedulerRuntime): { jobs: SchedulerDashboardJob[]; runningExecutions: number } => {\n const jobs = Object.values(runtime.schedulers).map((scheduler): SchedulerDashboardJob => {\n const upcomingExecutions = scheduler.job.cronExpression\n ? getNextExecutions(scheduler.job.cronExpression, 3, { timezone: scheduler.job.timezone })\n : [];\n\n const cronDescription = scheduler.job.cronExpression\n ? parseCronExpression(scheduler.job.cronExpression, undefined, { timezone: scheduler.job.timezone }).description\n : undefined;\n\n return {\n ...scheduler.job,\n isRunning: scheduler.isRunning,\n timeUntilNextRun: getTimeUntilNextRun(scheduler.job),\n upcomingExecutions,\n cronDescription,\n };\n });\n\n return { jobs, runningExecutions: runtime.runningExecutions };\n};\n\n// Pure function to build the executions view\nexport const createExecutionsSummary = (runtime: SchedulerRuntime) => ({\n executions: runtime.executionHistory.slice(-50), // Last 50 executions\n running: Object.values(runtime.executions).filter(e => e.status === 'running'),\n});\n","import { JobDefinition, JobExecution, JobHandler, ScheduledJob, SchedulerConfig, SchedulerService } from \"./types\";\nimport { detectExpressionType, convertRateToCron } from \"./cron-utils\";\nimport { generateExecutionId, generateJobId, calculateNextRun, calculateNextRunFromLastRun } from \"./utils\";\n\n// Pure function to validate a job definition before it's turned into a job.\n// A job needs exactly one timing source; only validate the cron expression\n// itself when one was actually given (intervalMs/delayMs-only jobs have no\n// cron expression to check).\nexport const validateJobDefinition = (jobDef: JobDefinition): void => {\n if (!jobDef.cronExpression && !jobDef.intervalMs && !jobDef.delayMs) {\n throw new Error(`Job ${jobDef.name} must specify a cronExpression, intervalMs, or delayMs`);\n }\n\n if (jobDef.cronExpression && detectExpressionType(jobDef.cronExpression) === \"unknown\") {\n throw new Error(`Invalid cron expression for job: ${jobDef.name}`);\n }\n};\n\n// Pure function to turn a job definition into a scheduled job\nexport const createJobFromDefinition = (jobDef: JobDefinition, config: SchedulerConfig): ScheduledJob => {\n validateJobDefinition(jobDef);\n\n const expressionType = detectExpressionType(jobDef.cronExpression);\n const cronExpression = expressionType === \"rate\"\n ? convertRateToCron(jobDef.cronExpression!).cronExpression\n : jobDef.cronExpression;\n\n const job: ScheduledJob = {\n id: generateJobId(),\n name: jobDef.name,\n cronExpression,\n intervalMs: jobDef.intervalMs,\n delayMs: jobDef.delayMs,\n nextRun: new Date(),\n enabled: jobDef.enabled ?? true,\n runCount: 0,\n maxRuns: jobDef.maxRuns,\n metadata: jobDef.metadata,\n createdAt: new Date(),\n timezone: jobDef.timezone,\n module: jobDef.module,\n };\n\n job.nextRun = calculateNextRun(job, config.restartBehavior.preserveNaturalTiming);\n return job;\n};\n\n// Pure function to create a scheduler service for a job\nexport const createSchedulerService = (job: ScheduledJob, handler: JobHandler): SchedulerService => ({\n job,\n handler,\n isRunning: false,\n});\n\n// Pure function to create a job execution record\nexport const createJobExecution = (jobId: string): JobExecution => ({\n id: generateExecutionId(),\n jobId,\n startTime: new Date(),\n status: 'running',\n});\n\n// Pure function to mark an execution as finished\nexport const completeExecution = (\n execution: JobExecution,\n result?: any,\n error?: string\n): JobExecution => ({\n ...execution,\n endTime: new Date(),\n status: error ? 'failed' : 'completed',\n result,\n error,\n});\n\n// Pure function to advance a job's run count/timing after an execution\nexport const updateJobAfterExecution = (\n job: ScheduledJob,\n execution: JobExecution,\n config: SchedulerConfig\n): ScheduledJob => {\n const updatedJob: ScheduledJob = {\n ...job,\n lastRun: execution.startTime,\n runCount: job.runCount + 1,\n };\n\n if (updatedJob.enabled) {\n updatedJob.nextRun = calculateNextRunFromLastRun(updatedJob, updatedJob.lastRun, config);\n }\n\n return updatedJob;\n};\n\n// Pure function to enable a job and recompute its next run\nexport const enableJob = (scheduler: SchedulerService): SchedulerService => ({\n ...scheduler,\n job: {\n ...scheduler.job,\n enabled: true,\n nextRun: calculateNextRun(scheduler.job),\n },\n});\n\n// Pure function to disable a job\nexport const disableJob = (scheduler: SchedulerService): SchedulerService => ({\n ...scheduler,\n job: { ...scheduler.job, enabled: false },\n});\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\n\nimport { JobExecution, ScheduledJob, SchedulerRuntime, SchedulerService } from \"./types\";\nimport { hasJobDefinitionChanged, calculateNextRunFromLastRun } from \"./utils\";\nimport { parseCronExpression } from \"./cron-utils\";\n\ninterface SchedulerStateData {\n jobs: ScheduledJob[];\n executions: JobExecution[];\n savedAt: Date;\n version: string;\n}\n\nconst stateFilePath = (directory: string): string => path.join(directory, 'scheduler-state.json');\n\nconst tempFilePath = (directory: string): string => path.join(directory, `scheduler-state.${Date.now()}.temp.json`);\n\nconst restoreExecutionHistory = (savedExecutions: JobExecution[]): JobExecution[] =>\n savedExecutions.map((exec) => ({\n ...exec,\n startTime: new Date(exec.startTime),\n endTime: exec.endTime ? new Date(exec.endTime) : undefined,\n }));\n\nconst readStateData = async (directory: string): Promise<SchedulerStateData | null> => {\n const data = await fs.readFile(stateFilePath(directory), 'utf8');\n return JSON.parse(data);\n};\n\nexport const saveSchedulerState = async (runtime: SchedulerRuntime): Promise<void> => {\n try {\n const stateData: SchedulerStateData = {\n jobs: Object.values(runtime.schedulers).map(s => s.job),\n executions: runtime.executionHistory.slice(-100),\n savedAt: new Date(),\n version: '1.0',\n };\n\n const file = stateFilePath(runtime.config.persistence.directory);\n const temp = tempFilePath(runtime.config.persistence.directory);\n\n // Write to a temp file first, then rename - rename is atomic, so a\n // reader never sees a half-written file.\n await fs.writeFile(temp, JSON.stringify(stateData, null, 2), 'utf8');\n await fs.rename(temp, file);\n\n runtime.logging.debug('Scheduler state saved');\n } catch (error: any) {\n runtime.logging.error({ error: error?.message }, 'Failed to save scheduler state');\n }\n};\n\n// Recalculates - or preserves - a restored job's nextRun depending on how\n// long ago the process restarted, so a quick redeploy doesn't lose timing\n// but a long outage doesn't fire a pile of catch-up runs.\nconst validateAndAdjustNextRun = (\n job: ScheduledJob,\n savedNextRun: Date | undefined,\n runtime: SchedulerRuntime\n): Date => {\n const { config, lastRestartTime, logging } = runtime;\n const now = new Date();\n\n if (!savedNextRun || savedNextRun <= now) {\n logging.debug({ module: job.module }, `Saved next run is in the past for ${job.name} - recalculating`);\n return calculateNextRunFromLastRun(job, job.lastRun, config);\n }\n\n const isRapidRestart = now.getTime() - lastRestartTime.getTime() < config.restartBehavior.rapidRestartThreshold;\n if (isRapidRestart) {\n logging.debug({ module: job.module }, `Rapid restart detected for ${job.name} - preserving saved timing`);\n return savedNextRun;\n }\n\n if (job.cronExpression || job.intervalMs) {\n const expectedNextRun = calculateNextRunFromLastRun(job, job.lastRun, config);\n const drift = Math.abs(savedNextRun.getTime() - expectedNextRun.getTime());\n if (drift > config.restartBehavior.maxTimingDrift) {\n logging.debug({ module: job.module }, `Adjusting timing for ${job.name} - drift of ${Math.round(drift / 1000)}s detected`);\n return expectedNextRun;\n }\n }\n\n return savedNextRun;\n};\n\n// Restores this job's saved run history (count, lastRun) and next-run\n// timing from the persisted state file. Mirrors queue-plugin's per-queue\n// loadQueueState: called from addJob right after the scheduler is\n// registered, not at plugin init - the saved file has nothing to match\n// against that early, since no jobs have been added yet.\nexport const loadJobState = async (runtime: SchedulerRuntime, scheduler: SchedulerService): Promise<SchedulerService> => {\n try {\n const stateData = await readStateData(runtime.config.persistence.directory);\n if (!stateData) {\n return scheduler;\n }\n\n const savedJob = stateData.jobs.find(job => job.name === scheduler.job.name);\n if (!savedJob) {\n return scheduler;\n }\n\n const definitionChanged = hasJobDefinitionChanged(scheduler.job, savedJob);\n const lastRun = savedJob.lastRun ? new Date(savedJob.lastRun) : undefined;\n\n const updatedJob: ScheduledJob = {\n ...scheduler.job,\n runCount: savedJob.runCount,\n lastRun,\n };\n\n if (definitionChanged) {\n runtime.logging.debug({ module: scheduler.job.module }, `Job definition changed: ${savedJob.name} - recalculating schedule`);\n updatedJob.nextRun = calculateNextRunFromLastRun(updatedJob, lastRun, runtime.config);\n } else {\n updatedJob.nextRun = validateAndAdjustNextRun(updatedJob, savedJob.nextRun ? new Date(savedJob.nextRun) : undefined, runtime);\n }\n\n if (runtime.config.cron.logCronDetails && updatedJob.cronExpression) {\n const result = parseCronExpression(updatedJob.cronExpression, updatedJob.lastRun, { timezone: updatedJob.timezone });\n runtime.logging.debug(\n { module: scheduler.job.module },\n `Job restored: ${savedJob.name} - ${result.description} - next: ${updatedJob.nextRun.toLocaleString()}`\n );\n } else {\n runtime.logging.debug({ module: scheduler.job.module }, `Job state restored: ${savedJob.name}`);\n }\n\n return { ...scheduler, job: updatedJob };\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n runtime.logging.debug('No saved scheduler state found - starting fresh');\n } else {\n runtime.logging.error({ error: error?.message }, `Failed to load job state for ${scheduler.job.name}`);\n }\n return scheduler;\n }\n};\n\n// Execution history isn't tied to any one job, so it's restored once at\n// plugin init (unlike per-job state, which loadJobState restores lazily as\n// each job is registered).\nexport const loadExecutionHistory = async (runtime: SchedulerRuntime): Promise<void> => {\n try {\n const stateData = await readStateData(runtime.config.persistence.directory);\n if (stateData?.executions) {\n runtime.executionHistory = restoreExecutionHistory(stateData.executions);\n }\n } catch (error: any) {\n if (error.code !== 'ENOENT') {\n runtime.logging.error({ error: error?.message }, 'Failed to load execution history');\n }\n }\n};\n\nexport const initializePersistence = async (runtime: SchedulerRuntime): Promise<void> => {\n try {\n await fs.mkdir(runtime.config.persistence.directory, { recursive: true });\n await loadExecutionHistory(runtime);\n\n if (runtime.config.persistence.saveOnShutdown) {\n const shutdownHandler = async () => {\n runtime.logging.debug('Saving scheduler state before shutdown...');\n await saveSchedulerState(runtime);\n process.exit(0);\n };\n\n process.on('SIGINT', shutdownHandler);\n process.on('SIGTERM', shutdownHandler);\n }\n\n runtime.logging.debug(`Scheduler persistence initialized: ${runtime.config.persistence.directory}`);\n } catch (error: any) {\n runtime.logging.error({ error: error?.message }, 'Failed to initialize scheduler persistence');\n }\n};\n","import { JobExecution, JobHandler, ScheduledJob, SchedulerRuntime, SchedulerService } from \"./types\";\nimport { completeExecution, createJobExecution, updateJobAfterExecution } from \"./jobs\";\nimport { isJobReadyToRun, shouldSkipJob } from \"./utils\";\nimport { saveSchedulerState } from \"./persistence\";\n\n// Pure function to check whether a job can run right now\nexport const canExecuteJob = (\n runtime: SchedulerRuntime,\n scheduler: SchedulerService\n): { canExecute: boolean; reason?: string } => {\n if (runtime.isShuttingDown) {\n return { canExecute: false, reason: 'System is shutting down' };\n }\n\n if (scheduler.isRunning) {\n return { canExecute: false, reason: 'Job is already running' };\n }\n\n if (shouldSkipJob(scheduler.job)) {\n const reason = !scheduler.job.enabled ? 'Job is disabled' : 'Job reached maximum runs';\n return { canExecute: false, reason };\n }\n\n if (runtime.runningExecutions >= runtime.config.execution.maxConcurrent) {\n return { canExecute: false, reason: 'Maximum concurrent executions reached' };\n }\n\n return { canExecute: true };\n};\n\nconst executeJobWithTimeout = async (\n handler: JobHandler,\n job: ScheduledJob,\n execution: JobExecution,\n timeoutMs: number\n): Promise<any> => {\n let timerId: NodeJS.Timeout;\n\n try {\n return await Promise.race([\n handler(job, execution),\n new Promise((_, reject) => {\n timerId = setTimeout(() => reject(new Error('Job execution timeout')), timeoutMs);\n }),\n ]);\n } finally {\n clearTimeout(timerId!);\n }\n};\n\n// Runs one job through its handler, recording the execution and advancing\n// its nextRun. Used by both the tick (once per due job) and triggerJob -\n// both go through the same path, wrapped in runWithLogContext by the\n// caller so every log call below carries the job's module/reqId.\nexport const executeJob = async (runtime: SchedulerRuntime, scheduler: SchedulerService): Promise<void> => {\n const execution = createJobExecution(scheduler.job.id);\n // Tracked in two places (the `executions` map and `executionHistory`)\n // but as a single shared reference - completeExecution below mutates\n // this same object via Object.assign so both views stay in sync,\n // instead of completeExecution's return value only updating one of them.\n runtime.executions[execution.id] = execution;\n runtime.executionHistory.push(execution);\n scheduler.isRunning = true;\n runtime.runningExecutions++;\n\n runtime.logging.info(`Executing job ${scheduler.job.name} (${execution.id})`);\n\n try {\n const result = await executeJobWithTimeout(\n scheduler.handler,\n scheduler.job,\n execution,\n runtime.config.execution.defaultTimeout\n );\n\n Object.assign(execution, completeExecution(execution, result));\n\n const duration = execution.endTime!.getTime() - execution.startTime.getTime();\n runtime.logging.debug(`Job completed in ${duration}ms`);\n } catch (error: any) {\n Object.assign(execution, completeExecution(execution, undefined, error.message));\n runtime.logging.error(`Job failed ${scheduler.job.name}: ${error.message}`);\n } finally {\n scheduler.isRunning = false;\n runtime.runningExecutions--;\n scheduler.job = updateJobAfterExecution(scheduler.job, execution, runtime.config);\n\n if (scheduler.job.maxRuns && scheduler.job.runCount >= scheduler.job.maxRuns) {\n runtime.logging.info(`Job ${scheduler.job.name} reached max runs (${scheduler.job.maxRuns})`);\n }\n\n if (runtime.config.persistence.enabled) {\n runtime.isDirty = true;\n }\n }\n};\n\nconst dispatchJobIfDue = (runtime: SchedulerRuntime, scheduler: SchedulerService): void => {\n if (!scheduler.job.enabled || !isJobReadyToRun(scheduler.job)) {\n return;\n }\n\n const { canExecute, reason } = canExecuteJob(runtime, scheduler);\n if (!canExecute) {\n // Not a permanent skip (except the maxRuns case, logged once above\n // instead) - e.g. at max concurrency, or another tick of the same\n // job already running. The job's nextRun hasn't moved, so the very\n // next tick simply tries again, instead of the old per-job timer\n // needing to be explicitly rescheduled with a delay. Logged at\n // debug to avoid spamming at tick frequency.\n if (reason === 'Maximum concurrent executions reached') {\n runtime.logging.debug({ module: scheduler.job.module }, `Delaying job ${scheduler.job.name} - ${reason}`);\n }\n return;\n }\n\n runtime.logging.runWithLogContext(\n { module: scheduler.job.module, reqId: scheduler.job.id },\n () => executeJob(runtime, scheduler)\n );\n};\n\nexport const cleanupExecutionHistory = (runtime: SchedulerRuntime): void => {\n const { maxExecutionHistory } = runtime.config.cleanup;\n if (runtime.executionHistory.length <= maxExecutionHistory) {\n return;\n }\n\n const removed = runtime.executionHistory.splice(0, runtime.executionHistory.length - maxExecutionHistory);\n runtime.logging.debug(`Cleaned up ${removed.length} old execution records`);\n};\n\nconst maybeCleanup = (runtime: SchedulerRuntime, now: number): void => {\n if (now - runtime.lastCleanupTime < runtime.config.cleanup.cleanupInterval) {\n return;\n }\n runtime.lastCleanupTime = now;\n cleanupExecutionHistory(runtime);\n};\n\nconst maybeSavePersistence = (runtime: SchedulerRuntime, now: number): void => {\n if (!runtime.config.persistence.enabled || !runtime.isDirty) {\n return;\n }\n\n const saveInterval = runtime.config.persistence.saveInterval ?? 0;\n if (saveInterval > 0 && now - runtime.lastSavedAt >= saveInterval) {\n runtime.lastSavedAt = now;\n runtime.isDirty = false;\n saveSchedulerState(runtime);\n }\n};\n\n// The one timer for the whole plugin. Every tickIntervalMs: run any job\n// whose nextRun has arrived (this is also how a manual triggerJob's\n// recurrence shows up - nothing schedules its own setTimeout anymore); then\n// clean up old execution history and save persistence if their intervals\n// have elapsed.\nexport const tick = (runtime: SchedulerRuntime): void => {\n const now = Date.now();\n for (const scheduler of Object.values(runtime.schedulers)) {\n dispatchJobIfDue(runtime, scheduler);\n }\n maybeCleanup(runtime, now);\n maybeSavePersistence(runtime, now);\n};\n","import { JobDefinition, JobHandler, SchedulerManager, SchedulerRuntime, SchedulerService } from \"./types\";\nimport { createJobFromDefinition, createSchedulerService, disableJob as disableJobData, enableJob as enableJobData } from \"./jobs\";\nimport { createDashboardSummary, createExecutionsSummary } from \"./core\";\nimport { getNextExecutions, parseCronExpression } from \"./cron-utils\";\nimport { loadJobState } from \"./persistence\";\nimport { executeJob } from \"./processing\";\n\nconst isValidJobName = (jobName: string): boolean => {\n return typeof jobName === 'string' && jobName.length > 0 && /^[a-zA-Z0-9_-]+$/.test(jobName);\n};\n\nconst validateJobName = (jobName: string): void => {\n if (!jobName || typeof jobName !== 'string') {\n throw new Error('Job name must be a non-empty string');\n }\n\n if (!isValidJobName(jobName)) {\n throw new Error('Job name must contain only alphanumeric characters, hyphens, and underscores');\n }\n};\n\nconst validateHandler = (handler: JobHandler): void => {\n if (typeof handler !== 'function') {\n throw new Error('Handler must be a function');\n }\n};\n\nconst findSchedulerByName = (runtime: SchedulerRuntime, jobName: string): SchedulerService | undefined =>\n Object.values(runtime.schedulers).find(scheduler => scheduler.job.name === jobName);\n\nexport const addJob = async (runtime: SchedulerRuntime, jobDefinition: JobDefinition): Promise<string> => {\n try {\n validateJobName(jobDefinition.name);\n validateHandler(jobDefinition.handler);\n\n const existing = findSchedulerByName(runtime, jobDefinition.name);\n if (existing) {\n runtime.logging.warn({ module: jobDefinition.module }, `Job already exists: ${jobDefinition.name}.`);\n return existing.job.id;\n }\n\n const job = createJobFromDefinition(jobDefinition, runtime.config);\n\n if (runtime.config.cron.logCronDetails && job.cronExpression) {\n const timezone = job.timezone ?? runtime.config.cron.defaultTimezone;\n const result = parseCronExpression(job.cronExpression, undefined, { timezone });\n runtime.logging.debug(\n { module: jobDefinition.module },\n `Job ${jobDefinition.name}: ${result.description} - Next: ${result.nextRun.toLocaleString()}`\n );\n\n const upcoming = getNextExecutions(job.cronExpression, 3, { timezone });\n runtime.logging.debug(\n { module: jobDefinition.module },\n `Upcoming: ${upcoming.map(d => d.toLocaleTimeString()).join(', ')}`\n );\n }\n\n let scheduler = createSchedulerService(job, jobDefinition.handler);\n\n if (runtime.config.persistence.enabled) {\n scheduler = await loadJobState(runtime, scheduler);\n }\n\n runtime.schedulers[scheduler.job.id] = scheduler;\n\n runtime.logging.info({ module: jobDefinition.module }, `Job added: ${jobDefinition.name} (${scheduler.job.id})`);\n\n return scheduler.job.id;\n } catch (error: any) {\n runtime.logging.error({ module: jobDefinition.module, error: error.message }, `Failed to add job ${jobDefinition.name}`);\n throw error;\n }\n};\n\nexport const removeJob = async (runtime: SchedulerRuntime, jobName: string): Promise<void> => {\n try {\n validateJobName(jobName);\n\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n throw new Error(`Job '${jobName}' does not exist`);\n }\n\n if (scheduler.isRunning) {\n runtime.logging.warn({ module: scheduler.job.module }, `Removing job that is currently running: ${jobName}`);\n }\n\n delete runtime.schedulers[scheduler.job.id];\n\n runtime.logging.info({ module: scheduler.job.module }, `Job removed: ${jobName}`);\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to remove job ${jobName}`);\n throw error;\n }\n};\n\nexport const hasJob = (runtime: SchedulerRuntime, jobName: string): boolean => {\n try {\n validateJobName(jobName);\n return !!findSchedulerByName(runtime, jobName);\n } catch {\n return false;\n }\n};\n\nexport const listJobs = (runtime: SchedulerRuntime, module?: string): string[] => {\n return Object.values(runtime.schedulers)\n .filter(scheduler => !module || scheduler.job.module === module)\n .map(scheduler => scheduler.job.name)\n .sort();\n};\n\nexport const getJobStats = (runtime: SchedulerRuntime, jobName: string): SchedulerService | null => {\n try {\n validateJobName(jobName);\n return findSchedulerByName(runtime, jobName) ?? null;\n } catch {\n return null;\n }\n};\n\nexport const getJobsMap = (runtime: SchedulerRuntime): Record<string, SchedulerService> => {\n // Return a copy to prevent external modification\n return { ...runtime.schedulers };\n};\n\nexport const enableJob = async (runtime: SchedulerRuntime, jobName: string): Promise<void> => {\n try {\n validateJobName(jobName);\n\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n throw new Error(`Job '${jobName}' does not exist`);\n }\n\n if (scheduler.job.enabled) {\n runtime.logging.debug({ module: scheduler.job.module }, `Job is already enabled: ${jobName}`);\n return;\n }\n\n runtime.schedulers[scheduler.job.id] = enableJobData(scheduler);\n runtime.logging.info({ module: scheduler.job.module }, `Job enabled: ${jobName}`);\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to enable job ${jobName}`);\n throw error;\n }\n};\n\nexport const disableJob = async (runtime: SchedulerRuntime, jobName: string): Promise<void> => {\n try {\n validateJobName(jobName);\n\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n throw new Error(`Job '${jobName}' does not exist`);\n }\n\n if (!scheduler.job.enabled) {\n runtime.logging.debug({ module: scheduler.job.module }, `Job is already disabled: ${jobName}`);\n return;\n }\n\n runtime.schedulers[scheduler.job.id] = disableJobData(scheduler);\n runtime.logging.info({ module: scheduler.job.module }, `Job disabled: ${jobName}`);\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to disable job ${jobName}`);\n throw error;\n }\n};\n\nexport const triggerJob = async (runtime: SchedulerRuntime, jobName: string): Promise<void> => {\n try {\n validateJobName(jobName);\n\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n throw new Error(`Job '${jobName}' does not exist`);\n }\n\n if (scheduler.isRunning) {\n throw new Error(`Job '${jobName}' is already running`);\n }\n\n runtime.logging.info({ module: scheduler.job.module }, `Job triggered: ${jobName}`);\n\n // Fire-and-forget, same as the tick's own dispatch - callers (e.g.\n // the trigger route) get an immediate response rather than waiting\n // out the job's full run.\n runtime.logging.runWithLogContext(\n { module: scheduler.job.module, reqId: scheduler.job.id },\n () => executeJob(runtime, scheduler)\n );\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to trigger job ${jobName}`);\n throw error;\n }\n};\n\nexport const getDashboardSummary = (runtime: SchedulerRuntime) => createDashboardSummary(runtime);\n\nexport const getExecutionsSummary = (runtime: SchedulerRuntime) => createExecutionsSummary(runtime);\n\n// Unlike getExecutionsSummary (last 50 across every job), this filters the\n// full executionHistory down to one job first - so a busy job elsewhere\n// can't push a quieter job's own runs out of view.\nexport const getJobExecutionHistory = (runtime: SchedulerRuntime, jobName: string, limit = 50) => {\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n return [];\n }\n\n return runtime.executionHistory\n .filter(execution => execution.jobId === scheduler.job.id)\n .slice(-limit)\n .reverse();\n};\n\n// The one place runtime gets bound into the public app.scheduler shape -\n// Fastify needs a plain object of methods with no runtime param, so this\n// wraps each plain function above with `runtime` pre-applied. Everything\n// above this line is a normal function you can call directly with an\n// explicit runtime, e.g. in tests.\nexport const createSchedulerManager = (runtime: SchedulerRuntime): SchedulerManager => ({\n addJob: (jobDefinition) => addJob(runtime, jobDefinition),\n removeJob: (jobName) => removeJob(runtime, jobName),\n hasJob: (jobName) => hasJob(runtime, jobName),\n listJobs: (module) => listJobs(runtime, module),\n getJobStats: (jobName) => getJobStats(runtime, jobName),\n getJobsMap: () => getJobsMap(runtime),\n getConfig: () => runtime.config,\n enableJob: (jobName) => enableJob(runtime, jobName),\n disableJob: (jobName) => disableJob(runtime, jobName),\n triggerJob: (jobName) => triggerJob(runtime, jobName),\n getDashboardSummary: () => getDashboardSummary(runtime),\n getExecutionsSummary: () => getExecutionsSummary(runtime),\n getJobExecutionHistory: (jobName, limit) => getJobExecutionHistory(runtime, jobName, limit),\n});\n","import { FastifyInstance, FastifyReply, FastifyRequest } from \"fastify\";\n\n// Function to register all routes\nexport const registerSchedulerRoutes = (\n app: FastifyInstance,\n prefix: string = \"schedule\"\n): void => {\n app.get(`/${prefix}/dashboard`,\n async (_: FastifyRequest, reply: FastifyReply) => {\n return reply.status(200).send(app.scheduler.getDashboardSummary());\n });\n\n app.get(`/${prefix}/executions`,\n async (_: FastifyRequest, reply: FastifyReply) => {\n return reply.status(200).send(app.scheduler.getExecutionsSummary());\n });\n\n app.post<{ Params: { jobName: string } }>(`/${prefix}/jobs/:jobName/trigger`,\n async (request: FastifyRequest<{ Params: { jobName: string } }>, reply: FastifyReply) => {\n try {\n await app.scheduler.triggerJob(request.params.jobName);\n return reply.status(200).send({ message: \"Job triggered successfully\" });\n } catch (error: any) {\n return reply.status(404).send({ error: error.message });\n }\n });\n\n app.put<{ Params: { jobName: string } }>(`/${prefix}/jobs/:jobName/enable`,\n async (request: FastifyRequest<{ Params: { jobName: string } }>, reply: FastifyReply) => {\n try {\n await app.scheduler.enableJob(request.params.jobName);\n return reply.status(200).send({ message: \"Job enabled successfully\" });\n } catch (error: any) {\n return reply.status(404).send({ error: error.message });\n }\n });\n\n app.put<{ Params: { jobName: string } }>(`/${prefix}/jobs/:jobName/disable`,\n async (request: FastifyRequest<{ Params: { jobName: string } }>, reply: FastifyReply) => {\n try {\n await app.scheduler.disableJob(request.params.jobName);\n return reply.status(200).send({ message: \"Job disabled successfully\" });\n } catch (error: any) {\n return reply.status(404).send({ error: error.message });\n }\n });\n};\n","import crypto from \"node:crypto\";\n\nimport { FastifyInstance, FastifyPluginAsync } from \"fastify\";\nimport fsPlugin from \"fastify-plugin\";\nimport websocketPlugin from \"@fastify/websocket\";\n\nimport \"../logger/types\";\nimport { WebSocketConnectionGoneError } from \"@cloudnux/core-cloud-provider\";\n\n\nimport {\n WebSocketPluginOptions,\n WebSocketConfig,\n WebSocketConnection,\n WebSocketRouteHandler,\n RegisteredWebSocketPath,\n} from \"./types\";\n\nconst DEFAULT_CONFIG: WebSocketConfig = {\n routeKeyField: \"action\",\n};\n\nfunction mergeConfig(\n defaults: WebSocketConfig,\n overrides?: Partial<WebSocketConfig>\n): WebSocketConfig {\n return { ...defaults, ...overrides };\n}\n\nexport const websocketsPlugin: FastifyPluginAsync<WebSocketPluginOptions> =\n fsPlugin(async (\n app: FastifyInstance,\n options: WebSocketPluginOptions\n ) => {\n const config = mergeConfig(DEFAULT_CONFIG, options.config);\n const connections = new Map<string, WebSocketConnection>();\n const handlers: WebSocketRouteHandler[] = [];\n const registeredPaths = new Set<string>();\n const pathModuleMap = new Map<string, string | undefined>();\n\n // Register @fastify/websocket\n await app.register(websocketPlugin);\n\n // Register WebSocket route for a path when first handler uses it\n function ensureRouteForPath(path: string) {\n if (registeredPaths.has(path)) return;\n registeredPaths.add(path);\n\n app.get(path, {\n websocket: true,\n preHandler: async (request, reply) => {\n const connectionId = crypto.randomUUID();\n (request as any)._wsConnectionId = connectionId;\n const reqId = `${request.id}:${connectionId}`;\n\n const connectHandlers = handlers.filter(h => h.path === path && h.event === \"connect\");\n for (const h of connectHandlers) {\n await app.logging.runWithLogContext(\n { module: h.module, reqId },\n () => h.handler(connectionId, \"connect\", null, request, reply)\n );\n }\n if (reply.statusCode !== 200)\n return reply; // Prevent WebSocket upgrade if preHandler set an error status\n },\n }, (socket, request) => {\n const connectionId = (request as any)._wsConnectionId ?? crypto.randomUUID();\n const reqId = `${request.id}:${connectionId}`;\n const connection: WebSocketConnection = {\n connectionId,\n socket,\n path,\n connectedAt: new Date(),\n };\n connections.set(connectionId, connection);\n\n // Filter handlers for this path at runtime so late-registered handlers are included\n const pathHandlers = () => handlers.filter(h => h.path === path);\n\n // Handle incoming messages\n socket.on(\"message\", (raw) => {\n const data = raw.toString();\n\n const currentHandlers = pathHandlers();\n\n // Try to parse and match a specific route handler\n let routeKey: string | undefined;\n try {\n const parsed = JSON.parse(data);\n routeKey = parsed?.[config.routeKeyField];\n } catch {\n // not JSON, no route key\n }\n\n let matched = false;\n if (routeKey) {\n const routeHandlers = currentHandlers.filter(\n h => h.event === \"message\" && h.route === routeKey\n );\n for (const h of routeHandlers) {\n matched = true;\n app.logging.runWithLogContext(\n { module: h.module, reqId },\n () => h.handler(connectionId, \"message\", data, request).catch((e) => app.logging.error(e))\n );\n }\n }\n\n // Fall back to default message handlers (no route)\n if (!matched) {\n const defaultHandlers = currentHandlers.filter(\n h => h.event === \"message\" && !h.route\n );\n for (const h of defaultHandlers) {\n app.logging.runWithLogContext(\n { module: h.module, reqId },\n () => h.handler(connectionId, \"message\", data, request).catch((e) => app.logging.error(e))\n );\n }\n }\n });\n\n // Handle disconnect\n socket.on(\"close\", () => {\n const disconnectHandlers = pathHandlers().filter(h => h.event === \"disconnect\");\n for (const h of disconnectHandlers) {\n app.logging.runWithLogContext(\n { module: h.module, reqId },\n () => h.handler(connectionId, \"disconnect\", null, request).catch((e) => app.logging.error(e))\n );\n }\n connections.delete(connectionId);\n });\n });\n }\n\n // Create manager with eager route registration\n const manager = {\n registerHandler(handler: WebSocketRouteHandler) {\n handlers.push(handler);\n if (!pathModuleMap.has(handler.path)) {\n pathModuleMap.set(handler.path, handler.module);\n }\n ensureRouteForPath(handler.path);\n },\n getConnections(path?: string): WebSocketConnection[] {\n const allConnections = Array.from(connections.values());\n if (path) {\n return allConnections.filter(c => c.path === path);\n }\n return allConnections;\n },\n getRegisteredPaths(module?: string): RegisteredWebSocketPath[] {\n const all: RegisteredWebSocketPath[] = Array.from(pathModuleMap.entries()).map(([path, mod]) => ({ path, module: mod }));\n if (module) {\n return all.filter(p => p.module === module);\n }\n return all;\n },\n async sendToClient(connectionId: string, data: any): Promise<void> {\n const connection = connections.get(connectionId);\n if (!connection) {\n throw new WebSocketConnectionGoneError(connectionId);\n }\n const payload = typeof data === \"string\" ? data : JSON.stringify(data);\n connection.socket.send(payload);\n },\n async disconnect(connectionId: string): Promise<void> {\n const connection = connections.get(connectionId);\n if (!connection) {\n throw new WebSocketConnectionGoneError(connectionId);\n }\n connection.socket.close();\n },\n };\n\n app.decorate('websockets', manager);\n });\n","export interface RouteInfo {\n method: string | string[]\n url: string\n handler: string\n registeredAt: Date,\n module?: string\n}\n\nclass RouteRegistry {\n private routes: RouteInfo[] = []\n\n private static readonly IGNORED_METHODS = new Set(['OPTIONS', 'HEAD'])\n\n register(routeOptions: any): void {\n const methods: string[] = Array.isArray(routeOptions.method)\n ? routeOptions.method\n : [routeOptions.method]\n\n if (methods.every(m => RouteRegistry.IGNORED_METHODS.has(m.toUpperCase()))) {\n return\n }\n\n const routeInfo: RouteInfo = {\n method: routeOptions.method,\n url: routeOptions.url,\n handler: routeOptions.handler?.name || 'anonymous',\n registeredAt: new Date(),\n module: routeOptions.config?.module\n }\n\n this.routes.push(routeInfo)\n }\n\n getAll(): RouteInfo[] {\n return [...this.routes]\n }\n\n getByMethod(method: string): RouteInfo[] {\n return this.routes.filter(route => {\n if (Array.isArray(route.method)) {\n return route.method.includes(method.toUpperCase())\n }\n return route.method.toUpperCase() === method.toUpperCase()\n })\n }\n\n clear(): void {\n this.routes = []\n }\n\n count(): number {\n return this.routes.length\n }\n}\n\nexport const routeRegistry = new RouteRegistry()","import * as fs from 'fs';\nimport * as path from 'path';\nimport { randomUUID } from 'crypto';\n\nimport { env } from \"@cloudnux/utils\";\n\nimport { EmailAttachment, EmailMessage, EmailSendResult, EmailService, getService, LoggerService } from \"@cloudnux/core-cloud-provider\";\n\nconst { mkdir, writeFile, readdir, readFile, unlink } = fs.promises;\n\nconst MAX_HISTORY = 100;\nconst PREVIEW_LENGTH = 150;\n\nexport type EmailHistoryEntry = {\n id: string;\n messageId: string;\n timestamp: string;\n from: string;\n to: string[];\n cc?: string[];\n subject: string;\n preview: string;\n hasAttachments: boolean;\n attachmentCount?: number;\n configurationSet?: string;\n status: \"sent\" | \"failed\";\n error?: string;\n};\n\nfunction resolveBaseDir(): string {\n return env(\"DEV_CLOUD_EMAIL_DIR\", path.join(process.cwd(), '.local-email'))!;\n}\n\nfunction toArray(value?: string | string[]): string[] {\n if (!value) return [];\n return Array.isArray(value) ? value : [value];\n}\n\nfunction assertValidMessage(message: EmailMessage): void {\n if (!message.to || (Array.isArray(message.to) && message.to.length === 0)) {\n throw new Error(\"At least one recipient (to) is required\");\n }\n if (!message.from) {\n throw new Error(\"Sender (from) is required\");\n }\n if (!message.subject) {\n throw new Error(\"Subject is required\");\n }\n if (!message.html && !message.text) {\n throw new Error(\"At least one of html or text is required\");\n }\n}\n\nfunction slugify(subject: string): string {\n const slug = subject\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n return (slug || 'email').slice(0, 50);\n}\n\n// Rough, regex-based tag strip - good enough for an inbox-style preview\n// snippet, not meant to be a general HTML sanitizer.\nfunction stripHtml(html: string): string {\n return html\n .replace(/<style[\\s\\S]*?<\\/style>/gi, ' ')\n .replace(/<script[\\s\\S]*?<\\/script>/gi, ' ')\n .replace(/<[^>]+>/g, ' ');\n}\n\nfunction buildPreview(message: EmailMessage): string {\n const source = message.text ?? stripHtml(message.html ?? '');\n const collapsed = source.replace(/\\s+/g, ' ').trim();\n return collapsed.length > PREVIEW_LENGTH\n ? collapsed.slice(0, PREVIEW_LENGTH).trimEnd() + '…'\n : collapsed;\n}\n\nfunction encodeHeaderValue(value: string): string {\n return /^[\\x00-\\x7F]*$/.test(value)\n ? value\n : `=?UTF-8?B?${Buffer.from(value, 'utf8').toString('base64')}?=`;\n}\n\nfunction randomBoundary(): string {\n return `----=_Part_${randomUUID().replace(/-/g, '')}`;\n}\n\nfunction base64Wrap(data: Buffer): string {\n return data.toString('base64').replace(/(.{76})/g, '$1\\r\\n');\n}\n\nfunction textPart(contentType: string, data: string): string {\n return [\n `Content-Type: ${contentType}; charset=UTF-8`,\n 'Content-Transfer-Encoding: base64',\n '',\n base64Wrap(Buffer.from(data, 'utf8')),\n ].join('\\r\\n');\n}\n\nfunction attachmentContent(attachment: EmailAttachment): Buffer {\n return Buffer.isBuffer(attachment.content)\n ? attachment.content\n : Buffer.from(attachment.content, 'base64');\n}\n\nfunction attachmentPart(attachment: EmailAttachment): string {\n return [\n `Content-Type: ${attachment.contentType}; name=\"${attachment.filename}\"`,\n `Content-Disposition: attachment; filename=\"${attachment.filename}\"`,\n 'Content-Transfer-Encoding: base64',\n '',\n base64Wrap(attachmentContent(attachment)),\n ].join('\\r\\n');\n}\n\nfunction multipart(boundary: string, type: string, parts: string[]): string {\n const body = parts.map((part) => `--${boundary}\\r\\n${part}`).join('\\r\\n');\n return `Content-Type: multipart/${type}; boundary=\"${boundary}\"\\r\\n\\r\\n${body}\\r\\n--${boundary}--`;\n}\n\nfunction buildEml(message: EmailMessage, messageId: string): string {\n const headers: string[] = [\n `From: ${message.from}`,\n `To: ${toArray(message.to).join(', ')}`,\n ];\n\n const cc = toArray(message.cc);\n if (cc.length) headers.push(`Cc: ${cc.join(', ')}`);\n\n const bcc = toArray(message.bcc);\n if (bcc.length) headers.push(`Bcc: ${bcc.join(', ')}`);\n\n if (message.replyTo) headers.push(`Reply-To: ${message.replyTo}`);\n\n headers.push(`Subject: ${encodeHeaderValue(message.subject)}`);\n headers.push(`Date: ${new Date().toUTCString()}`);\n headers.push(`Message-ID: <${messageId}@local-cloud-provider>`);\n headers.push('MIME-Version: 1.0');\n\n const bodyParts: string[] = [];\n if (message.text) bodyParts.push(textPart('text/plain', message.text));\n if (message.html) bodyParts.push(textPart('text/html', message.html));\n\n const bodyContent = bodyParts.length > 1\n ? multipart(randomBoundary(), 'alternative', bodyParts)\n : bodyParts[0];\n\n if (!message.attachments?.length) {\n return [...headers, bodyContent].join('\\r\\n');\n }\n\n const attachmentParts = message.attachments.map(attachmentPart);\n const mixedBody = multipart(randomBoundary(), 'mixed', [bodyContent, ...attachmentParts]);\n\n return [...headers, mixedBody].join('\\r\\n');\n}\n\n// Newest-first: ids are Date.now()-prefixed, so a reverse lexicographic\n// sort is a reverse chronological sort.\nasync function listEntryIds(baseDir: string): Promise<string[]> {\n if (!fs.existsSync(baseDir)) return [];\n const files = await readdir(baseDir);\n return files\n .filter((file) => file.endsWith('.json'))\n .map((file) => file.slice(0, -'.json'.length))\n .sort()\n .reverse();\n}\n\n// Deletes files on disk down to MAX_HISTORY entries - no in-memory list is\n// kept, so the directory itself is both the store and the retention log.\nasync function enforceRetention(baseDir: string, logger: LoggerService): Promise<void> {\n const ids = await listEntryIds(baseDir);\n const overflow = ids.length - MAX_HISTORY;\n if (overflow <= 0) return;\n\n const toRemove = ids.slice(-overflow);\n await Promise.all(toRemove.map(async (id) => {\n try {\n await unlink(path.join(baseDir, `${id}.eml`));\n await unlink(path.join(baseDir, `${id}.json`));\n } catch (error) {\n logger.warn({ error }, `Failed to prune local email history entry ${id}`);\n }\n }));\n}\n\n/**\n * Create a local email service that writes each send as an .eml file plus\n * a metadata sidecar (mirroring storage.ts's *.metadata.json convention).\n * No real network send happens - this is purely for dev-console inspection.\n * @returns Local filesystem-backed email service implementation\n */\nexport function createLocalEmailService(): EmailService {\n const baseDir = resolveBaseDir();\n const logger = getService<LoggerService>(\"logger\");\n\n if (!fs.existsSync(baseDir)) {\n fs.mkdirSync(baseDir, { recursive: true });\n }\n\n return {\n async send(message: EmailMessage): Promise<EmailSendResult> {\n assertValidMessage(message);\n\n const messageId = randomUUID();\n const id = `${Date.now()}-${slugify(message.subject)}-${Math.random().toString(36).slice(2, 7)}`;\n\n try {\n await mkdir(baseDir, { recursive: true });\n\n const eml = buildEml(message, messageId);\n await writeFile(path.join(baseDir, `${id}.eml`), eml, 'utf8');\n\n const metadata: EmailHistoryEntry = {\n id,\n messageId,\n timestamp: new Date().toISOString(),\n from: message.from,\n to: toArray(message.to),\n cc: toArray(message.cc).length ? toArray(message.cc) : undefined,\n subject: message.subject,\n preview: buildPreview(message),\n hasAttachments: !!message.attachments?.length,\n attachmentCount: message.attachments?.length || undefined,\n configurationSet: message.configurationSet,\n status: 'sent',\n };\n\n await writeFile(path.join(baseDir, `${id}.json`), JSON.stringify(metadata, null, 2), 'utf8');\n await enforceRetention(baseDir, logger);\n\n return { status: 'sent', messageId };\n } catch (error) {\n logger.error({ error }, 'Failed to write local email');\n return { status: 'failed', error: error instanceof Error ? error.message : String(error) };\n }\n },\n };\n}\n\n/**\n * Reads the most recent email history entries straight off disk - no\n * in-memory cache, so this is safe to call from any bundle (e.g.\n * dev-console-plugin) independently of the EmailService instance.\n * @param limit Maximum number of entries to return\n * @returns Metadata for the most recent sends, newest first\n */\nexport async function listEmailHistory(limit: number = MAX_HISTORY): Promise<EmailHistoryEntry[]> {\n const baseDir = resolveBaseDir();\n const ids = (await listEntryIds(baseDir)).slice(0, limit);\n\n return Promise.all(ids.map(async (id) => {\n const raw = await readFile(path.join(baseDir, `${id}.json`), 'utf8');\n return JSON.parse(raw) as EmailHistoryEntry;\n }));\n}\n\n/**\n * Reads one email's metadata by id.\n * @param id History entry id (the file basename)\n * @returns The entry's metadata, or undefined if not found\n */\nexport async function getEmailHistoryEntry(id: string): Promise<EmailHistoryEntry | undefined> {\n try {\n const raw = await readFile(path.join(resolveBaseDir(), `${id}.json`), 'utf8');\n return JSON.parse(raw) as EmailHistoryEntry;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Reads one email's raw .eml (MIME) content by id.\n * @param id History entry id (the file basename)\n * @returns The raw MIME content, or undefined if not found\n */\nexport async function getEmailRaw(id: string): Promise<string | undefined> {\n try {\n return await readFile(path.join(resolveBaseDir(), `${id}.eml`), 'utf8');\n } catch {\n return undefined;\n }\n}\n\nexport type EmailBody = {\n html?: string;\n text?: string;\n};\n\nfunction extractHeader(headerBlock: string, name: string): string | undefined {\n const match = headerBlock.match(new RegExp(`^${name}:\\\\s*(.+)$`, 'im'));\n return match?.[1]?.trim();\n}\n\n// Walks the MIME tree buildEml() produces (multipart/mixed wrapping\n// multipart/alternative wrapping text/plain + text/html, or any subset of\n// that) and collects the text/html and text/plain leaf parts. Not a\n// general-purpose MIME parser - just the inverse of buildEml().\nfunction collectParts(part: string, result: EmailBody): void {\n const boundaryIdx = part.indexOf('\\r\\n\\r\\n');\n const headerBlock = boundaryIdx === -1 ? part : part.slice(0, boundaryIdx);\n const body = boundaryIdx === -1 ? '' : part.slice(boundaryIdx + 4);\n\n const contentType = extractHeader(headerBlock, 'Content-Type') ?? 'text/plain';\n const boundaryMatch = contentType.match(/boundary=\"?([^\";]+)\"?/i);\n\n if (/^multipart\\//i.test(contentType) && boundaryMatch) {\n const boundary = boundaryMatch[1];\n for (const chunk of body.split(`--${boundary}`)) {\n const trimmed = chunk.replace(/^\\r\\n/, '');\n if (!trimmed || trimmed.startsWith('--')) continue;\n collectParts(trimmed, result);\n }\n return;\n }\n\n if (/^attachment/i.test(extractHeader(headerBlock, 'Content-Disposition') ?? '')) return;\n\n const encoding = (extractHeader(headerBlock, 'Content-Transfer-Encoding') ?? '').toLowerCase();\n const raw = body.replace(/\\r\\n$/, '');\n const decoded = encoding === 'base64'\n ? Buffer.from(raw.replace(/\\r?\\n/g, ''), 'base64').toString('utf8')\n : raw;\n\n if (/^text\\/html/i.test(contentType)) {\n result.html = decoded;\n } else if (/^text\\/plain/i.test(contentType)) {\n result.text = decoded;\n }\n}\n\n/**\n * Reads one email's .eml and extracts its text/html and text/plain body\n * parts, for rendering in the dev-console (rather than downloading the raw\n * MIME file).\n * @param id History entry id (the file basename)\n * @returns The extracted body parts, or undefined if the email isn't found\n */\nexport async function getEmailBody(id: string): Promise<EmailBody | undefined> {\n const raw = await getEmailRaw(id);\n if (raw === undefined) return undefined;\n\n const result: EmailBody = {};\n collectParts(raw, result);\n return result;\n}\n","/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\nexport default freeGlobal;\n","import freeGlobal from './_freeGlobal.js';\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\nexport default root;\n","import root from './_root.js';\n\n/** Built-in value references. */\nvar Symbol = root.Symbol;\n\nexport default Symbol;\n","import Symbol from './_Symbol.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\nfunction getRawTag(value) {\n var isOwn = hasOwnProperty.call(value, symToStringTag),\n tag = value[symToStringTag];\n\n try {\n value[symToStringTag] = undefined;\n var unmasked = true;\n } catch (e) {}\n\n var result = nativeObjectToString.call(value);\n if (unmasked) {\n if (isOwn) {\n value[symToStringTag] = tag;\n } else {\n delete value[symToStringTag];\n }\n }\n return result;\n}\n\nexport default getRawTag;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","import Symbol from './_Symbol.js';\nimport getRawTag from './_getRawTag.js';\nimport objectToString from './_objectToString.js';\n\n/** `Object#toString` result references. */\nvar nullTag = '[object Null]',\n undefinedTag = '[object Undefined]';\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n if (value == null) {\n return value === undefined ? undefinedTag : nullTag;\n }\n return (symToStringTag && symToStringTag in Object(value))\n ? getRawTag(value)\n : objectToString(value);\n}\n\nexport default baseGetTag;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","import baseGetTag from './_baseGetTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && baseGetTag(value) == symbolTag);\n}\n\nexport default isSymbol;\n","/**\n * A specialized version of `_.map` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the new mapped array.\n */\nfunction arrayMap(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length,\n result = Array(length);\n\n while (++index < length) {\n result[index] = iteratee(array[index], index, array);\n }\n return result;\n}\n\nexport default arrayMap;\n","/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","import Symbol from './_Symbol.js';\nimport arrayMap from './_arrayMap.js';\nimport isArray from './isArray.js';\nimport isSymbol from './isSymbol.js';\n\n/** Used as references for various `Number` constants. */\nvar INFINITY = 1 / 0;\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n symbolToString = symbolProto ? symbolProto.toString : undefined;\n\n/**\n * The base implementation of `_.toString` which doesn't convert nullish\n * values to empty strings.\n *\n * @private\n * @param {*} value The value to process.\n * @returns {string} Returns the string.\n */\nfunction baseToString(value) {\n // Exit early for strings to avoid a performance hit in some environments.\n if (typeof value == 'string') {\n return value;\n }\n if (isArray(value)) {\n // Recursively convert values (susceptible to call stack limits).\n return arrayMap(value, baseToString) + '';\n }\n if (isSymbol(value)) {\n return symbolToString ? symbolToString.call(value) : '';\n }\n var result = (value + '');\n return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;\n}\n\nexport default baseToString;\n","/** Used to match a single whitespace character. */\nvar reWhitespace = /\\s/;\n\n/**\n * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace\n * character of `string`.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {number} Returns the index of the last non-whitespace character.\n */\nfunction trimmedEndIndex(string) {\n var index = string.length;\n\n while (index-- && reWhitespace.test(string.charAt(index))) {}\n return index;\n}\n\nexport default trimmedEndIndex;\n","import trimmedEndIndex from './_trimmedEndIndex.js';\n\n/** Used to match leading whitespace. */\nvar reTrimStart = /^\\s+/;\n\n/**\n * The base implementation of `_.trim`.\n *\n * @private\n * @param {string} string The string to trim.\n * @returns {string} Returns the trimmed string.\n */\nfunction baseTrim(string) {\n return string\n ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')\n : string;\n}\n\nexport default baseTrim;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","import baseGetTag from './_baseGetTag.js';\nimport isObject from './isObject.js';\n\n/** `Object#toString` result references. */\nvar asyncTag = '[object AsyncFunction]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]',\n proxyTag = '[object Proxy]';\n\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n if (!isObject(value)) {\n return false;\n }\n // The use of `Object#toString` avoids issues with the `typeof` operator\n // in Safari 9 which returns 'object' for typed arrays and other constructors.\n var tag = baseGetTag(value);\n return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;\n}\n\nexport default isFunction;\n","import root from './_root.js';\n\n/** Used to detect overreaching core-js shims. */\nvar coreJsData = root['__core-js_shared__'];\n\nexport default coreJsData;\n","import coreJsData from './_coreJsData.js';\n\n/** Used to detect methods masquerading as native. */\nvar maskSrcKey = (function() {\n var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');\n return uid ? ('Symbol(src)_1.' + uid) : '';\n}());\n\n/**\n * Checks if `func` has its source masked.\n *\n * @private\n * @param {Function} func The function to check.\n * @returns {boolean} Returns `true` if `func` is masked, else `false`.\n */\nfunction isMasked(func) {\n return !!maskSrcKey && (maskSrcKey in func);\n}\n\nexport default isMasked;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","import isFunction from './isFunction.js';\nimport isMasked from './_isMasked.js';\nimport isObject from './isObject.js';\nimport toSource from './_toSource.js';\n\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n\n/** Used to detect host constructors (Safari). */\nvar reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n\n/** Used for built-in method references. */\nvar funcProto = Function.prototype,\n objectProto = Object.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to detect if a method is native. */\nvar reIsNative = RegExp('^' +\n funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\\\$&')\n .replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, '$1.*?') + '$'\n);\n\n/**\n * The base implementation of `_.isNative` without bad shim checks.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a native function,\n * else `false`.\n */\nfunction baseIsNative(value) {\n if (!isObject(value) || isMasked(value)) {\n return false;\n }\n var pattern = isFunction(value) ? reIsNative : reIsHostCtor;\n return pattern.test(toSource(value));\n}\n\nexport default baseIsNative;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","import baseIsNative from './_baseIsNative.js';\nimport getValue from './_getValue.js';\n\n/**\n * Gets the native function at `key` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the method to get.\n * @returns {*} Returns the function if it's native, else `undefined`.\n */\nfunction getNative(object, key) {\n var value = getValue(object, key);\n return baseIsNative(value) ? value : undefined;\n}\n\nexport default getNative;\n","/**\n * The base implementation of `_.findIndex` and `_.findLastIndex` without\n * support for iteratee shorthands.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {number} fromIndex The index to search from.\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction baseFindIndex(array, predicate, fromIndex, fromRight) {\n var length = array.length,\n index = fromIndex + (fromRight ? 1 : -1);\n\n while ((fromRight ? index-- : ++index < length)) {\n if (predicate(array[index], index, array)) {\n return index;\n }\n }\n return -1;\n}\n\nexport default baseFindIndex;\n","/**\n * The base implementation of `_.isNaN` without support for number objects.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.\n */\nfunction baseIsNaN(value) {\n return value !== value;\n}\n\nexport default baseIsNaN;\n","/**\n * A specialized version of `_.indexOf` which performs strict equality\n * comparisons of values, i.e. `===`.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} value The value to search for.\n * @param {number} fromIndex The index to search from.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction strictIndexOf(array, value, fromIndex) {\n var index = fromIndex - 1,\n length = array.length;\n\n while (++index < length) {\n if (array[index] === value) {\n return index;\n }\n }\n return -1;\n}\n\nexport default strictIndexOf;\n","import baseFindIndex from './_baseFindIndex.js';\nimport baseIsNaN from './_baseIsNaN.js';\nimport strictIndexOf from './_strictIndexOf.js';\n\n/**\n * The base implementation of `_.indexOf` without `fromIndex` bounds checks.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} value The value to search for.\n * @param {number} fromIndex The index to search from.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction baseIndexOf(array, value, fromIndex) {\n return value === value\n ? strictIndexOf(array, value, fromIndex)\n : baseFindIndex(array, baseIsNaN, fromIndex);\n}\n\nexport default baseIndexOf;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","import baseGetTag from './_baseGetTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]';\n\n/**\n * The base implementation of `_.isArguments`.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n */\nfunction baseIsArguments(value) {\n return isObjectLike(value) && baseGetTag(value) == argsTag;\n}\n\nexport default baseIsArguments;\n","import baseIsArguments from './_baseIsArguments.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n/**\n * Checks if `value` is likely an `arguments` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n * else `false`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\nvar isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {\n return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&\n !propertyIsEnumerable.call(value, 'callee');\n};\n\nexport default isArguments;\n","import isArray from './isArray.js';\nimport isSymbol from './isSymbol.js';\n\n/** Used to match property names within property paths. */\nvar reIsDeepProp = /\\.|\\[(?:[^[\\]]*|([\"'])(?:(?!\\1)[^\\\\]|\\\\.)*?\\1)\\]/,\n reIsPlainProp = /^\\w*$/;\n\n/**\n * Checks if `value` is a property name and not a property path.\n *\n * @private\n * @param {*} value The value to check.\n * @param {Object} [object] The object to query keys on.\n * @returns {boolean} Returns `true` if `value` is a property name, else `false`.\n */\nfunction isKey(value, object) {\n if (isArray(value)) {\n return false;\n }\n var type = typeof value;\n if (type == 'number' || type == 'symbol' || type == 'boolean' ||\n value == null || isSymbol(value)) {\n return true;\n }\n return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||\n (object != null && value in Object(object));\n}\n\nexport default isKey;\n","import getNative from './_getNative.js';\n\n/* Built-in method references that are verified to be native. */\nvar nativeCreate = getNative(Object, 'create');\n\nexport default nativeCreate;\n","import nativeCreate from './_nativeCreate.js';\n\n/**\n * Removes all key-value entries from the hash.\n *\n * @private\n * @name clear\n * @memberOf Hash\n */\nfunction hashClear() {\n this.__data__ = nativeCreate ? nativeCreate(null) : {};\n this.size = 0;\n}\n\nexport default hashClear;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Gets the hash value for `key`.\n *\n * @private\n * @name get\n * @memberOf Hash\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction hashGet(key) {\n var data = this.__data__;\n if (nativeCreate) {\n var result = data[key];\n return result === HASH_UNDEFINED ? undefined : result;\n }\n return hasOwnProperty.call(data, key) ? data[key] : undefined;\n}\n\nexport default hashGet;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Checks if a hash value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Hash\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction hashHas(key) {\n var data = this.__data__;\n return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);\n}\n\nexport default hashHas;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Sets the hash `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Hash\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the hash instance.\n */\nfunction hashSet(key, value) {\n var data = this.__data__;\n this.size += this.has(key) ? 0 : 1;\n data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;\n return this;\n}\n\nexport default hashSet;\n","import hashClear from './_hashClear.js';\nimport hashDelete from './_hashDelete.js';\nimport hashGet from './_hashGet.js';\nimport hashHas from './_hashHas.js';\nimport hashSet from './_hashSet.js';\n\n/**\n * Creates a hash object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Hash(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `Hash`.\nHash.prototype.clear = hashClear;\nHash.prototype['delete'] = hashDelete;\nHash.prototype.get = hashGet;\nHash.prototype.has = hashHas;\nHash.prototype.set = hashSet;\n\nexport default Hash;\n","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","import eq from './eq.js';\n\n/**\n * Gets the index at which the `key` is found in `array` of key-value pairs.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} key The key to search for.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction assocIndexOf(array, key) {\n var length = array.length;\n while (length--) {\n if (eq(array[length][0], key)) {\n return length;\n }\n }\n return -1;\n}\n\nexport default assocIndexOf;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/** Used for built-in method references. */\nvar arrayProto = Array.prototype;\n\n/** Built-in value references. */\nvar splice = arrayProto.splice;\n\n/**\n * Removes `key` and its value from the list cache.\n *\n * @private\n * @name delete\n * @memberOf ListCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction listCacheDelete(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n return false;\n }\n var lastIndex = data.length - 1;\n if (index == lastIndex) {\n data.pop();\n } else {\n splice.call(data, index, 1);\n }\n --this.size;\n return true;\n}\n\nexport default listCacheDelete;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/**\n * Gets the list cache value for `key`.\n *\n * @private\n * @name get\n * @memberOf ListCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction listCacheGet(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n return index < 0 ? undefined : data[index][1];\n}\n\nexport default listCacheGet;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/**\n * Checks if a list cache value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf ListCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction listCacheHas(key) {\n return assocIndexOf(this.__data__, key) > -1;\n}\n\nexport default listCacheHas;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/**\n * Sets the list cache `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf ListCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the list cache instance.\n */\nfunction listCacheSet(key, value) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n ++this.size;\n data.push([key, value]);\n } else {\n data[index][1] = value;\n }\n return this;\n}\n\nexport default listCacheSet;\n","import listCacheClear from './_listCacheClear.js';\nimport listCacheDelete from './_listCacheDelete.js';\nimport listCacheGet from './_listCacheGet.js';\nimport listCacheHas from './_listCacheHas.js';\nimport listCacheSet from './_listCacheSet.js';\n\n/**\n * Creates an list cache object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction ListCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `ListCache`.\nListCache.prototype.clear = listCacheClear;\nListCache.prototype['delete'] = listCacheDelete;\nListCache.prototype.get = listCacheGet;\nListCache.prototype.has = listCacheHas;\nListCache.prototype.set = listCacheSet;\n\nexport default ListCache;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar Map = getNative(root, 'Map');\n\nexport default Map;\n","import Hash from './_Hash.js';\nimport ListCache from './_ListCache.js';\nimport Map from './_Map.js';\n\n/**\n * Removes all key-value entries from the map.\n *\n * @private\n * @name clear\n * @memberOf MapCache\n */\nfunction mapCacheClear() {\n this.size = 0;\n this.__data__ = {\n 'hash': new Hash,\n 'map': new (Map || ListCache),\n 'string': new Hash\n };\n}\n\nexport default mapCacheClear;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","import isKeyable from './_isKeyable.js';\n\n/**\n * Gets the data for `map`.\n *\n * @private\n * @param {Object} map The map to query.\n * @param {string} key The reference key.\n * @returns {*} Returns the map data.\n */\nfunction getMapData(map, key) {\n var data = map.__data__;\n return isKeyable(key)\n ? data[typeof key == 'string' ? 'string' : 'hash']\n : data.map;\n}\n\nexport default getMapData;\n","import getMapData from './_getMapData.js';\n\n/**\n * Removes `key` and its value from the map.\n *\n * @private\n * @name delete\n * @memberOf MapCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction mapCacheDelete(key) {\n var result = getMapData(this, key)['delete'](key);\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default mapCacheDelete;\n","import getMapData from './_getMapData.js';\n\n/**\n * Gets the map value for `key`.\n *\n * @private\n * @name get\n * @memberOf MapCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction mapCacheGet(key) {\n return getMapData(this, key).get(key);\n}\n\nexport default mapCacheGet;\n","import getMapData from './_getMapData.js';\n\n/**\n * Checks if a map value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf MapCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction mapCacheHas(key) {\n return getMapData(this, key).has(key);\n}\n\nexport default mapCacheHas;\n","import getMapData from './_getMapData.js';\n\n/**\n * Sets the map `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf MapCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the map cache instance.\n */\nfunction mapCacheSet(key, value) {\n var data = getMapData(this, key),\n size = data.size;\n\n data.set(key, value);\n this.size += data.size == size ? 0 : 1;\n return this;\n}\n\nexport default mapCacheSet;\n","import mapCacheClear from './_mapCacheClear.js';\nimport mapCacheDelete from './_mapCacheDelete.js';\nimport mapCacheGet from './_mapCacheGet.js';\nimport mapCacheHas from './_mapCacheHas.js';\nimport mapCacheSet from './_mapCacheSet.js';\n\n/**\n * Creates a map cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction MapCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `MapCache`.\nMapCache.prototype.clear = mapCacheClear;\nMapCache.prototype['delete'] = mapCacheDelete;\nMapCache.prototype.get = mapCacheGet;\nMapCache.prototype.has = mapCacheHas;\nMapCache.prototype.set = mapCacheSet;\n\nexport default MapCache;\n","import MapCache from './_MapCache.js';\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a function that memoizes the result of `func`. If `resolver` is\n * provided, it determines the cache key for storing the result based on the\n * arguments provided to the memoized function. By default, the first argument\n * provided to the memoized function is used as the map cache key. The `func`\n * is invoked with the `this` binding of the memoized function.\n *\n * **Note:** The cache is exposed as the `cache` property on the memoized\n * function. Its creation may be customized by replacing the `_.memoize.Cache`\n * constructor with one whose instances implement the\n * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)\n * method interface of `clear`, `delete`, `get`, `has`, and `set`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to have its output memoized.\n * @param {Function} [resolver] The function to resolve the cache key.\n * @returns {Function} Returns the new memoized function.\n * @example\n *\n * var object = { 'a': 1, 'b': 2 };\n * var other = { 'c': 3, 'd': 4 };\n *\n * var values = _.memoize(_.values);\n * values(object);\n * // => [1, 2]\n *\n * values(other);\n * // => [3, 4]\n *\n * object.a = 2;\n * values(object);\n * // => [1, 2]\n *\n * // Modify the result cache.\n * values.cache.set(object, ['a', 'b']);\n * values(object);\n * // => ['a', 'b']\n *\n * // Replace `_.memoize.Cache`.\n * _.memoize.Cache = WeakMap;\n */\nfunction memoize(func, resolver) {\n if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n var memoized = function() {\n var args = arguments,\n key = resolver ? resolver.apply(this, args) : args[0],\n cache = memoized.cache;\n\n if (cache.has(key)) {\n return cache.get(key);\n }\n var result = func.apply(this, args);\n memoized.cache = cache.set(key, result) || cache;\n return result;\n };\n memoized.cache = new (memoize.Cache || MapCache);\n return memoized;\n}\n\n// Expose `MapCache`.\nmemoize.Cache = MapCache;\n\nexport default memoize;\n","import memoize from './memoize.js';\n\n/** Used as the maximum memoize cache size. */\nvar MAX_MEMOIZE_SIZE = 500;\n\n/**\n * A specialized version of `_.memoize` which clears the memoized function's\n * cache when it exceeds `MAX_MEMOIZE_SIZE`.\n *\n * @private\n * @param {Function} func The function to have its output memoized.\n * @returns {Function} Returns the new memoized function.\n */\nfunction memoizeCapped(func) {\n var result = memoize(func, function(key) {\n if (cache.size === MAX_MEMOIZE_SIZE) {\n cache.clear();\n }\n return key;\n });\n\n var cache = result.cache;\n return result;\n}\n\nexport default memoizeCapped;\n","import memoizeCapped from './_memoizeCapped.js';\n\n/** Used to match property names within property paths. */\nvar rePropName = /[^.[\\]]+|\\[(?:(-?\\d+(?:\\.\\d+)?)|([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2)\\]|(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))/g;\n\n/** Used to match backslashes in property paths. */\nvar reEscapeChar = /\\\\(\\\\)?/g;\n\n/**\n * Converts `string` to a property path array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the property path array.\n */\nvar stringToPath = memoizeCapped(function(string) {\n var result = [];\n if (string.charCodeAt(0) === 46 /* . */) {\n result.push('');\n }\n string.replace(rePropName, function(match, number, quote, subString) {\n result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match));\n });\n return result;\n});\n\nexport default stringToPath;\n","import baseToString from './_baseToString.js';\n\n/**\n * Converts `value` to a string. An empty string is returned for `null`\n * and `undefined` values. The sign of `-0` is preserved.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n * @example\n *\n * _.toString(null);\n * // => ''\n *\n * _.toString(-0);\n * // => '-0'\n *\n * _.toString([1, 2, 3]);\n * // => '1,2,3'\n */\nfunction toString(value) {\n return value == null ? '' : baseToString(value);\n}\n\nexport default toString;\n","import isArray from './isArray.js';\nimport isKey from './_isKey.js';\nimport stringToPath from './_stringToPath.js';\nimport toString from './toString.js';\n\n/**\n * Casts `value` to a path array if it's not one.\n *\n * @private\n * @param {*} value The value to inspect.\n * @param {Object} [object] The object to query keys on.\n * @returns {Array} Returns the cast property path array.\n */\nfunction castPath(value, object) {\n if (isArray(value)) {\n return value;\n }\n return isKey(value, object) ? [value] : stringToPath(toString(value));\n}\n\nexport default castPath;\n","import isSymbol from './isSymbol.js';\n\n/** Used as references for various `Number` constants. */\nvar INFINITY = 1 / 0;\n\n/**\n * Converts `value` to a string key if it's not a string or symbol.\n *\n * @private\n * @param {*} value The value to inspect.\n * @returns {string|symbol} Returns the key.\n */\nfunction toKey(value) {\n if (typeof value == 'string' || isSymbol(value)) {\n return value;\n }\n var result = (value + '');\n return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;\n}\n\nexport default toKey;\n","/**\n * The base implementation of `_.slice` without an iteratee call guard.\n *\n * @private\n * @param {Array} array The array to slice.\n * @param {number} [start=0] The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the slice of `array`.\n */\nfunction baseSlice(array, start, end) {\n var index = -1,\n length = array.length;\n\n if (start < 0) {\n start = -start > length ? 0 : (length + start);\n }\n end = end > length ? length : end;\n if (end < 0) {\n end += length;\n }\n length = start > end ? 0 : ((end - start) >>> 0);\n start >>>= 0;\n\n var result = Array(length);\n while (++index < length) {\n result[index] = array[index + start];\n }\n return result;\n}\n\nexport default baseSlice;\n","import baseSlice from './_baseSlice.js';\n\n/**\n * Casts `array` to a slice if it's needed.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {number} start The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the cast slice.\n */\nfunction castSlice(array, start, end) {\n var length = array.length;\n end = end === undefined ? length : end;\n return (!start && end >= length) ? array : baseSlice(array, start, end);\n}\n\nexport default castSlice;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsZWJ = '\\\\u200d';\n\n/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */\nvar reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');\n\n/**\n * Checks if `string` contains Unicode symbols.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {boolean} Returns `true` if a symbol is found, else `false`.\n */\nfunction hasUnicode(string) {\n return reHasUnicode.test(string);\n}\n\nexport default hasUnicode;\n","/**\n * Converts an ASCII `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction asciiToArray(string) {\n return string.split('');\n}\n\nexport default asciiToArray;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsAstral = '[' + rsAstralRange + ']',\n rsCombo = '[' + rsComboRange + ']',\n rsFitz = '\\\\ud83c[\\\\udffb-\\\\udfff]',\n rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',\n rsNonAstral = '[^' + rsAstralRange + ']',\n rsRegional = '(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}',\n rsSurrPair = '[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]',\n rsZWJ = '\\\\u200d';\n\n/** Used to compose unicode regexes. */\nvar reOptMod = rsModifier + '?',\n rsOptVar = '[' + rsVarRange + ']?',\n rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',\n rsSeq = rsOptVar + reOptMod + rsOptJoin,\n rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';\n\n/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */\nvar reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');\n\n/**\n * Converts a Unicode `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction unicodeToArray(string) {\n return string.match(reUnicode) || [];\n}\n\nexport default unicodeToArray;\n","import asciiToArray from './_asciiToArray.js';\nimport hasUnicode from './_hasUnicode.js';\nimport unicodeToArray from './_unicodeToArray.js';\n\n/**\n * Converts `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction stringToArray(string) {\n return hasUnicode(string)\n ? unicodeToArray(string)\n : asciiToArray(string);\n}\n\nexport default stringToArray;\n","import castPath from './_castPath.js';\nimport isArguments from './isArguments.js';\nimport isArray from './isArray.js';\nimport isIndex from './_isIndex.js';\nimport isLength from './isLength.js';\nimport toKey from './_toKey.js';\n\n/**\n * Checks if `path` exists on `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Array|string} path The path to check.\n * @param {Function} hasFunc The function to check properties.\n * @returns {boolean} Returns `true` if `path` exists, else `false`.\n */\nfunction hasPath(object, path, hasFunc) {\n path = castPath(path, object);\n\n var index = -1,\n length = path.length,\n result = false;\n\n while (++index < length) {\n var key = toKey(path[index]);\n if (!(result = object != null && hasFunc(object, key))) {\n break;\n }\n object = object[key];\n }\n if (result || ++index != length) {\n return result;\n }\n length = object == null ? 0 : object.length;\n return !!length && isLength(length) && isIndex(key, length) &&\n (isArray(object) || isArguments(object));\n}\n\nexport default hasPath;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * The base implementation of `_.has` without support for deep paths.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {Array|string} key The key to check.\n * @returns {boolean} Returns `true` if `key` exists, else `false`.\n */\nfunction baseHas(object, key) {\n return object != null && hasOwnProperty.call(object, key);\n}\n\nexport default baseHas;\n","import baseHas from './_baseHas.js';\nimport hasPath from './_hasPath.js';\n\n/**\n * Checks if `path` is a direct property of `object`.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @param {Array|string} path The path to check.\n * @returns {boolean} Returns `true` if `path` exists, else `false`.\n * @example\n *\n * var object = { 'a': { 'b': 2 } };\n * var other = _.create({ 'a': _.create({ 'b': 2 }) });\n *\n * _.has(object, 'a');\n * // => true\n *\n * _.has(object, 'a.b');\n * // => true\n *\n * _.has(object, ['a', 'b']);\n * // => true\n *\n * _.has(other, 'a');\n * // => false\n */\nfunction has(object, path) {\n return object != null && hasPath(object, path, baseHas);\n}\n\nexport default has;\n","import baseIndexOf from './_baseIndexOf.js';\n\n/**\n * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol\n * that is not found in the character symbols.\n *\n * @private\n * @param {Array} strSymbols The string symbols to inspect.\n * @param {Array} chrSymbols The character symbols to find.\n * @returns {number} Returns the index of the last unmatched string symbol.\n */\nfunction charsEndIndex(strSymbols, chrSymbols) {\n var index = strSymbols.length;\n\n while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}\n return index;\n}\n\nexport default charsEndIndex;\n","import baseIndexOf from './_baseIndexOf.js';\n\n/**\n * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol\n * that is not found in the character symbols.\n *\n * @private\n * @param {Array} strSymbols The string symbols to inspect.\n * @param {Array} chrSymbols The character symbols to find.\n * @returns {number} Returns the index of the first unmatched string symbol.\n */\nfunction charsStartIndex(strSymbols, chrSymbols) {\n var index = -1,\n length = strSymbols.length;\n\n while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}\n return index;\n}\n\nexport default charsStartIndex;\n","import baseToString from './_baseToString.js';\nimport baseTrim from './_baseTrim.js';\nimport castSlice from './_castSlice.js';\nimport charsEndIndex from './_charsEndIndex.js';\nimport charsStartIndex from './_charsStartIndex.js';\nimport stringToArray from './_stringToArray.js';\nimport toString from './toString.js';\n\n/**\n * Removes leading and trailing whitespace or specified characters from `string`.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to trim.\n * @param {string} [chars=whitespace] The characters to trim.\n * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.\n * @returns {string} Returns the trimmed string.\n * @example\n *\n * _.trim(' abc ');\n * // => 'abc'\n *\n * _.trim('-_-abc-_-', '_-');\n * // => 'abc'\n *\n * _.map([' foo ', ' bar '], _.trim);\n * // => ['foo', 'bar']\n */\nfunction trim(string, chars, guard) {\n string = toString(string);\n if (string && (guard || chars === undefined)) {\n return baseTrim(string);\n }\n if (!string || !(chars = baseToString(chars))) {\n return string;\n }\n var strSymbols = stringToArray(string),\n chrSymbols = stringToArray(chars),\n start = charsStartIndex(strSymbols, chrSymbols),\n end = charsEndIndex(strSymbols, chrSymbols) + 1;\n\n return castSlice(strSymbols, start, end).join('');\n}\n\nexport default trim;\n","import { has, trim } from \"lodash-es\";\n\n//import dotenv from \"dotenv\";\n// if (__DEV__) {\n// dotenv.config({\n// path: __ENV_PATH__\n// })\n// }\n\n//function _env(key: keyof EnvKeys, defaultValue?: string): string;\nfunction _env(key: string, defaultValue?: string): string {\n return has(process.env, key)\n ? (process.env[key] ?? \"\")\n : (defaultValue ?? \"\");\n}\n\n//function int(key: keyof EnvKeys, defaultValue?: number): number;\nfunction int(key: string, defaultValue?: number): number {\n if (!has(process.env, key)) {\n return defaultValue ?? 0;\n }\n const value = process.env[key] ?? \"0\";\n return parseInt(value, 10);\n}\n\n//function float(key: keyof EnvKeys, defaultValue?: number): number;\nfunction float(key: string, defaultValue?: number): number {\n if (!has(process.env, key)) {\n return defaultValue ?? 0;\n }\n\n const value = process.env[key] ?? \"0\";\n return parseFloat(value);\n}\n\n//function bool(key: keyof EnvKeys, defaultValue?: boolean): boolean;\nfunction bool(key: string, defaultValue?: boolean): boolean {\n if (!has(process.env, key)) {\n return defaultValue ?? false;\n }\n\n const value = process.env[key];\n return value === 'true';\n}\n\n//function json<T = any>(key: keyof EnvKeys, defaultValue?: T): T\nfunction json<T = any>(key: string, defaultValue?: T) {\n if (!has(process.env, key)) {\n return defaultValue ?? {};\n }\n\n const value = process.env[key] ?? \"{}\";\n try {\n return JSON.parse(value);\n } catch (error: any) {\n throw new Error(`Invalid json environment variable ${key}: ${error.message}`);\n }\n}\n\n//function array(key: keyof EnvKeys, defaultValue?: []): string[];\nfunction array(key: string, defaultValue?: []): Array<any> {\n if (!has(process.env, key)) {\n return defaultValue ?? [];\n }\n\n let value = process.env[key] ?? \"\";\n\n if (value.startsWith('[') && value.endsWith(']')) {\n value = value.substring(1, value.length - 1);\n }\n\n return value.split(',').map((v) => {\n return trim(trim(v, ' '), '\"');\n });\n}\n\n//function date(key: keyof EnvKeys, defaultValue?: Date): Date;\nfunction date(key: string, defaultValue?: Date): Date {\n if (!has(process.env, key)) {\n return defaultValue ?? new Date();\n }\n\n const value = process.env[key] ?? Date()\n return new Date(value);\n}\n\nconst utils = {\n\n int,\n\n float,\n\n bool,\n\n json,\n\n array,\n\n date,\n\n /**\n * Gets a value from env that matches oneOf provided values\n * @param {string} key\n * @param {string[]} expectedValues\n * @param {string|undefined} defaultValue\n * @returns {string|undefined}\n */\n oneOf(key: string, expectedValues: string[], defaultValue?: string): string {\n if (!expectedValues) {\n throw new Error(`env.oneOf requires expectedValues`);\n }\n\n if (defaultValue && !expectedValues.includes(defaultValue)) {\n throw new Error(`env.oneOf requires defaultValue to be included in expectedValues`);\n }\n\n const rawValue = env(key as any, defaultValue);\n return expectedValues.includes(rawValue) ? rawValue : (defaultValue ?? \"\");\n },\n};\n\nexport const env = Object.assign(_env, utils);"],"mappings":"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","names":["path","fsPlugin","WebSocketConnectionGoneError","tempFilePath","fsPlugin","DEFAULT_CONFIG","mergeConfig","createDashboardSummary","fs","path","initializePersistence","maybeSavePersistence","tick","validateHandler","enableJob","disableJob","getDashboardSummary","createDashboardSummary","fsPlugin","mergeConfig","DEFAULT_CONFIG","tick","initializePersistence","fsPlugin","DEFAULT_CONFIG","mergeConfig","fsPlugin","path","fs","path","objectProto","nativeObjectToString","symToStringTag","array","funcProto","objectProto","funcToString","hasOwnProperty","array","array","array","MAX_SAFE_INTEGER","objectProto","hasOwnProperty","objectProto","hasOwnProperty","objectProto","hasOwnProperty","HASH_UNDEFINED","array","Map","INFINITY","array","array","rsAstralRange","rsComboMarksRange","reComboHalfMarksRange","rsComboSymbolsRange","rsComboRange","rsVarRange","rsZWJ","path","objectProto","hasOwnProperty","path","mkdir","writeFile","readFile","readFile","require","WebSocketConnectionGoneError","unsubscribe","path","fsPlugin"]}