Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
5ceda1f
updates
noxify Jun 26, 2026
99a3dd0
updates
noxify Jun 26, 2026
6322302
update instructions
noxify Jun 26, 2026
cf32846
updates
noxify Jun 26, 2026
73c46c7
feat(core)!: rewrite for 1.0 - Queue/Worker split, workflow engine
noxify Jun 29, 2026
cdaf42a
feat(adapter-drizzle)!: rewrite for new QueueAdapter interface
noxify Jun 29, 2026
b2cef7e
feat(adapter-kysely)!: rewrite for new QueueAdapter interface
noxify Jun 29, 2026
09e8837
feat(adapter-prisma)!: rewrite for Prisma 7 and new QueueAdapter inte…
noxify Jun 29, 2026
b609f04
feat(server): initial release - GraphQL API with Hono + Yoga + Pothos
noxify Jun 29, 2026
4fd31b9
feat(cli): initial release - CLI for queue management
noxify Jun 29, 2026
144200a
feat(shared-tests): rewrite adapter test suite for new QueueAdapter i…
noxify Jun 29, 2026
70466a8
chore(create-vorsteh-queue): lint fixes
noxify Jun 29, 2026
fbc77b7
chore(tsconfig): upgrade to ES2024 and refactor build configuration
noxify Jun 29, 2026
cfed629
chore(examples): migrate to ES2024, update dependencies, and restructure
noxify Jun 29, 2026
c55a0e4
chore(changesets): document 1.0 releases and new features
noxify Jun 29, 2026
16e76e4
chore: format code and restructure root configuration
noxify Jun 29, 2026
44031ab
update docs
noxify Jun 29, 2026
6f854df
update assets
noxify Jun 29, 2026
c4830d0
chore: migrate build system from rolldown to tsdown and restructure s…
noxify Jun 29, 2026
01df24e
feat: integrate web dashboard into server and consolidate configuration
noxify Jun 29, 2026
cd7c720
chore: raise minimum Node.js version to 22
noxify Jun 29, 2026
3020bcd
docs(project): add JSDoc guidelines and format commands reference
noxify Jun 29, 2026
ed24ac7
remove node 20
noxify Jun 29, 2026
f42e534
update pnpm action
noxify Jun 30, 2026
a0e8e57
update deps
noxify Jun 30, 2026
c640e7b
add missing locked skipped tests
noxify Jun 30, 2026
742ad97
fix build issue
noxify Jun 30, 2026
8cc9922
fix docs build
noxify Jun 30, 2026
44df004
ci: optimize test workflow with package change detection
noxify Jun 30, 2026
a2ea5a7
update docs
noxify Jun 30, 2026
04e5e61
update docs
noxify Jul 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
28 changes: 28 additions & 0 deletions .changeset/adapter-drizzle-1.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
"@vorsteh-queue/adapter-drizzle": major
---

## @vorsteh-queue/adapter-drizzle 1.0

### Breaking: QueueAdapter Interface Rewritten

Implements the new `QueueAdapter` interface with additional methods:

- `getJobById(id)` — retrieve a single job
- `getNextJob(options)` — now requires `handlerNames` and `activeGroups` for FIFO support
- `getNextJobsForHandler(name, count, groupConstraints)` — batch picking with group constraints
- `updateJobStatus(id, update)` — new signature with `JobStatusUpdate` object
- `cancelJob(id, reason?)` / `cancelJobs(filter)` — cancellation support
- `getDeadJobs()` / `redriveJob(id)` / `redriveJobs(filter?)` — DLQ support
- `findJobByUniqueKey(uniqueKey)` — unique job lookup
- `updateJobSteps(id, steps)` — step state persistence

### Breaking: Schema Changes (migration required)

New columns: `group_key`, `unique_key`, `cancelled_at`, `cancellation_reason`, `steps`

Changed: `timeout` from JSONB to INT (nullable, milliseconds)
Changed: `progress` from nullable to non-nullable INT (default 0)
Changed: `repeat_count` from nullable to non-nullable (default 0)

New indexes: `idx_queue_jobs_polling`, `idx_queue_jobs_delayed`, `idx_queue_jobs_active_groups`, `idx_queue_jobs_stats`
30 changes: 30 additions & 0 deletions .changeset/adapter-kysely-1.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
"@vorsteh-queue/adapter-kysely": major
---

## @vorsteh-queue/adapter-kysely 1.0

### Breaking: QueueAdapter Interface Rewritten

Implements the new `QueueAdapter` interface with additional methods:

- `getJobById(id)` — retrieve a single job
- `getNextJob(options)` — now requires `handlerNames` and `activeGroups` for FIFO support
- `getNextJobsForHandler(name, count, groupConstraints)` — batch picking with group constraints
- `updateJobStatus(id, update)` — new signature with `JobStatusUpdate` object
- `cancelJob(id, reason?)` / `cancelJobs(filter)` — cancellation support
- `getDeadJobs()` / `redriveJob(id)` / `redriveJobs(filter?)` — DLQ support
- `findJobByUniqueKey(uniqueKey)` — unique job lookup
- `updateJobSteps(id, steps)` — step state persistence

### Breaking: Schema Changes (migration required)

New columns: `group_key`, `unique_key`, `cancelled_at`, `cancellation_reason`, `steps`

Changed: `timeout` from JSONB to INT (nullable, milliseconds)
Changed: `progress` from nullable to non-nullable INT (default 0)
Changed: `repeat_count` from nullable to non-nullable (default 0)

New indexes: `idx_queue_jobs_polling`, `idx_queue_jobs_delayed`, `idx_queue_jobs_active_groups`, `idx_queue_jobs_stats`

Updated `createQueueJobsTable()` helper and migration files with new schema.
30 changes: 30 additions & 0 deletions .changeset/adapter-prisma-1.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
"@vorsteh-queue/adapter-prisma": major
---

## @vorsteh-queue/adapter-prisma 1.0

### Breaking: QueueAdapter Interface Rewritten

Implements the new `QueueAdapter` interface with additional methods:

- `getJobById(id)` — retrieve a single job
- `getNextJob(options)` — now requires `handlerNames` and `activeGroups` for FIFO support
- `getNextJobsForHandler(name, count, groupConstraints)` — batch picking with group constraints
- `updateJobStatus(id, update)` — new signature with `JobStatusUpdate` object
- `cancelJob(id, reason?)` / `cancelJobs(filter)` — cancellation support
- `getDeadJobs()` / `redriveJob(id)` / `redriveJobs(filter?)` — DLQ support
- `findJobByUniqueKey(uniqueKey)` — unique job lookup
- `updateJobSteps(id, steps)` — step state persistence

### Breaking: Schema Changes (migration required)

New columns: `group_key`, `unique_key`, `cancelled_at`, `cancellation_reason`, `steps`

Changed: `timeout` from JSONB to INT (nullable, milliseconds)
Changed: `progress` from nullable to non-nullable INT (default 0)
Changed: `repeat_count` from nullable to non-nullable (default 0)

New indexes: `idx_queue_jobs_polling`, `idx_queue_jobs_delayed`, `idx_queue_jobs_active_groups`, `idx_queue_jobs_stats`

Updated `schema.prisma` with new model fields.
14 changes: 14 additions & 0 deletions .changeset/cli-initial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"@vorsteh-queue/cli": minor
---

## @vorsteh-queue/cli — Initial Release

CLI tool for monitoring and managing vorsteh-queue jobs.

- Commands: `status`, `inspect`, `cancel`, `redrive`, `clear`
- Transports: direct adapter connection or remote GraphQL server
- `--json` flag on all commands for machine-readable output
- Configuration via environment variables (`VORSTEH_QUEUE_URL`, `VORSTEH_QUEUE_TOKEN`)
- `defineCliConfig()` helper for typed configuration
- Built with citty (unjs CLI framework)
59 changes: 59 additions & 0 deletions .changeset/core-1.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
"@vorsteh-queue/core": major
---

## @vorsteh-queue/core 1.0

### Breaking: Queue/Worker Architecture Split

The `Queue` class is now a producer-only. Job processing is handled by the new `Worker` class.

Before:

```typescript
const queue = new Queue(adapter, { name: "my-queue" })
queue.register("job", handler)
queue.start()
```

After:

```typescript
const queue = new Queue(adapter, { name: "my-queue" })
const worker = new Worker(adapter, { name: "my-queue", concurrency: 5 })
worker.register("job", handler)
worker.start()

// Queue is now producer-only — use it to add jobs
await queue.add("job", { data: "payload" })
```

### Breaking: Handler Signature

Handlers now receive a `JobContext` with an `AbortSignal` for timeout/cancellation support.

Before: `(job) => Promise<result>`
After: `(job, { signal, step }) => Promise<result>`

### Breaking: New Statuses

Added `cancelled` and `dead` statuses. `QueueStats` now includes all 7 statuses.

### Breaking: Removed APIs

`queue.register()`, `queue.start()`, `queue.stop()`, `queue.pause()`, `queue.resume()`, `queue.enqueue()`, `queue.dequeue()`

### New Features

- Job cancellation (`queue.cancel()`, `worker.cancelJob()`)
- Dead-letter queue (`queue.getDeadJobs()`, `queue.redrive()`, `queue.redriveAll()`)
- Group FIFO ordering (`{ group: "tenant-1" }`)
- Unique job deduplication (`{ unique: { key: "...", action: "reject" | "replace" } }`)
- `enqueueAndWait()` — enqueue and wait for result (hybrid event + polling)
- Typed event emitter on both Queue and Worker
- Configurable retry strategies (exponential, linear, fixed, custom function)
- State machine validation for job status transitions
- Per-handler concurrency limits
- Job Steps (`step.run()`, `step.sleep()`, `step.all()`) for durable multi-step execution
- Job Dependencies (`dependsOn`, circular detection)
- Rate Limiting (token-bucket per handler)
13 changes: 13 additions & 0 deletions .changeset/node-22-minimum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@vorsteh-queue/core": major
"@vorsteh-queue/adapter-drizzle": major
"@vorsteh-queue/adapter-prisma": major
"@vorsteh-queue/adapter-kysely": major
"@vorsteh-queue/server": major
"@vorsteh-queue/cli": major
"create-vorsteh-queue": major
---

**Breaking:** Minimum Node.js version raised from 20 to 22.

Node.js 22 is the current active LTS. This allows the use of stable native `fetch`, improved `AbortSignal` support, and aligns with the TypeScript 6.x target.
23 changes: 23 additions & 0 deletions .changeset/retry-runnow-delete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
"@vorsteh-queue/core": minor
"@vorsteh-queue/adapter-drizzle": minor
"@vorsteh-queue/adapter-kysely": minor
"@vorsteh-queue/adapter-prisma": minor
"@vorsteh-queue/server": minor
"@vorsteh-queue/cli": minor
---

## New operations: retry, runNow, deleteJob

Added three new job management operations across the full stack:

- **`retry(jobId)`** — resets a `failed` job to `pending` (clears error, resets attempts to 0)
- **`runNow(jobId)`** — promotes a `delayed` job to `pending` immediately (sets processAt to now)
- **`deleteJob(jobId)`** — permanently removes a single job by ID

Available on:

- `Queue` class: `queue.retry()`, `queue.runNow()`, `queue.deleteJob()`
- `QueueAdapter` interface: `retryJob()`, `runJobNow()`, `deleteJob()`
- GraphQL API: mutations `retryJob`, `runJobNow`, `deleteJob`
- CLI: commands `retry`, `run-now`, `delete`
21 changes: 21 additions & 0 deletions .changeset/server-dashboard-merge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
"@vorsteh-queue/server": minor
"@vorsteh-queue/core": minor
---

Integrated web dashboard into the server package and added unified configuration.

**Server (`@vorsteh-queue/server`):**

- Embedded the dashboard UI — served as static assets via Hono when `dashboard: true` (default)
- Simplified auth: `tokens: string[]`, custom `middleware`, or `false` (removed basic auth)
- Added `loadConfig()` to load `queue.config.ts` via c12
- Restructured: `src/api/` (GraphQL schema, auth, pubsub) + `src/ui/` (React SPA)
- Added `flows` query and implemented the `jobs` query (was a stub)
- Dashboard communicates with the API via `gql.tada` + `graphql-request`
- UI: Overview stats, Jobs list (filtered/paginated), Job detail, DLQ, Flows, Flow DAG visualization

**Core (`@vorsteh-queue/core`):**

- Added `getJobs()` and `getFlows()` to `QueueAdapter` interface
- Implemented in Memory, Drizzle, Kysely, and Prisma adapters
17 changes: 17 additions & 0 deletions .changeset/server-initial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
"@vorsteh-queue/server": minor
---

## @vorsteh-queue/server — Initial Release

GraphQL server and monitoring API for vorsteh-queue.

- `createQueueServer(config)` — standalone server (Hono + Node.js)
- `createQueueMiddleware(config)` — composable Hono middleware
- GraphQL API (via GraphQL Yoga + Pothos):
- Queries: `stats`, `job`, `deadJobs`, `size`
- Mutations: `cancelJob`, `redriveJob`, `redriveAll`, `clearJobs`
- Subscriptions: `jobStatusChanged`, `statsUpdated` (SSE-based)
- Authentication: token (Bearer), basic auth, custom middleware, or disabled
- PubSub for real-time event streaming to GraphQL subscribers
- `defineConfig()` helper for typed configuration
66 changes: 66 additions & 0 deletions .changeset/workflow-engine.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
"@vorsteh-queue/core": minor
---

## Workflow Engine Features

### Saga Compensation

Steps can declare `compensate` functions that run in reverse order when a later step fails:

```typescript
await step.run("charge", () => payments.charge(amount), {
compensate: (result) => payments.refund(result.txId),
})
```

### Signals / Human-in-the-Loop

Jobs can pause and wait for an external signal:

```typescript
const approval = await step.waitFor("approval", "manager-decision", {
timeout: "24h",
})
// External: await queue.signal(jobId, "manager-decision", { approved: true })
```

### Event Triggers

Automatically create follow-up jobs on completion:

```typescript
worker.trigger({
on: "order",
create: "send-receipt",
data: (result, job) => ({ email: result.email }),
condition: (result) => result.total > 0,
})
```

### Flow Producer (Parent-Child Job Trees)

Declarative job trees with parent-child relationships:

```typescript
const flow = await queue.addFlow({
name: "deploy",
payload: { version: "1.0" },
children: [
{ name: "build", payload: { target: "linux" } },
{ name: "test", payload: {}, children: [{ name: "lint", payload: {} }] },
],
})
```

- Parent waits in `waiting-children` status until all children complete
- `failParentOnFailure` cascades child failures upward
- `ctx.getChildrenResults()` provides children results to parent handlers
- `queue.getFlowTree(flowId)` returns the full tree for visualization

### New Status: `waiting-children`

Added to the state machine. Valid transitions:

- `pending` → `waiting-children`
- `waiting-children` → `pending` (all children done), `cancelled`, `failed`
45 changes: 36 additions & 9 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# GitHub Copilot Instructions

## Development Philosophy

- **Quality over quantity**: Write clean, maintainable, and well-structured code
- **Senior-level TypeScript**: Leverage advanced TypeScript features for type safety
- **Minimal and focused**: Every line of code should serve a clear purpose
- **Performance-conscious**: Consider efficiency and avoid unnecessary complexity

## TypeScript & ESLint Rules
- **No console.log**: Use proper logging or remove debug statements
## TypeScript & Linting Rules (oxlint via ultracite)

- **No console.log**: Use proper logging or remove debug statements (`no-console: error`)
- **Consistent type imports**: Use `import type` for type-only imports
- **No unused vars**: Prefix with `_` if intentionally unused
- **No unnecessary conditions**: Avoid redundant null checks
Expand All @@ -20,22 +22,46 @@
- **No useless path segments**: Avoid `/index` in import paths when possible
- **Prefer directory imports**: Use `../src` instead of `../src/index` for cleaner imports

## Prettier Configuration
- **Print width**: 100 characters max
## Formatting Configuration (oxfmt via ultracite)

- **Line width**: 100 characters max
- **No semicolons**: Use semicolon-free style
- **Import order**: Follow the specified import grouping:
- **Trailing commas**: ES5 style
- **Import sorting**: Handled automatically by oxfmt (`sortImports: true`)
- **Import order** (enforced by oxfmt):
1. Types first
2. React/Next.js/Expo (if applicable)
3. Third-party modules
4. @vorsteh-queue packages
5. Relative imports (~/,../, ./)

## Tooling & Verification

After making code changes, verify with these commands (in this order):

1. `pnpm format:fix` — Apply formatting
2. `pnpm lint:fix` — Auto-fix lint issues
3. `pnpm typecheck` — Verify types
4. `vitest --run` — Run tests (single run, no watch mode)

Always use the pnpm scripts from the root `package.json`. Never call tools directly via `npx` or `pnpm dlx`.

| Tool | Check | Fix |
| ------------------ | ---------------- | ----------------- |
| Formatter (oxfmt) | `pnpm format` | `pnpm format:fix` |
| Linter (oxlint) | `pnpm lint` | `pnpm lint:fix` |
| Types (TypeScript) | `pnpm typecheck` | — |
| Tests (Vitest) | `vitest --run` | — |
| Build (Turborepo) | `pnpm build` | — |
| Workspace (sherif) | `pnpm lint:ws` | — |

## Code Generation Guidelines

- Remove all `console.log` statements from generated code
- Use proper TypeScript types instead of `any` when possible
- **Use type-fest when available** - Prefer battle-tested utility types from type-fest over custom implementations
- Add ESLint disable comments only when absolutely necessary
- Follow the import order specified in prettier config
- Add lint disable comments only when absolutely necessary
- Follow the import order enforced by oxfmt
- Use consistent naming conventions (camelCase for variables, PascalCase for types)
- **Generic type parameters**: Always prefix with `T` (e.g., `TJobPayload`, `TResult`, `TEventData`)
- Prefer explicit return types for functions
Expand All @@ -46,8 +72,9 @@
- Optimize for readability and maintainability

## File Structure
- Keep imports organized according to prettier rules

- Keep imports organized according to oxfmt rules
- Use meaningful variable and function names
- Add proper JSDoc comments for public APIs
- Prefer composition over inheritance
- Use readonly arrays and objects where appropriate
- Use readonly arrays and objects where appropriate
Loading
Loading