Skip to content

@queuert/sqlite

const stateAdapter = await createSqliteStateAdapter({
stateProvider: SqliteStateProvider, // You implement this
tablePrefix?: string, // Table name prefix (default: "queuert_")
idType?: string, // SQL type for job IDs (default: "TEXT")
generateId?: () => string, // ID generator (default: crypto.randomUUID())
validateId?: (id: string) => boolean, // Optional predicate; runs on generated and caller-supplied IDs
checkForeignKeys?: boolean, // Enable PRAGMA foreign_keys (default: true)
});

Returns Promise<SqliteStateAdapter>.

SqliteStateAdapterStateAdapter extended with migration support, following the same pattern as PgStateAdapter:

type SqliteStateAdapter = StateAdapter & {
migrateToLatest: () => Promise<MigrationResult>;
};

SqliteStateProvider — you implement this to bridge your SQLite client (node:sqlite, bun:sqlite, better-sqlite3, ORMs, etc.). Note the extra columnTypes parameter compared to PgStateProvider:

type SqliteStateProvider<TTxContext> = {
withTransaction: <T>(fn: (txCtx: TTxContext) => Promise<T>) => Promise<T>;
withSavepoint?: <T>(txCtx: TTxContext, fn: (txCtx: TTxContext) => Promise<T>) => Promise<T>;
executeSql: (options: {
txCtx?: TTxContext;
id?: string; // Stable cache key for `db.prepare(sql)` handles; unique per resolved SQL (omitted for one-off SQL)
sql: string;
params: unknown[];
paramTypes: Record<number, RuntimeType>; // Positional param runtime types
columnTypes: Record<string, RuntimeType>; // Non-empty when the query returns rows
readOnly: boolean; // true for pure SELECTs (no FOR UPDATE)
}) => Promise<unknown[]>;
close?: () => Promise<void>; // Optional. Pass-through providers can omit it; when defined, must be idempotent.
};

The adapter pre-serializes non-primitive values, so the built-in better-sqlite3 and node:sqlite providers ignore paramTypes. It exists for custom providers backed by drivers that need explicit type hints (e.g. remote SQLite bridges).

Runtime tag describing each parameter or column type. Providers use it to drive serialization (for parameters) and parsing (for columns). Optional variants (string?, uuid?, etc.) accept null:

type RuntimeType =
| "string"
| "number"
| "boolean"
| "uuid"
| "json"
| "array"
| "jsonArray"
| "string?"
| "number?"
| "boolean?"
| "uuid?"
| "json?"
| "date?";

createAsyncRwLock / AsyncRwLock / LockHandle

Section titled “createAsyncRwLock / AsyncRwLock / LockHandle”

Re-exported from queuert/internal. SQLite requires serialized write access but permits concurrent reads. If your application performs writes outside of Queuert (e.g., in your state provider), use createAsyncRwLock to coordinate access so that your writes and Queuert’s writes don’t conflict:

import { createAsyncRwLock } from "@queuert/sqlite";
const lock = createAsyncRwLock();
// Exclusive (writer) — blocks readers and other writers
{
using _h = await lock.acquireWrite();
// Serialized write access
}
// Shared (reader) — concurrent with other readers, blocks writers
{
using _h = await lock.acquireRead();
// Concurrent read access
}

Handles implement Symbol.dispose, so using releases at scope exit. You can also call handle.release() manually. Release is idempotent.

Same type as @queuert/postgres:

type MigrationResult = {
applied: string[]; // Migrations applied in this run
skipped: string[]; // Already-applied migrations
unrecognized: string[]; // Unknown migrations found in the database
};