{"version":3,"file":"index.cjs","names":["DEFAULT_OPTIONS: Partial<PgBoss.ConstructorOptions>","PgBoss","startPromise: Promise<void> | null","queue","jobList: string[]","configs: string[]","workOptions: PgBoss.WorkOptions & { includeMetadata: true }","results: unknown[]","entries: RuntimeSubscription[]","queue","TRAILING_SLASH_RE","api","highlightedCode: string","Prism","api","Hono","counts: QueueStateCounts","Hono","meta: QueueMeta | null","routes","api","Hono","currentPageUrl: URL | null","queues","Hono","filtered: QueueRow[]","Hono","Hono","routes","api","Hono","api","Hono","routes","api","Hono","toInt","api","Hono","Hono","def: Omit<SingleQueueDefinition<I, O>, \"name\">","def: Omit<BatchQueueDefinition<I, O>, \"name\">"],"sources":["../src/core/create-pg-boss.ts","../src/events/index.ts","../src/queues/client.ts","../src/types/index.ts","../src/create-bossman.ts","../src/create-client.ts","../src/dashboard/routes/utils/path.ts","../src/dashboard/routes/utils/api.ts","../src/dashboard/routes/components/code-block.ts","../src/dashboard/routes/components/job-detail.ts","../src/dashboard/routes/api/job-detail.ts","../src/dashboard/db/types.ts","../src/dashboard/db/get-queue-jobs.ts","../src/dashboard/db/get-queue-state-counts.ts","../src/dashboard/routes/components/queue-detail.ts","../src/dashboard/routes/api/queue-detail.ts","../src/dashboard/routes/components/refresh-control.ts","../src/dashboard/routes/components/jobs.ts","../src/dashboard/routes/utils/query.ts","../src/dashboard/routes/api/queue-jobs.ts","../src/dashboard/routes/components/queues.ts","../src/dashboard/routes/api/queues.ts","../src/dashboard/routes/api/index.ts","../src/dashboard/routes/components/breadcrumbs.ts","../src/dashboard/routes/components/layout.ts","../src/dashboard/routes/home.ts","../src/dashboard/routes/job.ts","../src/dashboard/routes/queue.ts","../src/dashboard/routes/queue-jobs.ts","../src/dashboard/routes/index.ts","../src/dashboard/server.ts","../src/queues/builder.ts"],"sourcesContent":["import PgBoss from \"pg-boss\";\n\n/**\n * Default options for pg-boss instances.\n * These align with pg-boss v11 maintenance defaults while ensuring\n * supervision and scheduling are enabled out of the box.\n */\nconst DEFAULT_OPTIONS: Partial<PgBoss.ConstructorOptions> = {\n  maintenanceIntervalSeconds: 60 * 60 * 24,\n  schedule: true,\n  supervise: true,\n  superviseIntervalSeconds: 60,\n  warningQueueSize: 10_000,\n  warningSlowQuerySeconds: 30,\n};\n\n/**\n * Create a pg-boss instance with default options and error handling\n * Used by both createBossman and createClient for consistency\n */\nexport function createPgBoss(\n  options: PgBoss.ConstructorOptions,\n  context: \"worker\" | \"client\" = \"worker\"\n): PgBoss {\n  // Merge default options with user options (user options take precedence)\n  const mergedOptions = {\n    ...DEFAULT_OPTIONS,\n    ...options,\n  };\n\n  const pgBoss = new PgBoss(mergedOptions);\n\n  // Always handle error events to prevent losing error information\n  pgBoss.on(\"error\", (error: Error) => {\n    // Ignore expected cleanup errors when database connection is closed\n    // This happens during test cleanup when PGlite closes before pg-boss workers finish\n    if (error.message?.includes(\"Database connection is not opened\")) {\n      return;\n    }\n    console.error(`[pg-bossman ${context}] Error:`, error);\n  });\n\n  // Handle warning events (pg-boss v11 feature)\n  pgBoss.on(\n    \"warning\",\n    (warning: { message: string; [key: string]: unknown }) => {\n      console.warn(`[pg-bossman ${context}] Warning:`, warning);\n    }\n  );\n\n  return pgBoss;\n}\n\n/**\n * Helper to ensure pg-boss is started (for lazy initialization)\n */\nexport function createLazyStarter(pgBoss: PgBoss) {\n  let started = false;\n  let startPromise: Promise<void> | null = null;\n\n  return async () => {\n    if (started) {\n      return pgBoss;\n    }\n\n    if (!startPromise) {\n      startPromise = pgBoss.start().then(() => {\n        started = true;\n      });\n    }\n\n    await startPromise;\n    return pgBoss;\n  };\n}\n","// Typed events registry for bossman\n\nexport type EventsDef<T extends Record<string, unknown>> = {\n  // marker for TS only\n  __events?: T;\n};\n\nexport function defineEvents<\n  T extends Record<string, unknown>,\n>(): EventsDef<T> {\n  return {} as EventsDef<T>;\n}\n\nexport type EventKeys<T extends EventsDef<Record<string, unknown>>> =\n  keyof NonNullable<T[\"__events\"]> & string;\nexport type EventPayloads<T extends EventsDef<Record<string, unknown>>> =\n  NonNullable<T[\"__events\"]>;\nexport type EventPayload<\n  TEvents extends EventsDef<Record<string, unknown>>,\n  E extends EventKeys<TEvents>,\n> = EventPayloads<TEvents>[E];\n\nexport function eventQueueName(event: string): string {\n  return `__bossman_event__${event}`;\n}\n","import type PgBoss from \"pg-boss\";\n\n/**\n * Queue client that provides type-safe methods for a specific queue\n * This is the shared implementation used by both bossman and createClient\n */\nexport class QueueClient<TInput = unknown, _TOutput = void> {\n  private readonly getPgBoss: () => Promise<PgBoss>;\n  private readonly queueName: string;\n\n  constructor(getPgBoss: () => Promise<PgBoss>, queueName: string) {\n    this.getPgBoss = getPgBoss;\n    this.queueName = queueName;\n  }\n\n  /**\n   * Send a job to the queue\n   * Can accept a single item or an array of items\n   *\n   * @param data - The job data to send. Can be a single item or array of items\n   * @param options - Optional pg-boss send options (priority, startAfter, etc)\n   * @returns Job ID(s) or null if sending failed\n   * @throws Error if pg-boss is not started or sending fails\n   *\n   * @example\n   * ```typescript\n   * // Send single job\n   * const jobId = await client.myQueue.send({ userId: '123' });\n   *\n   * // Send multiple jobs\n   * const jobIds = await client.myQueue.send([\n   *   { userId: '123' },\n   *   { userId: '456' }\n   * ]);\n   *\n   * // Send with options\n   * const jobId = await client.myQueue.send(\n   *   { userId: '123' },\n   *   { priority: 10, startAfter: new Date('2024-01-01') }\n   * );\n   * ```\n   */\n  async send(\n    data?: TInput | TInput[],\n    options?: PgBoss.SendOptions\n  ): Promise<string | string[] | null> {\n    try {\n      const pgBoss = await this.getPgBoss();\n      // Support empty payloads without special-casing types\n      const payload = (data as unknown) ?? {};\n\n      // Handle array input - send multiple jobs\n      if (Array.isArray(payload)) {\n        const jobIds = await Promise.all(\n          payload.map((item) =>\n            options\n              ? pgBoss.send(this.queueName, item as object, options)\n              : pgBoss.send(this.queueName, item as object)\n          )\n        );\n        return jobIds.filter((id) => id !== null) as string[];\n      }\n\n      // Single item\n      return options\n        ? await pgBoss.send(this.queueName, payload as object, options)\n        : await pgBoss.send(this.queueName, payload as object);\n    } catch (error) {\n      const errorMessage =\n        error instanceof Error ? error.message : String(error);\n      throw new Error(\n        `Failed to send job to queue \"${this.queueName}\": ${errorMessage}`\n      );\n    }\n  }\n\n  // Intentionally no schedule/unschedule on client queues.\n  // Schedules are defined via createQueue().schedule() at build time.\n}\n","import type PgBoss from \"pg-boss\";\n\n// Queue handler types - can be sync or async\nexport type QueueHandler<TInput, TOutput = void> = (\n  input: TInput\n) => TOutput | Promise<TOutput>;\nexport type BatchQueueHandler<TInput, TOutput = void> = (\n  inputs: TInput[]\n) => TOutput[] | Promise<TOutput[]>;\n\n// Queue options that pass through to pg-boss\n// Queue-level options that map to pg-boss Queue settings\n// Note: These are distinct from per-job SendOptions\nexport interface QueueOptions extends Partial<Omit<PgBoss.Queue, \"name\">> {\n  // Additional options can be added here\n  batchSize?: number; // For batch handlers\n}\n\n// Queue definition after builder completes\nexport type SingleQueueDefinition<TInput = unknown, TOutput = void> = {\n  name: string;\n  handler: QueueHandler<TInput, TOutput>;\n  options?: QueueOptions;\n  schedules?: QueueSchedule<TInput>[];\n};\n\nexport type BatchQueueDefinition<TInput = unknown, TOutput = void> = {\n  name: string;\n  batchHandler: BatchQueueHandler<TInput, TOutput>;\n  options?: QueueOptions;\n  schedules?: QueueSchedule<TInput>[];\n};\n\nexport type QueueDefinition<TInput = unknown, TOutput = void> =\n  | SingleQueueDefinition<TInput, TOutput>\n  | BatchQueueDefinition<TInput, TOutput>;\n\n// Optional attached schedule config on a queue\nexport type QueueSchedule<TInput = unknown> = {\n  key: string;\n  cron: string;\n  data?: TInput;\n  options?: PgBoss.ScheduleOptions;\n};\n\n// Helper to check if queue is batch\nexport function isBatchQueue<TInput, TOutput>(\n  queue: QueueDefinition<TInput, TOutput>\n): queue is BatchQueueDefinition<TInput, TOutput> {\n  return \"batchHandler\" in queue;\n}\n\n// Registry of all queues for type inference\nexport type QueueRegistry = Record<string, QueueDefinition>;\n\n// Extract input type from queue definition\nexport type ExtractInput<T> = T extends QueueDefinition<infer TInput, unknown>\n  ? TInput\n  : never;\n\n// Extract output type from queue definition\nexport type ExtractOutput<T> = T extends QueueDefinition<unknown, infer TOutput>\n  ? TOutput\n  : never;\n\n// Helper to check if a value is a promise\nexport function isPromise<T>(value: T | Promise<T>): value is Promise<T> {\n  return (\n    value !== null &&\n    typeof value === \"object\" &&\n    \"then\" in value &&\n    typeof value.then === \"function\"\n  );\n}\n\n// Flat queues map\nexport type QueueWithoutName = Omit<QueueDefinition, \"name\">;\nexport type QueuesMap = Record<string, QueueWithoutName>;\n\n// Helper to infer input from QueueWithoutName\nexport type InferInputFromQueue<J> = J extends {\n  handler: (input: infer I) => unknown;\n}\n  ? I\n  : J extends { batchHandler: (inputs: Array<infer I>) => unknown }\n    ? I\n    : unknown;\n","import type PgBoss from \"pg-boss\";\nimport { createPgBoss } from \"./core/create-pg-boss\";\nimport type { PgBossmanClientInstance } from \"./create-client\";\nimport type { EventKeys, EventPayloads, EventsDef } from \"./events/index\";\nimport { eventQueueName } from \"./events/index\";\nimport { QueueClient } from \"./queues/client\";\nimport type {\n  InferInputFromQueue,\n  QueueDefinition,\n  QueuesMap,\n  QueueWithoutName,\n} from \"./types/index\";\nimport { isBatchQueue, isPromise } from \"./types/index\";\n\n// Validation patterns\n// biome-ignore lint/suspicious/noControlCharactersInRegex: Control characters are intentionally checked for validation\nconst INVALID_NAME_PATTERN = /^__|[\\x00-\\x1F\\x7F]/;\n\n/**\n * Worker instance with queue processing capabilities\n * This class is internal to create-bossman and contains all worker logic\n */\nexport type ClientStructure<TQueues extends QueuesMap> = {\n  [K in keyof TQueues]: QueueClient<InferInputFromQueue<TQueues[K]>, unknown>;\n};\n\ntype RuntimeSubscription = {\n  queue: string;\n  map?: (payload: unknown) => unknown;\n};\n\nclass BossmanWorker<\n  TQueues extends QueuesMap,\n  TEvents extends EventsDef<Record<string, unknown>> = EventsDef<\n    Record<string, unknown>\n  >,\n> {\n  private static scheduleIdentifier(\n    name: string,\n    key: string | null | undefined\n  ): string {\n    return `${name}::${key ?? \"\"}`;\n  }\n\n  private readonly pgBoss: PgBoss;\n  private readonly jobs: Map<string, QueueDefinition>;\n  private isWorkerStarted = false;\n  private isPgBossStarted = false;\n  private readonly subs: Map<string, RuntimeSubscription[]> = new Map();\n\n  // Internal client structure for job access\n  private readonly clientMap: ClientStructure<TQueues>;\n  // Exposed typed client (queues + events + getPgBoss)\n  readonly client: {\n    queues: ClientStructure<TQueues>;\n    events: {\n      [E in EventKeys<TEvents>]: {\n        emit: (\n          payload: EventPayloads<TEvents>[E],\n          options?: PgBoss.SendOptions\n        ) => Promise<string | string[] | null>;\n      };\n    };\n    getPgBoss: () => Promise<PgBoss>;\n  };\n\n  constructor(\n    pgBoss: PgBoss,\n    jobs: Map<string, QueueDefinition>,\n    router: TQueues,\n    subscriptions?: Map<string, RuntimeSubscription[]>\n  ) {\n    this.pgBoss = pgBoss;\n    this.jobs = jobs;\n    if (subscriptions) {\n      this.subs = subscriptions;\n    }\n\n    // Create ensureStarted function that initializes pg-boss when needed\n    const ensureStarted = async () => {\n      await this.init();\n      return this.pgBoss;\n    };\n\n    // Build concrete client structure\n    const client = {} as Record<string, unknown>;\n    for (const name of Object.keys(router)) {\n      client[name] = new QueueClient(ensureStarted, name);\n    }\n    this.clientMap = client as ClientStructure<TQueues>;\n\n    const events = new Proxy(\n      {},\n      {\n        get: (_t, prop) => {\n          if (typeof prop !== \"string\") {\n            return;\n          }\n          const q = eventQueueName(prop);\n          const getPg = async () => {\n            await this.init();\n            return this.pgBoss;\n          };\n          const emitter = new QueueClient(getPg, q);\n          return {\n            emit: (payload: unknown, options?: PgBoss.SendOptions) =>\n              emitter.send((payload as object) ?? {}, options),\n          };\n        },\n      }\n    ) as unknown as {\n      [E in EventKeys<TEvents>]: {\n        emit: (\n          payload: EventPayloads<TEvents>[E],\n          options?: PgBoss.SendOptions\n        ) => Promise<string | string[] | null>;\n      };\n    };\n\n    const getPgBoss = async () => {\n      await this.init();\n      return this.pgBoss;\n    };\n\n    this.client = {\n      events,\n      getPgBoss,\n      queues: this.clientMap as ClientStructure<TQueues>,\n    };\n  }\n\n  /**\n   * Initialize pg-boss for sending (without starting workers)\n   * This is called automatically by start() if not already done\n   */\n  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: composed startup steps\n  private async init(): Promise<void> {\n    if (this.isPgBossStarted) {\n      return;\n    }\n\n    await this.pgBoss.start();\n\n    // Create queues for all registered definitions (required in pg-boss v10+)\n    for (const [name, job] of this.jobs) {\n      const { batchSize: _batchSize, ...queueOptions } = job.options ?? {};\n      const pgBossQueue = {\n        name,\n        ...queueOptions,\n      } satisfies PgBoss.Queue;\n\n      try {\n        await this.pgBoss.createQueue(name, pgBossQueue);\n      } catch (error) {\n        const errorMessage =\n          error instanceof Error ? error.message : String(error);\n        if (!errorMessage.includes(\"already exists\")) {\n          throw error;\n        }\n        await this.pgBoss.updateQueue(name, pgBossQueue);\n      }\n    }\n\n    this.isPgBossStarted = true;\n\n    // Create event queues based on subscriptions\n    for (const event of this.subs.keys()) {\n      const q = eventQueueName(event);\n      try {\n        await this.pgBoss.createQueue(q);\n      } catch (error) {\n        const errorMessage =\n          error instanceof Error ? error.message : String(error);\n        if (!errorMessage.includes(\"already exists\")) {\n          throw error;\n        }\n      }\n    }\n  }\n\n  /**\n   * Start the worker with all registered handlers\n   * Automatically handles SIGTERM/SIGINT for graceful shutdown\n   */\n  async start(): Promise<void> {\n    if (this.isWorkerStarted) {\n      console.warn(\"⚠️  Worker is already started\");\n      return;\n    }\n\n    console.log(\"🚀 Starting pg-bossman worker...\");\n\n    // Initialize pg-boss if not already done\n    await this.init();\n\n    // Reconcile schedules and register event handlers\n    await this.reconcileSchedules();\n    await this.registerEventHandlers();\n\n    // Register all queue handlers\n    const jobList = await this.registerQueueHandlers();\n\n    console.log(\"\\n📋 Registered queues:\");\n    for (const job of jobList) {\n      console.log(job);\n    }\n\n    console.log(\"\\n✅ Worker started successfully!\");\n    console.log(\"   Listening for jobs...\\n\");\n\n    this.isWorkerStarted = true;\n\n    // Set up graceful shutdown handlers\n    this.setupGracefulShutdown();\n  }\n\n  private async reconcileSchedules(): Promise<void> {\n    const existing = await this.pgBoss.getSchedules();\n    const remaining = new Map(\n      existing.map((schedule) => [\n        BossmanWorker.scheduleIdentifier(schedule.name, schedule.key),\n        schedule,\n      ])\n    );\n\n    const existingByQueue = new Map<string, PgBoss.Schedule[]>();\n    for (const schedule of existing) {\n      const list = existingByQueue.get(schedule.name);\n      if (list) {\n        list.push(schedule);\n      } else {\n        existingByQueue.set(schedule.name, [schedule]);\n      }\n    }\n\n    for (const [name, job] of this.jobs) {\n      await this.applySchedulesForQueue(\n        name,\n        job as QueueDefinition,\n        existingByQueue.get(name) ?? [],\n        remaining\n      );\n    }\n\n    for (const schedule of remaining.values()) {\n      await this.unscheduleSchedule(schedule);\n    }\n  }\n\n  private async applySchedulesForQueue(\n    name: string,\n    job: QueueDefinition,\n    existing: PgBoss.Schedule[],\n    remaining: Map<string, PgBoss.Schedule>\n  ): Promise<void> {\n    const definitions = job.schedules ?? [];\n\n    if (definitions.length === 0) {\n      for (const schedule of existing) {\n        remaining.delete(\n          BossmanWorker.scheduleIdentifier(schedule.name, schedule.key)\n        );\n        await this.unscheduleSchedule(schedule);\n      }\n      return;\n    }\n\n    for (const schedule of definitions) {\n      const key = schedule.key;\n      const scheduleOptions = schedule.options\n        ? { ...schedule.options, key }\n        : ({ key } satisfies PgBoss.ScheduleOptions);\n\n      await this.pgBoss.schedule(\n        name,\n        schedule.cron,\n        (schedule.data as object) ?? {},\n        scheduleOptions\n      );\n      remaining.delete(BossmanWorker.scheduleIdentifier(name, key));\n    }\n  }\n\n  private async unscheduleSchedule(schedule: PgBoss.Schedule): Promise<void> {\n    await this.pgBoss.unschedule(\n      schedule.name,\n      schedule.key ? schedule.key : undefined\n    );\n  }\n\n  /**\n   * Stop the pg-boss instance\n   */\n  async stop(options?: PgBoss.StopOptions): Promise<void> {\n    await this.pgBoss.stop(options);\n    this.isPgBossStarted = false;\n    this.isWorkerStarted = false;\n  }\n\n  /**\n   * Get all schedules\n   * Returns all schedules across all queues\n   */\n  async getSchedules(): Promise<PgBoss.Schedule[]> {\n    return await this.pgBoss.getSchedules();\n  }\n\n  /**\n   * Get the underlying pg-boss instance for advanced usage\n   * Ensures pg-boss is started before returning\n   */\n  async getPgBoss(): Promise<PgBoss> {\n    await this.init();\n    return this.pgBoss;\n  }\n\n  /**\n   * Register all job handlers and return formatted job list\n   */\n  private async registerQueueHandlers(): Promise<string[]> {\n    const jobList: string[] = [];\n\n    for (const [name, job] of this.jobs) {\n      // Build job info string\n      jobList.push(this.formatQueueInfo(name, job));\n\n      // Register the handler\n      await this.registerSingleQueueHandler(name, job);\n    }\n\n    return jobList;\n  }\n\n  /**\n   * Format job information for logging\n   */\n  private formatQueueInfo(name: string, job: QueueDefinition): string {\n    let jobInfo = `  • ${name}`;\n\n    // Add job configuration details\n    const configs: string[] = [];\n    if (\"batchHandler\" in job && job.options?.batchSize) {\n      configs.push(`batch size: ${job.options.batchSize}`);\n    }\n    if (job.options?.retryLimit !== undefined) {\n      configs.push(`retry limit: ${job.options.retryLimit}`);\n    }\n    if (job.options?.retryDelay !== undefined) {\n      configs.push(`retry delay: ${job.options.retryDelay}s`);\n    }\n\n    if (configs.length > 0) {\n      jobInfo += ` (${configs.join(\", \")})`;\n    }\n\n    return jobInfo;\n  }\n\n  /**\n   * Register a single job handler\n   */\n  private async registerSingleQueueHandler(\n    name: string,\n    job: QueueDefinition\n  ): Promise<void> {\n    if (isBatchQueue(job)) {\n      // Batch job handler - always receives an array\n      const workOptions: PgBoss.WorkOptions & { includeMetadata: true } = {\n        batchSize: job.options?.batchSize,\n        includeMetadata: true as const,\n      };\n\n      await this.pgBoss.work(\n        name,\n        workOptions,\n        async (jobs: PgBoss.JobWithMetadata[]) => {\n          console.log(\n            `📦 Processing batch for queue \"${name}\" (${jobs.length} jobs)`\n          );\n          const inputs = jobs.map((j) => j.data);\n          // Batch handler always receives an array\n          const result = job.batchHandler(inputs);\n          return isPromise(result) ? await result : result;\n        }\n      );\n    } else {\n      // Single handler - process each job individually\n      const workOptions: PgBoss.WorkOptions & { includeMetadata: true } = {\n        batchSize: 1,\n        includeMetadata: true as const,\n      };\n\n      await this.pgBoss.work(\n        name,\n        workOptions,\n        async (jobs: PgBoss.JobWithMetadata[]) => {\n          console.log(`⚡ Processing queue \"${name}\" (${jobs.length} jobs)`);\n          // Single handler is called once per job\n          const results: unknown[] = [];\n          for (const pgBossJob of jobs) {\n            const result = job.handler(pgBossJob.data);\n            results.push(isPromise(result) ? await result : result);\n          }\n          return results.length === 1 ? results[0] : results;\n        }\n      );\n    }\n  }\n\n  /**\n   * Set up graceful shutdown handlers\n   */\n  private setupGracefulShutdown(): void {\n    const shutdown = async (signal: string) => {\n      console.log(`\\n⚠️  Received ${signal}, shutting down gracefully...`);\n      try {\n        await this.stop({\n          graceful: true,\n          timeout: 30_000,\n        });\n        console.log(\"✅ Worker stopped successfully\");\n        process.exit(0);\n      } catch (error) {\n        console.error(\"❌ Error during shutdown:\", error);\n        process.exit(1);\n      }\n    };\n\n    // Handle termination signals\n    process.once(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n    process.once(\"SIGINT\", () => shutdown(\"SIGINT\"));\n\n    // Log that handlers are set up\n    console.log(\"   Graceful shutdown handlers registered (SIGTERM/SIGINT)\");\n  }\n\n  private async registerEventHandlers(): Promise<void> {\n    for (const [event, targets] of this.subs.entries()) {\n      const q = eventQueueName(event);\n      const workOptions: PgBoss.WorkOptions & { includeMetadata: true } = {\n        batchSize: 1,\n        includeMetadata: true as const,\n      };\n      await this.pgBoss.work(\n        q,\n        workOptions,\n        async (jobs: PgBoss.JobWithMetadata[]) => {\n          for (const job of jobs) {\n            const payload = job.data as unknown;\n            for (const t of targets) {\n              const data = t.map ? t.map(payload) : payload;\n              await this.pgBoss.send(t.queue, (data as object) ?? {});\n            }\n          }\n        }\n      );\n    }\n  }\n}\n\n/**\n * Builder for creating a pg-bossman instance\n */\nclass BossmanBuilder<\n  TQueues extends QueuesMap = Record<string, QueueWithoutName>,\n  TEvents extends EventsDef<Record<string, unknown>> = EventsDef<\n    Record<string, unknown>\n  >,\n> {\n  private readonly pgBoss: PgBoss;\n  private router?: TQueues;\n  // eventsDef reserved for future; not used at runtime\n  // biome-ignore lint/correctness/noUnusedPrivateClassMembers: Reserved for future event type tracking\n  private eventsDef?: TEvents;\n  private subscriptionMap: Map<string, RuntimeSubscription[]> = new Map();\n\n  constructor(options: PgBoss.ConstructorOptions) {\n    this.pgBoss = createPgBoss(options, \"worker\");\n  }\n\n  /**\n   * Register queues with the bossman instance\n   *\n   * @param router - Map of queue names to queue definitions\n   * @throws TypeError if queue names are invalid or router is null\n   *\n   * @example\n   * ```typescript\n   * const bossman = createBossman({ connectionString: '...' })\n   *   .register({\n   *     sendEmail: createQueue().handler(...),\n   *     processPayment: createQueue().handler(...),\n   *   })\n   *   .build();\n   * ```\n   */\n  register<TNewQueues extends QueuesMap>(\n    router: TNewQueues\n  ): BossmanBuilder<TNewQueues, TEvents> {\n    // Validate router is provided\n    if (!router || typeof router !== \"object\") {\n      throw new TypeError(\"register requires a non-null object of queues\");\n    }\n\n    const queueNames = Object.keys(router);\n\n    // Validate queue names\n    for (const name of queueNames) {\n      if (!name || name.trim().length === 0) {\n        throw new TypeError(\"Queue names cannot be empty or whitespace-only\");\n      }\n      if (INVALID_NAME_PATTERN.test(name)) {\n        throw new TypeError(\n          `Invalid queue name \"${name}\": cannot start with __ (reserved) or contain control characters`\n        );\n      }\n    }\n\n    // We need to cast here because TypeScript can't track the type change\n    const builder = this as unknown as BossmanBuilder<TNewQueues, TEvents>;\n    builder.router = router;\n    return builder;\n  }\n\n  events<TNewEvents extends EventsDef<Record<string, unknown>>>(\n    events: TNewEvents\n  ): BossmanBuilder<TQueues, TNewEvents> {\n    const builder = this as unknown as BossmanBuilder<TQueues, TNewEvents>;\n    builder.eventsDef = events;\n    return builder;\n  }\n\n  subscriptions(\n    map: {\n      [E in keyof EventPayloads<TEvents>]?: Partial<{\n        [Q in keyof TQueues]: EventPayloads<TEvents>[E] extends InferInputFromQueue<\n          TQueues[Q]\n        >\n          ?\n              | true\n              | {\n                  map: (\n                    p: EventPayloads<TEvents>[E]\n                  ) => InferInputFromQueue<TQueues[Q]>;\n                }\n          : {\n              map: (\n                p: EventPayloads<TEvents>[E]\n              ) => InferInputFromQueue<TQueues[Q]>;\n            };\n      }>;\n    }\n  ): BossmanBuilder<TQueues, TEvents> {\n    const subs = new Map<string, RuntimeSubscription[]>();\n    for (const [event, value] of Object.entries(\n      map as Record<string, unknown>\n    )) {\n      const entries: RuntimeSubscription[] = [];\n      for (const [queue, spec] of Object.entries(\n        (value as Record<string, unknown>) ?? {}\n      )) {\n        if (spec === true) {\n          entries.push({ queue });\n        } else if (\n          spec &&\n          typeof spec === \"object\" &&\n          typeof (spec as { map?: (p: unknown) => unknown }).map === \"function\"\n        ) {\n          entries.push({\n            map: (spec as { map: (p: unknown) => unknown }).map,\n            queue,\n          });\n        }\n      }\n      subs.set(event, entries);\n    }\n    this.subscriptionMap = subs;\n    return this;\n  }\n\n  /**\n   * Build the final bossman instance\n   */\n  build(): PgBossmanInstance<TQueues, TEvents> {\n    if (!this.router) {\n      throw new Error(\"No queues registered. Call .register() before .build()\");\n    }\n\n    // Build a map of queue definitions with names\n    const jobMap = new Map<string, QueueDefinition>();\n    for (const [name, def] of Object.entries(this.router)) {\n      const withName = {\n        ...(def as QueueWithoutName),\n        name,\n      } as QueueDefinition;\n      jobMap.set(name, withName);\n    }\n\n    // Create the worker instance with all functionality\n    return new BossmanWorker(\n      this.pgBoss,\n      jobMap,\n      this.router,\n      this.subscriptionMap\n    ) as PgBossmanInstance<TQueues, TEvents>;\n  }\n}\n\n/**\n * Create a pg-bossman instance builder\n *\n * @param options - pg-boss constructor options (connectionString, db, etc.)\n * @returns A builder instance to configure queues and events\n * @throws TypeError if options is invalid\n *\n * @example\n * ```typescript\n * // Basic usage\n * const bossman = createBossman({\n *   connectionString: 'postgres://user:pass@localhost/mydb'\n * })\n *   .register({\n *     sendEmail: createQueue()\n *       .input<{ to: string; subject: string }>()\n *       .handler(async (input) => {\n *         await emailService.send(input.to, input.subject);\n *       }),\n *     processPayment: createQueue()\n *       .input<{ amount: number }>()\n *       .options({ retryLimit: 5 })\n *       .handler(async (input) => {\n *         return await paymentGateway.charge(input.amount);\n *       })\n *   })\n *   .build();\n *\n * // With custom options\n * const bossman = createBossman({\n *   connectionString: 'postgres://localhost/mydb',\n *   maintenanceIntervalSeconds: 3600,\n *   superviseIntervalSeconds: 30,\n *   warningQueueSize: 5000\n * })\n *   .register({ ... })\n *   .build();\n *\n * // Start worker\n * await bossman.start();\n *\n * // Use client to send jobs\n * await bossman.client.queues.sendEmail.send({\n *   to: 'user@example.com',\n *   subject: 'Welcome!'\n * });\n * ```\n */\nexport function createBossman(\n  options: PgBoss.ConstructorOptions\n): BossmanBuilder {\n  if (!options) {\n    throw new TypeError(\"createBossman requires options object\");\n  }\n  if (!(options.connectionString || options.db)) {\n    throw new TypeError(\n      \"createBossman requires either connectionString or db option\"\n    );\n  }\n  return new BossmanBuilder(options);\n}\n\n/**\n * The full pg-bossman instance with worker methods and client structure\n */\nexport type PgBossmanInstance<\n  TQueues extends QueuesMap,\n  TEvents extends EventsDef<Record<string, unknown>> = EventsDef<\n    Record<string, unknown>\n  >,\n> = {\n  // Worker methods\n  start: () => Promise<void>;\n  stop: (options?: PgBoss.StopOptions) => Promise<void>;\n  getSchedules: () => Promise<PgBoss.Schedule[]>;\n  getPgBoss: () => Promise<PgBoss>;\n\n  // Bossman client accessor (queues + events emitters)\n  client: PgBossmanClientInstance<TQueues, TEvents>;\n};\n","import type PgBoss from \"pg-boss\";\nimport { createLazyStarter, createPgBoss } from \"./core/create-pg-boss\";\nimport type { PgBossmanInstance } from \"./create-bossman\";\nimport type { EventKeys, EventPayloads, EventsDef } from \"./events/index\";\nimport { eventQueueName } from \"./events/index\";\nimport { QueueClient } from \"./queues/client\";\nimport type { InferInputFromQueue, QueuesMap } from \"./types/index\";\n\n/**\n * Create a lightweight client without handlers (send-only)\n * This creates a client that can only send jobs, not process them\n *\n * Usage:\n * import type { bossman } from './jobs';\n * const client = createClient<typeof bossman>({\n *   connectionString: 'postgres://...'\n * });\n */\nexport type ClientStructure<TQueues extends QueuesMap> = {\n  [K in keyof TQueues]: QueueClient<InferInputFromQueue<TQueues[K]>, unknown>;\n};\n\nexport type PgBossmanClientInstance<\n  TQueues extends QueuesMap,\n  TEvents extends EventsDef<Record<string, unknown>>,\n> = {\n  queues: ClientStructure<TQueues>;\n  events: {\n    [K in EventKeys<TEvents>]: {\n      emit: (\n        payload: EventPayloads<TEvents>[K],\n        options?: PgBoss.SendOptions\n      ) => Promise<string | string[] | null>;\n    };\n  };\n  getPgBoss: () => Promise<PgBoss>;\n};\n\n// Minimal proxy just for createClient\n// Overload 1: Loosely typed client (no generics). Useful when not deriving types from a bossman instance.\nexport function createClient(\n  options: PgBoss.ConstructorOptions\n): PgBossmanClientInstance<QueuesMap, EventsDef<Record<string, unknown>>>;\n\n// Overload 2: Strongly typed client derived from a PgBossmanInstance\n// biome-ignore lint/suspicious/noExplicitAny: Loosen constraint to preserve event key/payload inference without forcing string index signature\nexport function createClient<TBossman extends PgBossmanInstance<any, any>>(\n  options: PgBoss.ConstructorOptions\n): TBossman extends PgBossmanInstance<infer TQueues, infer TEvents>\n  ? PgBossmanClientInstance<TQueues, TEvents>\n  : never;\n\nexport function createClient(options: PgBoss.ConstructorOptions): unknown {\n  const pgBoss = createPgBoss(options, \"client\");\n  const ensureStarted = createLazyStarter(pgBoss);\n\n  const queuesProxy = new Proxy(\n    {},\n    {\n      get: (_t, prop) =>\n        typeof prop === \"string\"\n          ? new QueueClient(ensureStarted, prop)\n          : undefined,\n    }\n  );\n\n  const eventsProxy = new Proxy(\n    {},\n    {\n      get: (_t, prop) => {\n        if (typeof prop !== \"string\") {\n          return;\n        }\n        const q = eventQueueName(prop);\n        const emitter = new QueueClient(ensureStarted, q);\n        return {\n          emit: (payload: unknown, opts?: PgBoss.SendOptions) =>\n            emitter.send((payload as object) ?? {}, opts),\n        } as {\n          emit: (\n            payload: unknown,\n            opts?: PgBoss.SendOptions\n          ) => Promise<string | string[] | null>;\n        };\n      },\n    }\n  );\n\n  const result = {\n    events: eventsProxy,\n    getPgBoss: () => ensureStarted(),\n    queues: queuesProxy,\n  } satisfies PgBossmanClientInstance<\n    QueuesMap,\n    EventsDef<Record<string, unknown>>\n  >;\n\n  return result as unknown;\n}\n","const TRAILING_SLASH_RE = /\\/+$/;\n\nexport function withBasePath(basePath: string | undefined, path: string) {\n  const base = (basePath || \"\").replace(TRAILING_SLASH_RE, \"\");\n  const suffix = path.startsWith(\"/\") ? path : `/${path}`;\n  const fullPath = `${base}${suffix}` || suffix;\n  // Remove trailing slash unless it's the root path \"/\"\n  return fullPath === \"/\" ? fullPath : fullPath.replace(TRAILING_SLASH_RE, \"\");\n}\n","import { withBasePath } from \"./path\";\n\nexport function api(basePath: string | undefined) {\n  const b = basePath ?? \"\";\n  return {\n    eventsCard(): string {\n      return withBasePath(b, \"/api/queues/queues-list-card?only=events\");\n    },\n    jobDetail(queueName: string, id: string): string {\n      return withBasePath(\n        b,\n        `/api/queues/${encodeURIComponent(queueName)}/jobs/${encodeURIComponent(id)}`\n      );\n    },\n    queueDetail(name: string): string {\n      return withBasePath(\n        b,\n        `/api/queues/${encodeURIComponent(name)}/detail-card`\n      );\n    },\n    queueJobsList(name: string, limit: number, offset: number): string {\n      return withBasePath(\n        b,\n        `/api/queues/${encodeURIComponent(name)}/jobs/list?limit=${limit}&offset=${offset}`\n      );\n    },\n    queueJobsPreview(name: string, limit: number): string {\n      return withBasePath(\n        b,\n        `/api/queues/${encodeURIComponent(name)}/jobs?limit=${limit}`\n      );\n    },\n    queuesCard(): string {\n      return withBasePath(b, \"/api/queues/queues-list-card\");\n    },\n  } as const;\n}\n","import { readFileSync } from \"node:fs\";\nimport { html, raw } from \"hono/html\";\nimport Prism from \"prismjs\";\n\n// Load additional language support\nimport \"prismjs/components/prism-json.js\";\nimport \"prismjs/components/prism-log.js\";\nimport \"prismjs/components/prism-bash.js\";\nimport \"prismjs/components/prism-javascript.js\";\nimport \"prismjs/components/prism-typescript.js\";\n\n// Load Prism dark theme CSS - Okaidia has a darker background\nconst prismThemePath = require.resolve(\"prismjs/themes/prism-okaidia.min.css\");\nconst prismTheme = readFileSync(prismThemePath, \"utf-8\");\n\nexport type CodeBlockProps = {\n  code: string;\n  language?: \"json\" | \"log\" | \"javascript\" | \"typescript\" | \"bash\" | \"text\";\n  className?: string;\n};\n\nexport function CodeBlock({\n  code,\n  language = \"text\",\n  className = \"\",\n}: CodeBlockProps) {\n  let highlightedCode: string;\n  let displayCode = code;\n\n  // Format JSON if needed\n  if (language === \"json\") {\n    try {\n      const parsed = JSON.parse(code);\n      displayCode = JSON.stringify(parsed, null, 2);\n    } catch {\n      // If not valid JSON, display as-is\n    }\n  }\n\n  // Determine the actual language for Prism\n  const prismLang = language === \"text\" ? \"plaintext\" : language;\n\n  // Highlight the code\n  const grammar = Prism.languages[prismLang] || Prism.languages.plaintext;\n  if (grammar) {\n    highlightedCode = Prism.highlight(displayCode, grammar, prismLang);\n  } else {\n    // Fallback to escaping HTML\n    highlightedCode = displayCode\n      .replace(/&/g, \"&amp;\")\n      .replace(/</g, \"&lt;\")\n      .replace(/>/g, \"&gt;\")\n      .replace(/\"/g, \"&quot;\")\n      .replace(/'/g, \"&#039;\");\n  }\n\n  // Inject Prism theme CSS\n  const prismStyles = html`<style>${prismTheme}</style>`;\n\n  return html`\n    ${prismStyles}\n    <div class=\"relative group ${className} min-w-0\">\n      <div class=\"absolute top-2 right-2 z-10 opacity-0 group-hover:opacity-100 transition-opacity\">\n        <button\n          class=\"btn btn-xs btn-ghost bg-gray-700 hover:bg-gray-600 text-gray-300\"\n          onclick=\"navigator.clipboard.writeText(this.closest('.group').querySelector('pre').textContent)\"\n          title=\"Copy to clipboard\"\n        >\n          <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n            <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n          </svg>\n        </button>\n      </div>\n      <div class=\"overflow-x-auto rounded-lg border border-gray-800\" style=\"width: 100%; max-width: 100%;\">\n        <pre class=\"p-4 m-0 text-sm\" style=\"background: #272822; color: #f8f8f2; width: 100%; min-width: max-content;\"><code class=\"language-${prismLang} whitespace-pre\">${raw(highlightedCode)}</code></pre>\n      </div>\n    </div>\n  `;\n}\n","import { html } from \"hono/html\";\nimport type { JobRow } from \"../../db\";\nimport { api } from \"../utils/api\";\nimport { CodeBlock } from \"./code-block\";\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: UI rendering function with several branches\nexport function JobDetailCard({\n  job,\n  basePath,\n}: {\n  job: JobRow;\n  basePath: string;\n}) {\n  // Determine state badge color\n  let stateClass = \"\";\n  let stateIcon = \"\";\n  if (job.state === \"completed\") {\n    stateClass = \"badge-success\";\n    stateIcon = \"✓\";\n  } else if (job.state === \"failed\") {\n    stateClass = \"badge-error\";\n    stateIcon = \"✗\";\n  } else if (job.state === \"active\") {\n    stateClass = \"badge-primary\";\n    stateIcon = \"⟳\";\n  } else if (job.state === \"retry\") {\n    stateClass = \"badge-warning\";\n    stateIcon = \"↻\";\n  } else if (job.state === \"created\") {\n    stateClass = \"badge-info\";\n    stateIcon = \"●\";\n  } else if (job.state === \"cancelled\") {\n    stateClass = \"badge-ghost\";\n    stateIcon = \"⊘\";\n  } else {\n    stateClass = \"badge-ghost\";\n    stateIcon = \"○\";\n  }\n\n  const RAW_EVENT_PREFIX = \"__bossman_event__\";\n  const isEvent = job.name.startsWith(RAW_EVENT_PREFIX);\n  const displayQueueName = isEvent\n    ? job.name.slice(RAW_EVENT_PREFIX.length)\n    : job.name;\n  const queueHref = `${basePath || \"\"}/queues/${encodeURIComponent(job.name)}`;\n  const refreshPath = api(basePath).jobDetail(job.name, job.id);\n\n  return html`\n    <div class=\"card bg-base-100 shadow overflow-hidden\">\n      <div class=\"card-body gap-4 overflow-hidden\">\n        <!-- Header with job ID and state -->\n        <div class=\"flex items-center justify-between\">\n          <h3 class=\"card-title font-mono text-lg\">${job.id}</h3>\n          <div class=\"flex items-center gap-2\">\n            <button \n              class=\"btn btn-sm btn-ghost\"\n              hx-get=\"${refreshPath}\"\n              hx-target=\"#job-detail\"\n              title=\"Refresh now\"\n            >\n              <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n                <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n              </svg>\n            </button>\n            <span class=\"badge ${stateClass} gap-1\">\n              <span>${stateIcon}</span>\n              <span>${job.state}</span>\n            </span>\n          </div>\n        </div>\n\n        <!-- Job metadata grid -->\n        <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n          <div class=\"card bg-base-200\">\n            <div class=\"card-body p-4 gap-2\">\n              <h4 class=\"font-semibold text-sm opacity-70\">Queue Info</h4>\n              <div class=\"text-sm space-y-1\">\n                <div class=\"flex justify-between\">\n                  <span class=\"opacity-60\">Queue:</span>\n                  <a href=\"${queueHref}\" class=\"link link-primary\">${\n                    isEvent ? `Event: ${displayQueueName}` : displayQueueName\n                  }</a>\n                </div>\n                <div class=\"flex justify-between\">\n                  <span class=\"opacity-60\">Priority:</span>\n                  <span>${job.priority}</span>\n                </div>\n                <div class=\"flex justify-between\">\n                  <span class=\"opacity-60\">Retries:</span>\n                  <span>${job.retry_count} / ${job.retry_limit}</span>\n                </div>\n                <div class=\"flex justify-between\">\n                  <span class=\"opacity-60\">Retry Delay:</span>\n                  <span class=\"cursor-help\" title=\"${job.retry_delay}s\">\n                    <span data-duration=\"${job.retry_delay}\"></span>\n                  </span>\n                </div>\n                ${\n                  job.retry_delay_max != null\n                    ? html`\n                <div class=\"flex justify-between\">\n                  <span class=\"opacity-60\">Retry Delay Max:</span>\n                  <span class=\"cursor-help\" title=\"${job.retry_delay_max}s\">\n                    <span data-duration=\"${job.retry_delay_max}\"></span>\n                  </span>\n                </div>\n                `\n                    : \"\"\n                }\n                ${\n                  job.retry_backoff\n                    ? html`\n                <div class=\"flex justify-between\">\n                  <span class=\"opacity-60\">Retry Backoff:</span>\n                  <span>Yes</span>\n                </div>\n                `\n                    : \"\"\n                }\n              </div>\n            </div>\n          </div>\n\n          <div class=\"card bg-base-200\">\n            <div class=\"card-body p-4 gap-2\">\n              <h4 class=\"font-semibold text-sm opacity-70\">Timestamps</h4>\n              <div class=\"text-sm space-y-1\">\n                <div class=\"flex justify-between\">\n                  <span class=\"opacity-60\">Created:</span>\n                  ${\n                    job.created_on\n                      ? html`<span class=\"cursor-help\" title=\"${new Date(job.created_on).toLocaleString()}\">\n                        <span data-relative-time=\"${new Date(job.created_on).toISOString()}\"></span>\n                      </span>`\n                      : html`<span>—</span>`\n                  }\n                </div>\n                <div class=\"flex justify-between\">\n                  <span class=\"opacity-60\">Start After:</span>\n                  ${(() => {\n                    if (job.start_after && job.created_on) {\n                      return html`<span class=\"cursor-help\" title=\"${new Date(job.start_after).toLocaleString()}\">\n                          <span data-duration-between-start=\"${new Date(job.created_on).toISOString()}\" data-duration-between-end=\"${new Date(job.start_after).toISOString()}\" data-show-in=\"false\"></span>\n                        </span>`;\n                    }\n                    if (job.start_after) {\n                      return html`<span>${new Date(job.start_after).toLocaleString()}</span>`;\n                    }\n                    return html`<span>—</span>`;\n                  })()}\n                </div>\n                <div class=\"flex justify-between\">\n                  <span class=\"opacity-60\">Started:</span>\n                  ${\n                    job.started_on\n                      ? html`<span class=\"cursor-help\" title=\"${new Date(job.started_on).toLocaleString()}\">\n                        <span data-relative-time=\"${new Date(job.started_on).toISOString()}\"></span>\n                      </span>`\n                      : html`<span>—</span>`\n                  }\n                </div>\n                <div class=\"flex justify-between\">\n                  <span class=\"opacity-60\">Completed:</span>\n                  ${(() => {\n                    if (job.completed_on && job.started_on) {\n                      return html`<span class=\"cursor-help\" title=\"${new Date(job.completed_on).toLocaleString()}\">\n                          <span data-duration-between-start=\"${new Date(job.started_on).toISOString()}\" data-duration-between-end=\"${new Date(job.completed_on).toISOString()}\"></span>\n                        </span>`;\n                    }\n                    if (job.completed_on) {\n                      return html`<span>${new Date(job.completed_on).toLocaleString()}</span>`;\n                    }\n                    return html`<span>—</span>`;\n                  })()}\n                </div>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <!-- Additional metadata if present -->\n        ${\n          job.singleton_key ||\n          job.expire_seconds != null ||\n          job.delete_after_seconds != null ||\n          job.keep_until ||\n          job.dead_letter ||\n          job.policy\n            ? html`\n        <div class=\"card bg-base-200\">\n          <div class=\"card-body p-4 gap-2\">\n            <h4 class=\"font-semibold text-sm opacity-70\">Additional Settings</h4>\n            <div class=\"text-sm space-y-1\">\n              ${\n                job.singleton_key\n                  ? html`\n              <div class=\"flex justify-between\">\n                <span class=\"opacity-60\">Singleton Key:</span>\n                <span class=\"font-mono text-xs\">${job.singleton_key}</span>\n              </div>\n              `\n                  : \"\"\n              }\n              ${\n                job.expire_seconds != null\n                  ? html`\n              <div class=\"flex justify-between\">\n                <span class=\"opacity-60\">Expire:</span>\n                <span class=\"cursor-help\" title=\"${job.expire_seconds}s\">\n                  <span data-duration=\"${job.expire_seconds}\"></span>\n                </span>\n              </div>\n              `\n                  : \"\"\n              }\n              ${\n                job.delete_after_seconds != null\n                  ? html`\n              <div class=\"flex justify-between\">\n                <span class=\"opacity-60\">Delete After:</span>\n                <span class=\"cursor-help\" title=\"${job.delete_after_seconds}s\">\n                  <span data-duration=\"${job.delete_after_seconds}\"></span>\n                </span>\n              </div>\n              `\n                  : \"\"\n              }\n              ${\n                job.keep_until\n                  ? html`\n              <div class=\"flex justify-between\">\n                <span class=\"opacity-60\">Keep Until:</span>\n                <span>${new Date(job.keep_until).toLocaleString()}</span>\n              </div>\n              `\n                  : \"\"\n              }\n              ${\n                job.dead_letter\n                  ? html`\n              <div class=\"flex justify-between\">\n                <span class=\"opacity-60\">Dead Letter:</span>\n                <span>${job.dead_letter}</span>\n              </div>\n              `\n                  : \"\"\n              }\n              <div class=\"flex justify-between\">\n                <span class=\"opacity-60\">Policy:</span>\n                <span>${job.policy ?? \"standard\"}</span>\n              </div>\n            </div>\n          </div>\n        </div>\n        `\n            : \"\"\n        }\n\n        <!-- Job Data -->\n        <div class=\"min-w-0 overflow-hidden\">\n          <div class=\"divider\">Job Data</div>\n          ${CodeBlock({\n            code: JSON.stringify(job.data ?? {}, null, 2),\n            language: \"json\",\n          })}\n        </div>\n\n        <!-- Job Output (if exists) -->\n        ${\n          job.output\n            ? html`\n          <div class=\"min-w-0 overflow-hidden\">\n            <div class=\"divider\">Job Output</div>\n            ${CodeBlock({\n              code:\n                typeof job.output === \"string\"\n                  ? job.output\n                  : JSON.stringify(job.output, null, 2),\n              language: typeof job.output === \"string\" ? \"log\" : \"json\",\n            })}\n          </div>\n        `\n            : \"\"\n        }\n      </div>\n    </div>\n  `;\n}\n","import { Hono } from \"hono\";\nimport { html } from \"hono/html\";\nimport type PgBoss from \"pg-boss\";\nimport type { Env } from \"../../types\";\nimport { JobDetailCard } from \"../components/job-detail\";\n\n// Type for pg-boss job with metadata (camelCase from pg-boss API)\ntype PgBossJob = PgBoss.JobWithMetadata<unknown>;\n\n// Convert pg-boss job to our JobRow format (snake_case for consistency with DB)\nfunction convertToJobRow(pgBossJob: PgBossJob) {\n  return {\n    completed_on: pgBossJob.completedOn,\n    created_on: pgBossJob.createdOn,\n    data: pgBossJob.data,\n    dead_letter: pgBossJob.deadLetter,\n    delete_after_seconds: pgBossJob.deleteAfterSeconds,\n    expire_seconds: pgBossJob.expireInSeconds,\n    id: pgBossJob.id,\n    keep_until: pgBossJob.keepUntil,\n    name: pgBossJob.name,\n    output: pgBossJob.output,\n    policy: pgBossJob.policy,\n    priority: pgBossJob.priority,\n    retry_backoff: pgBossJob.retryBackoff,\n    retry_count: pgBossJob.retryCount,\n    retry_delay: pgBossJob.retryDelay,\n    retry_delay_max: pgBossJob.retryDelayMax ?? null,\n    retry_limit: pgBossJob.retryLimit,\n    singleton_key: pgBossJob.singletonKey,\n    singleton_on: pgBossJob.singletonOn,\n    start_after: pgBossJob.startAfter,\n    started_on: pgBossJob.startedOn,\n    state: pgBossJob.state,\n  };\n}\n\nexport const jobDetail = new Hono<Env>().get(\"/:name/jobs/:id\", async (c) => {\n  const boss = await c.get(\"bossmanClient\").getPgBoss();\n  const queueName = c.req.param(\"name\");\n  const id = c.req.param(\"id\");\n\n  const pgBossJob = (await boss.getJobById(queueName, id)) as PgBossJob | null;\n  const basePath = c.get(\"basePath\") ?? \"\";\n\n  if (!pgBossJob) {\n    return c.html(\n      html`<div class=\"alert alert-error\">\n        <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"stroke-current shrink-0 h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\">\n          <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z\" />\n        </svg>\n        <span>Job with ID \"${id}\" not found in queue \"${queueName}\"</span>\n      </div>`\n    );\n  }\n\n  // Convert to our expected format\n  const job = convertToJobRow(pgBossJob);\n\n  return c.html(JobDetailCard({ basePath, job }));\n});\n","import type PgBoss from \"pg-boss\";\n\n// Database interface that pg-boss exposes\nexport type PgBossDb = {\n  executeSql: (\n    text: string,\n    values?: unknown[]\n  ) => Promise<{ rows: unknown[] }>;\n};\n\n// Job row from the database\nexport type JobRow = {\n  id: string;\n  name: string;\n  state: \"created\" | \"retry\" | \"active\" | \"completed\" | \"cancelled\" | \"failed\";\n  priority: number;\n  retry_limit: number;\n  retry_count: number;\n  retry_delay: number;\n  retry_delay_max: number | null;\n  retry_backoff: boolean;\n  start_after: Date | string | null;\n  started_on: Date | string | null;\n  singleton_key: string | null;\n  singleton_on: Date | string | null;\n  expire_seconds: number;\n  delete_after_seconds: number;\n  created_on: Date | string;\n  completed_on: Date | string | null;\n  keep_until: Date | string | null;\n  dead_letter: string | null;\n  policy: string | null;\n  data?: unknown;\n  output?: unknown;\n};\n\n// Helper to get the database instance from pg-boss\nexport function getDb(boss: PgBoss): PgBossDb {\n  return (boss as unknown as { getDb: () => PgBossDb }).getDb();\n}\n\n// Default pg-boss schema\nexport const PGBOSS_SCHEMA = \"pgboss\";\n","import type PgBoss from \"pg-boss\";\nimport { getDb, type JobRow, PGBOSS_SCHEMA } from \"./types\";\n\nexport type GetQueueJobsResult = {\n  jobs: JobRow[];\n  total: number;\n};\n\n/**\n * Fetches jobs for a specific queue with pagination\n * Jobs remain in the job table in pg-boss v11, so we query a single table.\n */\nexport async function getQueueJobs(\n  boss: PgBoss,\n  queueName: string,\n  limit: number,\n  offset: number\n): Promise<GetQueueJobsResult> {\n  const db = getDb(boss);\n\n  const jobsSql = `\n    SELECT id,\n           name,\n           state,\n           priority,\n           retry_limit,\n           retry_count,\n           retry_delay,\n           retry_delay_max,\n           retry_backoff,\n           start_after,\n           started_on,\n           singleton_key,\n           singleton_on,\n           expire_seconds,\n           deletion_seconds AS delete_after_seconds,\n           created_on,\n           completed_on,\n           keep_until,\n           dead_letter,\n           policy,\n           data,\n           output\n    FROM ${PGBOSS_SCHEMA}.job\n    WHERE name = $1\n    ORDER BY created_on DESC, id DESC\n    LIMIT $2 OFFSET $3\n  `;\n\n  const countSql = `\n    SELECT COUNT(*) AS total FROM ${PGBOSS_SCHEMA}.job WHERE name = $1\n  `;\n\n  const [jobsResult, countResult] = await Promise.all([\n    db.executeSql(jobsSql, [queueName, limit, offset]),\n    db.executeSql(countSql, [queueName]),\n  ]);\n\n  const jobs = (jobsResult.rows || []) as JobRow[];\n  const total = Number(\n    (countResult.rows?.[0] as { total?: unknown })?.total ?? 0\n  );\n\n  return { jobs, total };\n}\n","import type PgBoss from \"pg-boss\";\nimport { getDb, PGBOSS_SCHEMA } from \"./types\";\n\nexport type QueueStateCounts = {\n  created: number;\n  retry: number;\n  active: number;\n  completed: number;\n  cancelled: number;\n  failed: number;\n  all: number;\n};\n\n/**\n * Get job counts by state for a specific queue\n * Queries the job table (completed jobs remain in-place in pg-boss v11)\n */\nexport async function getQueueStateCounts(\n  boss: PgBoss,\n  queueName: string\n): Promise<QueueStateCounts> {\n  const db = getDb(boss);\n\n  const sql = `\n    SELECT state, COUNT(*) as count\n    FROM ${PGBOSS_SCHEMA}.job\n    WHERE name = $1\n    GROUP BY state\n  `;\n\n  const result = await db.executeSql(sql, [queueName]);\n  const rows = result.rows as Array<{ state: string; count: string }>;\n\n  // Initialize counts\n  const counts: QueueStateCounts = {\n    active: 0,\n    all: 0,\n    cancelled: 0,\n    completed: 0,\n    created: 0,\n    failed: 0,\n    retry: 0,\n  };\n\n  // Populate counts from query results\n  for (const row of rows) {\n    const count = Number(row.count);\n    counts[row.state as keyof Omit<QueueStateCounts, \"all\">] = count;\n    counts.all += count;\n  }\n\n  return counts;\n}\n\n/**\n * Get job counts by state for a specific queue since a cutoff time\n */\n// (Note) If needed in the future, a \"since\" variant can be added back, but\n// the dashboard currently uses aggregate counts for consistency with queue detail.\n","import { html } from \"hono/html\";\n\nexport type QueueMeta = {\n  name: string;\n  policy?: string | null;\n  retry_limit?: number | null;\n  retry_delay?: number | null;\n  retry_delay_max?: number | null;\n  retry_backoff?: boolean | null;\n  expire_seconds?: number | null;\n  retention_seconds?: number | null;\n  delete_after_seconds?: number | null;\n  dead_letter?: string | null;\n  warning_queue_size?: number | null;\n  partition?: boolean | null;\n  created_on?: Date | null;\n  updated_on?: Date | null;\n};\n\nexport type QueueSchedule = {\n  name: string;\n  cron: string;\n  key?: string | null;\n  timezone?: string | null;\n  options?: unknown;\n  data?: unknown;\n};\n\nexport type QueueStateCounts = {\n  created: number;\n  retry: number;\n  active: number;\n  completed: number;\n  cancelled: number;\n  failed: number;\n};\n\nfunction StatsGrid({\n  total,\n  counts,\n}: {\n  total: number;\n  counts: QueueStateCounts | null;\n}) {\n  return html`<div class=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3\">\n    <div class=\"stat bg-base-200 rounded-box\">\n      <div class=\"stat-title\">Total Jobs</div>\n      <div class=\"stat-value text-primary\">${total}</div>\n      <div class=\"stat-desc\">created + active + completed + failed</div>\n    </div>\n    <div class=\"stat bg-base-200 rounded-box\">\n      <div class=\"stat-title\">Pending</div>\n      <div class=\"stat-value\">${(counts?.created ?? 0) + (counts?.retry ?? 0)}</div>\n      <div class=\"stat-desc\">Created + Retry</div>\n    </div>\n    <div class=\"stat bg-base-200 rounded-box\">\n      <div class=\"stat-title\">Active</div>\n      <div class=\"stat-value\">${counts?.active ?? 0}</div>\n    </div>\n    <div class=\"stat bg-base-200 rounded-box\">\n      <div class=\"stat-title\">Completed</div>\n      <div class=\"stat-value text-success\">${counts?.completed ?? 0}</div>\n    </div>\n    <div class=\"stat bg-base-200 rounded-box\">\n      <div class=\"stat-title\">Failed</div>\n      <div class=\"stat-value text-error\">${counts?.failed ?? 0}</div>\n    </div>\n    <div class=\"stat bg-base-200 rounded-box\">\n      <div class=\"stat-title\">Cancelled</div>\n      <div class=\"stat-value\">${counts?.cancelled ?? 0}</div>\n    </div>\n  </div>`;\n}\n\nfunction ConfigGrid({ meta }: { meta: QueueMeta }) {\n  return html`<div class=\"grid grid-cols-1 md:grid-cols-2 gap-3 text-sm\">\n    <div class=\"card bg-base-200 p-3 space-y-1\">\n      <div><span class=\"font-medium\">Retry Limit:</span> ${meta.retry_limit ?? \"—\"}</div>\n      <div>\n        <span class=\"font-medium\">Retry Delay:</span>\n        ${\n          meta.retry_delay != null\n            ? html`<span class=\"cursor-help\" title=\"${meta.retry_delay}s\">\n              <span data-duration=\"${meta.retry_delay}\"></span>\n            </span>`\n            : \"—\"\n        }\n      </div>\n      <div>\n        <span class=\"font-medium\">Retry Delay Max:</span>\n        ${\n          meta.retry_delay_max != null\n            ? html`<span class=\"cursor-help\" title=\"${meta.retry_delay_max}s\">\n              <span data-duration=\"${meta.retry_delay_max}\"></span>\n            </span>`\n            : \"—\"\n        }\n      </div>\n      <div><span class=\"font-medium\">Retry Backoff:</span> ${meta.retry_backoff ? \"Yes\" : \"No\"}</div>\n    </div>\n    <div class=\"card bg-base-200 p-3 space-y-1\">\n      <div>\n        <span class=\"font-medium\">Expire:</span>\n        ${\n          meta.expire_seconds != null\n            ? html`<span class=\"cursor-help\" title=\"${meta.expire_seconds}s\">\n              <span data-duration=\"${meta.expire_seconds}\"></span>\n            </span>`\n            : \"—\"\n        }\n      </div>\n      <div>\n        <span class=\"font-medium\">Retention:</span>\n        ${\n          meta.retention_seconds != null\n            ? html`<span class=\"cursor-help\" title=\"${meta.retention_seconds}s\">\n              <span data-duration=\"${meta.retention_seconds}\"></span>\n            </span>`\n            : \"—\"\n        }\n      </div>\n      <div>\n        <span class=\"font-medium\">Delete After:</span>\n        ${\n          meta.delete_after_seconds != null\n            ? html`<span class=\"cursor-help\" title=\"${meta.delete_after_seconds}s\">\n              <span data-duration=\"${meta.delete_after_seconds}\"></span>\n            </span>`\n            : \"—\"\n        }\n      </div>\n      <div><span class=\"font-medium\">Warning Queue Size:</span> ${meta.warning_queue_size ?? \"—\"}</div>\n      <div><span class=\"font-medium\">Partitioned Table:</span> ${meta.partition ? \"Yes\" : \"No\"}</div>\n      <div><span class=\"font-medium\">Dead-letter:</span> ${meta.dead_letter ?? \"—\"}</div>\n    </div>\n  </div>`;\n}\n\nexport function QueueDetailCard({\n  meta,\n  counts,\n  schedules,\n}: {\n  meta: QueueMeta | null;\n  counts: QueueStateCounts | null;\n  schedules: QueueSchedule[];\n}) {\n  if (!meta) {\n    return html`<div class=\"alert alert-error\"><span>Queue not found</span></div>`;\n  }\n\n  const RAW_EVENT_PREFIX = \"__bossman_event__\";\n  const isEvent = meta.name?.startsWith(RAW_EVENT_PREFIX) ?? false;\n  const name = isEvent ? meta.name.slice(RAW_EVENT_PREFIX.length) : meta.name;\n  const total = counts\n    ? counts.created +\n      counts.retry +\n      counts.active +\n      counts.completed +\n      counts.cancelled +\n      counts.failed\n    : 0;\n\n  return html`\n    <section class=\"card bg-base-100 shadow-xl\">\n      <div class=\"card-body gap-4\">\n        <div class=\"flex items-center justify-between\">\n          <div>\n            <h2 class=\"card-title\">${isEvent ? `Event: ${name}` : name}</h2>\n            <p class=\"text-sm text-base-content/60\">Policy: ${meta.policy ?? \"standard\"}</p>\n          </div>\n        </div>\n\n        ${StatsGrid({ counts, total })}\n\n        <div class=\"divider\">Configuration</div>\n        ${ConfigGrid({ meta })}\n\n        <div class=\"divider\">Schedules</div>\n        ${\n          schedules.length > 0\n            ? html`<div class=\"space-y-2\">\n              ${schedules.map(\n                (schedule) =>\n                  html`<div class=\"alert alert-soft flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2\">\n                  <span>\n                    Cron: <code class=\"font-mono\">${schedule.cron}</code>${\n                      schedule.timezone ? ` (${schedule.timezone})` : \"\"\n                    }\n                  </span>\n                  ${\n                    schedule.key\n                      ? html`<span class=\"badge badge-outline\">Key: ${schedule.key}</span>`\n                      : \"\"\n                  }\n                </div>`\n              )}\n            </div>`\n            : html`<div class=\"alert\"><span>No schedules</span></div>`\n        }\n      </div>\n    </section>\n  `;\n}\n","import { Hono } from \"hono\";\nimport { getQueueStateCounts } from \"../../db\";\nimport type { Env } from \"../../types\";\nimport {\n  QueueDetailCard,\n  type QueueMeta,\n  type QueueSchedule,\n} from \"../components/queue-detail\";\n\nexport const queueDetail = new Hono<Env>().get(\n  \"/:name/detail-card\",\n  async (c) => {\n    const client = c.get(\"bossmanClient\");\n    const boss = await client.getPgBoss();\n\n    const name = c.req.param(\"name\");\n    const rawMeta = await boss.getQueue?.(name);\n\n    const meta: QueueMeta | null = rawMeta\n      ? {\n          created_on: rawMeta.createdOn,\n          dead_letter: rawMeta.deadLetter,\n          delete_after_seconds: rawMeta.deleteAfterSeconds,\n          expire_seconds: rawMeta.expireInSeconds,\n          name: rawMeta.name,\n          partition: rawMeta.partition,\n          policy: rawMeta.policy,\n          retention_seconds: rawMeta.retentionSeconds,\n          retry_backoff: rawMeta.retryBackoff,\n          retry_delay: rawMeta.retryDelay,\n          retry_delay_max: rawMeta.retryDelayMax,\n          retry_limit: rawMeta.retryLimit,\n          updated_on: rawMeta.updatedOn,\n          warning_queue_size: rawMeta.warningQueueSize,\n        }\n      : null;\n\n    // Get job counts by state\n    const counts = await getQueueStateCounts(boss, name);\n\n    // schedule info - schedules use the full queue name (e.g., \"processPayment\")\n    const allSchedules = (await boss.getSchedules?.()) as\n      | QueueSchedule[]\n      | null;\n    const schedules = allSchedules?.filter((s) => s.name === name) ?? [];\n\n    return c.html(\n      QueueDetailCard({\n        counts,\n        meta,\n        schedules,\n      })\n    );\n  }\n);\n","import { html } from \"hono/html\";\nimport type { HtmlEscapedString } from \"hono/utils/html\";\n\nexport function RefreshControl({\n  refreshOn,\n  indicatorId,\n  toggleHref,\n  controlId,\n  swapTargetId,\n}: {\n  refreshOn: boolean;\n  indicatorId: string;\n  toggleHref: string;\n  controlId?: string;\n  swapTargetId?: string;\n}): HtmlEscapedString {\n  const idAttr = controlId ? html` id=\"${controlId}\"` : html``;\n  const swapAttr = swapTargetId\n    ? html` hx-swap-oob=\"outerHTML:#${swapTargetId}\"`\n    : html``;\n  const content = html`<div${idAttr}${swapAttr} class=\"flex items-center gap-3 text-sm\">\n    <div class=\"flex items-center gap-2\" id=\"${indicatorId}\">\n      ${\n        refreshOn\n          ? html`<span class=\"loading loading-spinner loading-xs\"></span>\n          <span>Auto-refreshing…</span>`\n          : html`<span class=\"opacity-60\">Auto-refresh off</span>`\n      }\n    </div>\n    <a class=\"btn btn-ghost btn-xs\" href=\"${toggleHref}\">${\n      refreshOn ? \"Turn off\" : \"Turn on\"\n    }</a>\n  </div>`;\n  return content as unknown as HtmlEscapedString;\n}\n","import { html } from \"hono/html\";\nimport type { JobRow } from \"../api/queue-jobs\";\nimport { api } from \"../utils/api\";\nimport { RefreshControl } from \"./refresh-control\";\n\nexport function JobItem({ job, basePath }: { job: JobRow; basePath: string }) {\n  let stateClass = \"\";\n  if (job.state === \"completed\") {\n    stateClass = \"badge-success\";\n  } else if (job.state === \"failed\") {\n    stateClass = \"badge-error\";\n  } else if (job.state === \"active\") {\n    stateClass = \"badge-primary\";\n  } else if (job.state === \"retry\") {\n    stateClass = \"badge-warning\";\n  }\n  const jobHref = `${basePath || \"\"}/queues/${encodeURIComponent(job.name)}/jobs/${encodeURIComponent(job.id)}`;\n  return html`<tr>\n    <td class=\"font-mono text-xs\"><a class=\"link\" href=\"${jobHref}\">${job.id}</a></td>\n    <td><span class=\"badge ${stateClass}\">${job.state}</span></td>\n    <td class=\"hidden sm:table-cell\">${job.priority}</td>\n    <td class=\"hidden md:table-cell\">${job.retry_count}/${job.retry_limit}</td>\n    <td class=\"hidden lg:table-cell\">\n      ${\n        job.started_on\n          ? html`<span class=\"cursor-help\" title=\"${new Date(job.started_on).toLocaleString()}\">\n            <span data-relative-time=\"${new Date(job.started_on).toISOString()}\"></span>\n          </span>`\n          : \"—\"\n      }\n    </td>\n    <td class=\"hidden lg:table-cell\">\n      ${(() => {\n        if (job.completed_on && job.started_on) {\n          return html`<span class=\"cursor-help\" title=\"${new Date(job.completed_on).toLocaleString()}\">\n              <span data-duration-between-start=\"${new Date(job.started_on).toISOString()}\" data-duration-between-end=\"${new Date(job.completed_on).toISOString()}\"></span>\n            </span>`;\n        }\n        if (job.completed_on) {\n          return html`<span>${new Date(job.completed_on).toLocaleString()}</span>`;\n        }\n        return \"—\";\n      })()}\n    </td>\n    <td>\n      ${\n        job.created_on\n          ? html`<span class=\"cursor-help\" title=\"${new Date(job.created_on).toLocaleString()}\">\n            <span data-relative-time=\"${new Date(job.created_on).toISOString()}\"></span>\n          </span>`\n          : \"—\"\n      }\n    </td>\n  </tr>`;\n}\n\nexport function JobsTable({\n  jobs,\n  basePath = \"\",\n}: {\n  jobs: JobRow[];\n  basePath?: string;\n}) {\n  if (!jobs.length) {\n    return html`<div class=\"alert alert-soft\"><span>No runs found</span></div>`;\n  }\n  return html`<div class=\"overflow-x-auto\">\n    <table class=\"table table-sm w-full\">\n      <thead>\n        <tr>\n          <th>ID</th>\n          <th>State</th>\n          <th class=\"hidden sm:table-cell\">Priority</th>\n          <th class=\"hidden md:table-cell\">Retries</th>\n          <th class=\"hidden lg:table-cell\">Started</th>\n          <th class=\"hidden lg:table-cell\">Completed</th>\n          <th>Created</th>\n        </tr>\n      </thead>\n      <tbody>\n        ${jobs.map((job) => JobItem({ basePath, job }))}\n      </tbody>\n    </table>\n  </div>`;\n}\n\nexport function JobsList({\n  jobs,\n  name,\n  limit,\n  offset,\n  total,\n  basePath,\n  refreshOn,\n  refreshToggleHref,\n  refreshControlId,\n  refreshIndicatorId,\n}: {\n  jobs: JobRow[];\n  name: string;\n  limit: number;\n  offset: number;\n  total: number;\n  basePath: string;\n  refreshOn: boolean;\n  refreshToggleHref: string;\n  refreshControlId: string;\n  refreshIndicatorId: string;\n}) {\n  const start = total === 0 ? 0 : offset + 1;\n  const end = Math.min(offset + limit, total);\n  const prevOffset = Math.max(0, offset - limit);\n  const nextOffset = Math.min(total, offset + limit);\n  const prevDisabled = offset <= 0;\n  const nextDisabled = nextOffset >= total;\n  const routes = api(basePath);\n  const listPath = (o: number) => routes.queueJobsList(name, limit, o);\n  const currentPage = Math.floor(offset / limit) + 1;\n  const prevPage = Math.max(1, currentPage - 1);\n  const nextPage = currentPage + 1;\n  const prevPageUrl = `${basePath}/queues/${encodeURIComponent(name)}/jobs?page=${prevPage}`;\n  const nextPageUrl = `${basePath}/queues/${encodeURIComponent(name)}/jobs?page=${nextPage}`;\n  const caption = `Showing ${start}–${end} of ${total}`;\n  const pollerPath = listPath(offset);\n  const refreshControl = RefreshControl({\n    controlId: refreshControlId,\n    indicatorId: refreshIndicatorId,\n    refreshOn,\n    swapTargetId: refreshControlId,\n    toggleHref: refreshToggleHref,\n  });\n  return html`\n    ${refreshControl}\n    <div\n      hx-swap-oob=\"outerHTML:#jobs-poller\"\n      id=\"jobs-poller\"\n      hx-get=\"${pollerPath}\"\n      ${refreshOn ? html`hx-trigger=\"every 5s\"` : html``}\n      hx-target=\"#jobs-list\"\n      hx-indicator=\"#jobs-page-indicator\"\n      hx-swap=\"innerHTML\"\n      style=\"display:none\"\n    ></div>\n    <!-- OOB updates for counters & pagination (outside the list container) -->\n    <div hx-swap-oob=\"innerHTML:#jobs-count-top\">${caption}</div>\n    <div hx-swap-oob=\"innerHTML:#jobs-count-bottom\">${caption}</div>\n    <div hx-swap-oob=\"innerHTML:#jobs-pagination-top\" class=\"join\">\n      <button class=\"btn btn-sm join-item\" ${prevDisabled ? \"disabled\" : \"\"} hx-get=\"${listPath(prevOffset)}\" hx-target=\"#jobs-list\" hx-push-url=\"${prevPageUrl}\">Prev</button>\n      <button class=\"btn btn-sm join-item\" ${nextDisabled ? \"disabled\" : \"\"} hx-get=\"${listPath(nextOffset)}\" hx-target=\"#jobs-list\" hx-push-url=\"${nextPageUrl}\">Next</button>\n    </div>\n    <div hx-swap-oob=\"innerHTML:#jobs-pagination-bottom\" class=\"join\">\n      <button class=\"btn btn-sm join-item\" ${prevDisabled ? \"disabled\" : \"\"} hx-get=\"${listPath(prevOffset)}\" hx-target=\"#jobs-list\" hx-push-url=\"${prevPageUrl}\">Prev</button>\n      <button class=\"btn btn-sm join-item\" ${nextDisabled ? \"disabled\" : \"\"} hx-get=\"${listPath(nextOffset)}\" hx-target=\"#jobs-list\" hx-push-url=\"${nextPageUrl}\">Next</button>\n    </div>\n\n    ${JobsTable({ basePath, jobs })}\n  `;\n}\n","// Create a toggle URL that preserves existing query params (e.g. page)\nexport function buildRefreshToggleHref(\n  requestUrl: string,\n  refreshOn: boolean\n): string {\n  try {\n    const current = new URL(requestUrl);\n    const params = new URLSearchParams(current.searchParams);\n    if (refreshOn) {\n      params.set(\"refresh\", \"off\");\n    } else {\n      params.delete(\"refresh\");\n    }\n    const query = params.toString();\n    return query ? `${current.pathname}?${query}` : current.pathname;\n  } catch {\n    return refreshOn ? \"?refresh=off\" : \"\";\n  }\n}\n","import { Hono } from \"hono\";\nimport { getQueueJobs } from \"../../db\";\nimport type { Env } from \"../../types\";\nimport { JobsList, JobsTable } from \"../components/jobs\";\nimport { withBasePath } from \"../utils/path\";\nimport { buildRefreshToggleHref } from \"../utils/query\";\n\n// Re-export JobRow type for components\nexport type { JobRow } from \"../../db\";\n\nfunction toInt(value: string | null | undefined, fallback: number) {\n  const n = Number(value);\n  return Number.isFinite(n) && n >= 0 ? Math.floor(n) : fallback;\n}\n\nconst DEFAULT_PREVIEW_LIMIT = 5;\nconst DEFAULT_PAGE_LIMIT = 25;\n\nexport const queueJobs = new Hono<Env>()\n  // preview list\n  .get(\"/:name/jobs\", async (c) => {\n    const boss = await c.get(\"bossmanClient\").getPgBoss();\n    const name = c.req.param(\"name\");\n    const url = new URL(c.req.url);\n    const limit = toInt(url.searchParams.get(\"limit\"), DEFAULT_PREVIEW_LIMIT);\n    const { jobs } = await getQueueJobs(boss, name, limit, 0);\n    const basePath = c.get(\"basePath\") ?? \"\";\n    return c.html(JobsTable({ basePath, jobs }));\n  })\n  // paginated list\n  .get(\"/:name/jobs/list\", async (c) => {\n    const boss = await c.get(\"bossmanClient\").getPgBoss();\n    const name = c.req.param(\"name\");\n    const url = new URL(c.req.url);\n    const limit = toInt(url.searchParams.get(\"limit\"), DEFAULT_PAGE_LIMIT);\n    let offset = toInt(url.searchParams.get(\"offset\"), 0);\n    const basePath = c.get(\"basePath\") ?? \"\";\n    const currentUrlHeader = c.req.header(\"HX-Current-URL\");\n    let refreshOn = true;\n    let currentPageUrl: URL | null = null;\n    if (currentUrlHeader) {\n      try {\n        currentPageUrl = new URL(currentUrlHeader);\n        if (!url.searchParams.has(\"offset\")) {\n          const pageParam = currentPageUrl.searchParams.get(\"page\");\n          const page =\n            Number.isFinite(Number(pageParam)) && Number(pageParam) >= 1\n              ? Math.floor(Number(pageParam))\n              : 1;\n          offset = (page - 1) * limit;\n        }\n        refreshOn =\n          (currentPageUrl.searchParams.get(\"refresh\") ?? \"on\") !== \"off\";\n      } catch {\n        currentPageUrl = null;\n      }\n    }\n    const fallbackPage = Math.floor(offset / Math.max(1, limit)) + 1;\n    const fallbackPath = withBasePath(\n      basePath,\n      `/queues/${encodeURIComponent(name)}/jobs`\n    );\n    const fallbackUrl = new URL(\n      `${fallbackPath}?page=${fallbackPage}`,\n      \"http://pg-bossman.local\"\n    );\n    const toggleHref = buildRefreshToggleHref(\n      (currentPageUrl ?? fallbackUrl).toString(),\n      refreshOn\n    );\n    // Recompute query using the possibly updated offset\n    const { jobs, total } = await getQueueJobs(boss, name, limit, offset);\n    return c.html(\n      JobsList({\n        basePath,\n        jobs,\n        limit,\n        name,\n        offset,\n        refreshControlId: \"jobs-refresh-control\",\n        refreshIndicatorId: \"jobs-page-indicator\",\n        refreshOn,\n        refreshToggleHref: toggleHref,\n        total,\n      })\n    );\n  });\n","import { html } from \"hono/html\";\nimport type { QueueStateCounts } from \"../../db/get-queue-state-counts\";\n\ntype QueueRow = { name: string; counts: QueueStateCounts };\n\nfunction QueuesTable({\n  queues,\n  basePath,\n}: {\n  queues: QueueRow[];\n  basePath: string;\n}) {\n  if (!queues?.length) {\n    return html`\n      <div class=\"alert alert-soft\">\n        <span>No queues found.</span>\n      </div>\n    `;\n  }\n  return html`\n    <div class=\"overflow-x-auto\">\n      <table class=\"table w-full\">\n        <thead>\n          <tr>\n            <th>Name</th>\n            <th>Total</th>\n            <th>Pending</th>\n            <th>Active</th>\n            <th>Completed</th>\n            <th>Failed</th>\n            <th>Cancelled</th>\n          </tr>\n        </thead>\n        <tbody class=\"table-zebra\">\n          ${queues.map((q) => {\n            const href = `${basePath || \"\"}/queues/${encodeURIComponent(q.name)}`;\n            const RAW_EVENT_PREFIX = \"__bossman_event__\";\n            const displayName = q.name.startsWith(RAW_EVENT_PREFIX)\n              ? q.name.slice(RAW_EVENT_PREFIX.length)\n              : q.name;\n            const c = q.counts;\n            const pending = (c.created ?? 0) + (c.retry ?? 0);\n            return html`<tr>\n              <td class=\"font-mono\"><a class=\"link\" href=\"${href}\">${displayName}</a></td>\n              <td>${c.all}</td>\n              <td>${pending}</td>\n              <td>${c.active}</td>\n              <td class=\"text-success\">${c.completed}</td>\n              <td class=\"text-error\">${c.failed}</td>\n              <td>${c.cancelled}</td>\n            </tr>`;\n          })}\n        </tbody>\n      </table>\n    </div>\n  `;\n}\n\nexport function QueuesCard({\n  queues,\n  basePath,\n}: {\n  queues: QueueRow[];\n  basePath: string;\n}) {\n  return html`${QueuesTable({ basePath, queues })}`;\n}\n","import { Hono } from \"hono\";\nimport { getQueueStateCounts } from \"../../db/get-queue-state-counts\";\nimport type { Env } from \"../../types\";\nimport { QueuesCard } from \"../components/queues\";\n\ntype QueueRow = { name?: string } & Record<string, unknown>;\n\nexport const queues = new Hono<Env>()\n  // HTML partial for the queues list card\n  .get(\"/queues-list-card\", async (c) => {\n    const client = c.get(\"bossmanClient\");\n    const boss = await client.getPgBoss();\n    const allQueues = ((await boss.getQueues?.()) ??\n      []) as unknown as QueueRow[];\n    const url = new URL(c.req.url);\n    const only = url.searchParams.get(\"only\");\n    let filtered: QueueRow[];\n    if (only === \"events\") {\n      filtered = allQueues.filter((q) =>\n        q.name?.startsWith(\"__bossman_event__\")\n      );\n    } else {\n      // default: show user queues excluding internal and events\n      filtered = allQueues.filter(\n        (q) =>\n          !(\n            q.name?.startsWith(\"__pgboss__\") ||\n            q.name?.startsWith(\"__bossman_event__\")\n          )\n      );\n    }\n    // Build rows with aggregate counts (same semantics as queue detail page)\n    const rows = await Promise.all(\n      filtered.map(async (q) => ({\n        counts: await getQueueStateCounts(boss, q.name ?? \"\"),\n        name: q.name ?? \"\",\n      }))\n    );\n    const basePath = c.get(\"basePath\") ?? \"\";\n    return c.html(QueuesCard({ basePath, queues: rows }));\n  });\n","import { Hono } from \"hono\";\nimport type { Env } from \"../../types\";\nimport { jobDetail } from \"./job-detail\";\nimport { queueDetail } from \"./queue-detail\";\nimport { queueJobs } from \"./queue-jobs\";\nimport { queues } from \"./queues\";\n\nexport const api = new Hono<Env>()\n  .route(\"/queues\", queues)\n  .route(\"/queues\", queueDetail)\n  .route(\"/queues\", queueJobs)\n  .route(\"/queues\", jobDetail);\n","import { html } from \"hono/html\";\nimport type { HtmlEscapedString } from \"hono/utils/html\";\nimport { withBasePath } from \"../utils/path\";\n\nexport type BreadcrumbItem = {\n  label: string;\n  href?: string;\n  className?: string;\n};\n\nexport function Breadcrumbs({\n  items,\n  basePath,\n  rightContent,\n}: {\n  items: BreadcrumbItem[];\n  basePath: string;\n  rightContent?: HtmlEscapedString | null;\n}) {\n  const crumbs = items.length\n    ? html`<div class=\"breadcrumbs\">\n        <ul>\n          ${items.map((item, index) => {\n            const isLast = index === items.length - 1;\n            const href = item.href ? withBasePath(basePath, item.href) : null;\n            return html`<li>\n              ${\n                href && !isLast\n                  ? html`<a href=\"${href}\" class=\"underline ${item.className ?? \"\"}\">${item.label}</a>`\n                  : html`<span class=\"underline ${item.className ?? \"\"}\">${item.label}</span>`\n              }\n            </li>`;\n          })}\n        </ul>\n      </div>`\n    : html``;\n\n  return html`<div class=\"flex items-center justify-between mb-3 text-sm\">\n    ${crumbs}\n    <div>${rightContent ?? \"\"}</div>\n  </div>`;\n}\n","import { html } from \"hono/html\";\nimport type { HtmlEscapedString } from \"hono/utils/html\";\n\nexport function Layout({\n  children,\n  basePath = \"\",\n  title = \"pg-bossman Dashboard\",\n}: {\n  children: Promise<HtmlEscapedString> | HtmlEscapedString;\n  basePath?: string;\n  title?: string;\n}) {\n  const homeHref = `${basePath || \"\"}`;\n  return html`\n    <html data-theme=\"light\" lang=\"en\">\n      <head>\n        <meta charSet=\"utf-8\" />\n        <meta content=\"width=device-width, initial-scale=1\" name=\"viewport\" />\n        <title>${title}</title>\n        <script src=\"https://unpkg.com/htmx.org@1.9.12\"></script>\n        <link href=\"https://cdn.jsdelivr.net/npm/daisyui@5\" rel=\"stylesheet\" type=\"text/css\" />\n        <script src=\"https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4\"></script>\n        <script src=\"https://cdn.jsdelivr.net/npm/date-fns@4.1.0/cdn.min.js\"></script>\n        <script>\n          // Global date formatting functions\n          window.formatDurations = function(root) {\n            const elements = (root || document).querySelectorAll('[data-duration]');\n            elements.forEach(el => {\n              if (el.textContent && el.textContent.trim()) return; // Already formatted\n              const seconds = parseInt(el.getAttribute('data-duration'));\n              if (!isNaN(seconds) && typeof dateFns !== 'undefined') {\n                const duration = dateFns.intervalToDuration({ start: 0, end: seconds * 1000 });\n                el.textContent = dateFns.formatDuration(duration);\n              } else {\n                el.textContent = seconds + 's';\n              }\n            });\n          };\n\n          window.formatRelativeTimes = function(root) {\n            const elements = (root || document).querySelectorAll('[data-relative-time]');\n            elements.forEach(el => {\n              if (el.textContent && el.textContent.trim()) return; // Already formatted\n              const isoString = el.getAttribute('data-relative-time');\n              if (isoString && typeof dateFns !== 'undefined') {\n                const date = new Date(isoString);\n                el.textContent = dateFns.formatDistanceToNow(date, { addSuffix: true });\n              }\n            });\n          };\n\n          window.formatDurationBetween = function(root) {\n            const elements = (root || document).querySelectorAll('[data-duration-between-start]');\n            elements.forEach(el => {\n              if (el.textContent && el.textContent.trim()) return; // Already formatted\n              const startIso = el.getAttribute('data-duration-between-start');\n              const endIso = el.getAttribute('data-duration-between-end');\n              const showIn = el.getAttribute('data-show-in') !== 'false';\n              if (startIso && endIso && typeof dateFns !== 'undefined') {\n                const start = new Date(startIso);\n                const end = new Date(endIso);\n                const duration = dateFns.intervalToDuration({ start, end });\n                const formatted = dateFns.formatDuration(duration, {\n                  format: ['years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds']\n                });\n                el.textContent = (showIn ? 'in ' : '') + (formatted || '0 seconds');\n              }\n            });\n          };\n\n          // Format on page load and set up event listeners\n          document.addEventListener('DOMContentLoaded', function() {\n            formatDurations();\n            formatRelativeTimes();\n            formatDurationBetween();\n\n            // Format after htmx swaps\n            document.body.addEventListener('htmx:afterSwap', function(evt) {\n              formatDurations(evt.detail.target);\n              formatRelativeTimes(evt.detail.target);\n              formatDurationBetween(evt.detail.target);\n            });\n          });\n        </script>\n      </head>\n      <body class=\"min-h-screen bg-base-200\">\n        <nav class=\"navbar bg-base-100 shadow-sm sticky top-0 z-10\">\n          <div class=\"container mx-auto max-w-6xl px-4 navbar\">\n            <div class=\"navbar-start\">\n              <a href=\"${homeHref}\" class=\"btn btn-ghost text-xl\">pg-bossman</a>\n            </div>\n            <div class=\"navbar-end\">\n              <ul class=\"menu menu-horizontal px-1\">\n                <li><a href=\"${homeHref}\" class=\"menu-active\">Queues</a></li>\n              </ul>\n            </div>\n          </div>\n        </nav>\n        <main class=\"container mx-auto p-4 max-w-6xl\">${children}</main>\n      </body>\n    </html>\n  `;\n}\n","import { Hono } from \"hono\";\nimport { html } from \"hono/html\";\nimport type { Env } from \"../types\";\nimport { Breadcrumbs } from \"./components/breadcrumbs\";\nimport { Layout } from \"./components/layout\";\nimport { RefreshControl } from \"./components/refresh-control\";\nimport { api } from \"./utils/api\";\nimport { buildRefreshToggleHref } from \"./utils/query\";\n\nexport const home = new Hono<Env>().get((c) => {\n  const basePath = c.get(\"basePath\") ?? \"\";\n  const routes = api(basePath);\n  const queuesPath = routes.queuesCard();\n  const eventsPath = routes.eventsCard();\n  const refreshOn = (c.req.query(\"refresh\") ?? \"on\") !== \"off\";\n  const toggleHref = buildRefreshToggleHref(c.req.url, refreshOn);\n  return c.html(\n    Layout({\n      basePath,\n      children: html`\n        ${Breadcrumbs({\n          basePath,\n          items: [{ label: \"Dashboard\" }],\n          rightContent: RefreshControl({\n            indicatorId: \"home-page-indicator\",\n            refreshOn,\n            toggleHref,\n          }),\n        })}\n        <div class=\"grid gap-6\">\n          <div>\n            <div class=\"flex items-center justify-between mb-2\">\n              <h2 class=\"text-lg font-semibold\">Queues</h2>\n            </div>\n            <section id=\"queues-card\" hx-get=\"${queuesPath}\" hx-trigger=\"${refreshOn ? \"load, every 5s\" : \"load\"}\" hx-indicator=\"#home-page-indicator\" class=\"card bg-base-100 shadow\">\n              <div class=\"p-2\">\n                <div class=\"skeleton h-24 w-full\"></div>\n              </div>\n            </section>\n          </div>\n          <div>\n            <div class=\"flex items-center justify-between mb-2\">\n              <h2 class=\"text-lg font-semibold\">Events</h2>\n            </div>\n            <section id=\"events-card\" hx-get=\"${eventsPath}\" hx-trigger=\"${refreshOn ? \"load, every 5s\" : \"load\"}\" hx-indicator=\"#home-page-indicator\" class=\"card bg-base-100 shadow\">\n              <div class=\"p-2\">\n                <div class=\"skeleton h-24 w-full\"></div>\n              </div>\n            </section>\n          </div>\n        </div>\n      `,\n    })\n  );\n});\n","import { Hono } from \"hono\";\nimport { html } from \"hono/html\";\nimport type { Env } from \"../types\";\nimport { Breadcrumbs } from \"./components/breadcrumbs\";\nimport { Layout } from \"./components/layout\";\nimport { RefreshControl } from \"./components/refresh-control\";\nimport { api } from \"./utils/api\";\nimport { buildRefreshToggleHref } from \"./utils/query\";\n\nexport const jobPage = new Hono<Env>().get(\"/:name/jobs/:id\", (c) => {\n  const basePath = c.get(\"basePath\") ?? \"\";\n  const queueName = c.req.param(\"name\");\n  const id = c.req.param(\"id\");\n  const RAW_EVENT_PREFIX = \"__bossman_event__\";\n  const displayQueueName = queueName.startsWith(RAW_EVENT_PREFIX)\n    ? queueName.slice(RAW_EVENT_PREFIX.length)\n    : queueName;\n  const detailPath = api(basePath).jobDetail(queueName, id);\n  const refreshOn = (c.req.query(\"refresh\") ?? \"on\") !== \"off\";\n  const toggleHref = buildRefreshToggleHref(c.req.url, refreshOn);\n  const _queueHref = `${basePath || \"\"}/queues/${encodeURIComponent(queueName)}`;\n\n  return c.html(\n    Layout({\n      basePath,\n      children: html`\n        ${Breadcrumbs({\n          basePath,\n          items: [\n            { href: \"/\", label: \"Dashboard\" },\n            { href: \"/\", label: \"Queues\" },\n            {\n              href: `/queues/${encodeURIComponent(queueName)}`,\n              label: displayQueueName,\n            },\n            {\n              href: `/queues/${encodeURIComponent(queueName)}/jobs`,\n              label: \"Jobs\",\n            },\n            { className: \"font-mono\", label: id },\n          ],\n          rightContent: RefreshControl({\n            indicatorId: \"job-page-indicator\",\n            refreshOn,\n            toggleHref,\n          }),\n        })}\n        <div class=\"flex flex-col gap-6\">\n          <!-- Job detail container with auto-refresh -->\n          <section\n            id=\"job-detail\"\n            hx-get=\"${detailPath}\"\n            hx-trigger=\"${refreshOn ? \"load, every 5s\" : \"load\"}\"\n            hx-indicator=\"#job-page-indicator\"\n          >\n            <!-- Loading skeleton -->\n            <div class=\"card bg-base-100 shadow\">\n              <div class=\"card-body gap-4\">\n                <div class=\"flex items-center justify-between\">\n                  <div class=\"skeleton h-8 w-64\"></div>\n                  <div class=\"skeleton h-6 w-24\"></div>\n                </div>\n                <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n                  <div class=\"skeleton h-32 w-full\"></div>\n                  <div class=\"skeleton h-32 w-full\"></div>\n                </div>\n                <div class=\"skeleton h-48 w-full\"></div>\n              </div>\n            </div>\n          </section>\n        </div>\n      `,\n      title: `Job ${id} - pg-bossman Dashboard`,\n    })\n  );\n});\n","import { Hono } from \"hono\";\nimport { html } from \"hono/html\";\nimport type { Env } from \"../types\";\nimport { Breadcrumbs } from \"./components/breadcrumbs\";\nimport { Layout } from \"./components/layout\";\nimport { RefreshControl } from \"./components/refresh-control\";\nimport { api } from \"./utils/api\";\nimport { buildRefreshToggleHref } from \"./utils/query\";\n\nexport const queue = new Hono<Env>().get(\"/:name\", (c) => {\n  const basePath = c.get(\"basePath\") ?? \"\";\n  const name = c.req.param(\"name\");\n  const RAW_EVENT_PREFIX = \"__bossman_event__\";\n  const displayName = name.startsWith(RAW_EVENT_PREFIX)\n    ? name.slice(RAW_EVENT_PREFIX.length)\n    : name;\n  const routes = api(basePath);\n  const refreshOn = (c.req.query(\"refresh\") ?? \"on\") !== \"off\";\n  const toggleHref = buildRefreshToggleHref(c.req.url, refreshOn);\n  const PREVIEW_LIMIT = 5;\n  const cardPath = routes.queueDetail(name);\n  return c.html(\n    Layout({\n      basePath,\n      children: html`\n        ${Breadcrumbs({\n          basePath,\n          items: [\n            { href: \"/\", label: \"Dashboard\" },\n            { href: \"/\", label: \"Queues\" },\n            { label: displayName },\n          ],\n          rightContent: RefreshControl({\n            indicatorId: \"queue-page-indicator\",\n            refreshOn,\n            toggleHref,\n          }),\n        })}\n        <div class=\"grid gap-6\">\n          <section id=\"queue-detail\" hx-get=\"${cardPath}\" hx-trigger=\"${refreshOn ? \"load, every 5s\" : \"load\"}\" hx-indicator=\"#queue-page-indicator\" class=\"card bg-base-100 shadow-xl\">\n            <div class=\"card-body gap-4\">\n              <div class=\"flex items-center justify-between\">\n                <h2 class=\"card-title\">${name}</h2>\n              </div>\n              <div class=\"skeleton h-24 w-full\"></div>\n            </div>\n          </section>\n\n          <section class=\"card bg-base-100 shadow\">\n            <div class=\"card-body gap-3\">\n              <div class=\"flex items-center justify-between\">\n                <h3 class=\"card-title\">Last 5 Jobs</h3>\n            <a class=\"btn btn-sm\" href=\"${basePath ?? \"\"}/queues/${encodeURIComponent(name)}/jobs\">View All</a>\n              </div>\n              <div id=\"jobs-preview\"\n                  hx-get=\"${routes.queueJobsPreview(name, PREVIEW_LIMIT)}\"\n                  hx-trigger=\"${refreshOn ? \"load, every 5s\" : \"load\"}\"\n                   hx-indicator=\"#queue-page-indicator\">\n                <div class=\"skeleton h-24 w-full\"></div>\n              </div>\n            </div>\n          </section>\n        </div>\n      `,\n    })\n  );\n});\n","import { Hono } from \"hono\";\nimport { html } from \"hono/html\";\nimport type { Env } from \"../types\";\nimport { Breadcrumbs } from \"./components/breadcrumbs\";\nimport { Layout } from \"./components/layout\";\nimport { RefreshControl } from \"./components/refresh-control\";\nimport { api } from \"./utils/api\";\nimport { buildRefreshToggleHref } from \"./utils/query\";\n\nexport const queueJobsPage = new Hono<Env>().get(\"/:name/jobs\", (c) => {\n  const basePath = c.get(\"basePath\") ?? \"\";\n  const name = c.req.param(\"name\");\n  const RAW_EVENT_PREFIX = \"__bossman_event__\";\n  const displayName = name.startsWith(RAW_EVENT_PREFIX)\n    ? name.slice(RAW_EVENT_PREFIX.length)\n    : name;\n  const toInt = (v: string | null | undefined, f: number) => {\n    const n = Number(v);\n    return Number.isFinite(n) && n >= 1 ? Math.floor(n) : f;\n  };\n  const DEFAULT_LIST_LIMIT = 25;\n  const page = toInt(c.req.query(\"page\"), 1);\n  const offset = (page - 1) * DEFAULT_LIST_LIMIT;\n  const listPath = api(basePath).queueJobsList(\n    name,\n    DEFAULT_LIST_LIMIT,\n    offset\n  );\n  const refreshOn = (c.req.query(\"refresh\") ?? \"on\") !== \"off\";\n  const toggleHref = buildRefreshToggleHref(c.req.url, refreshOn);\n  const _overviewHref = `${basePath || \"\"}/queues/${encodeURIComponent(name)}`;\n\n  return c.html(\n    Layout({\n      basePath,\n      children: html`\n        ${Breadcrumbs({\n          basePath,\n          items: [\n            { href: \"/\", label: \"Dashboard\" },\n            { href: \"/\", label: \"Queues\" },\n            { href: `/queues/${encodeURIComponent(name)}`, label: displayName },\n            { label: \"Jobs\" },\n          ],\n          rightContent: RefreshControl({\n            controlId: \"jobs-refresh-control\",\n            indicatorId: \"jobs-page-indicator\",\n            refreshOn,\n            toggleHref,\n          }),\n        })}\n        <div class=\"flex items-center justify-between mb-2\">\n          <h3 class=\"text-lg font-semibold\">Jobs for ${displayName}</h3>\n          <div class=\"flex items-center gap-3\">\n            <span class=\"text-sm\" id=\"jobs-count-top\"></span>\n            <div class=\"join\" id=\"jobs-pagination-top\"></div>\n          </div>\n        </div>\n        <section class=\"card bg-base-100 shadow\">\n          <div class=\"p-2\">\n            <!-- Initial load of the current page -->\n            <div id=\"jobs-list\" hx-get=\"${listPath}\" hx-trigger=\"load\" hx-indicator=\"#jobs-page-indicator\">\n              <div class=\"skeleton h-24 w-full\"></div>\n            </div>\n            <!-- Separate poller keeps the page in sync with the URL (reads page from HX-Current-URL) -->\n            <div\n              id=\"jobs-poller\"\n              hx-get=\"${basePath}/api/queues/${encodeURIComponent(name)}/jobs/list?limit=${DEFAULT_LIST_LIMIT}&offset=${offset}\"\n              hx-target=\"#jobs-list\"\n              hx-indicator=\"#jobs-page-indicator\"\n              hx-swap=\"innerHTML\"\n              style=\"display:none\"\n            ></div>\n          </div>\n        </section>\n        <div class=\"flex items-center justify-between text-sm mt-2\">\n          <div id=\"jobs-count-bottom\"></div>\n          <div class=\"join\" id=\"jobs-pagination-bottom\"></div>\n        </div>\n      `,\n    })\n  );\n});\n","import { Hono } from \"hono\";\nimport type { Env } from \"../types\";\nimport { api } from \"./api\";\nimport { home } from \"./home\";\nimport { jobPage } from \"./job\";\nimport { queue } from \"./queue\";\nimport { queueJobsPage } from \"./queue-jobs\";\n\nexport const routes = new Hono<Env>()\n  .route(\"/\", home)\n  .route(\"/api\", api)\n  .route(\"/queues\", queue)\n  .route(\"/queues\", queueJobsPage)\n  .route(\"/queues\", jobPage);\n","import { Hono } from \"hono\";\nimport { handle } from \"hono/vercel\";\nimport { routes } from \"./routes\";\n\nconst TRAILING_SLASH_RE = /\\/+$/;\n\nimport type PgBoss from \"pg-boss\";\nimport type { PgBossmanInstance } from \"../create-bossman\";\nimport type { ClientStructure } from \"../create-client\";\nimport type { EventsDef } from \"../events/index\";\nimport type { QueuesMap } from \"../types/index\";\nimport type { BossmanClient, Env } from \"./types\";\n\nexport function createDashboard<\n  TBossman extends PgBossmanInstance<\n    QueuesMap,\n    EventsDef<Record<string, unknown>>\n  >,\n>(config: {\n  client: BossmanClient<TBossman>;\n  basePath?: string;\n}): (req: Request) => Promise<Response>;\n\nexport function createDashboard(config: {\n  client: {\n    queues: ClientStructure<QueuesMap>;\n    events: Record<string, unknown>;\n    getPgBoss: () => Promise<PgBoss>;\n  };\n  basePath?: string;\n}): (req: Request) => Promise<Response>;\n\nexport function createDashboard(config: {\n  client:\n    | BossmanClient<\n        PgBossmanInstance<QueuesMap, EventsDef<Record<string, unknown>>>\n      >\n    | {\n        queues: ClientStructure<QueuesMap>;\n        events: Record<string, unknown>;\n        getPgBoss: () => Promise<PgBoss>;\n      };\n  basePath?: string;\n}) {\n  let app = new Hono<Env>();\n  const client = config.client;\n  const normalizedBase = config.basePath\n    ? config.basePath.replace(TRAILING_SLASH_RE, \"\")\n    : undefined;\n  if (normalizedBase) {\n    app = app.basePath(normalizedBase);\n  }\n\n  app.use(\"*\", async (c, next) => {\n    // biome-ignore lint/suspicious/noExplicitAny: Environment stores a generic client\n    c.set(\"bossmanClient\", client as unknown as BossmanClient<any>);\n    if (normalizedBase) {\n      c.set(\"basePath\", normalizedBase);\n    }\n    await next();\n  });\n\n  const chained = app.route(\"/\", routes);\n  return handle(chained);\n}\n","import type {\n  BatchQueueDefinition,\n  BatchQueueHandler,\n  QueueHandler,\n  QueueOptions,\n  QueueSchedule,\n  SingleQueueDefinition,\n} from \"../types/index\";\n\n// Validation constants\nconst WHITESPACE_REGEX = /\\s+/;\nconst MIN_CRON_FIELDS = 5;\nconst MAX_CRON_FIELDS = 6;\n\n/**\n * Fluent builder for creating queue definitions\n * Usage: createQueue().options({...}).handler(async (input) => {...})\n */\nexport class QueueBuilder<TInput = unknown, TOutput = void> {\n  private queueOptions?: QueueOptions;\n  private queueSchedules: QueueSchedule<TInput>[] = [];\n\n  /**\n   * Declare the input type up-front to improve schedule type safety\n   *\n   * @example\n   * ```typescript\n   * const job = createQueue()\n   *   .input<{ userId: string }>()\n   *   .handler(async ({ userId }) => {\n   *     // userId is typed as string\n   *   });\n   * ```\n   */\n  input(): QueueBuilder<undefined, TOutput>;\n  input<I>(): QueueBuilder<I, TOutput>;\n  // Implementation signature uses unknown to satisfy linter; overload determines the visible return type\n  input(): unknown {\n    return this as unknown;\n  }\n\n  /**\n   * Set job options (retry, priority, etc)\n   * These options are passed directly to pg-boss\n   *\n   * @param options - Queue configuration options\n   * @throws TypeError if batchSize is less than 1\n   *\n   * @example\n   * ```typescript\n   * const job = createQueue()\n   *   .options({\n   *     retryLimit: 3,\n   *     retryDelay: 60,\n   *     expireInSeconds: 300,\n   *     batchSize: 10  // For batch handlers\n   *   })\n   *   .handler(async (input) => { ... });\n   * ```\n   */\n  options(options: QueueOptions): QueueBuilder<TInput, TOutput> {\n    // Validate batchSize if provided\n    if (options.batchSize !== undefined && options.batchSize < 1) {\n      throw new TypeError(\n        `batchSize must be at least 1, got ${options.batchSize}`\n      );\n    }\n\n    this.queueOptions = options;\n    return this;\n  }\n\n  /**\n   * Define a schedule for this job. Multiple schedules are supported via keys.\n   *\n   * @param config - Schedule configuration with cron expression, data, and key\n   * @throws TypeError if key is empty or cron expression is invalid\n   *\n   * @example\n   * ```typescript\n   * const job = createQueue()\n   *   .input<{ type: string }>()\n   *   .schedule({\n   *     key: 'daily',\n   *     cron: '0 0 * * *',  // Every day at midnight\n   *     data: { type: 'daily-report' }\n   *   })\n   *   .schedule({\n   *     key: 'hourly',\n   *     cron: '0 * * * *',  // Every hour\n   *     data: { type: 'hourly-sync' }\n   *   })\n   *   .handler(async (input) => { ... });\n   * ```\n   */\n  schedule(config: QueueSchedule<TInput>): QueueBuilder<TInput, TOutput> {\n    const { cron, data, key, options } = config;\n\n    // Validate key\n    if (!key || key.length === 0) {\n      throw new TypeError(\"schedule requires a non-empty key\");\n    }\n\n    // Basic cron validation (5 or 6 fields)\n    if (!cron || typeof cron !== \"string\") {\n      throw new TypeError(\"schedule requires a valid cron expression string\");\n    }\n    const cronParts = cron.trim().split(WHITESPACE_REGEX);\n    if (\n      cronParts.length < MIN_CRON_FIELDS ||\n      cronParts.length > MAX_CRON_FIELDS\n    ) {\n      throw new TypeError(\n        `Invalid cron expression \"${cron}\": must have ${MIN_CRON_FIELDS} or ${MAX_CRON_FIELDS} fields (got ${cronParts.length})`\n      );\n    }\n\n    this.upsertSchedule({\n      cron,\n      data,\n      key,\n      options,\n    });\n    return this;\n  }\n\n  private upsertSchedule(schedule: QueueSchedule<TInput>) {\n    this.queueSchedules = this.queueSchedules.filter(\n      (existing) => existing.key !== schedule.key\n    );\n    this.queueSchedules.push(schedule);\n  }\n\n  /**\n   * Define a single job handler (terminal method)\n   * The handler will be called once per job\n   *\n   * @param handler - Function that processes a single job\n   * @returns Queue definition (without name, which is inferred from the jobs map key)\n   * @throws TypeError if handler is not a function\n   *\n   * @example\n   * ```typescript\n   * const sendEmailJob = createQueue()\n   *   .input<{ to: string; subject: string }>()\n   *   .options({ retryLimit: 3 })\n   *   .handler(async ({ to, subject }) => {\n   *     await emailService.send(to, subject);\n   *     return { sent: true };\n   *   });\n   * ```\n   */\n  handler<I extends TInput, O = void>(\n    handler: QueueHandler<I, O>\n  ): Omit<SingleQueueDefinition<I, O>, \"name\"> {\n    if (typeof handler !== \"function\") {\n      throw new TypeError(\"handler must be a function\");\n    }\n\n    const def: Omit<SingleQueueDefinition<I, O>, \"name\"> = {\n      handler,\n      options: this.queueOptions,\n    };\n    if (this.queueSchedules.length > 0) {\n      def.schedules = this.queueSchedules as QueueSchedule<I>[];\n    }\n    return def;\n  }\n\n  /**\n   * Define a batch job handler (terminal method)\n   * The handler receives an array of inputs for bulk processing\n   *\n   * @param batchHandler - Function that processes multiple jobs at once\n   * @returns Queue definition (without name, which is inferred from the jobs map key)\n   * @throws TypeError if batchHandler is not a function or batchSize is not set\n   *\n   * @example\n   * ```typescript\n   * const processImagesJob = createQueue()\n   *   .input<{ imageUrl: string; width: number }>()\n   *   .options({ batchSize: 10, retryLimit: 2 })\n   *   .batchHandler(async (items) => {\n   *     const results = await Promise.all(\n   *       items.map(item => imageService.resize(item.imageUrl, item.width))\n   *     );\n   *     return results;\n   *   });\n   * ```\n   */\n  batchHandler<I extends TInput, O = void>(\n    batchHandler: BatchQueueHandler<I, O>\n  ): Omit<BatchQueueDefinition<I, O>, \"name\"> {\n    if (typeof batchHandler !== \"function\") {\n      throw new TypeError(\"batchHandler must be a function\");\n    }\n\n    // Warn if batchSize is not set (pg-boss will use default of 1)\n    if (!this.queueOptions?.batchSize) {\n      console.warn(\n        \"batchHandler used without batchSize option. Consider setting options({ batchSize: N }) for better performance.\"\n      );\n    }\n\n    const def: Omit<BatchQueueDefinition<I, O>, \"name\"> = {\n      batchHandler,\n      options: this.queueOptions,\n    };\n    if (this.queueSchedules.length > 0) {\n      def.schedules = this.queueSchedules as QueueSchedule<I>[];\n    }\n    return def;\n  }\n}\n\n/**\n * Factory function to create a queue builder\n * The queue name will be inferred from the object key when registered\n *\n * @returns A new queue builder instance\n *\n * @example\n * ```typescript\n * // Basic queue\n * const sendEmail = createQueue()\n *   .input<{ to: string; subject: string }>()\n *   .handler(async (input) => {\n *     await emailService.send(input.to, input.subject);\n *   });\n *\n * // Queue with options\n * const processPayment = createQueue()\n *   .input<{ amount: number; currency: string }>()\n *   .options({\n *     retryLimit: 5,\n *     retryDelay: 60,\n *     retryBackoff: true\n *   })\n *   .handler(async (input) => {\n *     return await paymentGateway.charge(input);\n *   });\n *\n * // Scheduled queue\n * const dailyReport = createQueue()\n *   .input<{ reportType: string }>()\n *   .schedule({\n *     key: 'daily',\n *     cron: '0 0 * * *',\n *     data: { reportType: 'daily' }\n *   })\n *   .handler(async (input) => {\n *     await reportService.generate(input.reportType);\n *   });\n *\n * // Batch queue\n * const resizeImages = createQueue()\n *   .input<{ url: string; width: number }>()\n *   .options({ batchSize: 10 })\n *   .batchHandler(async (items) => {\n *     return await Promise.all(\n *       items.map(item => imageService.resize(item.url, item.width))\n *     );\n *   });\n * ```\n */\nexport function createQueue(): QueueBuilder<undefined> {\n  return new QueueBuilder<undefined>();\n}\n"],"mappings":"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"}