From faed76b9a16af82556cd353e48d76ed43611cd3e Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Wed, 24 Sep 2025 15:55:52 +0200 Subject: [PATCH 01/17] init batch processing --- packages/core/src/adapters/base.ts | 20 +++- packages/core/src/adapters/memory.ts | 33 ++++- packages/core/src/core/queue.ts | 173 +++++++++++++++++++++++++-- packages/core/tests/batch.test.ts | 88 ++++++++++++++ packages/core/types/index.d.ts | 54 +++++++++ 5 files changed, 353 insertions(+), 15 deletions(-) create mode 100644 packages/core/tests/batch.test.ts diff --git a/packages/core/src/adapters/base.ts b/packages/core/src/adapters/base.ts index 501aad9..cdde6d1 100644 --- a/packages/core/src/adapters/base.ts +++ b/packages/core/src/adapters/base.ts @@ -1,4 +1,4 @@ -import type { BaseJob, JobStatus, QueueAdapter, QueueStats } from "../../types" +import type { BaseJob, BatchJob, JobStatus, QueueAdapter, QueueStats } from "../../types" /** * Base class for queue adapters providing common functionality. @@ -32,6 +32,16 @@ export abstract class BaseQueueAdapter implements QueueAdapter { job: Omit, "id" | "createdAt">, ): Promise> + /** + * Add multiple jobs to the queue storage in a single batch operation + * + * @param jobs Array of job data without id and createdAt + * @returns Promise resolving to the created jobs with id and createdAt + */ + abstract addJobs( + jobs: Omit, "id" | "createdAt">[], + ): Promise[]> + /** * Update job status and optionally set error or result * @@ -120,6 +130,14 @@ export abstract class BaseQueueAdapter implements QueueAdapter { return this.getPendingJobByPriority() } + /** + * Get up to `count` jobs to process, considering priority and delayed jobs. + * + * @param count Maximum number of jobs to retrieve + * @returns Promise resolving to an array of batch jobs (may be fewer than count) + */ + abstract getNextJobs(count: number): Promise + /** * Get a delayed job that is ready to be processed * diff --git a/packages/core/src/adapters/memory.ts b/packages/core/src/adapters/memory.ts index 7818660..92cef71 100644 --- a/packages/core/src/adapters/memory.ts +++ b/packages/core/src/adapters/memory.ts @@ -1,4 +1,4 @@ -import type { BaseJob, JobStatus, QueueStats } from "../../types" +import type { BaseJob, BatchJob, JobStatus, QueueStats } from "../../types" import { serializeError } from "../utils/error" import { BaseQueueAdapter } from "./base" @@ -48,6 +48,24 @@ export class MemoryQueueAdapter extends BaseQueueAdapter { return Promise.resolve(newJob) } + addJobs( + jobs: Omit, "id" | "createdAt">[], + ): Promise[]> { + const created: BatchJob[] = jobs.map((job) => { + const id = this.generateId() + const createdAt = new Date() + // Scheduling-Felder sind im BatchJob-Typ nicht enthalten + const newJob: BatchJob = { + ...job, + id, + createdAt, + } + this.jobs.set(id, newJob as BaseJob) + return newJob + }) + return Promise.resolve(created) + } + updateJobStatus(id: string, status: JobStatus, error?: unknown, result?: unknown): Promise { const job = this.jobs.get(id) if (!job) return Promise.resolve() @@ -157,4 +175,17 @@ export class MemoryQueueAdapter extends BaseQueueAdapter { return Promise.resolve(pendingJobs[0] ?? null) } + + getNextJobs(count: number): Promise { + const pendingJobs = Array.from(this.jobs.values()) + .filter((job) => job.status === "pending") + .sort((a, b) => { + const priorityDiff = a.priority - b.priority + return priorityDiff !== 0 ? priorityDiff : a.createdAt.getTime() - b.createdAt.getTime() + }) + .slice(0, count) + .map((job) => job as BatchJob) + + return Promise.resolve(pendingJobs) + } } diff --git a/packages/core/src/core/queue.ts b/packages/core/src/core/queue.ts index fb7b21c..cdb5c70 100644 --- a/packages/core/src/core/queue.ts +++ b/packages/core/src/core/queue.ts @@ -2,6 +2,8 @@ import type { Simplify } from "type-fest" import type { BaseJob, + BatchJob, + BatchJobHandler, JobHandler, JobOptions, JobStatus, @@ -33,6 +35,8 @@ export class Queue { private readonly adapter: QueueAdapter private readonly config: Required private readonly handlers = new Map() + private readonly batchHandlers = new Map() + // eslint-disable-next-line @typescript-eslint/no-explicit-any private readonly listeners = new Map[]>() @@ -56,6 +60,7 @@ export class Queue { removeOnFail: 50, pollInterval: 100, jobInterval: 10, + batch: { ...(config.batch ?? {}) }, ...config, } @@ -95,6 +100,27 @@ export class Queue { this.handlers.set(name, handler as JobHandler) } + /** + * Register a batch job handler for a specific job type. + * + * @param name The job type name + * @param handler Function to process jobs of this type in batches + * + * @example + * ```typescript + * queue.registerBatch("send-emails", async (jobs) => { + * // jobs: BatchJobWithProgress[] + * // Batch processing logic + * }) + * ``` + */ + registerBatch( + name: string, + handler: BatchJobHandler, + ): void { + this.batchHandlers.set(name, handler as BatchJobHandler) + } + /** * Add a new job to the queue. * @@ -191,6 +217,37 @@ export class Queue { return this.add(name, payload, options) } + /** + * Add multiple jobs to the queue in a single batch operation. + * + * @param name The job type name (must be registered) + * @param payloads Array of job data to process + * @param options Job configuration options (applied to all jobs) + * @returns Promise resolving to the created jobs + */ + async addJobs( + name: string, + payloads: TJobPayload[], + options: JobOptions = {}, + ): Promise[]> { + const jobOptions = { ...this.config.defaultJobOptions, ...options } + + const jobs = payloads.map((payload) => ({ + name, + payload, + status: "pending" as JobStatus, + priority: jobOptions.priority ?? 2, + attempts: 0, + maxAttempts: jobOptions.maxAttempts ?? 3, + timeout: jobOptions.timeout, + processAt: new Date(), + })) + + const createdJobs = await this.adapter.addJobs(jobs) + createdJobs.forEach((job) => this.emit("job:added", job as BaseJob)) + return createdJobs + } + /** * Start processing jobs from the queue. * Jobs will be processed according to priority and concurrency settings. @@ -265,6 +322,18 @@ export class Queue { return { ...this.config } } + /** + * Returns the batch config for processing jobs in batches. + */ + private getBatchConfig(): { minSize: number; maxSize: number; waitFor: number } { + const batch = this.config.batch + return { + minSize: typeof batch.minSize === "number" && batch.minSize > 0 ? batch.minSize : 5, + maxSize: typeof batch.maxSize === "number" && batch.maxSize > 0 ? batch.maxSize : 10, + waitFor: typeof batch.waitFor === "number" && batch.waitFor > 0 ? batch.waitFor : 30000, + } + } + /** * Clear jobs from the queue. * @@ -393,32 +462,110 @@ export class Queue { } let queueSize = await this.adapter.size() - if (queueSize === 0) { await waitFor(pollInterval) continue } - while (queueSize > 0) { - while (queueSize > 0 && this.activeJobs < concurrency) { + // Batch-Processing: Für jeden Batch-Handler werden bis zu maxSize Jobs gemeinsam verarbeitet + const { minSize, maxSize } = this.getBatchConfig() + const batchJobTypes = Array.from(this.batchHandlers.keys()) + + // Versuche für jeden Batch-Handler einen Batch zu holen und zu verarbeiten + for (const type of batchJobTypes) { + if (this.activeJobs >= concurrency) break + // Hole bis zu maxSize Jobs dieses Typs effizient per Adapter + const jobs: BatchJob[] = (await this.adapter.getNextJobs(maxSize)).filter( + (job) => job.name === type, + ) + if (jobs.length >= minSize) { this.activeJobs++ setImmediate(() => { - void this.dequeueAndProcess() - .then((processed) => { - if (!processed) queueSize = 0 - else queueSize-- - }) - .catch((error) => { - this.emit("queue:error", error) - }) + void this.processBatchJobs(type, jobs) + .catch((error) => this.emit("queue:error", error)) .finally(() => { this.activeJobs-- }) }) - await waitFor(jobInterval) } - await waitFor(jobInterval * 2) } + + // Normales Einzel-Job-Processing für alle anderen Jobs + while (queueSize > 0 && this.activeJobs < concurrency) { + this.activeJobs++ + setImmediate(() => { + void this.dequeueAndProcess() + .then((processed) => { + if (!processed) queueSize = 0 + else queueSize-- + }) + .catch((error) => { + this.emit("queue:error", error) + }) + .finally(() => { + this.activeJobs-- + }) + }) + await waitFor(jobInterval) + } + await waitFor(jobInterval * 2) + } + } + /** + * Interne Methode: Verarbeitet einen Batch von Jobs mit dem registrierten Batch-Handler. + */ + private async processBatchJobs(type: string, jobs: BatchJob[]): Promise { + const handler = this.batchHandlers.get(type) + if (!handler) return + + // Status auf processing setzen und Wrapper erzeugen + await Promise.all(jobs.map((job) => this.adapter.updateJobStatus(job.id, "processing"))) + jobs.forEach((job) => { + this.emit("job:processing", { ...job, status: "processing" } as BaseJob) + }) + + // Batch-Event: processing + this.emit("batch:processing", jobs as BaseJob[]) + + // Job-Wrapper mit updateProgress + const wrappedJobs = jobs.map((job) => createJobWrapper(job as BaseJob, this)) + + try { + const result = await handler(wrappedJobs) + // Ergebnisse auf Jobs mappen (optional) + await Promise.all( + jobs.map((job, i) => + this.adapter.updateJobStatus(job.id, "completed", undefined, result?.[i]), + ), + ) + jobs.forEach((job, i) => { + this.emit("job:completed", { + ...job, + status: "completed", + completedAt: new Date(), + result: result?.[i], + } as BaseJob) + }) + // Batch-Event: completed + this.emit( + "batch:completed", + jobs.map( + (job, i) => + ({ + ...job, + status: "completed", + completedAt: new Date(), + result: result?.[i], + }) as BaseJob, + ), + ) + await this.cleanupCompletedJob() + } catch (error) { + // Fehlerbehandlung für alle Jobs im Batch + const serializedError = serializeError(error) + await Promise.all((jobs as BaseJob[]).map((job) => this.handleJobError(job, error))) + // Batch-Event: failed + this.emit("batch:failed", { jobs: jobs as BaseJob[], error: serializedError }) } } diff --git a/packages/core/tests/batch.test.ts b/packages/core/tests/batch.test.ts new file mode 100644 index 0000000..511956c --- /dev/null +++ b/packages/core/tests/batch.test.ts @@ -0,0 +1,88 @@ +import { beforeEach, describe, expect, it } from "vitest" + +import type { BaseJob } from "../types" +import { MemoryQueueAdapter } from "../src/adapters/memory" +import { Queue } from "../src/core/queue" + +describe("Queue Batch Processing", () => { + let queue: Queue + let adapter: MemoryQueueAdapter + + beforeEach(async () => { + adapter = new MemoryQueueAdapter() + queue = new Queue(adapter, { name: "batch-test", batch: { minSize: 2, maxSize: 5 } }) + await queue.connect() + }) + + it("should process jobs in batches with the batch handler", async () => { + const processedBatches: BaseJob[][] = [] + queue.registerBatch("batch-job", (jobs) => { + processedBatches.push(jobs.map((j) => ({ ...j }))) + // Simulate result array + return jobs.map((j) => ({ ok: true, id: j.id })) + }) + + // Add 4 jobs + await queue.addJobs("batch-job", [{ foo: 1 }, { foo: 2 }, { foo: 3 }, { foo: 4 }]) + + queue.start() + // Wait for processing + await new Promise((resolve) => setTimeout(resolve, 100)) + + // Should process in one batch of 4 (minSize: 2, maxSize: 5) + expect(processedBatches.length).toBe(1) + expect(processedBatches[0]?.length).toBe(4) + expect(processedBatches[0]?.every((j) => j.name === "batch-job")).toBe(true) + }) + + it("should emit batch events", async () => { + const events: string[] = [] + queue.on("batch:processing", () => { + events.push("processing") + }) + queue.on("batch:completed", () => { + events.push("completed") + }) + queue.registerBatch("batch-job", () => Promise.resolve([])) + await queue.addJobs("batch-job", [{ foo: 1 }, { foo: 2 }]) + queue.start() + await new Promise((resolve) => setTimeout(resolve, 50)) + expect(events).toEqual(["processing", "completed"]) + }) + + it("should handle batch handler errors and emit batch:failed", async () => { + let failedEvent: unknown = null + queue.on("batch:failed", (data: unknown) => { + failedEvent = data + }) + queue.registerBatch("batch-job", () => { + throw new Error("batch fail") + }) + await queue.addJobs("batch-job", [{ foo: 1 }, { foo: 2 }]) + queue.start() + await new Promise((resolve) => setTimeout(resolve, 50)) + let jobs: BaseJob[] = [] + if ( + failedEvent && + typeof failedEvent === "object" && + "jobs" in failedEvent && + Array.isArray((failedEvent as Record).jobs) + ) { + jobs = (failedEvent as { jobs: BaseJob[] }).jobs + } + expect(jobs.length).toBe(2) + expect(failedEvent && typeof failedEvent === "object" && "error" in failedEvent).toBe(true) + }) + + it("should not process jobs in batch if below minSize", async () => { + const processedBatches: BaseJob[][] = [] + queue.registerBatch("batch-job", (jobs) => { + processedBatches.push(jobs.map((j) => ({ ...j }))) + return Promise.resolve([]) + }) + await queue.addJobs("batch-job", [{ foo: 1 }]) + queue.start() + await new Promise((resolve) => setTimeout(resolve, 50)) + expect(processedBatches.length).toBe(0) + }) +}) diff --git a/packages/core/types/index.d.ts b/packages/core/types/index.d.ts index bc7b798..716ea01 100644 --- a/packages/core/types/index.d.ts +++ b/packages/core/types/index.d.ts @@ -1,3 +1,33 @@ +export type MaybePromise = T | Promise + +/** + * BatchJob: BaseJob without scheduling fields (cron, repeat, delay, processAt) + */ +export type BatchJob = Omit< + BaseJob, + "cron" | "repeatEvery" | "repeatLimit" | "repeatCount" | "processAt" +> + +/** + * Function type for batch job handlers. + * + * @template TJobPayload Type of job payload + * @template TJobResult Type of return value + */ +export type BatchJobHandler = ( + jobs: BatchJobWithProgress[], +) => MaybePromise + +/** + * Batch job interface with progress update capability. + * + * @template TJobPayload Type of the job payload + * @template TJobResult Type of the job result + */ +export interface BatchJobWithProgress + extends BaseJob { + updateProgress(value: number): Promise +} // Using built-in TypeScript utility instead of type-fest type Simplify = { [K in keyof T]: T[K] } & {} @@ -114,6 +144,16 @@ export interface QueueConfig { readonly pollInterval?: number /** Delay in milliseconds between processing individual jobs (default: 10) */ readonly jobInterval?: number + + /** Batch processing configuration (optional) */ + readonly batch?: { + /** Minimum number of jobs before a batch is processed (default: 1) */ + minSize?: number + /** Maximum number of jobs per batch (default: 10) */ + maxSize?: number + /** Maximum wait time in ms before processing a batch, even if minSize is not reached (default: 30000) */ + waitFor?: number + } } /** @@ -164,6 +204,14 @@ export interface QueueAdapter { addJob( job: Omit, "id" | "createdAt">, ): Promise> + + /** Add multiple jobs in a single batch operation */ + addJobs( + jobs: Omit, "id" | "createdAt">[], + ): Promise[]> + + /** Retrieve up to `count` jobs for batch processing */ + getNextJobs(count: number): Promise getNextJob(): Promise updateJobStatus(id: string, status: JobStatus, error?: unknown, result?: unknown): Promise updateJobProgress(id: string, progress: number): Promise @@ -184,6 +232,12 @@ export interface QueueAdapter { * Events emitted by the queue during job processing. */ export interface QueueEvents { + /** Emitted when a batch of jobs is about to be processed */ + "batch:processing": BaseJob[] + /** Emitted when a batch of jobs completes successfully */ + "batch:completed": BaseJob[] + /** Emitted when a batch of jobs fails (includes error) */ + "batch:failed": { jobs: BaseJob[]; error: SerializedError } /** Emitted when a job is added to the queue */ "job:added": BaseJob /** Emitted when a job starts processing */ From 66c4848ab06f0a00590eea7dbc3bfbfdc580afa3 Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Wed, 24 Sep 2025 16:00:53 +0200 Subject: [PATCH 02/17] init changeset --- .changeset/sweet-oranges-cut.md | 43 +++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .changeset/sweet-oranges-cut.md diff --git a/.changeset/sweet-oranges-cut.md b/.changeset/sweet-oranges-cut.md new file mode 100644 index 0000000..3b7de54 --- /dev/null +++ b/.changeset/sweet-oranges-cut.md @@ -0,0 +1,43 @@ +--- +"@vorsteh-queue/core": minor +--- + +### Added + +- Batch processing support: You can now register batch handlers via `queue.registerBatch`, allowing the queue to process multiple jobs at once according to configurable batch sizes and timing. +- New batch configuration options: `minSize`, `maxSize`, and `waitFor` allow fine-grained control over when and how batches are processed. +- Type-safe batch jobs: Batch jobs are strictly separated from scheduled jobs and **do not support** cron, delay, or repeat options. +- Adapter API extended: All core adapters now support efficient batch operations. +- Events for batch lifecycle: The queue emits `batch:processing`, `batch:completed`, and `batch:failed` events for batch jobs. + +This enables efficient, high-throughput processing for workloads that benefit from batching, such as bulk database writes or external API calls. + +#### Example + +```ts +import { MemoryQueueAdapter, Queue } from "@vorsteh-queue/core" + +type EmailPayload = { to: string; body: string } +type EmailResult = { ok: true } + +const adapter = new MemoryQueueAdapter() +const queue = new Queue(adapter, { + name: "batch-demo", + batch: { minSize: 5, maxSize: 20, waitFor: 1000 }, +}) + +queue.registerBatch("send-emails", async (jobs) => { + // jobs is an array of up to 20 jobs + await sendBulkEmails(jobs.map((j) => j.payload)) + return jobs.map(() => ({ ok: true })) +}) + +// Add jobs as usual +await queue.addJobs("send-emails", [ + { to: "a@example.com", body: "Hi A" }, + { to: "b@example.com", body: "Hi B" }, + // ... +]) + +queue.start() +``` From 43ed8e54975421d768c8489345f3f04e99c4533c Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Wed, 24 Sep 2025 16:20:13 +0200 Subject: [PATCH 03/17] enhance job retrieval methods for batch processing and single job handling --- packages/core/src/adapters/base.ts | 4 +- packages/core/src/adapters/memory.ts | 1 - packages/core/src/core/queue.ts | 90 +++++++++++++++------------- 3 files changed, 50 insertions(+), 45 deletions(-) diff --git a/packages/core/src/adapters/base.ts b/packages/core/src/adapters/base.ts index cdde6d1..795a838 100644 --- a/packages/core/src/adapters/base.ts +++ b/packages/core/src/adapters/base.ts @@ -131,7 +131,9 @@ export abstract class BaseQueueAdapter implements QueueAdapter { } /** - * Get up to `count` jobs to process, considering priority and delayed jobs. + * Get up to `count` pending jobs for batch processing, ordered by priority and creation time. + * + * Only jobs with status "pending" are returned (delayed jobs are not included). * * @param count Maximum number of jobs to retrieve * @returns Promise resolving to an array of batch jobs (may be fewer than count) diff --git a/packages/core/src/adapters/memory.ts b/packages/core/src/adapters/memory.ts index 92cef71..4595e9e 100644 --- a/packages/core/src/adapters/memory.ts +++ b/packages/core/src/adapters/memory.ts @@ -54,7 +54,6 @@ export class MemoryQueueAdapter extends BaseQueueAdapter { const created: BatchJob[] = jobs.map((job) => { const id = this.generateId() const createdAt = new Date() - // Scheduling-Felder sind im BatchJob-Typ nicht enthalten const newJob: BatchJob = { ...job, id, diff --git a/packages/core/src/core/queue.ts b/packages/core/src/core/queue.ts index cdb5c70..4fb247e 100644 --- a/packages/core/src/core/queue.ts +++ b/packages/core/src/core/queue.ts @@ -258,7 +258,16 @@ export class Queue { this.isRunning = true this.isPaused = false this.stopped = false - void this.poll() + + const hasBatchHandlers = this.batchHandlers.size > 0 + const hasSingleHandlers = this.handlers.size > 0 || !hasBatchHandlers + + if (hasBatchHandlers) { + void this.pollBatchJobs() + } + if (hasSingleHandlers) { + void this.pollSingleJobs() + } } /** @@ -452,29 +461,17 @@ export class Queue { * @returns Promise that resolves when polling is stopped * @private */ - private async poll(): Promise { - const { concurrency, pollInterval, jobInterval } = this.config - + private async pollBatchJobs(): Promise { + const { concurrency, pollInterval } = this.config while (!this.stopped) { if (this.isPaused || this.activeJobs >= concurrency) { await waitFor(pollInterval) continue } - - let queueSize = await this.adapter.size() - if (queueSize === 0) { - await waitFor(pollInterval) - continue - } - - // Batch-Processing: Für jeden Batch-Handler werden bis zu maxSize Jobs gemeinsam verarbeitet const { minSize, maxSize } = this.getBatchConfig() const batchJobTypes = Array.from(this.batchHandlers.keys()) - - // Versuche für jeden Batch-Handler einen Batch zu holen und zu verarbeiten for (const type of batchJobTypes) { if (this.activeJobs >= concurrency) break - // Hole bis zu maxSize Jobs dieses Typs effizient per Adapter const jobs: BatchJob[] = (await this.adapter.getNextJobs(maxSize)).filter( (job) => job.name === type, ) @@ -489,53 +486,62 @@ export class Queue { }) } } + await waitFor(pollInterval) + } + } - // Normales Einzel-Job-Processing für alle anderen Jobs - while (queueSize > 0 && this.activeJobs < concurrency) { - this.activeJobs++ - setImmediate(() => { - void this.dequeueAndProcess() - .then((processed) => { - if (!processed) queueSize = 0 - else queueSize-- - }) - .catch((error) => { - this.emit("queue:error", error) - }) - .finally(() => { - this.activeJobs-- - }) - }) + private async pollSingleJobs(): Promise { + const { concurrency, pollInterval, jobInterval } = this.config + while (!this.stopped) { + if (this.isPaused || this.activeJobs >= concurrency) { + await waitFor(pollInterval) + continue + } + const nextJob = await this.adapter.getNextJob() + if (!nextJob) { + await waitFor(pollInterval) + continue + } + if (this.batchHandlers.has(nextJob.name)) { await waitFor(jobInterval) + continue } - await waitFor(jobInterval * 2) + this.activeJobs++ + setImmediate(() => { + void this.processJob(nextJob) + .catch((error) => { + this.emit("queue:error", error) + }) + .finally(() => { + this.activeJobs-- + }) + }) + await waitFor(jobInterval) } } + /** - * Interne Methode: Verarbeitet einen Batch von Jobs mit dem registrierten Batch-Handler. + * Internal method: Processes a batch of jobs using the registered batch handler. + * @private */ private async processBatchJobs(type: string, jobs: BatchJob[]): Promise { const handler = this.batchHandlers.get(type) if (!handler) return - // Status auf processing setzen und Wrapper erzeugen await Promise.all(jobs.map((job) => this.adapter.updateJobStatus(job.id, "processing"))) jobs.forEach((job) => { this.emit("job:processing", { ...job, status: "processing" } as BaseJob) }) - // Batch-Event: processing this.emit("batch:processing", jobs as BaseJob[]) - // Job-Wrapper mit updateProgress const wrappedJobs = jobs.map((job) => createJobWrapper(job as BaseJob, this)) try { const result = await handler(wrappedJobs) - // Ergebnisse auf Jobs mappen (optional) await Promise.all( jobs.map((job, i) => - this.adapter.updateJobStatus(job.id, "completed", undefined, result?.[i]), + this.adapter.updateJobStatus(job.id, "completed", undefined, result[i]), ), ) jobs.forEach((job, i) => { @@ -543,10 +549,10 @@ export class Queue { ...job, status: "completed", completedAt: new Date(), - result: result?.[i], + result: result[i], } as BaseJob) }) - // Batch-Event: completed + this.emit( "batch:completed", jobs.map( @@ -555,16 +561,14 @@ export class Queue { ...job, status: "completed", completedAt: new Date(), - result: result?.[i], + result: result[i], }) as BaseJob, ), ) await this.cleanupCompletedJob() } catch (error) { - // Fehlerbehandlung für alle Jobs im Batch const serializedError = serializeError(error) await Promise.all((jobs as BaseJob[]).map((job) => this.handleJobError(job, error))) - // Batch-Event: failed this.emit("batch:failed", { jobs: jobs as BaseJob[], error: serializedError }) } } From d86cad42117d17e3bda79c9dbee1bf6565f8dc0f Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Thu, 25 Sep 2025 09:27:25 +0200 Subject: [PATCH 04/17] implement exclusive handler registration for batch and single jobs; update job retrieval methods for specific handlers --- .changeset/sweet-oranges-cut.md | 2 ++ packages/core/src/adapters/base.ts | 7 +++---- packages/core/src/adapters/memory.ts | 4 ++-- packages/core/src/core/queue.ts | 28 ++++++++++++++++++++----- packages/core/tests/batch.test.ts | 24 +++++++++++++++++++++ packages/core/tests/error.test.ts | 31 ++++++++++++++++++++++++++++ packages/core/tests/queue.test.ts | 18 ++++++++++++++++ packages/core/types/index.d.ts | 4 ++-- 8 files changed, 105 insertions(+), 13 deletions(-) diff --git a/.changeset/sweet-oranges-cut.md b/.changeset/sweet-oranges-cut.md index 3b7de54..673537c 100644 --- a/.changeset/sweet-oranges-cut.md +++ b/.changeset/sweet-oranges-cut.md @@ -10,6 +10,8 @@ - Adapter API extended: All core adapters now support efficient batch operations. - Events for batch lifecycle: The queue emits `batch:processing`, `batch:completed`, and `batch:failed` events for batch jobs. +**Handler exclusivity:** A queue can handle only batch jobs or single jobs — not both. Attempting to register both handler types in the same queue will throw an error. This ensures clear and predictable processing. + This enables efficient, high-throughput processing for workloads that benefit from batching, such as bulk database writes or external API calls. #### Example diff --git a/packages/core/src/adapters/base.ts b/packages/core/src/adapters/base.ts index 795a838..4d2870a 100644 --- a/packages/core/src/adapters/base.ts +++ b/packages/core/src/adapters/base.ts @@ -131,14 +131,13 @@ export abstract class BaseQueueAdapter implements QueueAdapter { } /** - * Get up to `count` pending jobs for batch processing, ordered by priority and creation time. - * - * Only jobs with status "pending" are returned (delayed jobs are not included). + * Get up to `count` pending jobs for a specific handler (job name), ordered by priority and creation time. * + * @param handlerName Name of the registered handler (job name) * @param count Maximum number of jobs to retrieve * @returns Promise resolving to an array of batch jobs (may be fewer than count) */ - abstract getNextJobs(count: number): Promise + abstract getNextJobsForHandler(handlerName: string, count: number): Promise /** * Get a delayed job that is ready to be processed diff --git a/packages/core/src/adapters/memory.ts b/packages/core/src/adapters/memory.ts index 4595e9e..a156dda 100644 --- a/packages/core/src/adapters/memory.ts +++ b/packages/core/src/adapters/memory.ts @@ -175,9 +175,9 @@ export class MemoryQueueAdapter extends BaseQueueAdapter { return Promise.resolve(pendingJobs[0] ?? null) } - getNextJobs(count: number): Promise { + getNextJobsForHandler(handlerName: string, count: number): Promise { const pendingJobs = Array.from(this.jobs.values()) - .filter((job) => job.status === "pending") + .filter((job) => job.status === "pending" && job.name === handlerName) .sort((a, b) => { const priorityDiff = a.priority - b.priority return priorityDiff !== 0 ? priorityDiff : a.createdAt.getTime() - b.createdAt.getTime() diff --git a/packages/core/src/core/queue.ts b/packages/core/src/core/queue.ts index 4fb247e..e39f34f 100644 --- a/packages/core/src/core/queue.ts +++ b/packages/core/src/core/queue.ts @@ -97,6 +97,16 @@ export class Queue { name: string, handler: JobHandler, ): void { + if (this.handlers.has(name)) { + throw new Error( + `A handler for '${name}' is already registered in this queue. Handler names must be unique.`, + ) + } + if (this.batchHandlers.has(name)) { + throw new Error( + `Cannot register single job handler for '${name}': Batch handler already registered. Use either register or registerBatch, not both.`, + ) + } this.handlers.set(name, handler as JobHandler) } @@ -118,6 +128,16 @@ export class Queue { name: string, handler: BatchJobHandler, ): void { + if (this.batchHandlers.has(name)) { + throw new Error( + `A handler for '${name}' is already registered in this queue. Handler names must be unique.`, + ) + } + if (this.handlers.has(name)) { + throw new Error( + `Cannot register batch job handler for '${name}': Single job handler already registered. Use either register or registerBatch, not both.`, + ) + } this.batchHandlers.set(name, handler as BatchJobHandler) } @@ -470,15 +490,13 @@ export class Queue { } const { minSize, maxSize } = this.getBatchConfig() const batchJobTypes = Array.from(this.batchHandlers.keys()) - for (const type of batchJobTypes) { + for (const handlerName of batchJobTypes) { if (this.activeJobs >= concurrency) break - const jobs: BatchJob[] = (await this.adapter.getNextJobs(maxSize)).filter( - (job) => job.name === type, - ) + const jobs: BatchJob[] = await this.adapter.getNextJobsForHandler(handlerName, maxSize) if (jobs.length >= minSize) { this.activeJobs++ setImmediate(() => { - void this.processBatchJobs(type, jobs) + void this.processBatchJobs(handlerName, jobs) .catch((error) => this.emit("queue:error", error)) .finally(() => { this.activeJobs-- diff --git a/packages/core/tests/batch.test.ts b/packages/core/tests/batch.test.ts index 511956c..e243e04 100644 --- a/packages/core/tests/batch.test.ts +++ b/packages/core/tests/batch.test.ts @@ -5,6 +5,30 @@ import { MemoryQueueAdapter } from "../src/adapters/memory" import { Queue } from "../src/core/queue" describe("Queue Batch Processing", () => { + it("should process multiple batch job types with different handlers", async () => { + const fooBatches: BaseJob[][] = [] + const barBatches: BaseJob[][] = [] + queue.registerBatch("foo", (jobs) => { + fooBatches.push(jobs.map((j) => ({ ...j }))) + return jobs.map(() => ({ ok: "foo" })) + }) + queue.registerBatch("bar", (jobs) => { + barBatches.push(jobs.map((j) => ({ ...j }))) + return jobs.map(() => ({ ok: "bar" })) + }) + + await queue.addJobs("foo", [{ a: 1 }, { a: 2 }]) + await queue.addJobs("bar", [{ b: 1 }, { b: 2 }]) + queue.start() + await new Promise((resolve) => setTimeout(resolve, 100)) + + expect(fooBatches.length).toBe(1) + expect(barBatches.length).toBe(1) + expect(fooBatches[0]?.length).toBe(2) + expect(barBatches[0]?.length).toBe(2) + expect(fooBatches[0]?.every((j) => j.name === "foo")).toBe(true) + expect(barBatches[0]?.every((j) => j.name === "bar")).toBe(true) + }) let queue: Queue let adapter: MemoryQueueAdapter diff --git a/packages/core/tests/error.test.ts b/packages/core/tests/error.test.ts index 924daf2..45fed8d 100644 --- a/packages/core/tests/error.test.ts +++ b/packages/core/tests/error.test.ts @@ -1,5 +1,7 @@ import { describe, expect, it } from "vitest" +import { MemoryQueueAdapter } from "../src/adapters/memory" +import { Queue } from "../src/core/queue" import { serializeError } from "../src/utils/error" describe("serializeError", () => { @@ -61,3 +63,32 @@ describe("serializeError", () => { }) }) }) + +describe("Queue handler registration", () => { + it("should throw if registering the same single handler name twice", () => { + const queue = new Queue(new MemoryQueueAdapter(), { name: "unique-test" }) + queue.register("foo", () => Promise.resolve()) + expect(() => queue.register("foo", () => Promise.resolve())).toThrowError(/already registered/) + }) + + it("should throw if registering the same batch handler name twice", () => { + const queue = new Queue(new MemoryQueueAdapter(), { name: "unique-test" }) + queue.registerBatch("bar", () => Promise.resolve([])) + expect(() => queue.registerBatch("bar", () => Promise.resolve([]))).toThrowError( + /already registered/, + ) + }) + it("should throw if registering both single and batch handler for the same job name", () => { + const queue = new Queue(new MemoryQueueAdapter(), { name: "exclusive-test" }) + queue.register("foo", () => Promise.resolve()) + expect(() => queue.registerBatch("foo", () => Promise.resolve([]))).toThrowError( + /already registered/, + ) + }) + + it("should throw if registering both batch and single handler for the same job name (reverse order)", () => { + const queue = new Queue(new MemoryQueueAdapter(), { name: "exclusive-test" }) + queue.registerBatch("bar", () => Promise.resolve([])) + expect(() => queue.register("bar", () => Promise.resolve())).toThrowError(/already registered/) + }) +}) diff --git a/packages/core/tests/queue.test.ts b/packages/core/tests/queue.test.ts index 87b927e..e469fd0 100644 --- a/packages/core/tests/queue.test.ts +++ b/packages/core/tests/queue.test.ts @@ -63,6 +63,24 @@ describe("Queue", () => { }) describe("job processing", () => { + it("should process multiple job types with different handlers", async () => { + const fooHandler = vi.fn().mockResolvedValue({ foo: true }) + const barHandler = vi.fn().mockResolvedValue({ bar: true }) + queue.register("foo", fooHandler) + queue.register("bar", barHandler) + + await queue.connect() + await queue.add("foo", { data: 1 }) + await queue.add("bar", { data: 2 }) + queue.start() + + await waitFor(100) + + expect(fooHandler).toHaveBeenCalledTimes(1) + expect(barHandler).toHaveBeenCalledTimes(1) + + await queue.stop() + }) it("should process jobs", async () => { const handler = vi.fn().mockResolvedValue({ result: "success" }) queue.register("test-job", handler) diff --git a/packages/core/types/index.d.ts b/packages/core/types/index.d.ts index 716ea01..323e89e 100644 --- a/packages/core/types/index.d.ts +++ b/packages/core/types/index.d.ts @@ -198,6 +198,8 @@ export interface JobWithProgress * Provides database-agnostic job storage and retrieval. */ export interface QueueAdapter { + /** Retrieve up to `count` jobs for a specific handler (job name) for batch processing */ + getNextJobsForHandler(handlerName: string, count: number): Promise connect(): Promise disconnect(): Promise @@ -210,8 +212,6 @@ export interface QueueAdapter { jobs: Omit, "id" | "createdAt">[], ): Promise[]> - /** Retrieve up to `count` jobs for batch processing */ - getNextJobs(count: number): Promise getNextJob(): Promise updateJobStatus(id: string, status: JobStatus, error?: unknown, result?: unknown): Promise updateJobProgress(id: string, progress: number): Promise From a1875cec7db4ec827d9b2121bb62641ba32fe6db Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Thu, 25 Sep 2025 10:00:31 +0200 Subject: [PATCH 05/17] update result type in changeset example --- .changeset/sweet-oranges-cut.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.changeset/sweet-oranges-cut.md b/.changeset/sweet-oranges-cut.md index 673537c..54932e8 100644 --- a/.changeset/sweet-oranges-cut.md +++ b/.changeset/sweet-oranges-cut.md @@ -5,22 +5,20 @@ ### Added - Batch processing support: You can now register batch handlers via `queue.registerBatch`, allowing the queue to process multiple jobs at once according to configurable batch sizes and timing. -- New batch configuration options: `minSize`, `maxSize`, and `waitFor` allow fine-grained control over when and how batches are processed. -- Type-safe batch jobs: Batch jobs are strictly separated from scheduled jobs and **do not support** cron, delay, or repeat options. +- New `batch` configuration options: `minSize`, `maxSize`, and `waitFor` allow fine-grained control over when and how batches are processed. +- Type-safe batch jobs: Batch jobs are strictly separated from scheduled/single jobs and **do not support** cron, delay, or repeat options. - Adapter API extended: All core adapters now support efficient batch operations. - Events for batch lifecycle: The queue emits `batch:processing`, `batch:completed`, and `batch:failed` events for batch jobs. **Handler exclusivity:** A queue can handle only batch jobs or single jobs — not both. Attempting to register both handler types in the same queue will throw an error. This ensures clear and predictable processing. -This enables efficient, high-throughput processing for workloads that benefit from batching, such as bulk database writes or external API calls. - #### Example ```ts import { MemoryQueueAdapter, Queue } from "@vorsteh-queue/core" type EmailPayload = { to: string; body: string } -type EmailResult = { ok: true } +type EmailResult = { ok: boolean } const adapter = new MemoryQueueAdapter() const queue = new Queue(adapter, { From b18ec505e74b6a47f93942d2538a848ba59e6059 Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Thu, 25 Sep 2025 10:40:45 +0200 Subject: [PATCH 06/17] add batch functionality into adapters --- .changeset/fine-taxes-drive.md | 7 + .../adapter-drizzle/src/postgres-adapter.ts | 50 ++++++ .../adapter-kysely/src/postgres-adapter.ts | 70 ++++++++- packages/adapter-kysely/src/types.ts | 4 +- .../adapter-prisma/src/postgres-adapter.ts | 21 +++ packages/core/types/index.d.ts | 2 +- packages/shared-tests/src/tests/adapter.ts | 144 +++++++++++++++++- packages/shared-tests/src/types.ts | 4 +- 8 files changed, 293 insertions(+), 9 deletions(-) create mode 100644 .changeset/fine-taxes-drive.md diff --git a/.changeset/fine-taxes-drive.md b/.changeset/fine-taxes-drive.md new file mode 100644 index 0000000..59b14a1 --- /dev/null +++ b/.changeset/fine-taxes-drive.md @@ -0,0 +1,7 @@ +--- +"@vorsteh-queue/adapter-drizzle": minor +"@vorsteh-queue/adapter-kysely": minor +"@vorsteh-queue/adapter-prisma": minor +--- + +Added support for batch processing diff --git a/packages/adapter-drizzle/src/postgres-adapter.ts b/packages/adapter-drizzle/src/postgres-adapter.ts index 4caf61f..269a161 100644 --- a/packages/adapter-drizzle/src/postgres-adapter.ts +++ b/packages/adapter-drizzle/src/postgres-adapter.ts @@ -76,6 +76,32 @@ export class PostgresQueueAdapter extends BaseQueueAdapter { return this.transformJob(result) as BaseJob } + async addJobs( + jobs: readonly Omit, "id" | "createdAt">[], + ): Promise[]> { + if (!jobs.length) return [] + const values = jobs.map((job) => ({ + queueName: this.queueName, + name: job.name, + payload: job.payload, + status: job.status, + priority: job.priority, + attempts: job.attempts, + maxAttempts: job.maxAttempts, + processAt: sql`${job.processAt.toISOString()}::timestamptz`, + cron: job.cron, + repeatEvery: job.repeatEvery, + repeatLimit: job.repeatLimit, + repeatCount: job.repeatCount, + timeout: job.timeout, + })) + const results = await this.db.insert(schema.queueJobs).values(values).returning() + if (!results.length) { + throw new Error("Failed to create jobs") + } + return results.map((row) => this.transformJob(row) as BaseJob) + } + async updateJobStatus( id: string, status: JobStatus, @@ -198,6 +224,30 @@ export class PostgresQueueAdapter extends BaseQueueAdapter { return Number(result?.count ?? 0) } + async getNextJobsForHandler(handlerName: string, count: number) { + const jobs = await this.db + .select() + .from(schema.queueJobs) + .where( + and( + eq(schema.queueJobs.queueName, this.queueName), + eq(schema.queueJobs.status, "pending"), + eq(schema.queueJobs.name, handlerName), + ), + ) + .orderBy(asc(schema.queueJobs.priority), asc(schema.queueJobs.createdAt)) + .limit(count) + .for("update", { skipLocked: true }) + + // BatchJob omits scheduling fields, so we strip them + return jobs.map((job) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { cron, repeatEvery, repeatLimit, repeatCount, processAt, ...rest } = + this.transformJob(job) + return rest + }) + } + async transaction(fn: () => Promise): Promise { return this.db.transaction(async () => fn()) } diff --git a/packages/adapter-kysely/src/postgres-adapter.ts b/packages/adapter-kysely/src/postgres-adapter.ts index 891b4c9..5fa2a38 100644 --- a/packages/adapter-kysely/src/postgres-adapter.ts +++ b/packages/adapter-kysely/src/postgres-adapter.ts @@ -4,7 +4,7 @@ import { sql } from "kysely" import type { BaseJob, JobStatus, QueueStats, SerializedError } from "@vorsteh-queue/core" import { asUtc, BaseQueueAdapter, serializeError } from "@vorsteh-queue/core" -import type { DB, QueueJob } from "./types" +import type { DB, InsertQueueJobValue, QueueJob } from "./types" /** * PostgreSQL adapter for the queue system using Drizzle ORM. @@ -103,6 +103,40 @@ export class PostgresQueueAdapter extends BaseQueueAdapter { return this.transformJob(result) as BaseJob } + async addJobs( + jobs: readonly Omit, "id" | "createdAt">[], + ): Promise[]> { + if (!jobs.length) return [] + + const values: InsertQueueJobValue[] = jobs.map((job) => ({ + queue_name: this.queueName, + name: job.name, + payload: job.payload, + status: job.status, + priority: job.priority, + attempts: job.attempts, + max_attempts: job.maxAttempts, + process_at: sql`${job.processAt.toISOString()}::timestamptz`, + cron: job.cron, + repeat_every: job.repeatEvery, + repeat_limit: job.repeatLimit, + repeat_count: job.repeatCount, + timeout: job.timeout, + })) + + const results = await this.customDbClient + .insertInto("queue_jobs") + .values(values) + .returningAll() + .execute() + + if (!results.length) { + throw new Error("Failed to create jobs") + } + + return results.map((row) => this.transformJob(row) as BaseJob) + } + async updateJobStatus( id: string, status: JobStatus, @@ -221,6 +255,40 @@ export class PostgresQueueAdapter extends BaseQueueAdapter { return Number(result?.count ?? 0) } + async getNextJobsForHandler(handlerName: string, count: number) { + const jobs = await this.customDbClient + .selectFrom("queue_jobs") + .selectAll() + .where("queue_name", "=", this.queueName) + .where("status", "=", "pending") + .where("name", "=", handlerName) + .orderBy("priority", "asc") + .orderBy("created_at", "asc") + .limit(count) + .forUpdate() + .skipLocked() + .execute() + + // BatchJob omits scheduling fields, so we strip them + return jobs.map((job) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { cron, repeat_every, repeat_limit, repeat_count, process_at, ...rest } = job + return { + ...rest, + maxAttempts: job.max_attempts, + createdAt: job.created_at, + processAt: job.process_at, + processedAt: job.processed_at ?? undefined, + completedAt: job.completed_at ?? undefined, + failedAt: job.failed_at ?? undefined, + error: job.error as SerializedError | undefined, + result: job.result, + progress: job.progress ?? 0, + // Remove scheduling fields for BatchJob + } + }) + } + async transaction(fn: () => Promise): Promise { return this.customDbClient.transaction().execute(async () => fn()) } diff --git a/packages/adapter-kysely/src/types.ts b/packages/adapter-kysely/src/types.ts index 422ade2..f2afdfb 100644 --- a/packages/adapter-kysely/src/types.ts +++ b/packages/adapter-kysely/src/types.ts @@ -1,4 +1,4 @@ -import type { ColumnType, Insertable, Selectable, Updateable } from "kysely" +import type { ColumnType, Insertable, InsertObject, Selectable, Updateable } from "kysely" type Generated = T extends ColumnType @@ -37,3 +37,5 @@ export type QueueJobUpdate = Updateable export interface DB { queue_jobs: QueueJobTableDefinition } + +export type InsertQueueJobValue = InsertObject diff --git a/packages/adapter-prisma/src/postgres-adapter.ts b/packages/adapter-prisma/src/postgres-adapter.ts index b3869eb..82d3c72 100644 --- a/packages/adapter-prisma/src/postgres-adapter.ts +++ b/packages/adapter-prisma/src/postgres-adapter.ts @@ -242,6 +242,27 @@ export class PostgresPrismaQueueAdapter extends BaseQueueAdapter { timeout: job.timeout as number | false | undefined, } } + + async getNextJobsForHandler(handlerName: string, count: number) { + // Use raw SQL with SKIP LOCKED for concurrency safety + const result = await this.db.$queryRaw` + SELECT * FROM queue_jobs + WHERE queue_name = ${this.queueName} + AND status = 'pending' + AND name = ${handlerName} + ORDER BY priority ASC, created_at ASC + LIMIT ${count} + FOR UPDATE SKIP LOCKED + ` + const transformed = result.map(mapKeysToCamelCase) + // BatchJob omits scheduling fields, so we strip them + return transformed.map((job: QueueJob) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { cron, repeatEvery, repeatLimit, repeatCount, processAt, ...rest } = + this.transformJob(job) + return rest + }) + } } function toCamelCaseKey(key: string): string { diff --git a/packages/core/types/index.d.ts b/packages/core/types/index.d.ts index 323e89e..0ddd725 100644 --- a/packages/core/types/index.d.ts +++ b/packages/core/types/index.d.ts @@ -225,7 +225,7 @@ export interface QueueAdapter { transaction(fn: () => Promise): Promise /** @internal Set the queue name for job isolation */ - setQueueName?(queueName: string): void + setQueueName(queueName: string): void } /** diff --git a/packages/shared-tests/src/tests/adapter.ts b/packages/shared-tests/src/tests/adapter.ts index c4df581..0c85222 100644 --- a/packages/shared-tests/src/tests/adapter.ts +++ b/packages/shared-tests/src/tests/adapter.ts @@ -1,7 +1,7 @@ import postgres from "postgres" import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest" -import type { BaseQueueAdapter } from "@vorsteh-queue/core" +import type { QueueAdapter } from "@vorsteh-queue/core" import type { SharedTestContext } from "../types" import { initDatabase } from "../database" @@ -10,7 +10,7 @@ export function runTests(ctx: SharedTestContext) describe("Adapter Tests", () => { let database: Awaited> let db: ReturnType["initDbClient"]> - let adapter: BaseQueueAdapter + let adapter: QueueAdapter // the internal db client is based on postgres.js and will be used // to directly query the database for verification purposes @@ -53,6 +53,144 @@ export function runTests(ctx: SharedTestContext) adapter.setQueueName("test-queue") }) + describe("batch operations", () => { + it("should add multiple jobs with addJobs", async () => { + const jobs = await adapter.addJobs([ + { + name: "batch-job-1", + payload: { n: 1 }, + status: "pending", + priority: 1, + attempts: 0, + maxAttempts: 2, + }, + { + name: "batch-job-2", + payload: { n: 2 }, + status: "pending", + priority: 2, + attempts: 0, + maxAttempts: 2, + }, + ]) + expect(jobs).toHaveLength(2) + if (jobs.length >= 2) { + const [job0, job1] = jobs + expect(job0).toBeDefined() + expect(job1).toBeDefined() + if (job0 && job1) { + expect(job0.id).toBeDefined() + expect(job1.id).toBeDefined() + expect(job0.name).toBe("batch-job-1") + expect(job1.name).toBe("batch-job-2") + } + } + }) + + it("should get next jobs for handler (batch)", async () => { + await adapter.addJobs([ + { + name: "batch-handler", + payload: { n: 1 }, + status: "pending", + priority: 1, + attempts: 0, + maxAttempts: 2, + }, + { + name: "batch-handler", + payload: { n: 2 }, + status: "pending", + priority: 2, + attempts: 0, + maxAttempts: 2, + }, + { + name: "other-handler", + payload: { n: 3 }, + status: "pending", + priority: 3, + attempts: 0, + maxAttempts: 2, + }, + ]) + const jobs = await adapter.getNextJobsForHandler("batch-handler", 5) + expect(jobs).toHaveLength(2) + if (jobs.length >= 2) { + const [job0, job1] = jobs + expect(job0).toBeDefined() + expect(job1).toBeDefined() + if (job0 && job1) { + expect(job0.name).toBe("batch-handler") + expect(job1.name).toBe("batch-handler") + // Should be sorted by priority + expect(job0.priority).toBeLessThanOrEqual(job1.priority) + } + } + }) + + it("should respect batch size limit", async () => { + await adapter.addJobs([ + { + name: "batch", + payload: { n: 1 }, + status: "pending", + priority: 1, + attempts: 0, + maxAttempts: 2, + }, + { + name: "batch", + payload: { n: 2 }, + status: "pending", + priority: 2, + attempts: 0, + maxAttempts: 2, + }, + { + name: "batch", + payload: { n: 3 }, + status: "pending", + priority: 3, + attempts: 0, + maxAttempts: 2, + }, + ]) + const jobs = await adapter.getNextJobsForHandler("batch", 2) + expect(jobs).toHaveLength(2) + }) + + it("should isolate jobs by handler name", async () => { + await adapter.addJobs([ + { + name: "handler-a", + payload: {}, + status: "pending", + priority: 1, + attempts: 0, + maxAttempts: 2, + }, + { + name: "handler-b", + payload: {}, + status: "pending", + priority: 2, + attempts: 0, + maxAttempts: 2, + }, + ]) + const jobsA = await adapter.getNextJobsForHandler("handler-a", 5) + const jobsB = await adapter.getNextJobsForHandler("handler-b", 5) + expect(jobsA.every((j) => j.name === "handler-a")).toBe(true) + expect(jobsB.every((j) => j.name === "handler-b")).toBe(true) + }) + + it("should return empty array if no jobs for handler", async () => { + const jobs = await adapter.getNextJobsForHandler("nonexistent-handler", 3) + expect(jobs).toEqual([]) + }) + }) + describe("basic operations", () => { it("should add a job", async () => { const job = await adapter.addJob({ @@ -303,8 +441,6 @@ export function runTests(ctx: SharedTestContext) const [updated]: [{ result: unknown; status: string }?] = await internalDbClient`SELECT result, status FROM queue_jobs WHERE id=${job.id}` - console.dir({ updated }) - expect(updated?.result).toEqual(result) expect(updated?.status).toBe("completed") }) diff --git a/packages/shared-tests/src/types.ts b/packages/shared-tests/src/types.ts index b559cd5..e414f15 100644 --- a/packages/shared-tests/src/types.ts +++ b/packages/shared-tests/src/types.ts @@ -1,4 +1,4 @@ -import type { BaseQueueAdapter } from "@vorsteh-queue/core" +import type { QueueAdapter } from "@vorsteh-queue/core" import type { initDatabase } from "./database" @@ -9,6 +9,6 @@ export type DatabaseConnectionProps = Awaited> export interface SharedTestContext { initDbClient: (props: DatabaseConnectionProps) => TDatabase - initAdapter: (db: TDatabase) => Promise | BaseQueueAdapter + initAdapter: (db: TDatabase) => Promise | QueueAdapter migrate: (db: TDatabase) => Promise } From bc536c9b953d18a8e3169bb4978cb93f228fa625 Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Thu, 25 Sep 2025 10:43:59 +0200 Subject: [PATCH 07/17] update deps --- apps/docs/package.json | 10 +- examples/drizzle-pglite/package.json | 2 +- examples/pm2-workers/package.json | 2 +- examples/result-storage/package.json | 2 +- package.json | 2 +- packages/adapter-drizzle/package.json | 4 +- packages/adapter-kysely/package.json | 4 +- packages/adapter-prisma/package.json | 2 +- packages/core/package.json | 2 +- packages/create-vorsteh-queue/package.json | 2 +- pnpm-lock.yaml | 619 +++++++++++---------- tooling/eslint/package.json | 8 +- 12 files changed, 338 insertions(+), 321 deletions(-) diff --git a/apps/docs/package.json b/apps/docs/package.json index 6cd349b..bfa7ee9 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -22,7 +22,7 @@ "@mdx-js/loader": "3.1.1", "@mdx-js/node-loader": "3.1.1", "@mdx-js/react": "3.1.1", - "@next/mdx": "15.5.3", + "@next/mdx": "15.5.4", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-dialog": "^1.1.15", @@ -41,7 +41,7 @@ "interweave": "13.1.1", "lucide-react": "0.544.0", "multimatch": "7.0.0", - "next": "15.5.3", + "next": "15.5.4", "next-themes": "latest", "p-map": "7.0.3", "react": "19.1.1", @@ -53,17 +53,17 @@ "remark-mdx-frontmatter": "5.2.0", "remark-squeeze-paragraphs": "6.0.0", "remark-strip-badges": "7.0.0", - "renoun": "10.1.0", + "renoun": "10.1.2", "tm-grammars": "1.24.13", "tm-themes": "1.10.9", "ts-morph": "27.0.0", - "tw-animate-css": "^1.3.8", + "tw-animate-css": "^1.4.0", "use-debounce": "10.0.6", "zod": "4.1.11" }, "devDependencies": { "@tailwindcss/postcss": "4.1.13", - "@tailwindcss/typography": "0.5.18", + "@tailwindcss/typography": "0.5.19", "@types/mdx": "2.0.13", "@types/node": "22.18.6", "@types/react": "19.1.13", diff --git a/examples/drizzle-pglite/package.json b/examples/drizzle-pglite/package.json index aa377fb..02e15b7 100644 --- a/examples/drizzle-pglite/package.json +++ b/examples/drizzle-pglite/package.json @@ -9,7 +9,7 @@ "db:push": "drizzle-kit push" }, "dependencies": { - "@electric-sql/pglite": "^0.3.8", + "@electric-sql/pglite": "^0.3.10", "@vorsteh-queue/adapter-drizzle": "workspace:*", "@vorsteh-queue/core": "workspace:*", "drizzle-orm": "^0.44.5" diff --git a/examples/pm2-workers/package.json b/examples/pm2-workers/package.json index d80dfca..86f5014 100644 --- a/examples/pm2-workers/package.json +++ b/examples/pm2-workers/package.json @@ -25,7 +25,7 @@ "devDependencies": { "dotenv-cli": "10.0.0", "drizzle-kit": "^0.31.4", - "pm2": "6.0.11", + "pm2": "6.0.13", "tsx": "4.20.5", "typescript": "^5.9.2" } diff --git a/examples/result-storage/package.json b/examples/result-storage/package.json index 1b84441..254b958 100644 --- a/examples/result-storage/package.json +++ b/examples/result-storage/package.json @@ -9,7 +9,7 @@ "db:push": "drizzle-kit push" }, "dependencies": { - "@electric-sql/pglite": "^0.3.8", + "@electric-sql/pglite": "^0.3.10", "@vorsteh-queue/adapter-drizzle": "workspace:*", "@vorsteh-queue/core": "workspace:*", "drizzle-orm": "^0.44.5" diff --git a/package.json b/package.json index bd0fe99..3906b73 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@vorsteh-queue/prettier-config": "workspace:*", "prettier": "^3.6.2", "sherif": "1.6.1", - "turbo": "2.5.6", + "turbo": "2.5.8", "typescript": "^5.9.2", "vite-tsconfig-paths": "^5.1.4", "vitest": "^3.2.4" diff --git a/packages/adapter-drizzle/package.json b/packages/adapter-drizzle/package.json index a4cbe2f..6603f1b 100644 --- a/packages/adapter-drizzle/package.json +++ b/packages/adapter-drizzle/package.json @@ -67,7 +67,7 @@ "@vorsteh-queue/core": "workspace:*" }, "devDependencies": { - "@electric-sql/pglite": "^0.3.8", + "@electric-sql/pglite": "^0.3.10", "@vorsteh-queue/eslint-config": "workspace:*", "@vorsteh-queue/prettier-config": "workspace:*", "@vorsteh-queue/shared-tests": "workspace:*", @@ -77,7 +77,7 @@ "eslint": "^9.36.0", "postgres": "^3.4.7", "prettier": "^3.6.2", - "rolldown": "1.0.0-beta.38", + "rolldown": "1.0.0-beta.40", "rollup-plugin-delete": "^3.0.1", "typescript": "^5.9.2", "vitest": "^3.2.4" diff --git a/packages/adapter-kysely/package.json b/packages/adapter-kysely/package.json index af1c28b..2f443ce 100644 --- a/packages/adapter-kysely/package.json +++ b/packages/adapter-kysely/package.json @@ -70,7 +70,7 @@ "@vorsteh-queue/core": "workspace:*" }, "devDependencies": { - "@electric-sql/pglite": "^0.3.8", + "@electric-sql/pglite": "^0.3.10", "@vorsteh-queue/eslint-config": "workspace:*", "@vorsteh-queue/prettier-config": "workspace:*", "@vorsteh-queue/shared-tests": "workspace:*", @@ -81,7 +81,7 @@ "kysely-postgres-js": "^3.0.0", "postgres": "^3.4.7", "prettier": "^3.6.2", - "rolldown": "1.0.0-beta.38", + "rolldown": "1.0.0-beta.40", "rollup-plugin-delete": "^3.0.1", "typescript": "^5.9.2", "vitest": "^3.2.4" diff --git a/packages/adapter-prisma/package.json b/packages/adapter-prisma/package.json index 47f8981..ff3232f 100644 --- a/packages/adapter-prisma/package.json +++ b/packages/adapter-prisma/package.json @@ -68,7 +68,7 @@ "eslint": "^9.36.0", "prettier": "^3.6.2", "prisma": "^6.16.2", - "rolldown": "1.0.0-beta.38", + "rolldown": "1.0.0-beta.40", "rollup-plugin-delete": "^3.0.1", "testcontainers": "^11.6.0", "typescript": "^5.9.2", diff --git a/packages/core/package.json b/packages/core/package.json index 4bf990d..5480240 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -72,7 +72,7 @@ "@vorsteh-queue/prettier-config": "workspace:*", "@vorsteh-queue/tsconfig": "workspace:*", "eslint": "^9.36.0", - "rolldown": "1.0.0-beta.38", + "rolldown": "1.0.0-beta.40", "rollup-plugin-delete": "^3.0.1", "typescript": "^5.9.2", "vitest": "^3.2.4" diff --git a/packages/create-vorsteh-queue/package.json b/packages/create-vorsteh-queue/package.json index 0df9358..297b9fb 100644 --- a/packages/create-vorsteh-queue/package.json +++ b/packages/create-vorsteh-queue/package.json @@ -49,7 +49,7 @@ "@vorsteh-queue/tsconfig": "workspace:*", "eslint": "^9.36.0", "prettier": "^3.6.2", - "rolldown": "1.0.0-beta.38", + "rolldown": "1.0.0-beta.40", "rollup-plugin-delete": "^3.0.1", "tsx": "4.20.5", "typescript": "^5.9.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8240370..6e565a7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,8 +27,8 @@ importers: specifier: 1.6.1 version: 1.6.1 turbo: - specifier: 2.5.6 - version: 2.5.6 + specifier: 2.5.8 + version: 2.5.8 typescript: specifier: ^5.9.2 version: 5.9.2 @@ -54,8 +54,8 @@ importers: specifier: 3.1.1 version: 3.1.1(@types/react@19.1.13)(react@19.1.1) '@next/mdx': - specifier: 15.5.3 - version: 15.5.3(@mdx-js/loader@3.1.1)(@mdx-js/react@3.1.1(@types/react@19.1.13)(react@19.1.1)) + specifier: 15.5.4 + version: 15.5.4(@mdx-js/loader@3.1.1)(@mdx-js/react@3.1.1(@types/react@19.1.13)(react@19.1.1)) '@radix-ui/react-collapsible': specifier: ^1.1.12 version: 1.1.12(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -111,8 +111,8 @@ importers: specifier: 7.0.0 version: 7.0.0 next: - specifier: 15.5.3 - version: 15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + specifier: 15.5.4 + version: 15.5.4(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) next-themes: specifier: latest version: 0.4.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -147,8 +147,8 @@ importers: specifier: 7.0.0 version: 7.0.0 renoun: - specifier: 10.1.0 - version: 10.1.0(prettier@3.6.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(tm-grammars@1.24.13)(tm-themes@1.10.9) + specifier: 10.1.2 + version: 10.1.2(prettier@3.6.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(tm-grammars@1.24.13)(tm-themes@1.10.9) tm-grammars: specifier: 1.24.13 version: 1.24.13 @@ -159,8 +159,8 @@ importers: specifier: 27.0.0 version: 27.0.0 tw-animate-css: - specifier: ^1.3.8 - version: 1.3.8 + specifier: ^1.4.0 + version: 1.4.0 use-debounce: specifier: 10.0.6 version: 10.0.6(react@19.1.1) @@ -172,8 +172,8 @@ importers: specifier: 4.1.13 version: 4.1.13 '@tailwindcss/typography': - specifier: 0.5.18 - version: 0.5.18(tailwindcss@4.1.13) + specifier: 0.5.19 + version: 0.5.19(tailwindcss@4.1.13) '@types/mdx': specifier: 2.0.13 version: 2.0.13 @@ -251,7 +251,7 @@ importers: version: link:../../packages/core drizzle-orm: specifier: ^0.44.5 - version: 0.44.5(@electric-sql/pglite@0.3.8)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)) + version: 0.44.5(@electric-sql/pglite@0.3.10)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)) pg: specifier: 8.16.3 version: 8.16.3 @@ -272,8 +272,8 @@ importers: examples/drizzle-pglite: dependencies: '@electric-sql/pglite': - specifier: ^0.3.8 - version: 0.3.8 + specifier: ^0.3.10 + version: 0.3.10 '@vorsteh-queue/adapter-drizzle': specifier: workspace:* version: link:../../packages/adapter-drizzle @@ -282,7 +282,7 @@ importers: version: link:../../packages/core drizzle-orm: specifier: ^0.44.5 - version: 0.44.5(@electric-sql/pglite@0.3.8)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)) + version: 0.44.5(@electric-sql/pglite@0.3.10)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)) devDependencies: '@types/node': specifier: 22.18.6 @@ -304,7 +304,7 @@ importers: version: link:../../packages/core drizzle-orm: specifier: ^0.44.5 - version: 0.44.5(@electric-sql/pglite@0.3.8)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)) + version: 0.44.5(@electric-sql/pglite@0.3.10)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)) postgres: specifier: ^3.4.7 version: 3.4.7 @@ -332,7 +332,7 @@ importers: version: link:../../packages/core drizzle-orm: specifier: ^0.44.5 - version: 0.44.5(@electric-sql/pglite@0.3.8)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)) + version: 0.44.5(@electric-sql/pglite@0.3.10)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)) postgres: specifier: ^3.4.7 version: 3.4.7 @@ -388,7 +388,7 @@ importers: version: link:../../packages/core drizzle-orm: specifier: ^0.44.5 - version: 0.44.5(@electric-sql/pglite@0.3.8)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)) + version: 0.44.5(@electric-sql/pglite@0.3.10)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)) postgres: specifier: ^3.4.7 version: 3.4.7 @@ -400,8 +400,8 @@ importers: specifier: ^0.31.4 version: 0.31.4 pm2: - specifier: 6.0.11 - version: 6.0.11 + specifier: 6.0.13 + version: 6.0.13 tsx: specifier: 4.20.5 version: 4.20.5 @@ -472,7 +472,7 @@ importers: version: link:../../packages/core drizzle-orm: specifier: ^0.44.5 - version: 0.44.5(@electric-sql/pglite@0.3.8)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)) + version: 0.44.5(@electric-sql/pglite@0.3.10)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)) postgres: specifier: ^3.4.7 version: 3.4.7 @@ -490,8 +490,8 @@ importers: examples/result-storage: dependencies: '@electric-sql/pglite': - specifier: ^0.3.8 - version: 0.3.8 + specifier: ^0.3.10 + version: 0.3.10 '@vorsteh-queue/adapter-drizzle': specifier: workspace:* version: link:../../packages/adapter-drizzle @@ -500,7 +500,7 @@ importers: version: link:../../packages/core drizzle-orm: specifier: ^0.44.5 - version: 0.44.5(@electric-sql/pglite@0.3.8)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)) + version: 0.44.5(@electric-sql/pglite@0.3.10)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)) devDependencies: drizzle-kit: specifier: ^0.31.4 @@ -519,8 +519,8 @@ importers: version: link:../core devDependencies: '@electric-sql/pglite': - specifier: ^0.3.8 - version: 0.3.8 + specifier: ^0.3.10 + version: 0.3.10 '@vorsteh-queue/eslint-config': specifier: workspace:* version: link:../../tooling/eslint @@ -538,7 +538,7 @@ importers: version: 0.31.4 drizzle-orm: specifier: ^0.44.5 - version: 0.44.5(@electric-sql/pglite@0.3.8)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)) + version: 0.44.5(@electric-sql/pglite@0.3.10)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)) eslint: specifier: ^9.36.0 version: 9.36.0(jiti@2.5.1) @@ -549,8 +549,8 @@ importers: specifier: ^3.6.2 version: 3.6.2 rolldown: - specifier: 1.0.0-beta.38 - version: 1.0.0-beta.38 + specifier: 1.0.0-beta.40 + version: 1.0.0-beta.40 rollup-plugin-delete: specifier: ^3.0.1 version: 3.0.1(rollup@4.45.1) @@ -568,8 +568,8 @@ importers: version: link:../core devDependencies: '@electric-sql/pglite': - specifier: ^0.3.8 - version: 0.3.8 + specifier: ^0.3.10 + version: 0.3.10 '@vorsteh-queue/eslint-config': specifier: workspace:* version: link:../../tooling/eslint @@ -601,8 +601,8 @@ importers: specifier: ^3.6.2 version: 3.6.2 rolldown: - specifier: 1.0.0-beta.38 - version: 1.0.0-beta.38 + specifier: 1.0.0-beta.40 + version: 1.0.0-beta.40 rollup-plugin-delete: specifier: ^3.0.1 version: 3.0.1(rollup@4.45.1) @@ -653,8 +653,8 @@ importers: specifier: ^6.16.2 version: 6.16.2(magicast@0.3.5)(typescript@5.9.2) rolldown: - specifier: 1.0.0-beta.38 - version: 1.0.0-beta.38 + specifier: 1.0.0-beta.40 + version: 1.0.0-beta.40 rollup-plugin-delete: specifier: ^3.0.1 version: 3.0.1(rollup@4.45.1) @@ -693,8 +693,8 @@ importers: specifier: ^9.36.0 version: 9.36.0(jiti@2.5.1) rolldown: - specifier: 1.0.0-beta.38 - version: 1.0.0-beta.38 + specifier: 1.0.0-beta.40 + version: 1.0.0-beta.40 rollup-plugin-delete: specifier: ^3.0.1 version: 3.0.1(rollup@4.45.1) @@ -745,8 +745,8 @@ importers: specifier: ^3.6.2 version: 3.6.2 rolldown: - specifier: 1.0.0-beta.38 - version: 1.0.0-beta.38 + specifier: 1.0.0-beta.40 + version: 1.0.0-beta.40 rollup-plugin-delete: specifier: ^3.0.1 version: 3.0.1(rollup@4.45.1) @@ -793,17 +793,17 @@ importers: tooling/eslint: dependencies: '@eslint/compat': - specifier: 1.3.2 - version: 1.3.2(eslint@9.36.0(jiti@2.5.1)) + specifier: 1.4.0 + version: 1.4.0(eslint@9.36.0(jiti@2.5.1)) '@next/eslint-plugin-next': - specifier: 15.5.3 - version: 15.5.3 + specifier: 15.5.4 + version: 15.5.4 eslint-config-turbo: - specifier: 2.5.6 - version: 2.5.6(eslint@9.36.0(jiti@2.5.1))(turbo@2.5.6) + specifier: 2.5.8 + version: 2.5.8(eslint@9.36.0(jiti@2.5.1))(turbo@2.5.8) eslint-plugin-import: specifier: 2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.36.0(jiti@2.5.1)) + version: 2.32.0(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.36.0(jiti@2.5.1)) eslint-plugin-package-json: specifier: 0.56.3 version: 0.56.3(@types/estree@1.0.8)(eslint@9.36.0(jiti@2.5.1))(jsonc-eslint-parser@2.4.1) @@ -817,8 +817,8 @@ importers: specifier: 2.4.1 version: 2.4.1 typescript-eslint: - specifier: 8.44.0 - version: 8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) + specifier: 8.44.1 + version: 8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) devDependencies: '@eslint/js': specifier: 9.36.0 @@ -1007,8 +1007,8 @@ packages: '@drizzle-team/brocli@0.10.2': resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} - '@electric-sql/pglite@0.3.8': - resolution: {integrity: sha512-VlAz/R7mktifp9IHzNvjxWJM8p3fPH2lHpustYuRSOXOpXiAMTlA5qqxcufPaDnfee6CZCE9qrT1MHDT7riSHg==} + '@electric-sql/pglite@0.3.10': + resolution: {integrity: sha512-1XtXXprd848aR4hvjNqBc3Gc86zNGmd60x+MgOUShbHYxt+J76N8A81DqTEl275T8xBD0vdTgqR/dJ4yJyz0NQ==} '@emnapi/core@1.5.0': resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==} @@ -1481,8 +1481,8 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/compat@1.3.2': - resolution: {integrity: sha512-jRNwzTbd6p2Rw4sZ1CgWRS8YMtqG15YyZf7zvb6gY2rB2u6n+2Z+ELW0GtL0fQgyl0pr4Y/BzBfng/BdsereRA==} + '@eslint/compat@1.4.0': + resolution: {integrity: sha512-DEzm5dKeDBPm3r08Ixli/0cmxr8LkRdwxMRUIJBlSCpAwSrvFEJpVBzV+66JhDxiaqKxnRzCXhtiMiczF7Hglg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.40 || 9 @@ -1502,6 +1502,10 @@ packages: resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/core@0.16.0': + resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/eslintrc@3.3.1': resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1845,14 +1849,14 @@ packages: '@napi-rs/wasm-runtime@1.0.5': resolution: {integrity: sha512-TBr9Cf9onSAS2LQ2+QHx6XcC6h9+RIzJgbqG3++9TUZSH204AwEy5jg3BTQ0VATsyoGj4ee49tN/y6rvaOOtcg==} - '@next/env@15.5.3': - resolution: {integrity: sha512-RSEDTRqyihYXygx/OJXwvVupfr9m04+0vH8vyy0HfZ7keRto6VX9BbEk0J2PUk0VGy6YhklJUSrgForov5F9pw==} + '@next/env@15.5.4': + resolution: {integrity: sha512-27SQhYp5QryzIT5uO8hq99C69eLQ7qkzkDPsk3N+GuS2XgOgoYEeOav7Pf8Tn4drECOVDsDg8oj+/DVy8qQL2A==} - '@next/eslint-plugin-next@15.5.3': - resolution: {integrity: sha512-SdhaKdko6dpsSr0DldkESItVrnPYB1NS2NpShCSX5lc7SSQmLZt5Mug6t2xbiuVWEVDLZSuIAoQyYVBYp0dR5g==} + '@next/eslint-plugin-next@15.5.4': + resolution: {integrity: sha512-SR1vhXNNg16T4zffhJ4TS7Xn7eq4NfKfcOsRwea7RIAHrjRpI9ALYbamqIJqkAhowLlERffiwk0FMvTLNdnVtw==} - '@next/mdx@15.5.3': - resolution: {integrity: sha512-tpD3sdWfAiqjqD1WXL4ZEpxswXdbeoTQjlgvDzbQOxDr37qaAo9bFkpMVb3P3pgAJAQ9Q6w1Yql6YtOsmgZrzg==} + '@next/mdx@15.5.4': + resolution: {integrity: sha512-QUc14KkswCau2/Lul13t13v8QYRiEh3aeyUMUix5mK/Zd8c/J9NQuVvLGhxS7fxGPU+fOcv0GaXqZshkvNaX7A==} peerDependencies: '@mdx-js/loader': '>=0.15.0' '@mdx-js/react': '>=0.15.0' @@ -1862,50 +1866,50 @@ packages: '@mdx-js/react': optional: true - '@next/swc-darwin-arm64@15.5.3': - resolution: {integrity: sha512-nzbHQo69+au9wJkGKTU9lP7PXv0d1J5ljFpvb+LnEomLtSbJkbZyEs6sbF3plQmiOB2l9OBtN2tNSvCH1nQ9Jg==} + '@next/swc-darwin-arm64@15.5.4': + resolution: {integrity: sha512-nopqz+Ov6uvorej8ndRX6HlxCYWCO3AHLfKK2TYvxoSB2scETOcfm/HSS3piPqc3A+MUgyHoqE6je4wnkjfrOA==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.5.3': - resolution: {integrity: sha512-w83w4SkOOhekJOcA5HBvHyGzgV1W/XvOfpkrxIse4uPWhYTTRwtGEM4v/jiXwNSJvfRvah0H8/uTLBKRXlef8g==} + '@next/swc-darwin-x64@15.5.4': + resolution: {integrity: sha512-QOTCFq8b09ghfjRJKfb68kU9k2K+2wsC4A67psOiMn849K9ZXgCSRQr0oVHfmKnoqCbEmQWG1f2h1T2vtJJ9mA==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.5.3': - resolution: {integrity: sha512-+m7pfIs0/yvgVu26ieaKrifV8C8yiLe7jVp9SpcIzg7XmyyNE7toC1fy5IOQozmr6kWl/JONC51osih2RyoXRw==} + '@next/swc-linux-arm64-gnu@15.5.4': + resolution: {integrity: sha512-eRD5zkts6jS3VfE/J0Kt1VxdFqTnMc3QgO5lFE5GKN3KDI/uUpSyK3CjQHmfEkYR4wCOl0R0XrsjpxfWEA++XA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.5.3': - resolution: {integrity: sha512-u3PEIzuguSenoZviZJahNLgCexGFhso5mxWCrrIMdvpZn6lkME5vc/ADZG8UUk5K1uWRy4hqSFECrON6UKQBbQ==} + '@next/swc-linux-arm64-musl@15.5.4': + resolution: {integrity: sha512-TOK7iTxmXFc45UrtKqWdZ1shfxuL4tnVAOuuJK4S88rX3oyVV4ZkLjtMT85wQkfBrOOvU55aLty+MV8xmcJR8A==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.5.3': - resolution: {integrity: sha512-lDtOOScYDZxI2BENN9m0pfVPJDSuUkAD1YXSvlJF0DKwZt0WlA7T7o3wrcEr4Q+iHYGzEaVuZcsIbCps4K27sA==} + '@next/swc-linux-x64-gnu@15.5.4': + resolution: {integrity: sha512-7HKolaj+481FSW/5lL0BcTkA4Ueam9SPYWyN/ib/WGAFZf0DGAN8frNpNZYFHtM4ZstrHZS3LY3vrwlIQfsiMA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.5.3': - resolution: {integrity: sha512-9vWVUnsx9PrY2NwdVRJ4dUURAQ8Su0sLRPqcCCxtX5zIQUBES12eRVHq6b70bbfaVaxIDGJN2afHui0eDm+cLg==} + '@next/swc-linux-x64-musl@15.5.4': + resolution: {integrity: sha512-nlQQ6nfgN0nCO/KuyEUwwOdwQIGjOs4WNMjEUtpIQJPR2NUfmGpW2wkJln1d4nJ7oUzd1g4GivH5GoEPBgfsdw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.5.3': - resolution: {integrity: sha512-1CU20FZzY9LFQigRi6jM45oJMU3KziA5/sSG+dXeVaTm661snQP6xu3ykGxxwU5sLG3sh14teO/IOEPVsQMRfA==} + '@next/swc-win32-arm64-msvc@15.5.4': + resolution: {integrity: sha512-PcR2bN7FlM32XM6eumklmyWLLbu2vs+D7nJX8OAIoWy69Kef8mfiN4e8TUv2KohprwifdpFKPzIP1njuCjD0YA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.5.3': - resolution: {integrity: sha512-JMoLAq3n3y5tKXPQwCK5c+6tmwkuFDa2XAxz8Wm4+IVthdBZdZGh+lmiLUHg9f9IDwIQpUjp+ysd6OkYTyZRZw==} + '@next/swc-win32-x64-msvc@15.5.4': + resolution: {integrity: sha512-1ur2tSHZj8Px/KMAthmuI9FMp/YFusMMGoRNJaRZMOlSkgvLjzosSdQI0cJAKogdHl3qXUQKL9MGaYvKwA7DXg==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1939,8 +1943,8 @@ packages: resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} - '@oxc-project/types@0.89.0': - resolution: {integrity: sha512-yuo+ECPIW5Q9mSeNmCDC2im33bfKuwW18mwkaHMQh8KakHYDzj4ci/q7wxf2qS3dMlVVCIyrs3kFtH5LmnlYnw==} + '@oxc-project/types@0.92.0': + resolution: {integrity: sha512-PDLfCbwgXjGdTBxzcuDOUxJYNBl6P8dOp3eDKWw54dYvqONan9rwGDRQU0zrkdEMiItfXQQUOI17uOcMX5Zm7A==} '@pagefind/darwin-arm64@1.4.0': resolution: {integrity: sha512-2vMqkbv3lbx1Awea90gTaBsvpzgRs7MuSgKDxW0m9oV1GPZCZbZBJg/qL83GIUEN2BFlY46dtUZi54pwH+/pTQ==} @@ -1982,6 +1986,11 @@ packages: '@pm2/agent@2.1.1': resolution: {integrity: sha512-0V9ckHWd/HSC8BgAbZSoq8KXUG81X97nSkAxmhKDhmF8vanyaoc1YXwc2KVkbWz82Rg4gjd2n9qiT3i7bdvGrQ==} + '@pm2/blessed@0.1.81': + resolution: {integrity: sha512-ZcNHqQjMuNRcQ7Z1zJbFIQZO/BDKV3KbiTckWdfbUaYhj7uNmUwb+FbdDWSCkvxNr9dBJQwvV17o6QBkAvgO0g==} + engines: {node: '>= 0.8.0'} + hasBin: true + '@pm2/io@6.1.0': resolution: {integrity: sha512-IxHuYURa3+FQ6BKePlgChZkqABUKFYH6Bwbw7V/pWU1pP6iR1sCI26l7P9ThUEB385ruZn/tZS3CXDUF5IA1NQ==} engines: {node: '>=6.0'} @@ -2462,91 +2471,91 @@ packages: resolution: {integrity: sha512-C7c51Nn4yTxXFKvgh2txJFNweaVcfUPQxwEUFw4aWsCmfiBDJsTSwviIF8EcwjQ6k8bPyMWCl1vw4BdxE569Cg==} engines: {node: '>= 10'} - '@rolldown/binding-android-arm64@1.0.0-beta.38': - resolution: {integrity: sha512-AE3HFQrjWCKLFZD1Vpiy+qsqTRwwoil1oM5WsKPSmfQ5fif/A+ZtOZetF32erZdsR7qyvns6qHEteEsF6g6rsQ==} + '@rolldown/binding-android-arm64@1.0.0-beta.40': + resolution: {integrity: sha512-9Ii9phC7QU6Lb+ncMfG1Xlosq0NBB1N/4sw+EGZ3y0BBWGy02TOb5ghWZalphAKv9rn1goqo5WkBjyd2YvsLmA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-beta.38': - resolution: {integrity: sha512-RaoWOKc0rrFsVmKOjQpebMY6c6/I7GR1FBc25v7L/R7NlM0166mUotwGEv7vxu7ruXH4SJcFeVrfADFUUXUmmQ==} + '@rolldown/binding-darwin-arm64@1.0.0-beta.40': + resolution: {integrity: sha512-5O6d0y2tBQTL+ecQY3qXIwSnF1/Zik8q7LZMKeyF+VJ9l194d0IdMhl2zUF0cqWbYHuF4Pnxplk4OhurPQ/Z9Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-beta.38': - resolution: {integrity: sha512-Ymojqc2U35iUc8NFU2XX1WQPfBRRHN6xHcrxAf9WS8BFFBn8pDrH5QPvH1tYs3lDkw6UGGbanr1RGzARqdUp1g==} + '@rolldown/binding-darwin-x64@1.0.0-beta.40': + resolution: {integrity: sha512-izB9jygt3miPQbOTZfSu5K51isUplqa8ysByOKQqcJHgrBWmbTU8TM9eouv6tRmBR0kjcEcID9xhmA1CeZ1VIg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-beta.38': - resolution: {integrity: sha512-0ermTQ//WzSI0nOL3z/LUWMNiE9xeM5cLGxjewPFEexqxV/0uM8/lNp9QageQ8jfc/VO1OURsGw34HYO5PaL8w==} + '@rolldown/binding-freebsd-x64@1.0.0-beta.40': + resolution: {integrity: sha512-2fdpEpKT+wwP0vig9dqxu+toTeWmVSjo3psJQVDeLJ51rO+GXcCJ1IkCXjhMKVEevNtZS7B8T8Z2vvmRV9MAdA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.38': - resolution: {integrity: sha512-GADxzVUTCTp6EWI52831A29Tt7PukFe94nhg/SUsfkI33oTiNQtPxyLIT/3oRegizGuPSZSlrdBurkjDwxyEUQ==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.40': + resolution: {integrity: sha512-HP2lo78OWULN+8TewpLbS9PS00jh0CaF04tA2u8z2I+6QgVgrYOYKvX+T0hlO5smgso4+qb3YchzumWJl3yCPQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.38': - resolution: {integrity: sha512-SKO7Exl5Yem/OSNoA5uLHzyrptUQ8Hg70kHDxuwEaH0+GUg+SQe9/7PWmc4hFKBMrJGdQtii8WZ0uIz9Dofg5Q==} + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.40': + resolution: {integrity: sha512-ng00gfr9BhA2NPAOU5RWAlTiL+JcwAD+L+4yUD1sbBy6tgHdLiNBOvKtHISIF9RM9/eQeS0tAiWOYZGIH9JMew==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.38': - resolution: {integrity: sha512-SOo6+WqhXPBaShLxLT0eCgH17d3Yu1lMAe4mFP0M9Bvr/kfMSOPQXuLxBcbBU9IFM9w3N6qP9xWOHO+oUJvi8Q==} + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.40': + resolution: {integrity: sha512-mF0R1l9kLcaag/9cLEiYYdNZ4v1uuX4jklSDZ1s6vJE4RB3LirUney0FavdVRwCJ5sDvfvsPgXgtBXWYr2M2tQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.38': - resolution: {integrity: sha512-yvsQ3CyrodOX+lcoi+lejZGCOvJZa9xTsNB8OzpMDmHeZq3QzJfpYjXSAS6vie70fOkLVJb77UqYO193Cl8XBQ==} + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.40': + resolution: {integrity: sha512-+wi08S7wT5iLPHRZb0USrS6n+T6m+yY++dePYedE5uvKIpWCJJioFTaRtWjpm0V6dVNLcq2OukrvfdlGtH9Wgg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - '@rolldown/binding-linux-x64-musl@1.0.0-beta.38': - resolution: {integrity: sha512-84qzKMwUwikfYeOuJ4Kxm/3z15rt0nFGGQArHYIQQNSTiQdxGHxOkqXtzPFqrVfBJUdxBAf+jYzR1pttFJuWyg==} + '@rolldown/binding-linux-x64-musl@1.0.0-beta.40': + resolution: {integrity: sha512-W5qBGAemUocIBKCcOsDjlV9GUt28qhl/+M6etWBeLS5gQK0J6XDg0YVzfOQdvq57ZGjYNP0NvhYzqhOOnEx+4g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - '@rolldown/binding-openharmony-arm64@1.0.0-beta.38': - resolution: {integrity: sha512-QrNiWlce01DYH0rL8K3yUBu+lNzY+B0DyCbIc2Atan6/S6flxOL0ow5DLQvMamOI/oKhrJ4xG+9MkMb9dDHbLQ==} + '@rolldown/binding-openharmony-arm64@1.0.0-beta.40': + resolution: {integrity: sha512-vJwoDehtt+yqj2zacq1AqNc2uE/oh7mnRGqAUbuldV6pgvU01OSQUJ7Zu+35hTopnjFoDNN6mIezkYlGAv5RFA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-beta.38': - resolution: {integrity: sha512-fnLtHyjwEsG4/aNV3Uv3Qd1ZbdH+CopwJNoV0RgBqrcQB8V6/Qdikd5JKvnO23kb3QvIpP+dAMGZMv1c2PJMzw==} + '@rolldown/binding-wasm32-wasi@1.0.0-beta.40': + resolution: {integrity: sha512-Oj3YyqVUPurr1FlMpEE/bJmMC+VWAWPM/SGUfklO5KUX97bk5Q/733nPg4RykK8q8/TluJoQYvRc05vL/B74dw==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.38': - resolution: {integrity: sha512-19cTfnGedem+RY+znA9J6ARBOCEFD4YSjnx0p5jiTm9tR6pHafRfFIfKlTXhun+NL0WWM/M0eb2IfPPYUa8+wg==} + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.40': + resolution: {integrity: sha512-0ZtO6yN8XjVoFfN4HDWQj4nDu3ndMybr7jIM00DJqOmc+yFhly7rdOy7fNR9Sky3leCpBtsXfepVqRmVpYKPVA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.38': - resolution: {integrity: sha512-HcICm4YzFJZV+fI0O0bFLVVlsWvRNo/AB9EfUXvNYbtAxakCnQZ15oq22deFdz6sfi9Y4/SagH2kPU723dhCFA==} + '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.40': + resolution: {integrity: sha512-BPl1inoJXPpIe38Ja46E4y11vXlJyuleo+9Rmu//pYL5fIDYJkXUj/oAXqjSuwLcssrcwnuPgzvzvlz9++cr3w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.38': - resolution: {integrity: sha512-4Qx6cgEPXLb0XsCyLoQcUgYBpfL0sjugftob+zhUH0EOk/NVCAIT+h0NJhY+jn7pFpeKxhNMqhvTNx3AesxIAQ==} + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.40': + resolution: {integrity: sha512-UguA4ltbAk+nbwHRxqaUP/etpTbR0HjyNlsu4Zjbh/ytNbFsbw8CA4tEBkwDyjgI5NIPea6xY11zpl7R2/ddVA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-beta.38': - resolution: {integrity: sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==} + '@rolldown/pluginutils@1.0.0-beta.40': + resolution: {integrity: sha512-s3GeJKSQOwBlzdUrj4ISjJj5SfSh+aqn0wjOar4Bx95iV1ETI7F6S/5hLcfAxZ9kXDcyrAkxPlqmd1ZITttf+w==} '@rollup/rollup-android-arm-eabi@4.43.0': resolution: {integrity: sha512-Krjy9awJl6rKbruhQDgivNbD1WuLb8xAclM4IR4cN5pHGAs2oIMMQJEiC3IC/9TZJ+QZkmZhlMO/6MBGxPidpw==} @@ -2854,8 +2863,8 @@ packages: '@tailwindcss/postcss@4.1.13': resolution: {integrity: sha512-HLgx6YSFKJT7rJqh9oJs/TkBFhxuMOfUKSBEPYwV+t78POOBsdQ7crhZLzwcH3T0UyUuOzU/GK5pk5eKr3wCiQ==} - '@tailwindcss/typography@0.5.18': - resolution: {integrity: sha512-dDIgwZOlf+tVkZ7A029VvQ1+ngKATENDjMEx2N35s2yPjfTS05RWSM8ilhEWSa5DMJ6ci2Ha9WNZEd2GQjrdQg==} + '@tailwindcss/typography@0.5.19': + resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==} peerDependencies: tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' @@ -2972,63 +2981,63 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - '@typescript-eslint/eslint-plugin@8.44.0': - resolution: {integrity: sha512-EGDAOGX+uwwekcS0iyxVDmRV9HX6FLSM5kzrAToLTsr9OWCIKG/y3lQheCq18yZ5Xh78rRKJiEpP0ZaCs4ryOQ==} + '@typescript-eslint/eslint-plugin@8.44.1': + resolution: {integrity: sha512-molgphGqOBT7t4YKCSkbasmu1tb1MgrZ2szGzHbclF7PNmOkSTQVHy+2jXOSnxvR3+Xe1yySHFZoqMpz3TfQsw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.44.0 + '@typescript-eslint/parser': ^8.44.1 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.44.0': - resolution: {integrity: sha512-VGMpFQGUQWYT9LfnPcX8ouFojyrZ/2w3K5BucvxL/spdNehccKhB4jUyB1yBCXpr2XFm0jkECxgrpXBW2ipoAw==} + '@typescript-eslint/parser@8.44.1': + resolution: {integrity: sha512-EHrrEsyhOhxYt8MTg4zTF+DJMuNBzWwgvvOYNj/zm1vnaD/IC5zCXFehZv94Piqa2cRFfXrTFxIvO95L7Qc/cw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.44.0': - resolution: {integrity: sha512-ZeaGNraRsq10GuEohKTo4295Z/SuGcSq2LzfGlqiuEvfArzo/VRrT0ZaJsVPuKZ55lVbNk8U6FcL+ZMH8CoyVA==} + '@typescript-eslint/project-service@8.44.1': + resolution: {integrity: sha512-ycSa60eGg8GWAkVsKV4E6Nz33h+HjTXbsDT4FILyL8Obk5/mx4tbvCNsLf9zret3ipSumAOG89UcCs/KRaKYrA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.44.0': - resolution: {integrity: sha512-87Jv3E+al8wpD+rIdVJm/ItDBe/Im09zXIjFoipOjr5gHUhJmTzfFLuTJ/nPTMc2Srsroy4IBXwcTCHyRR7KzA==} + '@typescript-eslint/scope-manager@8.44.1': + resolution: {integrity: sha512-NdhWHgmynpSvyhchGLXh+w12OMT308Gm25JoRIyTZqEbApiBiQHD/8xgb6LqCWCFcxFtWwaVdFsLPQI3jvhywg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.44.0': - resolution: {integrity: sha512-x5Y0+AuEPqAInc6yd0n5DAcvtoQ/vyaGwuX5HE9n6qAefk1GaedqrLQF8kQGylLUb9pnZyLf+iEiL9fr8APDtQ==} + '@typescript-eslint/tsconfig-utils@8.44.1': + resolution: {integrity: sha512-B5OyACouEjuIvof3o86lRMvyDsFwZm+4fBOqFHccIctYgBjqR3qT39FBYGN87khcgf0ExpdCBeGKpKRhSFTjKQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.44.0': - resolution: {integrity: sha512-9cwsoSxJ8Sak67Be/hD2RNt/fsqmWnNE1iHohG8lxqLSNY8xNfyY7wloo5zpW3Nu9hxVgURevqfcH6vvKCt6yg==} + '@typescript-eslint/type-utils@8.44.1': + resolution: {integrity: sha512-KdEerZqHWXsRNKjF9NYswNISnFzXfXNDfPxoTh7tqohU/PRIbwTmsjGK6V9/RTYWau7NZvfo52lgVk+sJh0K3g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.44.0': - resolution: {integrity: sha512-ZSl2efn44VsYM0MfDQe68RKzBz75NPgLQXuGypmym6QVOWL5kegTZuZ02xRAT9T+onqvM6T8CdQk0OwYMB6ZvA==} + '@typescript-eslint/types@8.44.1': + resolution: {integrity: sha512-Lk7uj7y9uQUOEguiDIDLYLJOrYHQa7oBiURYVFqIpGxclAFQ78f6VUOM8lI2XEuNOKNB7XuvM2+2cMXAoq4ALQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.44.0': - resolution: {integrity: sha512-lqNj6SgnGcQZwL4/SBJ3xdPEfcBuhCG8zdcwCPgYcmiPLgokiNDKlbPzCwEwu7m279J/lBYWtDYL+87OEfn8Jw==} + '@typescript-eslint/typescript-estree@8.44.1': + resolution: {integrity: sha512-qnQJ+mVa7szevdEyvfItbO5Vo+GfZ4/GZWWDRRLjrxYPkhM+6zYB2vRYwCsoJLzqFCdZT4mEqyJoyzkunsZ96A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.44.0': - resolution: {integrity: sha512-nktOlVcg3ALo0mYlV+L7sWUD58KG4CMj1rb2HUVOO4aL3K/6wcD+NERqd0rrA5Vg06b42YhF6cFxeixsp9Riqg==} + '@typescript-eslint/utils@8.44.1': + resolution: {integrity: sha512-DpX5Fp6edTlocMCwA+mHY8Mra+pPjRZ0TfHkXI8QFelIKcbADQz1LUPNtzOFUriBB2UYqw4Pi9+xV4w9ZczHFg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.44.0': - resolution: {integrity: sha512-zaz9u8EJ4GBmnehlrpoKvj/E3dNbuQ7q0ucyZImm3cLqJ8INTc970B1qEqDX/Rzq65r3TvVTN7kHWPBoyW7DWw==} + '@typescript-eslint/visitor-keys@8.44.1': + resolution: {integrity: sha512-576+u0QD+Jp3tZzvfRfxon0EA2lzcDt3lhUbsC6Lgzy9x2VR4E+JUiNyGHi5T8vk0TV+fpJ5GLG1JsJuWCaKhw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.0': @@ -3343,11 +3352,6 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - blessed@0.1.81: - resolution: {integrity: sha512-LoF5gae+hlmfORcG1M5+5XZi4LBmvlXTzwJWzUlPryN/SJdSflZvROM2TwkT0GMpq7oqT48NRd4GS7BiVBc5OQ==} - engines: {node: '>= 0.8.0'} - hasBin: true - bodec@0.1.0: resolution: {integrity: sha512-Ylo+MAo5BDUq1KA3f3R/MFhh+g8cnHmo8bz3YPGhI1znrMaf77ol1sfvYJzsw3nTE+Y2GryfDxBaR+AqpAkEHQ==} @@ -3428,8 +3432,8 @@ packages: camelize@1.0.1: resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} - caniuse-lite@1.0.30001743: - resolution: {integrity: sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==} + caniuse-lite@1.0.30001745: + resolution: {integrity: sha512-ywt6i8FzvdgrrrGbr1jZVObnVv6adj+0if2/omv9cmR2oiZs30zL4DIyaptKcbOrBdOIc74QTMoJvSE2QHh5UQ==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -3653,8 +3657,8 @@ packages: date-fns@4.1.0: resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} - dayjs@1.11.18: - resolution: {integrity: sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==} + dayjs@1.11.15: + resolution: {integrity: sha512-MC+DfnSWiM9APs7fpiurHGCoeIx0Gdl6QZBy+5lu8MbYKN5FZEXqOgrundfibdfhGZ15o9hzmZ2xJjZnbvgKXQ==} dayjs@1.8.36: resolution: {integrity: sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==} @@ -3753,6 +3757,10 @@ packages: resolution: {integrity: sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg==} engines: {node: '>=8'} + detect-libc@2.1.1: + resolution: {integrity: sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==} + engines: {node: '>=8'} + detect-newline@4.0.1: resolution: {integrity: sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -4041,8 +4049,8 @@ packages: engines: {node: '>=6.0'} hasBin: true - eslint-config-turbo@2.5.6: - resolution: {integrity: sha512-1EV/UqdKE75st9q6y0MCxz7qp2v7RyGvbQsMLSuCz+VH8ScnSfmhd8FcAbqx3BshCy5IluujzMB6T5iCgL3/sA==} + eslint-config-turbo@2.5.8: + resolution: {integrity: sha512-wzxmN7dJNFGDwOvR/4j8U2iaIH/ruYez8qg/sCKrezJ3+ljbFMvJLmgKKt/1mDuyU9wj5aZqO6VijP3QH169FA==} peerDependencies: eslint: '>6.6.0' turbo: '>2.0.0' @@ -4110,8 +4118,8 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - eslint-plugin-turbo@2.5.6: - resolution: {integrity: sha512-KUDE23aP2JV8zbfZ4TeM1HpAXzMM/AYG/bJam7P4AalUxas8Pd/lS/6R3p4uX91qJcH1LwL4h0ED48nDe8KorQ==} + eslint-plugin-turbo@2.5.8: + resolution: {integrity: sha512-bVjx4vTH0oTKIyQ7EGFAXnuhZMrKIfu17qlex/dps7eScPnGQLJ3r1/nFq80l8xA+8oYjsSirSQ2tXOKbz3kEw==} peerDependencies: eslint: '>6.6.0' turbo: '>2.0.0' @@ -5381,8 +5389,8 @@ packages: next-validate-link@1.6.3: resolution: {integrity: sha512-batZxYlkQQSa8jl0gi1AQd5BlJDY3FG41yecpvBWVIM1t/FnBmbo3cMZZx8sSt4UdrsbLuRE2P3p5s+TsQ8m1A==} - next@15.5.3: - resolution: {integrity: sha512-r/liNAx16SQj4D+XH/oI1dlpv9tdKJ6cONYPwwcCC46f2NjpaRWY+EKCzULfgQYV6YKXjHBchff2IZBSlZmJNw==} + next@15.5.4: + resolution: {integrity: sha512-xH4Yjhb82sFYQfY3vbkJfgSDgXvBB6a8xPs9i35k6oZJRoQRihZH+4s9Yo2qsWpzBmZ3lPXaJ2KPXLfkvW4LnA==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: @@ -5727,8 +5735,8 @@ packages: pm2-sysmonit@1.2.8: resolution: {integrity: sha512-ACOhlONEXdCTVwKieBIQLSi2tQZ8eKinhcr9JpZSUAL8Qy0ajIgRtsLxG/lwPOW3JEKqPyw/UaHmTWhUzpP4kA==} - pm2@6.0.11: - resolution: {integrity: sha512-vD6uYdLLxs6xT6jKvLSJx3V+IhViHac8zEsvZm+0QDjR2dUyZtvem+sDLteZRnQ21tsp2oF7P03vCTDtOWD2HQ==} + pm2@6.0.13: + resolution: {integrity: sha512-1hS/adMgKoDpX4S1ichJW8SiGpex+oBSZK31dP1FSYOOGtaeuemXzhXPOCefmddgIY4K6v7uu+7xNPnmEnK3ag==} engines: {node: '>=16.0.0'} hasBin: true @@ -6086,8 +6094,8 @@ packages: remark@15.0.1: resolution: {integrity: sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==} - renoun@10.1.0: - resolution: {integrity: sha512-i3pfnn2hQ6wAcG//5uvK89ejOAaoyZEmhOOXj3vgEu/xJUASJ859InKf8qya1RZiPZ19Od9QkREm6kCvqKjrkg==} + renoun@10.1.2: + resolution: {integrity: sha512-PksXEA4XhMMRt36envCw8OPSBplcj95tMCEDD2pG+aBbHCfTlw55E7eI2bUMhtzogHL0oiVSzzR0Jepg3X24IA==} engines: {node: '>=20.19.0'} hasBin: true peerDependencies: @@ -6164,8 +6172,8 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rolldown@1.0.0-beta.38: - resolution: {integrity: sha512-58frPNX55Je1YsyrtPJv9rOSR3G5efUZpRqok94Efsj0EUa8dnqJV3BldShyI7A+bVPleucOtzXHwVpJRcR0kQ==} + rolldown@1.0.0-beta.40: + resolution: {integrity: sha512-VqEHbKpOgTPmQrZ4fVn4eshDQS/6g/fRpNE7cFSJY+eQLDZn4B9X61J6L+hnlt1u2uRI+pF7r1USs6S5fuWCvw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -6736,46 +6744,46 @@ packages: engines: {node: '>=18.0.0'} hasBin: true - turbo-darwin-64@2.5.6: - resolution: {integrity: sha512-3C1xEdo4aFwMJAPvtlPqz1Sw/+cddWIOmsalHFMrsqqydcptwBfu26WW2cDm3u93bUzMbBJ8k3zNKFqxJ9ei2A==} + turbo-darwin-64@2.5.8: + resolution: {integrity: sha512-Dh5bCACiHO8rUXZLpKw+m3FiHtAp2CkanSyJre+SInEvEr5kIxjGvCK/8MFX8SFRjQuhjtvpIvYYZJB4AGCxNQ==} cpu: [x64] os: [darwin] - turbo-darwin-arm64@2.5.6: - resolution: {integrity: sha512-LyiG+rD7JhMfYwLqB6k3LZQtYn8CQQUePbpA8mF/hMLPAekXdJo1g0bUPw8RZLwQXUIU/3BU7tXENvhSGz5DPA==} + turbo-darwin-arm64@2.5.8: + resolution: {integrity: sha512-f1H/tQC9px7+hmXn6Kx/w8Jd/FneIUnvLlcI/7RGHunxfOkKJKvsoiNzySkoHQ8uq1pJnhJ0xNGTlYM48ZaJOQ==} cpu: [arm64] os: [darwin] - turbo-linux-64@2.5.6: - resolution: {integrity: sha512-GOcUTT0xiT/pSnHL4YD6Yr3HreUhU8pUcGqcI2ksIF9b2/r/kRHwGFcsHgpG3+vtZF/kwsP0MV8FTlTObxsYIA==} + turbo-linux-64@2.5.8: + resolution: {integrity: sha512-hMyvc7w7yadBlZBGl/bnR6O+dJTx3XkTeyTTH4zEjERO6ChEs0SrN8jTFj1lueNXKIHh1SnALmy6VctKMGnWfw==} cpu: [x64] os: [linux] - turbo-linux-arm64@2.5.6: - resolution: {integrity: sha512-10Tm15bruJEA3m0V7iZcnQBpObGBcOgUcO+sY7/2vk1bweW34LMhkWi8svjV9iDF68+KJDThnYDlYE/bc7/zzQ==} + turbo-linux-arm64@2.5.8: + resolution: {integrity: sha512-LQELGa7bAqV2f+3rTMRPnj5G/OHAe2U+0N9BwsZvfMvHSUbsQ3bBMWdSQaYNicok7wOZcHjz2TkESn1hYK6xIQ==} cpu: [arm64] os: [linux] - turbo-windows-64@2.5.6: - resolution: {integrity: sha512-FyRsVpgaj76It0ludwZsNN40ytHN+17E4PFJyeliBEbxrGTc5BexlXVpufB7XlAaoaZVxbS6KT8RofLfDRyEPg==} + turbo-windows-64@2.5.8: + resolution: {integrity: sha512-3YdcaW34TrN1AWwqgYL9gUqmZsMT4T7g8Y5Azz+uwwEJW+4sgcJkIi9pYFyU4ZBSjBvkfuPZkGgfStir5BBDJQ==} cpu: [x64] os: [win32] - turbo-windows-arm64@2.5.6: - resolution: {integrity: sha512-j/tWu8cMeQ7HPpKri6jvKtyXg9K1gRyhdK4tKrrchH8GNHscPX/F71zax58yYtLRWTiK04zNzPcUJuoS0+v/+Q==} + turbo-windows-arm64@2.5.8: + resolution: {integrity: sha512-eFC5XzLmgXJfnAK3UMTmVECCwuBcORrWdewoiXBnUm934DY6QN8YowC/srhNnROMpaKaqNeRpoB5FxCww3eteQ==} cpu: [arm64] os: [win32] - turbo@2.5.6: - resolution: {integrity: sha512-gxToHmi9oTBNB05UjUsrWf0OyN5ZXtD0apOarC1KIx232Vp3WimRNy3810QzeNSgyD5rsaIDXlxlbnOzlouo+w==} + turbo@2.5.8: + resolution: {integrity: sha512-5c9Fdsr9qfpT3hA0EyYSFRZj1dVVsb6KIWubA9JBYZ/9ZEAijgUEae0BBR/Xl/wekt4w65/lYLTFaP3JmwSO8w==} hasBin: true tv4@1.3.0: resolution: {integrity: sha512-afizzfpJgvPr+eDkREK4MxJ/+r8nEEHcmitwgnPUqpaP+FpwQyadnxNoSACbgc/b1LsZYtODGoPiFxQrgJgjvw==} engines: {node: '>= 0.8.0'} - tw-animate-css@1.3.8: - resolution: {integrity: sha512-Qrk3PZ7l7wUcGYhwZloqfkWCmaXZAoqjkdbIDvzfGshwGtexa/DAs9koXxIkrpEasyevandomzCBAV1Yyop5rw==} + tw-animate-css@1.4.0: + resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} tweetnacl@0.14.5: resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} @@ -6807,8 +6815,8 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} - typescript-eslint@8.44.0: - resolution: {integrity: sha512-ib7mCkYuIzYonCq9XWF5XNw+fkj2zg629PSa9KNIQ47RXFF763S5BIX4wqz1+FLPogTZoiw8KmCiRPRa8bL3qw==} + typescript-eslint@8.44.1: + resolution: {integrity: sha512-0ws8uWGrUVTjEeN2OM4K1pLKHK/4NiNP/vz6ns+LjT/6sqpaYzIVFajZb1fj/IDwpsrrHb3Jy0Qm5u9CPcKaeg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -7477,7 +7485,7 @@ snapshots: '@drizzle-team/brocli@0.10.2': {} - '@electric-sql/pglite@0.3.8': {} + '@electric-sql/pglite@0.3.10': {} '@emnapi/core@1.5.0': dependencies: @@ -7734,7 +7742,9 @@ snapshots: '@eslint-community/regexpp@4.12.1': {} - '@eslint/compat@1.3.2(eslint@9.36.0(jiti@2.5.1))': + '@eslint/compat@1.4.0(eslint@9.36.0(jiti@2.5.1))': + dependencies: + '@eslint/core': 0.16.0 optionalDependencies: eslint: 9.36.0(jiti@2.5.1) @@ -7752,6 +7762,10 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 + '@eslint/core@0.16.0': + dependencies: + '@types/json-schema': 7.0.15 + '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 @@ -8113,41 +8127,41 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true - '@next/env@15.5.3': {} + '@next/env@15.5.4': {} - '@next/eslint-plugin-next@15.5.3': + '@next/eslint-plugin-next@15.5.4': dependencies: fast-glob: 3.3.1 - '@next/mdx@15.5.3(@mdx-js/loader@3.1.1)(@mdx-js/react@3.1.1(@types/react@19.1.13)(react@19.1.1))': + '@next/mdx@15.5.4(@mdx-js/loader@3.1.1)(@mdx-js/react@3.1.1(@types/react@19.1.13)(react@19.1.1))': dependencies: source-map: 0.7.6 optionalDependencies: '@mdx-js/loader': 3.1.1 '@mdx-js/react': 3.1.1(@types/react@19.1.13)(react@19.1.1) - '@next/swc-darwin-arm64@15.5.3': + '@next/swc-darwin-arm64@15.5.4': optional: true - '@next/swc-darwin-x64@15.5.3': + '@next/swc-darwin-x64@15.5.4': optional: true - '@next/swc-linux-arm64-gnu@15.5.3': + '@next/swc-linux-arm64-gnu@15.5.4': optional: true - '@next/swc-linux-arm64-musl@15.5.3': + '@next/swc-linux-arm64-musl@15.5.4': optional: true - '@next/swc-linux-x64-gnu@15.5.3': + '@next/swc-linux-x64-gnu@15.5.4': optional: true - '@next/swc-linux-x64-musl@15.5.3': + '@next/swc-linux-x64-musl@15.5.4': optional: true - '@next/swc-win32-arm64-msvc@15.5.3': + '@next/swc-win32-arm64-msvc@15.5.4': optional: true - '@next/swc-win32-x64-msvc@15.5.3': + '@next/swc-win32-x64-msvc@15.5.4': optional: true '@noble/hashes@1.8.0': {} @@ -8178,7 +8192,7 @@ snapshots: '@opentelemetry/api@1.9.0': {} - '@oxc-project/types@0.89.0': {} + '@oxc-project/types@0.92.0': {} '@pagefind/darwin-arm64@1.4.0': optional: true @@ -8224,6 +8238,8 @@ snapshots: - supports-color - utf-8-validate + '@pm2/blessed@0.1.81': {} + '@pm2/io@6.1.0': dependencies: async: 2.6.4 @@ -8820,51 +8836,51 @@ snapshots: '@resvg/resvg-wasm@2.4.0': {} - '@rolldown/binding-android-arm64@1.0.0-beta.38': + '@rolldown/binding-android-arm64@1.0.0-beta.40': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-beta.38': + '@rolldown/binding-darwin-arm64@1.0.0-beta.40': optional: true - '@rolldown/binding-darwin-x64@1.0.0-beta.38': + '@rolldown/binding-darwin-x64@1.0.0-beta.40': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-beta.38': + '@rolldown/binding-freebsd-x64@1.0.0-beta.40': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.38': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.40': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.38': + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.40': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.38': + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.40': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.38': + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.40': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-beta.38': + '@rolldown/binding-linux-x64-musl@1.0.0-beta.40': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-beta.38': + '@rolldown/binding-openharmony-arm64@1.0.0-beta.40': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-beta.38': + '@rolldown/binding-wasm32-wasi@1.0.0-beta.40': dependencies: '@napi-rs/wasm-runtime': 1.0.5 optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.38': + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.40': optional: true - '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.38': + '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.40': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.38': + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.40': optional: true - '@rolldown/pluginutils@1.0.0-beta.38': {} + '@rolldown/pluginutils@1.0.0-beta.40': {} '@rollup/rollup-android-arm-eabi@4.43.0': optional: true @@ -9073,7 +9089,7 @@ snapshots: postcss: 8.5.6 tailwindcss: 4.1.13 - '@tailwindcss/typography@0.5.18(tailwindcss@4.1.13)': + '@tailwindcss/typography@0.5.19(tailwindcss@4.1.13)': dependencies: postcss-selector-parser: 6.0.10 tailwindcss: 4.1.13 @@ -9211,14 +9227,14 @@ snapshots: '@types/unist@3.0.3': {} - '@typescript-eslint/eslint-plugin@8.44.0(@typescript-eslint/parser@8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/eslint-plugin@8.44.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/scope-manager': 8.44.0 - '@typescript-eslint/type-utils': 8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/utils': 8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.44.0 + '@typescript-eslint/parser': 8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.44.1 + '@typescript-eslint/type-utils': 8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.44.1 eslint: 9.36.0(jiti@2.5.1) graphemer: 1.4.0 ignore: 7.0.5 @@ -9228,41 +9244,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: - '@typescript-eslint/scope-manager': 8.44.0 - '@typescript-eslint/types': 8.44.0 - '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.44.0 + '@typescript-eslint/scope-manager': 8.44.1 + '@typescript-eslint/types': 8.44.1 + '@typescript-eslint/typescript-estree': 8.44.1(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.44.1 debug: 4.4.3 eslint: 9.36.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.44.0(typescript@5.9.2)': + '@typescript-eslint/project-service@8.44.1(typescript@5.9.2)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.44.0(typescript@5.9.2) - '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/tsconfig-utils': 8.44.1(typescript@5.9.2) + '@typescript-eslint/types': 8.44.1 debug: 4.4.3 typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.44.0': + '@typescript-eslint/scope-manager@8.44.1': dependencies: - '@typescript-eslint/types': 8.44.0 - '@typescript-eslint/visitor-keys': 8.44.0 + '@typescript-eslint/types': 8.44.1 + '@typescript-eslint/visitor-keys': 8.44.1 - '@typescript-eslint/tsconfig-utils@8.44.0(typescript@5.9.2)': + '@typescript-eslint/tsconfig-utils@8.44.1(typescript@5.9.2)': dependencies: typescript: 5.9.2 - '@typescript-eslint/type-utils@8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/type-utils@8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: - '@typescript-eslint/types': 8.44.0 - '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/types': 8.44.1 + '@typescript-eslint/typescript-estree': 8.44.1(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) debug: 4.4.3 eslint: 9.36.0(jiti@2.5.1) ts-api-utils: 2.1.0(typescript@5.9.2) @@ -9270,14 +9286,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.44.0': {} + '@typescript-eslint/types@8.44.1': {} - '@typescript-eslint/typescript-estree@8.44.0(typescript@5.9.2)': + '@typescript-eslint/typescript-estree@8.44.1(typescript@5.9.2)': dependencies: - '@typescript-eslint/project-service': 8.44.0(typescript@5.9.2) - '@typescript-eslint/tsconfig-utils': 8.44.0(typescript@5.9.2) - '@typescript-eslint/types': 8.44.0 - '@typescript-eslint/visitor-keys': 8.44.0 + '@typescript-eslint/project-service': 8.44.1(typescript@5.9.2) + '@typescript-eslint/tsconfig-utils': 8.44.1(typescript@5.9.2) + '@typescript-eslint/types': 8.44.1 + '@typescript-eslint/visitor-keys': 8.44.1 debug: 4.4.3 fast-glob: 3.3.3 is-glob: 4.0.3 @@ -9288,20 +9304,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.36.0(jiti@2.5.1)) - '@typescript-eslint/scope-manager': 8.44.0 - '@typescript-eslint/types': 8.44.0 - '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.44.1 + '@typescript-eslint/types': 8.44.1 + '@typescript-eslint/typescript-estree': 8.44.1(typescript@5.9.2) eslint: 9.36.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.44.0': + '@typescript-eslint/visitor-keys@8.44.1': dependencies: - '@typescript-eslint/types': 8.44.0 + '@typescript-eslint/types': 8.44.1 eslint-visitor-keys: 4.2.1 '@ungap/structured-clone@1.3.0': {} @@ -9654,8 +9670,6 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - blessed@0.1.81: {} - bodec@0.1.0: {} boolbase@1.0.0: {} @@ -9751,7 +9765,7 @@ snapshots: camelize@1.0.1: {} - caniuse-lite@1.0.30001743: {} + caniuse-lite@1.0.30001745: {} ccount@2.0.1: {} @@ -9959,7 +9973,7 @@ snapshots: date-fns@4.1.0: {} - dayjs@1.11.18: {} + dayjs@1.11.15: {} dayjs@1.8.36: {} @@ -10033,6 +10047,9 @@ snapshots: detect-libc@2.1.0: {} + detect-libc@2.1.1: + optional: true + detect-newline@4.0.1: {} detect-node-es@1.1.0: {} @@ -10106,9 +10123,9 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.44.5(@electric-sql/pglite@0.3.8)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)): + drizzle-orm@0.44.5(@electric-sql/pglite@0.3.10)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)): optionalDependencies: - '@electric-sql/pglite': 0.3.8 + '@electric-sql/pglite': 0.3.10 '@opentelemetry/api': 1.9.0 '@prisma/client': 6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2) '@types/pg': 8.15.5 @@ -10386,11 +10403,11 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-turbo@2.5.6(eslint@9.36.0(jiti@2.5.1))(turbo@2.5.6): + eslint-config-turbo@2.5.8(eslint@9.36.0(jiti@2.5.1))(turbo@2.5.8): dependencies: eslint: 9.36.0(jiti@2.5.1) - eslint-plugin-turbo: 2.5.6(eslint@9.36.0(jiti@2.5.1))(turbo@2.5.6) - turbo: 2.5.6 + eslint-plugin-turbo: 2.5.8(eslint@9.36.0(jiti@2.5.1))(turbo@2.5.8) + turbo: 2.5.8 eslint-fix-utils@0.4.0(@types/estree@1.0.8)(eslint@9.36.0(jiti@2.5.1)): dependencies: @@ -10406,17 +10423,17 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.36.0(jiti@2.5.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.36.0(jiti@2.5.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) eslint: 9.36.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.36.0(jiti@2.5.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.36.0(jiti@2.5.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -10427,7 +10444,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.36.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.36.0(jiti@2.5.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.36.0(jiti@2.5.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -10439,7 +10456,7 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -10488,11 +10505,11 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 - eslint-plugin-turbo@2.5.6(eslint@9.36.0(jiti@2.5.1))(turbo@2.5.6): + eslint-plugin-turbo@2.5.8(eslint@9.36.0(jiti@2.5.1))(turbo@2.5.8): dependencies: dotenv: 16.0.3 eslint: 9.36.0(jiti@2.5.1) - turbo: 2.5.6 + turbo: 2.5.8 eslint-scope@8.4.0: dependencies: @@ -12129,24 +12146,24 @@ snapshots: transitivePeerDependencies: - supports-color - next@15.5.3(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + next@15.5.4(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: - '@next/env': 15.5.3 + '@next/env': 15.5.4 '@swc/helpers': 0.5.15 - caniuse-lite: 1.0.30001743 + caniuse-lite: 1.0.30001745 postcss: 8.4.31 react: 19.1.1 react-dom: 19.1.1(react@19.1.1) styled-jsx: 5.1.6(react@19.1.1) optionalDependencies: - '@next/swc-darwin-arm64': 15.5.3 - '@next/swc-darwin-x64': 15.5.3 - '@next/swc-linux-arm64-gnu': 15.5.3 - '@next/swc-linux-arm64-musl': 15.5.3 - '@next/swc-linux-x64-gnu': 15.5.3 - '@next/swc-linux-x64-musl': 15.5.3 - '@next/swc-win32-arm64-msvc': 15.5.3 - '@next/swc-win32-x64-msvc': 15.5.3 + '@next/swc-darwin-arm64': 15.5.4 + '@next/swc-darwin-x64': 15.5.4 + '@next/swc-linux-arm64-gnu': 15.5.4 + '@next/swc-linux-arm64-musl': 15.5.4 + '@next/swc-linux-x64-gnu': 15.5.4 + '@next/swc-linux-x64-musl': 15.5.4 + '@next/swc-win32-arm64-msvc': 15.5.4 + '@next/swc-win32-x64-msvc': 15.5.4 '@opentelemetry/api': 1.9.0 sharp: 0.34.4 transitivePeerDependencies: @@ -12530,20 +12547,20 @@ snapshots: - supports-color optional: true - pm2@6.0.11: + pm2@6.0.13: dependencies: '@pm2/agent': 2.1.1 + '@pm2/blessed': 0.1.81 '@pm2/io': 6.1.0 '@pm2/js-api': 0.8.0 '@pm2/pm2-version-check': 1.0.4 ansis: 4.0.0-node10 async: 3.2.6 - blessed: 0.1.81 chokidar: 3.6.0 cli-tableau: 2.0.1 commander: 2.15.1 croner: 4.1.97 - dayjs: 1.11.18 + dayjs: 1.11.15 debug: 4.4.3 enquirer: 2.3.6 eventemitter2: 5.0.1 @@ -13010,7 +13027,7 @@ snapshots: transitivePeerDependencies: - supports-color - renoun@10.1.0(prettier@3.6.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(tm-grammars@1.24.13)(tm-themes@1.10.9): + renoun@10.1.2(prettier@3.6.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(tm-grammars@1.24.13)(tm-themes@1.10.9): dependencies: '@mdx-js/mdx': 3.1.1 '@renoun/mdx': 3.1.1 @@ -13106,26 +13123,26 @@ snapshots: reusify@1.1.0: {} - rolldown@1.0.0-beta.38: + rolldown@1.0.0-beta.40: dependencies: - '@oxc-project/types': 0.89.0 - '@rolldown/pluginutils': 1.0.0-beta.38 + '@oxc-project/types': 0.92.0 + '@rolldown/pluginutils': 1.0.0-beta.40 ansis: 4.1.0 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-beta.38 - '@rolldown/binding-darwin-arm64': 1.0.0-beta.38 - '@rolldown/binding-darwin-x64': 1.0.0-beta.38 - '@rolldown/binding-freebsd-x64': 1.0.0-beta.38 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.38 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.38 - '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.38 - '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.38 - '@rolldown/binding-linux-x64-musl': 1.0.0-beta.38 - '@rolldown/binding-openharmony-arm64': 1.0.0-beta.38 - '@rolldown/binding-wasm32-wasi': 1.0.0-beta.38 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.38 - '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.38 - '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.38 + '@rolldown/binding-android-arm64': 1.0.0-beta.40 + '@rolldown/binding-darwin-arm64': 1.0.0-beta.40 + '@rolldown/binding-darwin-x64': 1.0.0-beta.40 + '@rolldown/binding-freebsd-x64': 1.0.0-beta.40 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.40 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.40 + '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.40 + '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.40 + '@rolldown/binding-linux-x64-musl': 1.0.0-beta.40 + '@rolldown/binding-openharmony-arm64': 1.0.0-beta.40 + '@rolldown/binding-wasm32-wasi': 1.0.0-beta.40 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.40 + '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.40 + '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.40 rollup-plugin-delete@3.0.1(rollup@4.45.1): dependencies: @@ -13284,7 +13301,7 @@ snapshots: sharp@0.34.4: dependencies: '@img/colour': 1.0.0 - detect-libc: 2.1.0 + detect-libc: 2.1.1 semver: 7.7.2 optionalDependencies: '@img/sharp-darwin-arm64': 0.34.4 @@ -13831,36 +13848,36 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - turbo-darwin-64@2.5.6: + turbo-darwin-64@2.5.8: optional: true - turbo-darwin-arm64@2.5.6: + turbo-darwin-arm64@2.5.8: optional: true - turbo-linux-64@2.5.6: + turbo-linux-64@2.5.8: optional: true - turbo-linux-arm64@2.5.6: + turbo-linux-arm64@2.5.8: optional: true - turbo-windows-64@2.5.6: + turbo-windows-64@2.5.8: optional: true - turbo-windows-arm64@2.5.6: + turbo-windows-arm64@2.5.8: optional: true - turbo@2.5.6: + turbo@2.5.8: optionalDependencies: - turbo-darwin-64: 2.5.6 - turbo-darwin-arm64: 2.5.6 - turbo-linux-64: 2.5.6 - turbo-linux-arm64: 2.5.6 - turbo-windows-64: 2.5.6 - turbo-windows-arm64: 2.5.6 + turbo-darwin-64: 2.5.8 + turbo-darwin-arm64: 2.5.8 + turbo-linux-64: 2.5.8 + turbo-linux-arm64: 2.5.8 + turbo-windows-64: 2.5.8 + turbo-windows-arm64: 2.5.8 tv4@1.3.0: {} - tw-animate-css@1.3.8: {} + tw-animate-css@1.4.0: {} tweetnacl@0.14.5: {} @@ -13908,12 +13925,12 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript-eslint@8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2): + typescript-eslint@8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.44.0(@typescript-eslint/parser@8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/parser': 8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.44.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/eslint-plugin': 8.44.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/typescript-estree': 8.44.1(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.1(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2) eslint: 9.36.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: diff --git a/tooling/eslint/package.json b/tooling/eslint/package.json index 241b40f..8491d6b 100644 --- a/tooling/eslint/package.json +++ b/tooling/eslint/package.json @@ -15,15 +15,15 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@eslint/compat": "1.3.2", - "@next/eslint-plugin-next": "15.5.3", - "eslint-config-turbo": "2.5.6", + "@eslint/compat": "1.4.0", + "@next/eslint-plugin-next": "15.5.4", + "eslint-config-turbo": "2.5.8", "eslint-plugin-import": "2.32.0", "eslint-plugin-package-json": "0.56.3", "eslint-plugin-react": "7.37.5", "eslint-plugin-react-hooks": "5.2.0", "jsonc-eslint-parser": "2.4.1", - "typescript-eslint": "8.44.0" + "typescript-eslint": "8.44.1" }, "devDependencies": { "@eslint/js": "9.36.0", From 9fa5e1edb4687a351fb958a5fcc9556ad70664f0 Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Thu, 25 Sep 2025 10:45:31 +0200 Subject: [PATCH 08/17] use pnpm version from the `packageManager` --- .github/workflows/tests.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 63ad982..740f3e7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -46,7 +46,6 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 10.15.1 run_install: false - shell: bash @@ -95,7 +94,6 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 10.15.1 run_install: false - shell: bash @@ -127,7 +125,6 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 10.15.1 run_install: false - shell: bash @@ -161,7 +158,6 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 10.15.1 run_install: false - shell: bash From 7e3f0772cdfa5f59b9f4332d70cbcb07ccec6d2e Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Thu, 25 Sep 2025 11:06:20 +0200 Subject: [PATCH 09/17] fix build issues, add missing exports --- .../adapter-drizzle/src/postgres-adapter.ts | 18 ++++++------ .../adapter-kysely/src/postgres-adapter.ts | 23 +++++++-------- .../adapter-prisma/src/postgres-adapter.ts | 28 ++++++++++++++++++- packages/core/src/index.ts | 1 + 4 files changed, 49 insertions(+), 21 deletions(-) diff --git a/packages/adapter-drizzle/src/postgres-adapter.ts b/packages/adapter-drizzle/src/postgres-adapter.ts index 269a161..75091d9 100644 --- a/packages/adapter-drizzle/src/postgres-adapter.ts +++ b/packages/adapter-drizzle/src/postgres-adapter.ts @@ -3,7 +3,7 @@ import type { PgliteDatabase } from "drizzle-orm/pglite" import type { PostgresJsDatabase } from "drizzle-orm/postgres-js" import { and, asc, count, eq, lte, sql } from "drizzle-orm" -import type { BaseJob, JobStatus, QueueStats, SerializedError } from "@vorsteh-queue/core" +import type { BaseJob, BatchJob, JobStatus, QueueStats, SerializedError } from "@vorsteh-queue/core" import { asUtc, BaseQueueAdapter, serializeError } from "@vorsteh-queue/core" import * as schema from "./postgres-schema" @@ -77,8 +77,8 @@ export class PostgresQueueAdapter extends BaseQueueAdapter { } async addJobs( - jobs: readonly Omit, "id" | "createdAt">[], - ): Promise[]> { + jobs: Omit, "id" | "createdAt">[], + ): Promise[]> { if (!jobs.length) return [] const values = jobs.map((job) => ({ queueName: this.queueName, @@ -88,18 +88,18 @@ export class PostgresQueueAdapter extends BaseQueueAdapter { priority: job.priority, attempts: job.attempts, maxAttempts: job.maxAttempts, - processAt: sql`${job.processAt.toISOString()}::timestamptz`, - cron: job.cron, - repeatEvery: job.repeatEvery, - repeatLimit: job.repeatLimit, - repeatCount: job.repeatCount, timeout: job.timeout, + processAt: sql`${new Date().toISOString()}::timestamptz`, + cron: null, + repeatEvery: null, + repeatLimit: null, + repeatCount: 0, })) const results = await this.db.insert(schema.queueJobs).values(values).returning() if (!results.length) { throw new Error("Failed to create jobs") } - return results.map((row) => this.transformJob(row) as BaseJob) + return results.map((row) => this.transformJob(row) as BatchJob) } async updateJobStatus( diff --git a/packages/adapter-kysely/src/postgres-adapter.ts b/packages/adapter-kysely/src/postgres-adapter.ts index 5fa2a38..3d1cf80 100644 --- a/packages/adapter-kysely/src/postgres-adapter.ts +++ b/packages/adapter-kysely/src/postgres-adapter.ts @@ -1,7 +1,7 @@ import type { Kysely } from "kysely" import { sql } from "kysely" -import type { BaseJob, JobStatus, QueueStats, SerializedError } from "@vorsteh-queue/core" +import type { BaseJob, BatchJob, JobStatus, QueueStats, SerializedError } from "@vorsteh-queue/core" import { asUtc, BaseQueueAdapter, serializeError } from "@vorsteh-queue/core" import type { DB, InsertQueueJobValue, QueueJob } from "./types" @@ -104,8 +104,8 @@ export class PostgresQueueAdapter extends BaseQueueAdapter { } async addJobs( - jobs: readonly Omit, "id" | "createdAt">[], - ): Promise[]> { + jobs: Omit, "id" | "createdAt">[], + ): Promise[]> { if (!jobs.length) return [] const values: InsertQueueJobValue[] = jobs.map((job) => ({ @@ -116,11 +116,11 @@ export class PostgresQueueAdapter extends BaseQueueAdapter { priority: job.priority, attempts: job.attempts, max_attempts: job.maxAttempts, - process_at: sql`${job.processAt.toISOString()}::timestamptz`, - cron: job.cron, - repeat_every: job.repeatEvery, - repeat_limit: job.repeatLimit, - repeat_count: job.repeatCount, + process_at: sql`${asUtc(new Date()).toISOString()}::timestamptz`, + cron: null, + repeat_every: null, + repeat_limit: null, + repeat_count: 0, timeout: job.timeout, })) @@ -134,7 +134,7 @@ export class PostgresQueueAdapter extends BaseQueueAdapter { throw new Error("Failed to create jobs") } - return results.map((row) => this.transformJob(row) as BaseJob) + return results.map((row) => this.transformJob(row) as BatchJob) } async updateJobStatus( @@ -272,9 +272,10 @@ export class PostgresQueueAdapter extends BaseQueueAdapter { // BatchJob omits scheduling fields, so we strip them return jobs.map((job) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { cron, repeat_every, repeat_limit, repeat_count, process_at, ...rest } = job + const { cron, repeat_every, repeat_limit, repeat_count, process_at, status, ...rest } = job return { ...rest, + status: status as JobStatus, maxAttempts: job.max_attempts, createdAt: job.created_at, processAt: job.process_at, @@ -284,7 +285,7 @@ export class PostgresQueueAdapter extends BaseQueueAdapter { error: job.error as SerializedError | undefined, result: job.result, progress: job.progress ?? 0, - // Remove scheduling fields for BatchJob + timeout: job.timeout ?? undefined, } }) } diff --git a/packages/adapter-prisma/src/postgres-adapter.ts b/packages/adapter-prisma/src/postgres-adapter.ts index 82d3c72..06bc56c 100644 --- a/packages/adapter-prisma/src/postgres-adapter.ts +++ b/packages/adapter-prisma/src/postgres-adapter.ts @@ -1,4 +1,4 @@ -import type { BaseJob, JobStatus, QueueStats, SerializedError } from "@vorsteh-queue/core" +import type { BaseJob, BatchJob, JobStatus, QueueStats, SerializedError } from "@vorsteh-queue/core" import { BaseQueueAdapter, serializeError } from "@vorsteh-queue/core" import type { PrismaClient, PrismaClientInternal } from "../types" @@ -69,6 +69,32 @@ export class PostgresPrismaQueueAdapter extends BaseQueueAdapter { return this.transformJob(result) as BaseJob } + async addJobs( + jobs: Omit, "id" | "createdAt">[], + ): Promise[]> { + if (!jobs.length) return [] + const created: BatchJob[] = [] + for (const job of jobs) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = (await this.db[this.modelName]!.create({ + data: { + queueName: this.queueName, + name: job.name, + payload: JSON.stringify(job.payload), + status: job.status, + priority: job.priority, + attempts: job.attempts, + maxAttempts: job.maxAttempts, + progress: job.progress ?? 0, + timeout: job.timeout, + }, + })) as QueueJob + + created.push(this.transformJob(result) as BatchJob) + } + return created + } + async updateJobStatus( id: string, status: JobStatus, diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 7327e95..f5ab86d 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -9,6 +9,7 @@ export { serializeError } from "./utils/error" export type { BaseJob, + BatchJob, JobHandler, JobOptions, JobPriority, From 5d6fa6fece37d94e9dddbcfe69442ce3aeeaec30 Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Thu, 25 Sep 2025 11:17:20 +0200 Subject: [PATCH 10/17] add missing `processAt` to prisma-adapter/addJobs --- packages/adapter-drizzle/src/postgres-adapter.ts | 2 +- packages/adapter-prisma/src/postgres-adapter.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/adapter-drizzle/src/postgres-adapter.ts b/packages/adapter-drizzle/src/postgres-adapter.ts index 75091d9..4b38784 100644 --- a/packages/adapter-drizzle/src/postgres-adapter.ts +++ b/packages/adapter-drizzle/src/postgres-adapter.ts @@ -89,7 +89,7 @@ export class PostgresQueueAdapter extends BaseQueueAdapter { attempts: job.attempts, maxAttempts: job.maxAttempts, timeout: job.timeout, - processAt: sql`${new Date().toISOString()}::timestamptz`, + processAt: sql`${asUtc(new Date()).toISOString()}::timestamptz`, cron: null, repeatEvery: null, repeatLimit: null, diff --git a/packages/adapter-prisma/src/postgres-adapter.ts b/packages/adapter-prisma/src/postgres-adapter.ts index 06bc56c..4c6d28a 100644 --- a/packages/adapter-prisma/src/postgres-adapter.ts +++ b/packages/adapter-prisma/src/postgres-adapter.ts @@ -1,5 +1,5 @@ import type { BaseJob, BatchJob, JobStatus, QueueStats, SerializedError } from "@vorsteh-queue/core" -import { BaseQueueAdapter, serializeError } from "@vorsteh-queue/core" +import { asUtc, BaseQueueAdapter, serializeError } from "@vorsteh-queue/core" import type { PrismaClient, PrismaClientInternal } from "../types" import type { QueueJobModel as QueueJob } from "./generated/prisma/models" @@ -84,6 +84,7 @@ export class PostgresPrismaQueueAdapter extends BaseQueueAdapter { status: job.status, priority: job.priority, attempts: job.attempts, + processAt: asUtc(new Date()), maxAttempts: job.maxAttempts, progress: job.progress ?? 0, timeout: job.timeout, From 0e4c917ddb87e5dac2d210429f6433b0aff55080 Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Thu, 25 Sep 2025 11:41:08 +0200 Subject: [PATCH 11/17] update job handling in MemoryQueueAdapter to include processAt and adjust batch job types in tests --- packages/core/src/adapters/memory.ts | 15 +++++++++--- packages/core/tests/batch.test.ts | 34 +++++++++++++++------------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/packages/core/src/adapters/memory.ts b/packages/core/src/adapters/memory.ts index a156dda..dbf4b33 100644 --- a/packages/core/src/adapters/memory.ts +++ b/packages/core/src/adapters/memory.ts @@ -1,4 +1,5 @@ import type { BaseJob, BatchJob, JobStatus, QueueStats } from "../../types" +import { asUtc } from "~/utils/scheduler" import { serializeError } from "../utils/error" import { BaseQueueAdapter } from "./base" @@ -54,13 +55,21 @@ export class MemoryQueueAdapter extends BaseQueueAdapter { const created: BatchJob[] = jobs.map((job) => { const id = this.generateId() const createdAt = new Date() - const newJob: BatchJob = { + const newJob: BaseJob = { ...job, id, createdAt, + processAt: asUtc(new Date()), + cron: undefined, + repeatEvery: undefined, + repeatLimit: undefined, + repeatCount: 0, + timeout: job.timeout ?? undefined, } - this.jobs.set(id, newJob as BaseJob) - return newJob + this.jobs.set(id, newJob) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { cron, repeatEvery, repeatLimit, repeatCount, processAt, ...batchJob } = newJob + return batchJob as BatchJob }) return Promise.resolve(created) } diff --git a/packages/core/tests/batch.test.ts b/packages/core/tests/batch.test.ts index e243e04..1fb29fb 100644 --- a/packages/core/tests/batch.test.ts +++ b/packages/core/tests/batch.test.ts @@ -1,13 +1,22 @@ import { beforeEach, describe, expect, it } from "vitest" -import type { BaseJob } from "../types" +import type { BatchJob } from "../types" import { MemoryQueueAdapter } from "../src/adapters/memory" import { Queue } from "../src/core/queue" describe("Queue Batch Processing", () => { + let queue: Queue + let adapter: MemoryQueueAdapter + + beforeEach(async () => { + adapter = new MemoryQueueAdapter() + queue = new Queue(adapter, { name: "batch-test", batch: { minSize: 2, maxSize: 5 } }) + await queue.connect() + }) + it("should process multiple batch job types with different handlers", async () => { - const fooBatches: BaseJob[][] = [] - const barBatches: BaseJob[][] = [] + const fooBatches: BatchJob[][] = [] + const barBatches: BatchJob[][] = [] queue.registerBatch("foo", (jobs) => { fooBatches.push(jobs.map((j) => ({ ...j }))) return jobs.map(() => ({ ok: "foo" })) @@ -19,8 +28,9 @@ describe("Queue Batch Processing", () => { await queue.addJobs("foo", [{ a: 1 }, { a: 2 }]) await queue.addJobs("bar", [{ b: 1 }, { b: 2 }]) + queue.start() - await new Promise((resolve) => setTimeout(resolve, 100)) + await new Promise((resolve) => setTimeout(resolve, 500)) expect(fooBatches.length).toBe(1) expect(barBatches.length).toBe(1) @@ -29,17 +39,9 @@ describe("Queue Batch Processing", () => { expect(fooBatches[0]?.every((j) => j.name === "foo")).toBe(true) expect(barBatches[0]?.every((j) => j.name === "bar")).toBe(true) }) - let queue: Queue - let adapter: MemoryQueueAdapter - - beforeEach(async () => { - adapter = new MemoryQueueAdapter() - queue = new Queue(adapter, { name: "batch-test", batch: { minSize: 2, maxSize: 5 } }) - await queue.connect() - }) it("should process jobs in batches with the batch handler", async () => { - const processedBatches: BaseJob[][] = [] + const processedBatches: BatchJob[][] = [] queue.registerBatch("batch-job", (jobs) => { processedBatches.push(jobs.map((j) => ({ ...j }))) // Simulate result array @@ -85,21 +87,21 @@ describe("Queue Batch Processing", () => { await queue.addJobs("batch-job", [{ foo: 1 }, { foo: 2 }]) queue.start() await new Promise((resolve) => setTimeout(resolve, 50)) - let jobs: BaseJob[] = [] + let jobs: BatchJob[] = [] if ( failedEvent && typeof failedEvent === "object" && "jobs" in failedEvent && Array.isArray((failedEvent as Record).jobs) ) { - jobs = (failedEvent as { jobs: BaseJob[] }).jobs + jobs = (failedEvent as { jobs: BatchJob[] }).jobs } expect(jobs.length).toBe(2) expect(failedEvent && typeof failedEvent === "object" && "error" in failedEvent).toBe(true) }) it("should not process jobs in batch if below minSize", async () => { - const processedBatches: BaseJob[][] = [] + const processedBatches: BatchJob[][] = [] queue.registerBatch("batch-job", (jobs) => { processedBatches.push(jobs.map((j) => ({ ...j }))) return Promise.resolve([]) From f8ee18ea3069ad250bcc9092614b725b8b4bb724 Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Thu, 25 Sep 2025 11:42:21 +0200 Subject: [PATCH 12/17] use relative path --- packages/core/src/adapters/memory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/adapters/memory.ts b/packages/core/src/adapters/memory.ts index dbf4b33..363b833 100644 --- a/packages/core/src/adapters/memory.ts +++ b/packages/core/src/adapters/memory.ts @@ -1,6 +1,6 @@ import type { BaseJob, BatchJob, JobStatus, QueueStats } from "../../types" -import { asUtc } from "~/utils/scheduler" import { serializeError } from "../utils/error" +import { asUtc } from "../utils/scheduler" import { BaseQueueAdapter } from "./base" /** From be36cb8a1c8968c1af8c825af4e4cea0c595794d Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Thu, 25 Sep 2025 11:50:02 +0200 Subject: [PATCH 13/17] fix type issues --- apps/docs/package.json | 1 + packages/shared-tests/src/tests/progress.ts | 4 ++-- packages/shared-tests/src/tests/timezone.ts | 4 ++-- pnpm-lock.yaml | 3 +++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/docs/package.json b/apps/docs/package.json index bfa7ee9..aa7c5ed 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -70,6 +70,7 @@ "@types/react-dom": "19.1.9", "@types/serve-handler": "6.1.4", "@vorsteh-queue/adapter-drizzle": "workspace:*", + "@vorsteh-queue/adapter-kysely": "workspace:*", "@vorsteh-queue/adapter-prisma": "workspace:*", "@vorsteh-queue/core": "workspace:*", "@vorsteh-queue/eslint-config": "workspace:*", diff --git a/packages/shared-tests/src/tests/progress.ts b/packages/shared-tests/src/tests/progress.ts index eb788af..d7113d6 100644 --- a/packages/shared-tests/src/tests/progress.ts +++ b/packages/shared-tests/src/tests/progress.ts @@ -1,7 +1,7 @@ import postgres from "postgres" import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest" -import type { BaseQueueAdapter } from "@vorsteh-queue/core" +import type { QueueAdapter } from "@vorsteh-queue/core" import type { SharedTestContext } from "../types" import { initDatabase } from "../database" @@ -10,7 +10,7 @@ export function runTests(ctx: SharedTestContext) describe("Progress Tests", () => { let database: Awaited> let db: ReturnType["initDbClient"]> - let adapter: BaseQueueAdapter + let adapter: QueueAdapter // the internal db client is based on postgres.js and will be used // to directly query the database for verification purposes diff --git a/packages/shared-tests/src/tests/timezone.ts b/packages/shared-tests/src/tests/timezone.ts index d2b8e51..f6751e2 100644 --- a/packages/shared-tests/src/tests/timezone.ts +++ b/packages/shared-tests/src/tests/timezone.ts @@ -1,7 +1,7 @@ import postgres from "postgres" import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest" -import type { BaseQueueAdapter } from "@vorsteh-queue/core" +import type { QueueAdapter } from "@vorsteh-queue/core" import type { SharedTestContext } from "../types" import { initDatabase } from "../database" @@ -10,7 +10,7 @@ export function runTests(ctx: SharedTestContext) describe("Timezone Tests", () => { let database: Awaited> let db: ReturnType["initDbClient"]> - let adapter: BaseQueueAdapter + let adapter: QueueAdapter // the internal db client is based on postgres.js and will be used // to directly query the database for verification purposes diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6e565a7..6ed3e0c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -192,6 +192,9 @@ importers: '@vorsteh-queue/adapter-drizzle': specifier: workspace:* version: link:../../packages/adapter-drizzle + '@vorsteh-queue/adapter-kysely': + specifier: workspace:* + version: link:../../packages/adapter-kysely '@vorsteh-queue/adapter-prisma': specifier: workspace:* version: link:../../packages/adapter-prisma From 007eae9210bf5d49a436efc917ef644447bb608e Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Thu, 25 Sep 2025 12:07:13 +0200 Subject: [PATCH 14/17] add example for batch processing --- examples/batch-processing/.env.example | 1 + examples/batch-processing/drizzle.config.ts | 10 +++ examples/batch-processing/package.json | 22 +++++++ examples/batch-processing/readme.mdx | 18 ++++++ examples/batch-processing/src/database.ts | 13 ++++ examples/batch-processing/src/index.ts | 72 +++++++++++++++++++++ examples/batch-processing/src/schema.ts | 3 + examples/batch-processing/tsconfig.json | 13 ++++ 8 files changed, 152 insertions(+) create mode 100644 examples/batch-processing/.env.example create mode 100644 examples/batch-processing/drizzle.config.ts create mode 100644 examples/batch-processing/package.json create mode 100644 examples/batch-processing/readme.mdx create mode 100644 examples/batch-processing/src/database.ts create mode 100644 examples/batch-processing/src/index.ts create mode 100644 examples/batch-processing/src/schema.ts create mode 100644 examples/batch-processing/tsconfig.json diff --git a/examples/batch-processing/.env.example b/examples/batch-processing/.env.example new file mode 100644 index 0000000..efc0f48 --- /dev/null +++ b/examples/batch-processing/.env.example @@ -0,0 +1 @@ +DATABASE_URL=postgresql://postgres:password@localhost:5432/queue_db \ No newline at end of file diff --git a/examples/batch-processing/drizzle.config.ts b/examples/batch-processing/drizzle.config.ts new file mode 100644 index 0000000..04c3b3c --- /dev/null +++ b/examples/batch-processing/drizzle.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from "drizzle-kit" + +export default defineConfig({ + schema: "./src/schema.ts", + out: "./drizzle", + dialect: "postgresql", + dbCredentials: { + url: process.env.DATABASE_URL || "postgresql://postgres:postgres@localhost:5432/queue_tracking", + }, +}) diff --git a/examples/batch-processing/package.json b/examples/batch-processing/package.json new file mode 100644 index 0000000..068a58c --- /dev/null +++ b/examples/batch-processing/package.json @@ -0,0 +1,22 @@ +{ + "name": "batch-processing-example", + "version": "1.0.0", + "description": "batch processing example using Drizzle ORM with postgres.js", + "type": "module", + "private": true, + "scripts": { + "dev": "tsx src/index.ts", + "db:push": "drizzle-kit push" + }, + "dependencies": { + "@vorsteh-queue/adapter-drizzle": "workspace:*", + "@vorsteh-queue/core": "workspace:*", + "drizzle-orm": "^0.44.5", + "postgres": "^3.4.7" + }, + "devDependencies": { + "drizzle-kit": "^0.31.4", + "tsx": "4.20.5", + "typescript": "^5.9.2" + } +} diff --git a/examples/batch-processing/readme.mdx b/examples/batch-processing/readme.mdx new file mode 100644 index 0000000..bb9ee9b --- /dev/null +++ b/examples/batch-processing/readme.mdx @@ -0,0 +1,18 @@ +--- +title: Batch Processing Example +navTitle: Batch Processing +description: Demonstrates batch job processing. Shows how to register batch handlers, dispatch jobs in batches, and monitor batch events for robust, event-driven workflows. +--- + +## Setup + +Use the CLI to create this example: + +```bash +npx create-vorsteh-queue@latest my-project --template batch-processing +cd my-project +cp .env.example .env +# Edit .env with your PostgreSQL database URL +pnpm db:push +pnpm dev +``` diff --git a/examples/batch-processing/src/database.ts b/examples/batch-processing/src/database.ts new file mode 100644 index 0000000..38138c4 --- /dev/null +++ b/examples/batch-processing/src/database.ts @@ -0,0 +1,13 @@ +import { drizzle } from "drizzle-orm/postgres-js" +import postgres from "postgres" + +import * as schema from "./schema" + +// Shared database connection +const client = postgres( + process.env.DATABASE_URL || "postgresql://postgres:password@localhost:5432/queue_tracking", + { max: 10 } // Connection pool +) + +export const db = drizzle(client, { schema }) +export { client } \ No newline at end of file diff --git a/examples/batch-processing/src/index.ts b/examples/batch-processing/src/index.ts new file mode 100644 index 0000000..4e90a04 --- /dev/null +++ b/examples/batch-processing/src/index.ts @@ -0,0 +1,72 @@ +import { PostgresQueueAdapter } from "@vorsteh-queue/adapter-drizzle" +import { Queue } from "@vorsteh-queue/core" + +import { client, db } from "./database" + +// Queue setup with batch config +const queue = new Queue(new PostgresQueueAdapter(db), { + name: "batch-demo", + batch: { minSize: 3, maxSize: 10, waitFor: 2000 }, + removeOnComplete: 5, + removeOnFail: 3, +}) + +interface FilePayload { + file: string +} +interface FileResult { + ok: boolean +} + +// Register a batch handler for processing files +queue.registerBatch("process-files", async (jobs) => { + console.log(`Processing batch of ${jobs.length} files...`) + // Simulate processing + await Promise.all( + jobs.map(async (job) => { + await new Promise((resolve) => setTimeout(resolve, 200)) + console.log(` ✔️ Processed: ${job.payload.file}`) + }), + ) + return jobs.map(() => ({ ok: true })) +}) + +// Listen to batch events +queue.on("batch:processing", (jobs) => { + console.log(`Batch processing started: ${jobs.length} jobs`) +}) +queue.on("batch:completed", (jobs) => { + console.log(`Batch completed: ${jobs.length} jobs`) +}) +queue.on("batch:failed", ({ jobs, error }) => { + console.error(`Batch failed: ${jobs.length} jobs`, error) +}) + +async function main() { + console.log("🚀 Starting Batch Processing Example\n") + + // Add jobs in a batch + await queue.addJobs("process-files", [ + { file: "a.csv" }, + { file: "b.csv" }, + { file: "c.csv" }, + { file: "d.csv" }, + ]) + + // Start processing + queue.start() + console.log("🔄 Queue processing started!") + + // Wait for batches to complete + setTimeout(async () => { + await queue.stop() + await client.end() + console.log("✅ Batch processing complete. Shutdown.") + process.exit(0) + }, 5000) +} + +main().catch((error) => { + console.error("❌ Batch processing error:", error) + process.exit(1) +}) diff --git a/examples/batch-processing/src/schema.ts b/examples/batch-processing/src/schema.ts new file mode 100644 index 0000000..5df706c --- /dev/null +++ b/examples/batch-processing/src/schema.ts @@ -0,0 +1,3 @@ +import { postgresSchema } from "@vorsteh-queue/adapter-drizzle" + +export const { queueJobs } = postgresSchema \ No newline at end of file diff --git a/examples/batch-processing/tsconfig.json b/examples/batch-processing/tsconfig.json new file mode 100644 index 0000000..b064900 --- /dev/null +++ b/examples/batch-processing/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} \ No newline at end of file From fadebab58aad85c82b03426655f6251b35c652cb Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Thu, 25 Sep 2025 12:10:17 +0200 Subject: [PATCH 15/17] update lock file --- pnpm-lock.yaml | 301 +++++-------------------------------------------- 1 file changed, 29 insertions(+), 272 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6ed3e0c..6412601 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -244,6 +244,31 @@ importers: specifier: ^5.9.2 version: 5.9.2 + examples/batch-processing: + dependencies: + '@vorsteh-queue/adapter-drizzle': + specifier: workspace:* + version: link:../../packages/adapter-drizzle + '@vorsteh-queue/core': + specifier: workspace:* + version: link:../../packages/core + drizzle-orm: + specifier: ^0.44.5 + version: 0.44.5(@electric-sql/pglite@0.3.10)(@opentelemetry/api@1.9.0)(@prisma/client@6.16.2(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2))(typescript@5.9.2))(@types/pg@8.15.5)(kysely@0.28.7)(mysql2@3.14.2)(pg@8.16.3)(postgres@3.4.7)(prisma@6.16.2(magicast@0.3.5)(typescript@5.9.2)) + postgres: + specifier: ^3.4.7 + version: 3.4.7 + devDependencies: + drizzle-kit: + specifier: ^0.31.4 + version: 0.31.4 + tsx: + specifier: 4.20.5 + version: 4.20.5 + typescript: + specifier: ^5.9.2 + version: 5.9.2 + examples/drizzle-pg: dependencies: '@vorsteh-queue/adapter-drizzle': @@ -1030,12 +1055,6 @@ packages: resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} deprecated: 'Merged into tsx: https://tsx.is' - '@esbuild/aix-ppc64@0.25.6': - resolution: {integrity: sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.25.9': resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} engines: {node: '>=18'} @@ -1048,12 +1067,6 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.25.6': - resolution: {integrity: sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.25.9': resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} engines: {node: '>=18'} @@ -1066,12 +1079,6 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.25.6': - resolution: {integrity: sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.25.9': resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} engines: {node: '>=18'} @@ -1084,12 +1091,6 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.25.6': - resolution: {integrity: sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.25.9': resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} engines: {node: '>=18'} @@ -1102,12 +1103,6 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.25.6': - resolution: {integrity: sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.25.9': resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} engines: {node: '>=18'} @@ -1120,12 +1115,6 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.25.6': - resolution: {integrity: sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.25.9': resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} engines: {node: '>=18'} @@ -1138,12 +1127,6 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.25.6': - resolution: {integrity: sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.25.9': resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} engines: {node: '>=18'} @@ -1156,12 +1139,6 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.6': - resolution: {integrity: sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.25.9': resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} engines: {node: '>=18'} @@ -1174,12 +1151,6 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.25.6': - resolution: {integrity: sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.25.9': resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} engines: {node: '>=18'} @@ -1192,12 +1163,6 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.25.6': - resolution: {integrity: sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.25.9': resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} engines: {node: '>=18'} @@ -1210,12 +1175,6 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.25.6': - resolution: {integrity: sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.25.9': resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} engines: {node: '>=18'} @@ -1228,12 +1187,6 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.25.6': - resolution: {integrity: sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.25.9': resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} engines: {node: '>=18'} @@ -1246,12 +1199,6 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.25.6': - resolution: {integrity: sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.25.9': resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} engines: {node: '>=18'} @@ -1264,12 +1211,6 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.25.6': - resolution: {integrity: sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.25.9': resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} engines: {node: '>=18'} @@ -1282,12 +1223,6 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.25.6': - resolution: {integrity: sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.25.9': resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} engines: {node: '>=18'} @@ -1300,12 +1235,6 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.25.6': - resolution: {integrity: sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.25.9': resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} engines: {node: '>=18'} @@ -1318,24 +1247,12 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.25.6': - resolution: {integrity: sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.25.9': resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.6': - resolution: {integrity: sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-arm64@0.25.9': resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} engines: {node: '>=18'} @@ -1348,24 +1265,12 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.6': - resolution: {integrity: sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.25.9': resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.6': - resolution: {integrity: sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-arm64@0.25.9': resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==} engines: {node: '>=18'} @@ -1378,24 +1283,12 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.6': - resolution: {integrity: sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.25.9': resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.6': - resolution: {integrity: sha512-+SqBcAWoB1fYKmpWoQP4pGtx+pUUC//RNYhFdbcSA16617cchuryuhOCRpPsjCblKukAckWsV+aQ3UKT/RMPcA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - '@esbuild/openharmony-arm64@0.25.9': resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==} engines: {node: '>=18'} @@ -1408,12 +1301,6 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.25.6': - resolution: {integrity: sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.25.9': resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} engines: {node: '>=18'} @@ -1426,12 +1313,6 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.25.6': - resolution: {integrity: sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.25.9': resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} engines: {node: '>=18'} @@ -1444,12 +1325,6 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.25.6': - resolution: {integrity: sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.25.9': resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} engines: {node: '>=18'} @@ -1462,12 +1337,6 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.25.6': - resolution: {integrity: sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.25.9': resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} engines: {node: '>=18'} @@ -4022,11 +3891,6 @@ packages: engines: {node: '>=12'} hasBin: true - esbuild@0.25.6: - resolution: {integrity: sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.25.9: resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} engines: {node: '>=18'} @@ -7516,225 +7380,147 @@ snapshots: '@esbuild-kit/core-utils': 3.3.2 get-tsconfig: 4.10.1 - '@esbuild/aix-ppc64@0.25.6': - optional: true - '@esbuild/aix-ppc64@0.25.9': optional: true '@esbuild/android-arm64@0.18.20': optional: true - '@esbuild/android-arm64@0.25.6': - optional: true - '@esbuild/android-arm64@0.25.9': optional: true '@esbuild/android-arm@0.18.20': optional: true - '@esbuild/android-arm@0.25.6': - optional: true - '@esbuild/android-arm@0.25.9': optional: true '@esbuild/android-x64@0.18.20': optional: true - '@esbuild/android-x64@0.25.6': - optional: true - '@esbuild/android-x64@0.25.9': optional: true '@esbuild/darwin-arm64@0.18.20': optional: true - '@esbuild/darwin-arm64@0.25.6': - optional: true - '@esbuild/darwin-arm64@0.25.9': optional: true '@esbuild/darwin-x64@0.18.20': optional: true - '@esbuild/darwin-x64@0.25.6': - optional: true - '@esbuild/darwin-x64@0.25.9': optional: true '@esbuild/freebsd-arm64@0.18.20': optional: true - '@esbuild/freebsd-arm64@0.25.6': - optional: true - '@esbuild/freebsd-arm64@0.25.9': optional: true '@esbuild/freebsd-x64@0.18.20': optional: true - '@esbuild/freebsd-x64@0.25.6': - optional: true - '@esbuild/freebsd-x64@0.25.9': optional: true '@esbuild/linux-arm64@0.18.20': optional: true - '@esbuild/linux-arm64@0.25.6': - optional: true - '@esbuild/linux-arm64@0.25.9': optional: true '@esbuild/linux-arm@0.18.20': optional: true - '@esbuild/linux-arm@0.25.6': - optional: true - '@esbuild/linux-arm@0.25.9': optional: true '@esbuild/linux-ia32@0.18.20': optional: true - '@esbuild/linux-ia32@0.25.6': - optional: true - '@esbuild/linux-ia32@0.25.9': optional: true '@esbuild/linux-loong64@0.18.20': optional: true - '@esbuild/linux-loong64@0.25.6': - optional: true - '@esbuild/linux-loong64@0.25.9': optional: true '@esbuild/linux-mips64el@0.18.20': optional: true - '@esbuild/linux-mips64el@0.25.6': - optional: true - '@esbuild/linux-mips64el@0.25.9': optional: true '@esbuild/linux-ppc64@0.18.20': optional: true - '@esbuild/linux-ppc64@0.25.6': - optional: true - '@esbuild/linux-ppc64@0.25.9': optional: true '@esbuild/linux-riscv64@0.18.20': optional: true - '@esbuild/linux-riscv64@0.25.6': - optional: true - '@esbuild/linux-riscv64@0.25.9': optional: true '@esbuild/linux-s390x@0.18.20': optional: true - '@esbuild/linux-s390x@0.25.6': - optional: true - '@esbuild/linux-s390x@0.25.9': optional: true '@esbuild/linux-x64@0.18.20': optional: true - '@esbuild/linux-x64@0.25.6': - optional: true - '@esbuild/linux-x64@0.25.9': optional: true - '@esbuild/netbsd-arm64@0.25.6': - optional: true - '@esbuild/netbsd-arm64@0.25.9': optional: true '@esbuild/netbsd-x64@0.18.20': optional: true - '@esbuild/netbsd-x64@0.25.6': - optional: true - '@esbuild/netbsd-x64@0.25.9': optional: true - '@esbuild/openbsd-arm64@0.25.6': - optional: true - '@esbuild/openbsd-arm64@0.25.9': optional: true '@esbuild/openbsd-x64@0.18.20': optional: true - '@esbuild/openbsd-x64@0.25.6': - optional: true - '@esbuild/openbsd-x64@0.25.9': optional: true - '@esbuild/openharmony-arm64@0.25.6': - optional: true - '@esbuild/openharmony-arm64@0.25.9': optional: true '@esbuild/sunos-x64@0.18.20': optional: true - '@esbuild/sunos-x64@0.25.6': - optional: true - '@esbuild/sunos-x64@0.25.9': optional: true '@esbuild/win32-arm64@0.18.20': optional: true - '@esbuild/win32-arm64@0.25.6': - optional: true - '@esbuild/win32-arm64@0.25.9': optional: true '@esbuild/win32-ia32@0.18.20': optional: true - '@esbuild/win32-ia32@0.25.6': - optional: true - '@esbuild/win32-ia32@0.25.9': optional: true '@esbuild/win32-x64@0.18.20': optional: true - '@esbuild/win32-x64@0.25.6': - optional: true - '@esbuild/win32-x64@0.25.9': optional: true @@ -10121,8 +9907,8 @@ snapshots: dependencies: '@drizzle-team/brocli': 0.10.2 '@esbuild-kit/esm-loader': 2.6.5 - esbuild: 0.25.6 - esbuild-register: 3.6.0(esbuild@0.25.6) + esbuild: 0.25.9 + esbuild-register: 3.6.0(esbuild@0.25.9) transitivePeerDependencies: - supports-color @@ -10300,10 +10086,10 @@ snapshots: esast-util-from-estree: 2.0.0 vfile-message: 4.0.3 - esbuild-register@3.6.0(esbuild@0.25.6): + esbuild-register@3.6.0(esbuild@0.25.9): dependencies: debug: 4.4.3 - esbuild: 0.25.6 + esbuild: 0.25.9 transitivePeerDependencies: - supports-color @@ -10332,35 +10118,6 @@ snapshots: '@esbuild/win32-ia32': 0.18.20 '@esbuild/win32-x64': 0.18.20 - esbuild@0.25.6: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.6 - '@esbuild/android-arm': 0.25.6 - '@esbuild/android-arm64': 0.25.6 - '@esbuild/android-x64': 0.25.6 - '@esbuild/darwin-arm64': 0.25.6 - '@esbuild/darwin-x64': 0.25.6 - '@esbuild/freebsd-arm64': 0.25.6 - '@esbuild/freebsd-x64': 0.25.6 - '@esbuild/linux-arm': 0.25.6 - '@esbuild/linux-arm64': 0.25.6 - '@esbuild/linux-ia32': 0.25.6 - '@esbuild/linux-loong64': 0.25.6 - '@esbuild/linux-mips64el': 0.25.6 - '@esbuild/linux-ppc64': 0.25.6 - '@esbuild/linux-riscv64': 0.25.6 - '@esbuild/linux-s390x': 0.25.6 - '@esbuild/linux-x64': 0.25.6 - '@esbuild/netbsd-arm64': 0.25.6 - '@esbuild/netbsd-x64': 0.25.6 - '@esbuild/openbsd-arm64': 0.25.6 - '@esbuild/openbsd-x64': 0.25.6 - '@esbuild/openharmony-arm64': 0.25.6 - '@esbuild/sunos-x64': 0.25.6 - '@esbuild/win32-arm64': 0.25.6 - '@esbuild/win32-ia32': 0.25.6 - '@esbuild/win32-x64': 0.25.6 - esbuild@0.25.9: optionalDependencies: '@esbuild/aix-ppc64': 0.25.9 From 6116dd5d6d043e14bebda7c2bf88abce66ba3884 Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Thu, 25 Sep 2025 12:15:37 +0200 Subject: [PATCH 16/17] fix audit findings --- package.json | 8 +- pnpm-lock.yaml | 466 +++---------------------------------------------- 2 files changed, 30 insertions(+), 444 deletions(-) diff --git a/package.json b/package.json index 3906b73..52c8095 100644 --- a/package.json +++ b/package.json @@ -51,5 +51,11 @@ "vite-tsconfig-paths": "^5.1.4", "vitest": "^3.2.4" }, - "prettier": "@vorsteh-queue/prettier-config" + "prettier": "@vorsteh-queue/prettier-config", + "pnpm": { + "overrides": { + "esbuild@<=0.24.2": ">=0.25.0", + "vite@>=6.0.0 <=6.3.5": "6.3.6" + } + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6412601..a2244f9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,10 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + esbuild@<=0.24.2: '>=0.25.0' + vite@>=6.0.0 <=6.3.5: 6.3.6 + importers: .: @@ -34,7 +38,7 @@ importers: version: 5.9.2 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.6(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1)) vitest: specifier: ^3.2.4 version: 3.2.4(@types/debug@4.1.12)(@types/node@24.5.2)(@vitest/ui@3.2.4)(jiti@2.5.1)(lightningcss@1.30.1)(msw@2.10.4(@types/node@24.5.2)(typescript@5.9.2))(tsx@4.20.5)(yaml@2.8.1) @@ -1061,192 +1065,96 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.18.20': - resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.25.9': resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.18.20': - resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.25.9': resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.18.20': - resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.25.9': resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.18.20': - resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.25.9': resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.18.20': - resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.25.9': resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.18.20': - resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.25.9': resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.18.20': - resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.25.9': resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.18.20': - resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.25.9': resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.18.20': - resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.25.9': resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.18.20': - resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.25.9': resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.18.20': - resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.25.9': resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.18.20': - resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.25.9': resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.18.20': - resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.25.9': resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.18.20': - resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.25.9': resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.18.20': - resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.25.9': resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.18.20': - resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.25.9': resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} engines: {node: '>=18'} @@ -1259,12 +1167,6 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.18.20': - resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.25.9': resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} engines: {node: '>=18'} @@ -1277,12 +1179,6 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.18.20': - resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.25.9': resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} engines: {node: '>=18'} @@ -1295,48 +1191,24 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.18.20': - resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.25.9': resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.18.20': - resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.25.9': resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.18.20': - resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.25.9': resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.18.20': - resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.25.9': resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} engines: {node: '>=18'} @@ -2429,201 +2301,101 @@ packages: '@rolldown/pluginutils@1.0.0-beta.40': resolution: {integrity: sha512-s3GeJKSQOwBlzdUrj4ISjJj5SfSh+aqn0wjOar4Bx95iV1ETI7F6S/5hLcfAxZ9kXDcyrAkxPlqmd1ZITttf+w==} - '@rollup/rollup-android-arm-eabi@4.43.0': - resolution: {integrity: sha512-Krjy9awJl6rKbruhQDgivNbD1WuLb8xAclM4IR4cN5pHGAs2oIMMQJEiC3IC/9TZJ+QZkmZhlMO/6MBGxPidpw==} - cpu: [arm] - os: [android] - '@rollup/rollup-android-arm-eabi@4.45.1': resolution: {integrity: sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.43.0': - resolution: {integrity: sha512-ss4YJwRt5I63454Rpj+mXCXicakdFmKnUNxr1dLK+5rv5FJgAxnN7s31a5VchRYxCFWdmnDWKd0wbAdTr0J5EA==} - cpu: [arm64] - os: [android] - '@rollup/rollup-android-arm64@4.45.1': resolution: {integrity: sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.43.0': - resolution: {integrity: sha512-eKoL8ykZ7zz8MjgBenEF2OoTNFAPFz1/lyJ5UmmFSz5jW+7XbH1+MAgCVHy72aG59rbuQLcJeiMrP8qP5d/N0A==} - cpu: [arm64] - os: [darwin] - '@rollup/rollup-darwin-arm64@4.45.1': resolution: {integrity: sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.43.0': - resolution: {integrity: sha512-SYwXJgaBYW33Wi/q4ubN+ldWC4DzQY62S4Ll2dgfr/dbPoF50dlQwEaEHSKrQdSjC6oIe1WgzosoaNoHCdNuMg==} - cpu: [x64] - os: [darwin] - '@rollup/rollup-darwin-x64@4.45.1': resolution: {integrity: sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.43.0': - resolution: {integrity: sha512-SV+U5sSo0yujrjzBF7/YidieK2iF6E7MdF6EbYxNz94lA+R0wKl3SiixGyG/9Klab6uNBIqsN7j4Y/Fya7wAjQ==} - cpu: [arm64] - os: [freebsd] - '@rollup/rollup-freebsd-arm64@4.45.1': resolution: {integrity: sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.43.0': - resolution: {integrity: sha512-J7uCsiV13L/VOeHJBo5SjasKiGxJ0g+nQTrBkAsmQBIdil3KhPnSE9GnRon4ejX1XDdsmK/l30IYLiAaQEO0Cg==} - cpu: [x64] - os: [freebsd] - '@rollup/rollup-freebsd-x64@4.45.1': resolution: {integrity: sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.43.0': - resolution: {integrity: sha512-gTJ/JnnjCMc15uwB10TTATBEhK9meBIY+gXP4s0sHD1zHOaIh4Dmy1X9wup18IiY9tTNk5gJc4yx9ctj/fjrIw==} - cpu: [arm] - os: [linux] - '@rollup/rollup-linux-arm-gnueabihf@4.45.1': resolution: {integrity: sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.43.0': - resolution: {integrity: sha512-ZJ3gZynL1LDSIvRfz0qXtTNs56n5DI2Mq+WACWZ7yGHFUEirHBRt7fyIk0NsCKhmRhn7WAcjgSkSVVxKlPNFFw==} - cpu: [arm] - os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.45.1': resolution: {integrity: sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.43.0': - resolution: {integrity: sha512-8FnkipasmOOSSlfucGYEu58U8cxEdhziKjPD2FIa0ONVMxvl/hmONtX/7y4vGjdUhjcTHlKlDhw3H9t98fPvyA==} - cpu: [arm64] - os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.45.1': resolution: {integrity: sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.43.0': - resolution: {integrity: sha512-KPPyAdlcIZ6S9C3S2cndXDkV0Bb1OSMsX0Eelr2Bay4EsF9yi9u9uzc9RniK3mcUGCLhWY9oLr6er80P5DE6XA==} - cpu: [arm64] - os: [linux] - '@rollup/rollup-linux-arm64-musl@4.45.1': resolution: {integrity: sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.43.0': - resolution: {integrity: sha512-HPGDIH0/ZzAZjvtlXj6g+KDQ9ZMHfSP553za7o2Odegb/BEfwJcR0Sw0RLNpQ9nC6Gy8s+3mSS9xjZ0n3rhcYg==} - cpu: [loong64] - os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.45.1': resolution: {integrity: sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.43.0': - resolution: {integrity: sha512-gEmwbOws4U4GLAJDhhtSPWPXUzDfMRedT3hFMyRAvM9Mrnj+dJIFIeL7otsv2WF3D7GrV0GIewW0y28dOYWkmw==} - cpu: [ppc64] - os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.45.1': resolution: {integrity: sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.43.0': - resolution: {integrity: sha512-XXKvo2e+wFtXZF/9xoWohHg+MuRnvO29TI5Hqe9xwN5uN8NKUYy7tXUG3EZAlfchufNCTHNGjEx7uN78KsBo0g==} - cpu: [riscv64] - os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.45.1': resolution: {integrity: sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.43.0': - resolution: {integrity: sha512-ruf3hPWhjw6uDFsOAzmbNIvlXFXlBQ4nk57Sec8E8rUxs/AI4HD6xmiiasOOx/3QxS2f5eQMKTAwk7KHwpzr/Q==} - cpu: [riscv64] - os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.45.1': resolution: {integrity: sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.43.0': - resolution: {integrity: sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw==} - cpu: [s390x] - os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.45.1': resolution: {integrity: sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.43.0': - resolution: {integrity: sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ==} - cpu: [x64] - os: [linux] - '@rollup/rollup-linux-x64-gnu@4.45.1': resolution: {integrity: sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.43.0': - resolution: {integrity: sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ==} - cpu: [x64] - os: [linux] - '@rollup/rollup-linux-x64-musl@4.45.1': resolution: {integrity: sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.43.0': - resolution: {integrity: sha512-wVzXp2qDSCOpcBCT5WRWLmpJRIzv23valvcTwMHEobkjippNf+C3ys/+wf07poPkeNix0paTNemB2XrHr2TnGw==} - cpu: [arm64] - os: [win32] - '@rollup/rollup-win32-arm64-msvc@4.45.1': resolution: {integrity: sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.43.0': - resolution: {integrity: sha512-fYCTEyzf8d+7diCw8b+asvWDCLMjsCEA8alvtAutqJOJp/wL5hs1rWSqJ1vkjgW0L2NB4bsYJrpKkiIPRR9dvw==} - cpu: [ia32] - os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.45.1': resolution: {integrity: sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.43.0': - resolution: {integrity: sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw==} - cpu: [x64] - os: [win32] - '@rollup/rollup-win32-x64-msvc@4.45.1': resolution: {integrity: sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==} cpu: [x64] @@ -2773,9 +2545,6 @@ packages: '@types/estree-jsx@1.0.5': resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} - '@types/estree@1.0.7': - resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} - '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} @@ -2935,7 +2704,7 @@ packages: resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} peerDependencies: msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + vite: 6.3.6 peerDependenciesMeta: msw: optional: true @@ -3884,12 +3653,7 @@ packages: esbuild-register@3.6.0: resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} peerDependencies: - esbuild: '>=0.12 <1' - - esbuild@0.18.20: - resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} - engines: {node: '>=12'} - hasBin: true + esbuild: '>=0.25.0' esbuild@0.25.9: resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} @@ -6050,11 +5814,6 @@ packages: peerDependencies: rollup: '*' - rollup@4.43.0: - resolution: {integrity: sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - rollup@4.45.1: resolution: {integrity: sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -6889,13 +6648,13 @@ packages: vite-tsconfig-paths@5.1.4: resolution: {integrity: sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==} peerDependencies: - vite: '*' + vite: 6.3.6 peerDependenciesMeta: vite: optional: true - vite@6.3.5: - resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} + vite@6.3.6: + resolution: {integrity: sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: @@ -7372,7 +7131,7 @@ snapshots: '@esbuild-kit/core-utils@3.3.2': dependencies: - esbuild: 0.18.20 + esbuild: 0.25.9 source-map-support: 0.5.21 '@esbuild-kit/esm-loader@2.6.5': @@ -7383,144 +7142,78 @@ snapshots: '@esbuild/aix-ppc64@0.25.9': optional: true - '@esbuild/android-arm64@0.18.20': - optional: true - '@esbuild/android-arm64@0.25.9': optional: true - '@esbuild/android-arm@0.18.20': - optional: true - '@esbuild/android-arm@0.25.9': optional: true - '@esbuild/android-x64@0.18.20': - optional: true - '@esbuild/android-x64@0.25.9': optional: true - '@esbuild/darwin-arm64@0.18.20': - optional: true - '@esbuild/darwin-arm64@0.25.9': optional: true - '@esbuild/darwin-x64@0.18.20': - optional: true - '@esbuild/darwin-x64@0.25.9': optional: true - '@esbuild/freebsd-arm64@0.18.20': - optional: true - '@esbuild/freebsd-arm64@0.25.9': optional: true - '@esbuild/freebsd-x64@0.18.20': - optional: true - '@esbuild/freebsd-x64@0.25.9': optional: true - '@esbuild/linux-arm64@0.18.20': - optional: true - '@esbuild/linux-arm64@0.25.9': optional: true - '@esbuild/linux-arm@0.18.20': - optional: true - '@esbuild/linux-arm@0.25.9': optional: true - '@esbuild/linux-ia32@0.18.20': - optional: true - '@esbuild/linux-ia32@0.25.9': optional: true - '@esbuild/linux-loong64@0.18.20': - optional: true - '@esbuild/linux-loong64@0.25.9': optional: true - '@esbuild/linux-mips64el@0.18.20': - optional: true - '@esbuild/linux-mips64el@0.25.9': optional: true - '@esbuild/linux-ppc64@0.18.20': - optional: true - '@esbuild/linux-ppc64@0.25.9': optional: true - '@esbuild/linux-riscv64@0.18.20': - optional: true - '@esbuild/linux-riscv64@0.25.9': optional: true - '@esbuild/linux-s390x@0.18.20': - optional: true - '@esbuild/linux-s390x@0.25.9': optional: true - '@esbuild/linux-x64@0.18.20': - optional: true - '@esbuild/linux-x64@0.25.9': optional: true '@esbuild/netbsd-arm64@0.25.9': optional: true - '@esbuild/netbsd-x64@0.18.20': - optional: true - '@esbuild/netbsd-x64@0.25.9': optional: true '@esbuild/openbsd-arm64@0.25.9': optional: true - '@esbuild/openbsd-x64@0.18.20': - optional: true - '@esbuild/openbsd-x64@0.25.9': optional: true '@esbuild/openharmony-arm64@0.25.9': optional: true - '@esbuild/sunos-x64@0.18.20': - optional: true - '@esbuild/sunos-x64@0.25.9': optional: true - '@esbuild/win32-arm64@0.18.20': - optional: true - '@esbuild/win32-arm64@0.25.9': optional: true - '@esbuild/win32-ia32@0.18.20': - optional: true - '@esbuild/win32-ia32@0.25.9': optional: true - '@esbuild/win32-x64@0.18.20': - optional: true - '@esbuild/win32-x64@0.25.9': optional: true @@ -8671,123 +8364,63 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.40': {} - '@rollup/rollup-android-arm-eabi@4.43.0': - optional: true - '@rollup/rollup-android-arm-eabi@4.45.1': optional: true - '@rollup/rollup-android-arm64@4.43.0': - optional: true - '@rollup/rollup-android-arm64@4.45.1': optional: true - '@rollup/rollup-darwin-arm64@4.43.0': - optional: true - '@rollup/rollup-darwin-arm64@4.45.1': optional: true - '@rollup/rollup-darwin-x64@4.43.0': - optional: true - '@rollup/rollup-darwin-x64@4.45.1': optional: true - '@rollup/rollup-freebsd-arm64@4.43.0': - optional: true - '@rollup/rollup-freebsd-arm64@4.45.1': optional: true - '@rollup/rollup-freebsd-x64@4.43.0': - optional: true - '@rollup/rollup-freebsd-x64@4.45.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.43.0': - optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.45.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.43.0': - optional: true - '@rollup/rollup-linux-arm-musleabihf@4.45.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.43.0': - optional: true - '@rollup/rollup-linux-arm64-gnu@4.45.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.43.0': - optional: true - '@rollup/rollup-linux-arm64-musl@4.45.1': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.43.0': - optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.45.1': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.43.0': - optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.45.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.43.0': - optional: true - '@rollup/rollup-linux-riscv64-gnu@4.45.1': optional: true - '@rollup/rollup-linux-riscv64-musl@4.43.0': - optional: true - '@rollup/rollup-linux-riscv64-musl@4.45.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.43.0': - optional: true - '@rollup/rollup-linux-s390x-gnu@4.45.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.43.0': - optional: true - '@rollup/rollup-linux-x64-gnu@4.45.1': optional: true - '@rollup/rollup-linux-x64-musl@4.43.0': - optional: true - '@rollup/rollup-linux-x64-musl@4.45.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.43.0': - optional: true - '@rollup/rollup-win32-arm64-msvc@4.45.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.43.0': - optional: true - '@rollup/rollup-win32-ia32-msvc@4.45.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.43.0': - optional: true - '@rollup/rollup-win32-x64-msvc@4.45.1': optional: true @@ -8932,8 +8565,6 @@ snapshots: dependencies: '@types/estree': 1.0.8 - '@types/estree@1.0.7': {} - '@types/estree@1.0.8': {} '@types/hast@3.0.4': @@ -9143,14 +8774,14 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(msw@2.10.4(@types/node@24.5.2)(typescript@5.9.2))(vite@6.3.5(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1))': + '@vitest/mocker@3.2.4(msw@2.10.4(@types/node@24.5.2)(typescript@5.9.2))(vite@6.3.6(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: msw: 2.10.4(@types/node@24.5.2)(typescript@5.9.2) - vite: 6.3.5(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1) + vite: 6.3.6(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1) '@vitest/pretty-format@3.2.4': dependencies: @@ -10093,31 +9724,6 @@ snapshots: transitivePeerDependencies: - supports-color - esbuild@0.18.20: - optionalDependencies: - '@esbuild/android-arm': 0.18.20 - '@esbuild/android-arm64': 0.18.20 - '@esbuild/android-x64': 0.18.20 - '@esbuild/darwin-arm64': 0.18.20 - '@esbuild/darwin-x64': 0.18.20 - '@esbuild/freebsd-arm64': 0.18.20 - '@esbuild/freebsd-x64': 0.18.20 - '@esbuild/linux-arm': 0.18.20 - '@esbuild/linux-arm64': 0.18.20 - '@esbuild/linux-ia32': 0.18.20 - '@esbuild/linux-loong64': 0.18.20 - '@esbuild/linux-mips64el': 0.18.20 - '@esbuild/linux-ppc64': 0.18.20 - '@esbuild/linux-riscv64': 0.18.20 - '@esbuild/linux-s390x': 0.18.20 - '@esbuild/linux-x64': 0.18.20 - '@esbuild/netbsd-x64': 0.18.20 - '@esbuild/openbsd-x64': 0.18.20 - '@esbuild/sunos-x64': 0.18.20 - '@esbuild/win32-arm64': 0.18.20 - '@esbuild/win32-ia32': 0.18.20 - '@esbuild/win32-x64': 0.18.20 - esbuild@0.25.9: optionalDependencies: '@esbuild/aix-ppc64': 0.25.9 @@ -12909,32 +12515,6 @@ snapshots: del: 8.0.0 rollup: 4.45.1 - rollup@4.43.0: - dependencies: - '@types/estree': 1.0.7 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.43.0 - '@rollup/rollup-android-arm64': 4.43.0 - '@rollup/rollup-darwin-arm64': 4.43.0 - '@rollup/rollup-darwin-x64': 4.43.0 - '@rollup/rollup-freebsd-arm64': 4.43.0 - '@rollup/rollup-freebsd-x64': 4.43.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.43.0 - '@rollup/rollup-linux-arm-musleabihf': 4.43.0 - '@rollup/rollup-linux-arm64-gnu': 4.43.0 - '@rollup/rollup-linux-arm64-musl': 4.43.0 - '@rollup/rollup-linux-loongarch64-gnu': 4.43.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.43.0 - '@rollup/rollup-linux-riscv64-gnu': 4.43.0 - '@rollup/rollup-linux-riscv64-musl': 4.43.0 - '@rollup/rollup-linux-s390x-gnu': 4.43.0 - '@rollup/rollup-linux-x64-gnu': 4.43.0 - '@rollup/rollup-linux-x64-musl': 4.43.0 - '@rollup/rollup-win32-arm64-msvc': 4.43.0 - '@rollup/rollup-win32-ia32-msvc': 4.43.0 - '@rollup/rollup-win32-x64-msvc': 4.43.0 - fsevents: 2.3.3 - rollup@4.45.1: dependencies: '@types/estree': 1.0.8 @@ -13934,7 +13514,7 @@ snapshots: debug: 4.4.1 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.3.5(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1) + vite: 6.3.6(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1) transitivePeerDependencies: - '@types/node' - jiti @@ -13949,25 +13529,25 @@ snapshots: - tsx - yaml - vite-tsconfig-paths@5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1)): + vite-tsconfig-paths@5.1.4(typescript@5.9.2)(vite@6.3.6(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1)): dependencies: debug: 4.4.1 globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.9.2) optionalDependencies: - vite: 6.3.5(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1) + vite: 6.3.6(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1) transitivePeerDependencies: - supports-color - typescript - vite@6.3.5(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1): + vite@6.3.6(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1): dependencies: esbuild: 0.25.9 - fdir: 6.4.6(picomatch@4.0.2) - picomatch: 4.0.2 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.43.0 - tinyglobby: 0.2.14 + rollup: 4.45.1 + tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.5.2 fsevents: 2.3.3 @@ -13980,7 +13560,7 @@ snapshots: dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(msw@2.10.4(@types/node@24.5.2)(typescript@5.9.2))(vite@6.3.5(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1)) + '@vitest/mocker': 3.2.4(msw@2.10.4(@types/node@24.5.2)(typescript@5.9.2))(vite@6.3.6(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -13998,7 +13578,7 @@ snapshots: tinyglobby: 0.2.14 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 6.3.5(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1) + vite: 6.3.6(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1) vite-node: 3.2.4(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.1) why-is-node-running: 2.3.0 optionalDependencies: From 5066d2f20deaa3054f1a8d72afcdeaf2cbb769aa Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Thu, 25 Sep 2025 12:22:09 +0200 Subject: [PATCH 17/17] [SKIP CI] update readme --- README.md | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1997fb0..f064064 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,11 @@ ## Features - **Type-safe**: Full TypeScript support with generic job payloads -- **Multiple adapters**: Drizzle ORM (PostgreSQL), Prisma ORM (PostgreSQL), and in-memory implementations +- **Multiple adapters**: Drizzle ORM (PostgreSQL), Prisma ORM (PostgreSQL), Kysely (PostgreSQL) and in-memory implementations - **Priority queues**: Numeric priority system (lower = higher priority) - **Delayed jobs**: Schedule jobs for future execution - **Recurring jobs**: Cron expressions and interval-based repetition +- **Batch processing**: Process multiple jobs concurrently for higher efficiency and better performance by supporting parallel execution and grouping of jobs. - **UTC-first timezone support**: Reliable timezone handling with UTC storage - **Progress tracking**: Real-time job progress updates - **Event system**: Listen to job lifecycle events @@ -24,6 +25,7 @@ │ ├── core/ # Core queue logic and interfaces │ ├── adapter-drizzle/ # Drizzle ORM adapter (PostgreSQL) │ └── adapter-prisma/ # Prisma ORM adapter (PostgreSQL) +│ └── adapter-kysely/ # Kysely adapter (PostgreSQL) ├── examples/ # Standalone usage examples └── tooling/ # Shared development tools ``` @@ -49,9 +51,14 @@ pnpm add @vorsteh-queue/core @vorsteh-queue/adapter-drizzle ```typescript // Drizzle ORM with PostgreSQL + +// Prisma ORM with PostgreSQL +import { PrismaClient } from "@prisma/client" import { drizzle } from "drizzle-orm/node-postgres" import { Pool } from "pg" + import { PostgresQueueAdapter } from "@vorsteh-queue/adapter-drizzle" +import { PostgresPrismaQueueAdapter } from "@vorsteh-queue/adapter-prisma" import { Queue } from "@vorsteh-queue/core" interface EmailPayload { @@ -69,10 +76,6 @@ const pool = new Pool({ connectionString: "postgresql://..." }) const db = drizzle(pool) const queue = new Queue(new PostgresQueueAdapter(db), { name: "my-queue" }) -// Prisma ORM with PostgreSQL -import { PrismaClient } from "@prisma/client" -import { PostgresPrismaQueueAdapter } from "@vorsteh-queue/adapter-prisma" - const prisma = new PrismaClient() const queue = new Queue(new PostgresPrismaQueueAdapter(prisma), { name: "my-queue" }) @@ -139,6 +142,26 @@ await queue.add("health-check", payload, { }) ``` +## Batch Processing + +Process multiple jobs in a single batch for higher throughput and efficiency. + +```typescript +queue.registerBatch<{ file: string }, { ok: boolean }>("process-files", async (jobs) => { + console.log(`Processing batch of ${jobs.length} files...`) + return jobs.map(() => ({ ok: true })) +}) + +await queue.addJobs("process-files", [{ file: "a.csv" }, { file: "b.csv" }, { file: "c.csv" }]) + +queue.on("batch:processing", (jobs) => { + console.log(`Batch started: ${jobs.length} jobs`) +}) +queue.on("batch:completed", (jobs) => { + console.log(`Batch completed: ${jobs.length} jobs`) +}) +``` + ## Job Cleanup ```typescript