@bumail/queue 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +44 -8
  2. package/dist/chunks/index-b4xvg3xn.js +23 -0
  3. package/dist/chunks/index-b4xvg3xn.js.map +10 -0
  4. package/dist/chunks/index-vg971acr.js.map +2 -2
  5. package/dist/contract/queue-store.d.ts +8 -2
  6. package/dist/contract/queue-store.d.ts.map +1 -1
  7. package/dist/dsn/build.d.ts +7 -3
  8. package/dist/dsn/build.d.ts.map +1 -1
  9. package/dist/errors.d.ts +5 -2
  10. package/dist/errors.d.ts.map +1 -1
  11. package/dist/index.js +117 -33
  12. package/dist/index.js.map +8 -7
  13. package/dist/masked.d.ts +8 -0
  14. package/dist/masked.d.ts.map +1 -0
  15. package/dist/postgres/connect.d.ts +6 -0
  16. package/dist/postgres/connect.d.ts.map +1 -1
  17. package/dist/postgres/index.js +49 -28
  18. package/dist/postgres/index.js.map +7 -6
  19. package/dist/postgres/isolation.d.ts +6 -0
  20. package/dist/postgres/isolation.d.ts.map +1 -0
  21. package/dist/postgres/schema.d.ts.map +1 -1
  22. package/dist/postgres/store.d.ts.map +1 -1
  23. package/dist/queue/deliver.d.ts +10 -1
  24. package/dist/queue/deliver.d.ts.map +1 -1
  25. package/dist/queue/lease.d.ts +41 -0
  26. package/dist/queue/lease.d.ts.map +1 -0
  27. package/dist/queue/notify.d.ts +3 -2
  28. package/dist/queue/notify.d.ts.map +1 -1
  29. package/dist/queue/worker.d.ts.map +1 -1
  30. package/dist/redis/connect.d.ts +27 -0
  31. package/dist/redis/connect.d.ts.map +1 -0
  32. package/dist/redis/index.d.ts +3 -0
  33. package/dist/redis/index.d.ts.map +1 -0
  34. package/dist/redis/index.js +438 -0
  35. package/dist/redis/index.js.map +14 -0
  36. package/dist/redis/items.d.ts +13 -0
  37. package/dist/redis/items.d.ts.map +1 -0
  38. package/dist/redis/options.d.ts +47 -0
  39. package/dist/redis/options.d.ts.map +1 -0
  40. package/dist/redis/run.d.ts +12 -0
  41. package/dist/redis/run.d.ts.map +1 -0
  42. package/dist/redis/scripts.d.ts +60 -0
  43. package/dist/redis/scripts.d.ts.map +1 -0
  44. package/dist/redis/store.d.ts +30 -0
  45. package/dist/redis/store.d.ts.map +1 -0
  46. package/docs/README.md +1 -1
  47. package/docs/guide.md +271 -16
  48. package/docs/roadmap.md +49 -7
  49. package/docs/troubleshooting.md +303 -16
  50. package/package.json +9 -3
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/postgres/connect.ts", "../src/postgres/rows.ts", "../src/postgres/schema.ts", "../src/postgres/statements.ts", "../src/postgres/store.ts"],
3
+ "sources": ["../src/postgres/connect.ts", "../src/postgres/rows.ts", "../src/postgres/isolation.ts", "../src/postgres/schema.ts", "../src/postgres/statements.ts", "../src/postgres/store.ts"],
4
4
  "sourcesContent": [
5
- "import { invalid } from '../errors';\nimport type { PostgresClient, PostgresQueueStoreOptions } from './options';\n\n/** The tables of one queue, each name its prefix and a fixed suffix. */\nexport interface Tables {\n\treadonly prefix: string;\n\treadonly items: string;\n\treadonly messages: string;\n\treadonly schema: string;\n}\n\n/** The client a store uses, and whether it opened it (and so closes it). */\nexport interface Connection {\n\treadonly client: PostgresClient;\n\treadonly owned: boolean;\n\treadonly tables: Tables;\n}\n\nconst DEFAULT_PREFIX = 'bumail_queue_';\n\n/**\n * Within PostgreSQL's 63 bytes for a name once the longest name derived\n * from it (`messages_item_id_fkey`, 21) follows. Nothing else is allowed:\n * the prefix is written into the statements, never bound.\n */\nconst PREFIX = /^[a-z_][a-z0-9_]{0,39}$/;\n\nfunction tablesOf(value: unknown): Tables {\n\tconst prefix = value ?? DEFAULT_PREFIX;\n\tif (typeof prefix !== 'string' || !PREFIX.test(prefix)) {\n\t\tthrow invalid(\n\t\t\t`tablePrefix must be lowercase letters, digits and underscores, starting with a letter or an underscore, at most 40 characters, not ${JSON.stringify(prefix)}`,\n\t\t);\n\t}\n\treturn {\n\t\tprefix,\n\t\titems: `${prefix}items`,\n\t\tmessages: `${prefix}messages`,\n\t\tschema: `${prefix}schema`,\n\t};\n}\n\nconst NEEDS_SQL =\n\t'A PostgreSQL queue store needs sql: a Bun.SQL client or a postgres:// URL';\n\n/** A `postgres://` or `postgresql://` URL; never echoed, since it may hold a password. */\nfunction urlOf(value: string | URL): URL {\n\tconst url = URL.parse(String(value));\n\tif (url === null || !['postgres:', 'postgresql:'].includes(url.protocol)) {\n\t\tthrow invalid(NEEDS_SQL);\n\t}\n\treturn url;\n}\n\n/** `text` with the password masked, as written in the URL and decoded, if it decodes. */\nfunction masked(text: string, raw: string): string {\n\tlet decoded = raw;\n\ttry {\n\t\tdecoded = decodeURIComponent(raw);\n\t} catch {\n\t\t// Not percent-encoding Bun reads either: the raw form is what it would repeat.\n\t}\n\tlet out = text;\n\tfor (const password of [raw, decoded]) {\n\t\tif (password !== '') out = out.replaceAll(password, '…');\n\t}\n\treturn out;\n}\n\n/**\n * A client of the store's own for the URL. `Bun.SQL` refuses some\n * parameters at once (a `sslmode` it does not know): that is `INVALID`,\n * its reason kept and the password, should it be repeated, masked.\n */\nfunction clientFor(url: URL): PostgresClient {\n\ttry {\n\t\treturn new Bun.SQL(url.href);\n\t} catch (error) {\n\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\tthrow invalid(\n\t\t\t`The URL in sql cannot be opened: ${masked(reason, url.password)}`,\n\t\t);\n\t}\n}\n\nconst isClient = (value: unknown): value is PostgresClient =>\n\t(typeof value === 'object' || typeof value === 'function') &&\n\tvalue !== null &&\n\ttypeof (value as PostgresClient).unsafe === 'function' &&\n\ttypeof (value as PostgresClient).begin === 'function' &&\n\ttypeof (value as PostgresClient).close === 'function';\n\n/** A `Bun.SQL` client says which database it speaks: the queue needs PostgreSQL. */\nfunction checkAdapter(client: PostgresClient): void {\n\tconst adapter = (client as { options?: { adapter?: unknown } }).options\n\t\t?.adapter;\n\tif (adapter !== undefined && adapter !== 'postgres') {\n\t\tthrow invalid(\n\t\t\t`sql is a ${String(adapter)} client; the queue needs a PostgreSQL one`,\n\t\t);\n\t}\n}\n\n/** Checks the options and opens a client for a URL; connects to nothing yet. */\nexport function connect(options: PostgresQueueStoreOptions): Connection {\n\tconst given = (options as PostgresQueueStoreOptions | undefined)?.sql;\n\tconst tables = tablesOf(options?.tablePrefix);\n\tif (isClient(given)) {\n\t\tcheckAdapter(given);\n\t\treturn { client: given, owned: false, tables };\n\t}\n\tif (typeof given !== 'string' && !(given instanceof URL)) {\n\t\tthrow invalid(NEEDS_SQL);\n\t}\n\treturn { client: clientFor(urlOf(given)), owned: true, tables };\n}\n",
5
+ "import { invalid } from '../errors';\nimport { masked } from '../masked';\nimport type { PostgresClient, PostgresQueueStoreOptions } from './options';\n\n/** The tables of one queue, each name its prefix and a fixed suffix. */\nexport interface Tables {\n\treadonly prefix: string;\n\treadonly items: string;\n\treadonly messages: string;\n\treadonly schema: string;\n}\n\n/** The client a store uses, and whether it opened it (and so closes it). */\nexport interface Connection {\n\treadonly client: PostgresClient;\n\treadonly owned: boolean;\n\treadonly tables: Tables;\n\t/**\n\t * The password the client logs in with, as far as the store can know\n\t * it — its URL's, or a given `Bun.SQL`'s `options.password` — so an\n\t * error that repeats it is masked; `''` when unknown.\n\t */\n\treadonly password: string;\n}\n\nconst DEFAULT_PREFIX = 'bumail_queue_';\n\n/**\n * Within PostgreSQL's 63 bytes for a name once the longest name derived\n * from it (`messages_item_id_fkey`, 21) follows. Nothing else is allowed:\n * the prefix is written into the statements, never bound.\n */\nconst PREFIX = /^[a-z_][a-z0-9_]{0,39}$/;\n\nfunction tablesOf(value: unknown): Tables {\n\tconst prefix = value ?? DEFAULT_PREFIX;\n\tif (typeof prefix !== 'string' || !PREFIX.test(prefix)) {\n\t\tthrow invalid(\n\t\t\t`tablePrefix must be lowercase letters, digits and underscores, starting with a letter or an underscore, at most 40 characters, not ${JSON.stringify(prefix)}`,\n\t\t);\n\t}\n\treturn {\n\t\tprefix,\n\t\titems: `${prefix}items`,\n\t\tmessages: `${prefix}messages`,\n\t\tschema: `${prefix}schema`,\n\t};\n}\n\nconst NEEDS_SQL =\n\t'A PostgreSQL queue store needs sql: a Bun.SQL client or a postgres:// URL';\n\n/** A `postgres://` or `postgresql://` URL; never echoed, since it may hold a password. */\nfunction urlOf(value: string | URL): URL {\n\tconst url = URL.parse(String(value));\n\tif (url === null || !['postgres:', 'postgresql:'].includes(url.protocol)) {\n\t\tthrow invalid(NEEDS_SQL);\n\t}\n\treturn url;\n}\n\n/**\n * A client of the store's own for the URL. `Bun.SQL` refuses some\n * parameters at once (a `sslmode` it does not know): that is `INVALID`,\n * its reason kept and the password, should it be repeated, masked.\n */\nfunction clientFor(url: URL): PostgresClient {\n\ttry {\n\t\treturn new Bun.SQL(url.href);\n\t} catch (error) {\n\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\tthrow invalid(\n\t\t\t`The URL in sql cannot be opened: ${masked(reason, url.password)}`,\n\t\t);\n\t}\n}\n\nconst isClient = (value: unknown): value is PostgresClient =>\n\t(typeof value === 'object' || typeof value === 'function') &&\n\tvalue !== null &&\n\ttypeof (value as PostgresClient).unsafe === 'function' &&\n\ttypeof (value as PostgresClient).begin === 'function' &&\n\ttypeof (value as PostgresClient).close === 'function';\n\n/** A `Bun.SQL` client says which database it speaks: the queue needs PostgreSQL. */\nfunction checkAdapter(client: PostgresClient): void {\n\tconst adapter = (client as { options?: { adapter?: unknown } }).options\n\t\t?.adapter;\n\tif (adapter !== undefined && adapter !== 'postgres') {\n\t\tthrow invalid(\n\t\t\t`sql is a ${String(adapter)} client; the queue needs a PostgreSQL one`,\n\t\t);\n\t}\n}\n\n/** A given client's password, when it says it as text (`Bun.SQL` does). */\nfunction passwordOf(client: PostgresClient): string {\n\tconst password = (client as { options?: { password?: unknown } }).options\n\t\t?.password;\n\treturn typeof password === 'string' ? password : '';\n}\n\n/** Checks the options and opens a client for a URL; connects to nothing yet. */\nexport function connect(options: PostgresQueueStoreOptions): Connection {\n\tconst given = (options as PostgresQueueStoreOptions | undefined)?.sql;\n\tconst tables = tablesOf(options?.tablePrefix);\n\tif (isClient(given)) {\n\t\tcheckAdapter(given);\n\t\treturn {\n\t\t\tclient: given,\n\t\t\towned: false,\n\t\t\ttables,\n\t\t\tpassword: passwordOf(given),\n\t\t};\n\t}\n\tif (typeof given !== 'string' && !(given instanceof URL)) {\n\t\tthrow invalid(NEEDS_SQL);\n\t}\n\tconst url = urlOf(given);\n\treturn {\n\t\tclient: clientFor(url),\n\t\towned: true,\n\t\ttables,\n\t\tpassword: url.password,\n\t};\n}\n",
6
6
  "import type { QueueItem, RecipientState } from '../contract/types';\n\n/** A row of the items table, as `Bun.SQL` reads it. */\nexport interface ItemRow {\n\treadonly id: string;\n\treadonly sender: string;\n\t/** `jsonb`: parsed or not, depending on the client. */\n\treadonly recipients: string | RecipientState[];\n\treadonly size: number;\n\treadonly created_at: number;\n\treadonly next_attempt_at: number;\n\treadonly attempts: number;\n\treadonly delay_notified: boolean;\n\treadonly lease_owner: string | null;\n\treadonly lease_expires_at: number | null;\n}\n\n/** The columns a query reads to build an item. */\nexport const COLUMNS =\n\t'id, sender, recipients, size, created_at, next_attempt_at, attempts, delay_notified, lease_owner, lease_expires_at';\n\nexport function itemOf(row: ItemRow): QueueItem {\n\tconst recipients =\n\t\ttypeof row.recipients === 'string'\n\t\t\t? (JSON.parse(row.recipients) as RecipientState[])\n\t\t\t: structuredClone(row.recipients);\n\tconst item: QueueItem = {\n\t\tid: row.id,\n\t\tfrom: row.sender,\n\t\trecipients,\n\t\tsize: row.size,\n\t\tcreatedAt: row.created_at,\n\t\tnextAttemptAt: row.next_attempt_at,\n\t\tattempts: row.attempts,\n\t\tdelayNotified: row.delay_notified,\n\t};\n\tif (row.lease_owner === null || row.lease_expires_at === null) return item;\n\treturn {\n\t\t...item,\n\t\tlease: { owner: row.lease_owner, expiresAt: row.lease_expires_at },\n\t};\n}\n\n/** The rows a statement returned. */\nexport const rowsOf = async <T>(pending: PromiseLike<unknown>) =>\n\t(await pending) as T[];\n",
7
- "import { QueueError } from '../errors';\nimport type { Tables } from './connect';\nimport type { PostgresClient, PostgresQueryable } from './options';\nimport { rowsOf } from './rows';\n\n/**\n * The migrations, in order, each a list of statements: the schema table's\n * `version` is how many of them the database has run. A migration is\n * never edited once released; a change is a new one at the end. They\n * follow the `bun:sqlite` store's, column for column: times are\n * milliseconds as `double precision` (SQLite's `REAL`), the recipients\n * JSON, the message its bytes, in a table of its own.\n */\nexport function migrations({\n\tprefix,\n\titems,\n\tmessages,\n}: Tables): readonly (readonly string[])[] {\n\treturn [\n\t\t// 1: the items, and their messages in a table of their own.\n\t\t[\n\t\t\t`CREATE TABLE ${items} (\n\t\t\t\tseq bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,\n\t\t\t\tid text NOT NULL UNIQUE,\n\t\t\t\tsender text NOT NULL,\n\t\t\t\trecipients jsonb NOT NULL CHECK (jsonb_typeof(recipients) = 'array'),\n\t\t\t\tsize integer NOT NULL,\n\t\t\t\tcreated_at double precision NOT NULL,\n\t\t\t\tnext_attempt_at double precision NOT NULL,\n\t\t\t\tattempts integer NOT NULL,\n\t\t\t\tdelay_notified boolean NOT NULL,\n\t\t\t\tlease_owner text,\n\t\t\t\tlease_expires_at double precision,\n\t\t\t\tCHECK ((lease_owner IS NULL) = (lease_expires_at IS NULL))\n\t\t\t)`,\n\t\t\t// The claim's order, and its range: the earliest due first.\n\t\t\t`CREATE INDEX ${prefix}items_due ON ${items} (next_attempt_at, seq)`,\n\t\t\t`CREATE TABLE ${messages} (\n\t\t\t\titem_id text PRIMARY KEY REFERENCES ${items} (id) ON DELETE CASCADE,\n\t\t\t\tcontent bytea NOT NULL\n\t\t\t)`,\n\t\t],\n\t];\n}\n\n/** Tables a newer store wrote, with more migrations than this one knows, are refused. */\nfunction checkNotNewer(version: number, known: number): void {\n\tif (version > known) {\n\t\tthrow new QueueError(\n\t\t\t'INVALID',\n\t\t\t`The database is at schema version ${version}, newer than this store's ${known}`,\n\t\t);\n\t}\n}\n\n/**\n * The version the tables are at, read with no lock and no DDL — so a role\n * with no `CREATE` reads it — or `undefined` with no schema table yet.\n */\nasync function versionOf(\n\tsql: PostgresQueryable,\n\ttables: Tables,\n): Promise<number | undefined> {\n\tconst [found] = await rowsOf<{ present: boolean }>(\n\t\tsql.unsafe('SELECT to_regclass($1) IS NOT NULL AS present', [\n\t\t\ttables.schema,\n\t\t]),\n\t);\n\tif (!found?.present) return undefined;\n\tconst [row] = await rowsOf<{ version: number }>(\n\t\tsql.unsafe(`SELECT version FROM ${tables.schema}`),\n\t);\n\treturn row?.version ?? 0;\n}\n\n/**\n * Brings the tables to the last migration. Tables already current are\n * only read: no lock, no DDL, so a worker's role needs no `CREATE`.\n * Otherwise in one transaction — a migration that fails leaves them as\n * they were — under one advisory lock, so instances starting together\n * run each migration once.\n */\nexport async function migrate(\n\tclient: PostgresClient,\n\ttables: Tables,\n): Promise<void> {\n\tconst all = migrations(tables);\n\tconst current = await versionOf(client, tables);\n\tif (current !== undefined) {\n\t\tcheckNotNewer(current, all.length);\n\t\tif (current === all.length) return;\n\t}\n\tawait client.begin(async (sql: PostgresQueryable) => {\n\t\tawait sql.unsafe('SELECT pg_advisory_xact_lock(hashtext($1)) IS NULL', [\n\t\t\ttables.schema,\n\t\t]);\n\t\tawait sql.unsafe(\n\t\t\t`CREATE TABLE IF NOT EXISTS ${tables.schema} (version integer NOT NULL)`,\n\t\t);\n\t\tconst [row] = await rowsOf<{ version: number }>(\n\t\t\tsql.unsafe(`SELECT version FROM ${tables.schema}`),\n\t\t);\n\t\tconst version = row?.version ?? 0;\n\t\tcheckNotNewer(version, all.length);\n\t\tfor (const statements of all.slice(version)) {\n\t\t\tfor (const statement of statements) await sql.unsafe(statement);\n\t\t}\n\t\tif (row === undefined) {\n\t\t\tawait sql.unsafe(\n\t\t\t\t`INSERT INTO ${tables.schema} (version) VALUES ($1::int)`,\n\t\t\t\t[all.length],\n\t\t\t);\n\t\t} else if (version < all.length) {\n\t\t\tawait sql.unsafe(`UPDATE ${tables.schema} SET version = $1::int`, [\n\t\t\t\tall.length,\n\t\t\t]);\n\t\t}\n\t});\n}\n",
7
+ "import type { PostgresClient, PostgresQueryable } from './options';\nimport { rowsOf } from './rows';\n\n/**\n * The first statement of every transaction that writes: READ COMMITTED\n * whatever the client's sessions default to. The claim's `FOR UPDATE SKIP\n * LOCKED` and the `maxItems` advisory lock count on it: under `repeatable\n * read` or `serializable`, a row another transaction changed since the\n * snapshot fails with SQLSTATE 40001, and the count taken after the lock\n * would read a snapshot from before it.\n */\nconst READ_COMMITTED =\n\t'SET TRANSACTION ISOLATION LEVEL READ COMMITTED, READ WRITE';\n\n/** `fn` in a transaction at READ COMMITTED: every write of the store, its migration included, goes through here. */\nexport async function writing<T>(\n\tsql: PostgresClient,\n\tfn: (tx: PostgresQueryable) => Promise<T>,\n): Promise<T> {\n\treturn (await sql.begin(async (tx: PostgresQueryable) => {\n\t\tawait tx.unsafe(READ_COMMITTED);\n\t\treturn fn(tx);\n\t})) as T;\n}\n\n/** One statement that writes, at READ COMMITTED; its rows. */\nexport function written<T>(\n\tsql: PostgresClient,\n\tquery: string,\n\tvalues: unknown[] = [],\n): Promise<T[]> {\n\treturn writing(sql, (tx) => rowsOf<T>(tx.unsafe(query, values)));\n}\n",
8
+ "import { QueueError } from '../errors';\nimport type { Tables } from './connect';\nimport { writing } from './isolation';\nimport type { PostgresClient, PostgresQueryable } from './options';\nimport { rowsOf } from './rows';\n\n/**\n * The migrations, in order, each a list of statements: the schema table's\n * `version` is how many of them the database has run. A migration is\n * never edited once released; a change is a new one at the end. They\n * follow the `bun:sqlite` store's, column for column: times are\n * milliseconds as `double precision` (SQLite's `REAL`), the recipients\n * JSON, the message its bytes, in a table of its own.\n */\nexport function migrations({\n\tprefix,\n\titems,\n\tmessages,\n}: Tables): readonly (readonly string[])[] {\n\treturn [\n\t\t// 1: the items, and their messages in a table of their own.\n\t\t[\n\t\t\t`CREATE TABLE ${items} (\n\t\t\t\tseq bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,\n\t\t\t\tid text NOT NULL UNIQUE,\n\t\t\t\tsender text NOT NULL,\n\t\t\t\trecipients jsonb NOT NULL CHECK (jsonb_typeof(recipients) = 'array'),\n\t\t\t\tsize integer NOT NULL,\n\t\t\t\tcreated_at double precision NOT NULL,\n\t\t\t\tnext_attempt_at double precision NOT NULL,\n\t\t\t\tattempts integer NOT NULL,\n\t\t\t\tdelay_notified boolean NOT NULL,\n\t\t\t\tlease_owner text,\n\t\t\t\tlease_expires_at double precision,\n\t\t\t\tCHECK ((lease_owner IS NULL) = (lease_expires_at IS NULL))\n\t\t\t)`,\n\t\t\t// The claim's order, and its range: the earliest due first.\n\t\t\t`CREATE INDEX ${prefix}items_due ON ${items} (next_attempt_at, seq)`,\n\t\t\t`CREATE TABLE ${messages} (\n\t\t\t\titem_id text PRIMARY KEY REFERENCES ${items} (id) ON DELETE CASCADE,\n\t\t\t\tcontent bytea NOT NULL\n\t\t\t)`,\n\t\t],\n\t];\n}\n\n/** Tables a newer store wrote, with more migrations than this one knows, are refused. */\nfunction checkNotNewer(version: number, known: number): void {\n\tif (version > known) {\n\t\tthrow new QueueError(\n\t\t\t'INVALID',\n\t\t\t`The database is at schema version ${version}, newer than this store's ${known}`,\n\t\t);\n\t}\n}\n\n/**\n * The version the tables are at, read with no lock and no DDL — so a role\n * with no `CREATE` reads it — or `undefined` with no schema table yet.\n */\nasync function versionOf(\n\tsql: PostgresQueryable,\n\ttables: Tables,\n): Promise<number | undefined> {\n\tconst [found] = await rowsOf<{ present: boolean }>(\n\t\tsql.unsafe('SELECT to_regclass($1) IS NOT NULL AS present', [\n\t\t\ttables.schema,\n\t\t]),\n\t);\n\tif (!found?.present) return undefined;\n\tconst [row] = await rowsOf<{ version: number }>(\n\t\tsql.unsafe(`SELECT version FROM ${tables.schema}`),\n\t);\n\treturn row?.version ?? 0;\n}\n\n/**\n * Brings the tables to the last migration. Tables already current are\n * only read: no lock, no DDL, so a worker's role needs no `CREATE`.\n * Otherwise in one transaction — a migration that fails leaves them as\n * they were — under one advisory lock, so instances starting together\n * run each migration once.\n */\nexport async function migrate(\n\tclient: PostgresClient,\n\ttables: Tables,\n): Promise<void> {\n\tconst all = migrations(tables);\n\tconst current = await versionOf(client, tables);\n\tif (current !== undefined) {\n\t\tcheckNotNewer(current, all.length);\n\t\tif (current === all.length) return;\n\t}\n\t// READ COMMITTED, as every write: under a stricter level the version\n\t// read after the lock would be the snapshot's, from before it.\n\tawait writing(client, async (sql: PostgresQueryable) => {\n\t\tawait sql.unsafe('SELECT pg_advisory_xact_lock(hashtext($1)) IS NULL', [\n\t\t\ttables.schema,\n\t\t]);\n\t\tawait sql.unsafe(\n\t\t\t`CREATE TABLE IF NOT EXISTS ${tables.schema} (version integer NOT NULL)`,\n\t\t);\n\t\tconst [row] = await rowsOf<{ version: number }>(\n\t\t\tsql.unsafe(`SELECT version FROM ${tables.schema}`),\n\t\t);\n\t\tconst version = row?.version ?? 0;\n\t\tcheckNotNewer(version, all.length);\n\t\tfor (const statements of all.slice(version)) {\n\t\t\tfor (const statement of statements) await sql.unsafe(statement);\n\t\t}\n\t\tif (row === undefined) {\n\t\t\tawait sql.unsafe(\n\t\t\t\t`INSERT INTO ${tables.schema} (version) VALUES ($1::int)`,\n\t\t\t\t[all.length],\n\t\t\t);\n\t\t} else if (version < all.length) {\n\t\t\tawait sql.unsafe(`UPDATE ${tables.schema} SET version = $1::int`, [\n\t\t\t\tall.length,\n\t\t\t]);\n\t\t}\n\t});\n}\n",
8
9
  "import type { Tables } from './connect';\nimport { COLUMNS } from './rows';\n\n/**\n * The statements a store runs on its tables, written once per store: the\n * table names are its prefix's (checked to be a plain name), and every\n * value is a parameter. Each parameter is cast, so nothing depends on the\n * type a client infers for it; JSON goes as text, cast to `jsonb`.\n */\nexport function statementsOf({ items, messages }: Tables) {\n\treturn {\n\t\t/** $1 id, $2 sender, $3 recipients, $4 size, $5 created_at, $6 message: the item and its message in one statement, or neither. */\n\t\tinsert: `WITH item AS (\n\t\t\tINSERT INTO ${items} (id, sender, recipients, size, created_at,\n\t\t\t\tnext_attempt_at, attempts, delay_notified)\n\t\t\tVALUES ($1, $2, $3::text::jsonb, $4::int, $5::float8, $5::float8, 0, false)\n\t\t\tRETURNING id)\n\t\tINSERT INTO ${messages} (item_id, content) SELECT id, $6::bytea FROM item`,\n\t\t/** Taken before counting, by every add given `maxItems`. */\n\t\tlockAdds: `SELECT pg_advisory_xact_lock(hashtext('${items}')) IS NULL`,\n\t\tcount: `SELECT count(*)::int AS n FROM ${items}`,\n\t\tget: `SELECT ${COLUMNS} FROM ${items} WHERE id = $1`,\n\t\tlist: `SELECT ${COLUMNS} FROM ${items}\n\t\t\tORDER BY next_attempt_at, seq LIMIT $1::int OFFSET $2::int`,\n\t\tmessage: `SELECT content FROM ${messages} WHERE item_id = $1`,\n\t\t/**\n\t\t * $1 owner, $2 now, $3 expiry. The earliest due item no other\n\t\t * transaction holds, locked as it is picked — one being claimed\n\t\t * elsewhere is skipped, not waited for — then leased.\n\t\t */\n\t\tclaim: `UPDATE ${items} SET lease_owner = $1, lease_expires_at = $3::float8\n\t\t\tWHERE seq = (SELECT seq FROM ${items}\n\t\t\t\tWHERE next_attempt_at <= $2::float8\n\t\t\t\t\tAND (lease_owner IS NULL OR lease_expires_at <= $2::float8)\n\t\t\t\tORDER BY next_attempt_at, seq LIMIT 1\n\t\t\t\tFOR UPDATE SKIP LOCKED)\n\t\t\tRETURNING ${COLUMNS}`,\n\t\trenew: `UPDATE ${items} SET lease_expires_at = $1::float8\n\t\t\tWHERE id = $2 AND lease_owner = $3 RETURNING seq`,\n\t\t/** The owner's item, locked until the transaction ends. */\n\t\theld: `SELECT ${COLUMNS} FROM ${items}\n\t\t\tWHERE id = $1 AND lease_owner = $2 FOR UPDATE`,\n\t\t/** $1 id, $2 recipients, $3 next attempt, $4 attempts, $5 delay notified: the lease let go of. */\n\t\trecord: `UPDATE ${items} SET recipients = $2::text::jsonb,\n\t\t\tnext_attempt_at = $3::float8, attempts = $4::int,\n\t\t\tdelay_notified = $5::boolean, lease_owner = NULL,\n\t\t\tlease_expires_at = NULL WHERE id = $1`,\n\t\t/** The message goes with it: ON DELETE CASCADE. */\n\t\tdrop: `DELETE FROM ${items} WHERE id = $1 RETURNING ${COLUMNS}`,\n\t\tmoveDue: `UPDATE ${items} SET next_attempt_at = $1::float8\n\t\t\tWHERE id = $2 RETURNING seq`,\n\t\tgiveBack: `UPDATE ${items} SET next_attempt_at = $1::float8,\n\t\t\tlease_owner = NULL, lease_expires_at = NULL\n\t\t\tWHERE id = $2 AND lease_owner = $3 RETURNING seq`,\n\t} as const;\n}\n\nexport type Statements = ReturnType<typeof statementsOf>;\n",
9
- "import {\n\tapplyAttempt,\n\tcheckClaim,\n\tcheckList,\n\tcheckMaxItems,\n\tcheckNewItem,\n\tcheckOwner,\n\tcheckResult,\n\tcheckTime,\n\tisDone,\n\tnewItem,\n} from '../contract/checks';\nimport type { QueueStore } from '../contract/queue-store';\nimport type {\n\tAddOptions,\n\tAttemptResult,\n\tClaimRequest,\n\tNewQueueItem,\n\tQueueItem,\n\tQueueListOptions,\n} from '../contract/types';\nimport { QueueError } from '../errors';\nimport { isStorable } from '../text';\nimport { type Connection, connect, type Tables } from './connect';\nimport type {\n\tPostgresClient,\n\tPostgresQueryable,\n\tPostgresQueueStoreOptions,\n} from './options';\nimport { type ItemRow, itemOf, rowsOf } from './rows';\nimport { migrate } from './schema';\nimport { type Statements, statementsOf } from './statements';\n\nexport type {\n\tPostgresClient,\n\tPostgresQueryable,\n\tPostgresQueueStoreOptions,\n} from './options';\n\nconst messageOf = (error: unknown) =>\n\terror instanceof Error ? error.message : String(error);\n\n/**\n * A `QueueStore` on PostgreSQL through Bun's own `Bun.SQL`: several\n * instances, on one machine or many, share one queue. A claim is one\n * `UPDATE … RETURNING` whose item a `SELECT … FOR UPDATE SKIP LOCKED`\n * picks, so two instances never take the same item, and none waits on an\n * item another is taking. Messages live in a table of their own, dropped\n * with their item. The tables are made, or brought up to date, by\n * `migrate()`, or by the first call that needs them.\n */\nexport class PostgresQueueStore implements QueueStore {\n\treadonly #client: PostgresClient;\n\treadonly #owned: boolean;\n\treadonly #tables: Tables;\n\treadonly #q: Statements;\n\t#migrated: Promise<void> | undefined;\n\t#closed = false;\n\n\tprivate constructor({ client, owned, tables }: Connection) {\n\t\tthis.#client = client;\n\t\tthis.#owned = owned;\n\t\tthis.#tables = tables;\n\t\tthis.#q = statementsOf(tables);\n\t}\n\n\t/** Checks the options; connects to nothing until the first call. What is wrong is `INVALID`. */\n\tstatic open(options: PostgresQueueStoreOptions): PostgresQueueStore {\n\t\treturn new PostgresQueueStore(connect(options));\n\t}\n\n\t/**\n\t * Makes the tables, or brings them to the last migration; once per\n\t * store, and safe while other instances do the same. A failure is\n\t * `INVALID`, and the next call tries again.\n\t */\n\tmigrate(): Promise<void> {\n\t\tif (this.#closed) return Promise.reject(closed());\n\t\tthis.#migrated ??= migrate(this.#client, this.#tables).catch((error) => {\n\t\t\tthis.#migrated = undefined;\n\t\t\tif (error instanceof QueueError) throw error;\n\t\t\tthrow new QueueError(\n\t\t\t\t'INVALID',\n\t\t\t\t`The PostgreSQL queue cannot be set up: ${messageOf(error)}`,\n\t\t\t);\n\t\t});\n\t\treturn this.#migrated;\n\t}\n\n\t/** Closes the client the store opened for a URL, never one it was given; closing twice is fine. */\n\tasync close(): Promise<void> {\n\t\tif (this.#closed) return;\n\t\tthis.#closed = true;\n\t\tif (this.#owned) await this.#client.close();\n\t}\n\n\t/** The client, once the tables are there; `CLOSED` after `close()`. */\n\tasync #sql(): Promise<PostgresClient> {\n\t\tif (this.#closed) throw closed();\n\t\tawait this.migrate();\n\t\treturn this.#client;\n\t}\n\n\tasync #rows<T>(query: string, values: unknown[] = []): Promise<T[]> {\n\t\treturn rowsOf<T>((await this.#sql()).unsafe(query, values));\n\t}\n\n\tasync add(item: NewQueueItem, options: AddOptions = {}): Promise<QueueItem> {\n\t\tcheckNewItem(item);\n\t\tconst max = checkMaxItems(options.maxItems);\n\t\tconst added = newItem(crypto.randomUUID(), item);\n\t\tconst values = [\n\t\t\tadded.id,\n\t\t\tadded.from,\n\t\t\tJSON.stringify(added.recipients),\n\t\t\tadded.size,\n\t\t\tadded.createdAt,\n\t\t\titem.message,\n\t\t];\n\t\tconst sql = await this.#sql();\n\t\tconst q = this.#q;\n\t\tif (max === undefined) {\n\t\t\tawait sql.unsafe(q.insert, values);\n\t\t\treturn added;\n\t\t}\n\t\t// Adds that count wait on one lock, so two never both take the last place.\n\t\tawait sql.begin(async (tx: PostgresQueryable) => {\n\t\t\tawait tx.unsafe(q.lockAdds);\n\t\t\tconst [row] = await rowsOf<{ n: number }>(tx.unsafe(q.count));\n\t\t\tconst n = row?.n ?? 0;\n\t\t\tif (n >= max) {\n\t\t\t\tthrow new QueueError(\n\t\t\t\t\t'QUEUE_FULL',\n\t\t\t\t\t`The queue holds ${n} items, its limit`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tawait tx.unsafe(q.insert, values);\n\t\t});\n\t\treturn added;\n\t}\n\n\tasync get(id: string): Promise<QueueItem | undefined> {\n\t\tif (!isStorable(id)) return undefined;\n\t\tconst [row] = await this.#rows<ItemRow>(this.#q.get, [id]);\n\t\treturn row ? itemOf(row) : undefined;\n\t}\n\n\tasync list(options?: QueueListOptions): Promise<QueueItem[]> {\n\t\tconst { offset, limit } = checkList(options);\n\t\tconst rows = await this.#rows<ItemRow>(this.#q.list, [limit, offset]);\n\t\treturn rows.map(itemOf);\n\t}\n\n\tasync count(): Promise<number> {\n\t\tconst [row] = await this.#rows<{ n: number }>(this.#q.count);\n\t\treturn row?.n ?? 0;\n\t}\n\n\tasync readMessage(id: string): Promise<Uint8Array | undefined> {\n\t\tif (!isStorable(id)) return undefined;\n\t\tconst [row] = await this.#rows<{ content: Uint8Array }>(this.#q.message, [\n\t\t\tid,\n\t\t]);\n\t\treturn row ? new Uint8Array(row.content) : undefined;\n\t}\n\n\tasync claim(request: ClaimRequest): Promise<QueueItem | undefined> {\n\t\tcheckClaim(request);\n\t\tconst { owner, now, leaseMs } = request;\n\t\tconst [row] = await this.#rows<ItemRow>(this.#q.claim, [\n\t\t\towner,\n\t\t\tnow,\n\t\t\tnow + leaseMs,\n\t\t]);\n\t\treturn row ? itemOf(row) : undefined;\n\t}\n\n\tasync renew(id: string, owner: string, expiresAt: number): Promise<boolean> {\n\t\tcheckOwner(owner);\n\t\tcheckTime('expiresAt', expiresAt);\n\t\tif (!isStorable(id)) return false;\n\t\tconst rows = await this.#rows(this.#q.renew, [expiresAt, id, owner]);\n\t\treturn rows.length > 0;\n\t}\n\n\tasync complete(\n\t\tid: string,\n\t\towner: string,\n\t\tresult: AttemptResult,\n\t): Promise<QueueItem | undefined> {\n\t\tcheckOwner(owner);\n\t\tcheckResult(result);\n\t\tif (!isStorable(id)) return undefined;\n\t\tconst sql = await this.#sql();\n\t\tconst q = this.#q;\n\t\tlet done: QueueItem | undefined;\n\t\tawait sql.begin(async (tx: PostgresQueryable) => {\n\t\t\tconst [row] = await rowsOf<ItemRow>(tx.unsafe(q.held, [id, owner]));\n\t\t\tif (!row) return;\n\t\t\tconst item = applyAttempt(itemOf(row), result);\n\t\t\tif (isDone(item)) {\n\t\t\t\tawait tx.unsafe(q.drop, [id]);\n\t\t\t} else {\n\t\t\t\tawait tx.unsafe(q.record, [\n\t\t\t\t\tid,\n\t\t\t\t\tJSON.stringify(item.recipients),\n\t\t\t\t\titem.nextAttemptAt,\n\t\t\t\t\titem.attempts,\n\t\t\t\t\titem.delayNotified,\n\t\t\t\t]);\n\t\t\t}\n\t\t\tdone = item;\n\t\t});\n\t\treturn done;\n\t}\n\n\tasync reschedule(id: string, at: number, owner?: string): Promise<boolean> {\n\t\tcheckTime('at', at);\n\t\tif (!isStorable(id)) return false;\n\t\tif (owner === undefined) {\n\t\t\treturn (await this.#rows(this.#q.moveDue, [at, id])).length > 0;\n\t\t}\n\t\tcheckOwner(owner);\n\t\treturn (await this.#rows(this.#q.giveBack, [at, id, owner])).length > 0;\n\t}\n\n\tasync cancel(id: string): Promise<QueueItem | undefined> {\n\t\t// An id PostgreSQL cannot hold is one no item has.\n\t\tif (!isStorable(id)) return undefined;\n\t\tconst [row] = await this.#rows<ItemRow>(this.#q.drop, [id]);\n\t\treturn row ? itemOf(row) : undefined;\n\t}\n}\n\nconst closed = () => new QueueError('CLOSED', 'The queue store is closed');\n"
10
+ "import {\n\tapplyAttempt,\n\tcheckClaim,\n\tcheckList,\n\tcheckMaxItems,\n\tcheckNewItem,\n\tcheckOwner,\n\tcheckResult,\n\tcheckTime,\n\tisDone,\n\tnewItem,\n} from '../contract/checks';\nimport type { QueueStore } from '../contract/queue-store';\nimport type {\n\tAddOptions,\n\tAttemptResult,\n\tClaimRequest,\n\tNewQueueItem,\n\tQueueItem,\n\tQueueListOptions,\n} from '../contract/types';\nimport { QueueError } from '../errors';\nimport { masked } from '../masked';\nimport { isStorable } from '../text';\nimport { type Connection, connect, type Tables } from './connect';\nimport { writing, written } from './isolation';\nimport type { PostgresClient, PostgresQueueStoreOptions } from './options';\nimport { type ItemRow, itemOf, rowsOf } from './rows';\nimport { migrate } from './schema';\nimport { type Statements, statementsOf } from './statements';\n\nexport type {\n\tPostgresClient,\n\tPostgresQueryable,\n\tPostgresQueueStoreOptions,\n} from './options';\n\nconst messageOf = (error: unknown) =>\n\terror instanceof Error ? error.message : String(error);\n\n/**\n * A `QueueStore` on PostgreSQL through Bun's own `Bun.SQL`: several\n * instances, on one machine or many, share one queue. A claim is one\n * `UPDATE … RETURNING` whose item a `SELECT … FOR UPDATE SKIP LOCKED`\n * picks, so two instances never take the same item, and none waits on an\n * item another is taking. Messages live in a table of their own, dropped\n * with their item. The tables are made, or brought up to date, by\n * `migrate()`, or by the first call that needs them.\n */\nexport class PostgresQueueStore implements QueueStore {\n\treadonly #client: PostgresClient;\n\treadonly #owned: boolean;\n\treadonly #tables: Tables;\n\treadonly #q: Statements;\n\treadonly #password: string;\n\t#migrated: Promise<void> | undefined;\n\t#closed = false;\n\n\tprivate constructor({ client, owned, tables, password }: Connection) {\n\t\tthis.#client = client;\n\t\tthis.#owned = owned;\n\t\tthis.#tables = tables;\n\t\tthis.#password = password;\n\t\tthis.#q = statementsOf(tables);\n\t}\n\n\t/** Checks the options; connects to nothing until the first call. What is wrong is `INVALID`. */\n\tstatic open(options: PostgresQueueStoreOptions): PostgresQueueStore {\n\t\treturn new PostgresQueueStore(connect(options));\n\t}\n\n\t/**\n\t * Makes the tables, or brings them to the last migration; once per\n\t * store, and safe while other instances do the same. A failure is\n\t * `INVALID`, and the next call tries again.\n\t */\n\tmigrate(): Promise<void> {\n\t\tif (this.#closed) return Promise.reject(closed());\n\t\tthis.#migrated ??= migrate(this.#client, this.#tables).catch((error) => {\n\t\t\tthis.#migrated = undefined;\n\t\t\tif (error instanceof QueueError) throw error;\n\t\t\tthrow new QueueError(\n\t\t\t\t'INVALID',\n\t\t\t\t`The PostgreSQL queue cannot be set up: ${masked(messageOf(error), this.#password)}`,\n\t\t\t);\n\t\t});\n\t\treturn this.#migrated;\n\t}\n\n\t/** Closes the client the store opened for a URL, never one it was given; closing twice is fine. */\n\tasync close(): Promise<void> {\n\t\tif (this.#closed) return;\n\t\tthis.#closed = true;\n\t\tif (this.#owned) await this.#client.close();\n\t}\n\n\t/** The client, once the tables are there; `CLOSED` after `close()`. */\n\tasync #sql(): Promise<PostgresClient> {\n\t\tif (this.#closed) throw closed();\n\t\tawait this.migrate();\n\t\treturn this.#client;\n\t}\n\n\tasync #rows<T>(query: string, values: unknown[] = []): Promise<T[]> {\n\t\treturn rowsOf<T>((await this.#sql()).unsafe(query, values));\n\t}\n\n\t/** One statement that writes, at READ COMMITTED; its rows. */\n\tasync #written<T>(query: string, values: unknown[] = []): Promise<T[]> {\n\t\treturn written<T>(await this.#sql(), query, values);\n\t}\n\n\tasync add(item: NewQueueItem, options: AddOptions = {}): Promise<QueueItem> {\n\t\tcheckNewItem(item);\n\t\tconst max = checkMaxItems(options.maxItems);\n\t\tconst added = newItem(crypto.randomUUID(), item);\n\t\tconst values = [\n\t\t\tadded.id,\n\t\t\tadded.from,\n\t\t\tJSON.stringify(added.recipients),\n\t\t\tadded.size,\n\t\t\tadded.createdAt,\n\t\t\titem.message,\n\t\t];\n\t\tconst q = this.#q;\n\t\tif (max === undefined) {\n\t\t\tawait this.#written(q.insert, values);\n\t\t\treturn added;\n\t\t}\n\t\t// Adds that count wait on one lock, so two never both take the last place.\n\t\tawait writing(await this.#sql(), async (tx) => {\n\t\t\tawait tx.unsafe(q.lockAdds);\n\t\t\tconst [row] = await rowsOf<{ n: number }>(tx.unsafe(q.count));\n\t\t\tconst n = row?.n ?? 0;\n\t\t\tif (n >= max) {\n\t\t\t\tthrow new QueueError(\n\t\t\t\t\t'QUEUE_FULL',\n\t\t\t\t\t`The queue holds ${n} items, its limit`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tawait tx.unsafe(q.insert, values);\n\t\t});\n\t\treturn added;\n\t}\n\n\tasync get(id: string): Promise<QueueItem | undefined> {\n\t\tif (!isStorable(id)) return undefined;\n\t\tconst [row] = await this.#rows<ItemRow>(this.#q.get, [id]);\n\t\treturn row ? itemOf(row) : undefined;\n\t}\n\n\tasync list(options?: QueueListOptions): Promise<QueueItem[]> {\n\t\tconst { offset, limit } = checkList(options);\n\t\tconst rows = await this.#rows<ItemRow>(this.#q.list, [limit, offset]);\n\t\treturn rows.map(itemOf);\n\t}\n\n\tasync count(): Promise<number> {\n\t\tconst [row] = await this.#rows<{ n: number }>(this.#q.count);\n\t\treturn row?.n ?? 0;\n\t}\n\n\tasync readMessage(id: string): Promise<Uint8Array | undefined> {\n\t\tif (!isStorable(id)) return undefined;\n\t\tconst [row] = await this.#rows<{ content: Uint8Array }>(this.#q.message, [\n\t\t\tid,\n\t\t]);\n\t\treturn row ? new Uint8Array(row.content) : undefined;\n\t}\n\n\tasync claim(request: ClaimRequest): Promise<QueueItem | undefined> {\n\t\tcheckClaim(request);\n\t\tconst { owner, now, leaseMs } = request;\n\t\tconst [row] = await this.#written<ItemRow>(this.#q.claim, [\n\t\t\towner,\n\t\t\tnow,\n\t\t\tnow + leaseMs,\n\t\t]);\n\t\treturn row ? itemOf(row) : undefined;\n\t}\n\n\tasync renew(id: string, owner: string, expiresAt: number): Promise<boolean> {\n\t\tcheckOwner(owner);\n\t\tcheckTime('expiresAt', expiresAt);\n\t\tif (!isStorable(id)) return false;\n\t\tconst rows = await this.#written(this.#q.renew, [expiresAt, id, owner]);\n\t\treturn rows.length > 0;\n\t}\n\n\tasync complete(\n\t\tid: string,\n\t\towner: string,\n\t\tresult: AttemptResult,\n\t): Promise<QueueItem | undefined> {\n\t\tcheckOwner(owner);\n\t\tcheckResult(result);\n\t\tif (!isStorable(id)) return undefined;\n\t\tconst q = this.#q;\n\t\tlet done: QueueItem | undefined;\n\t\tawait writing(await this.#sql(), async (tx) => {\n\t\t\tconst [row] = await rowsOf<ItemRow>(tx.unsafe(q.held, [id, owner]));\n\t\t\tif (!row) return;\n\t\t\tconst item = applyAttempt(itemOf(row), result);\n\t\t\tif (isDone(item)) {\n\t\t\t\tawait tx.unsafe(q.drop, [id]);\n\t\t\t} else {\n\t\t\t\tawait tx.unsafe(q.record, [\n\t\t\t\t\tid,\n\t\t\t\t\tJSON.stringify(item.recipients),\n\t\t\t\t\titem.nextAttemptAt,\n\t\t\t\t\titem.attempts,\n\t\t\t\t\titem.delayNotified,\n\t\t\t\t]);\n\t\t\t}\n\t\t\tdone = item;\n\t\t});\n\t\treturn done;\n\t}\n\n\tasync reschedule(id: string, at: number, owner?: string): Promise<boolean> {\n\t\tcheckTime('at', at);\n\t\tif (!isStorable(id)) return false;\n\t\tif (owner === undefined) {\n\t\t\treturn (await this.#written(this.#q.moveDue, [at, id])).length > 0;\n\t\t}\n\t\tcheckOwner(owner);\n\t\treturn (await this.#written(this.#q.giveBack, [at, id, owner])).length > 0;\n\t}\n\n\tasync cancel(id: string): Promise<QueueItem | undefined> {\n\t\t// An id PostgreSQL cannot hold is one no item has.\n\t\tif (!isStorable(id)) return undefined;\n\t\tconst [row] = await this.#written<ItemRow>(this.#q.drop, [id]);\n\t\treturn row ? itemOf(row) : undefined;\n\t}\n}\n\nconst closed = () => new QueueError('CLOSED', 'The queue store is closed');\n"
10
11
  ],
11
- "mappings": "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",
12
- "debugId": "2305882EAB72E70464756E2164756E21",
12
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAyBA,IAAM,iBAAiB;AAOvB,IAAM,SAAS;AAEf,SAAS,QAAQ,CAAC,OAAwB;AAAA,EACzC,MAAM,SAAS,SAAS;AAAA,EACxB,IAAI,OAAO,WAAW,YAAY,CAAC,OAAO,KAAK,MAAM,GAAG;AAAA,IACvD,MAAM,QACL,sIAAsI,KAAK,UAAU,MAAM,GAC5J;AAAA,EACD;AAAA,EACA,OAAO;AAAA,IACN;AAAA,IACA,OAAO,GAAG;AAAA,IACV,UAAU,GAAG;AAAA,IACb,QAAQ,GAAG;AAAA,EACZ;AAAA;AAGD,IAAM,YACL;AAGD,SAAS,KAAK,CAAC,OAA0B;AAAA,EACxC,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,EACnC,IAAI,QAAQ,QAAQ,CAAC,CAAC,aAAa,aAAa,EAAE,SAAS,IAAI,QAAQ,GAAG;AAAA,IACzE,MAAM,QAAQ,SAAS;AAAA,EACxB;AAAA,EACA,OAAO;AAAA;AAQR,SAAS,SAAS,CAAC,KAA0B;AAAA,EAC5C,IAAI;AAAA,IACH,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI;AAAA,IAC1B,OAAO,OAAO;AAAA,IACf,MAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IACpE,MAAM,QACL,oCAAoC,OAAO,QAAQ,IAAI,QAAQ,GAChE;AAAA;AAAA;AAIF,IAAM,WAAW,CAAC,WAChB,OAAO,UAAU,YAAY,OAAO,UAAU,eAC/C,UAAU,QACV,OAAQ,MAAyB,WAAW,cAC5C,OAAQ,MAAyB,UAAU,cAC3C,OAAQ,MAAyB,UAAU;AAG5C,SAAS,YAAY,CAAC,QAA8B;AAAA,EACnD,MAAM,UAAW,OAA+C,SAC7D;AAAA,EACH,IAAI,YAAY,aAAa,YAAY,YAAY;AAAA,IACpD,MAAM,QACL,YAAY,OAAO,OAAO,4CAC3B;AAAA,EACD;AAAA;AAID,SAAS,UAAU,CAAC,QAAgC;AAAA,EACnD,MAAM,WAAY,OAAgD,SAC/D;AAAA,EACH,OAAO,OAAO,aAAa,WAAW,WAAW;AAAA;AAI3C,SAAS,OAAO,CAAC,SAAgD;AAAA,EACvE,MAAM,QAAS,SAAmD;AAAA,EAClE,MAAM,SAAS,SAAS,SAAS,WAAW;AAAA,EAC5C,IAAI,SAAS,KAAK,GAAG;AAAA,IACpB,aAAa,KAAK;AAAA,IAClB,OAAO;AAAA,MACN,QAAQ;AAAA,MACR,OAAO;AAAA,MACP;AAAA,MACA,UAAU,WAAW,KAAK;AAAA,IAC3B;AAAA,EACD;AAAA,EACA,IAAI,OAAO,UAAU,YAAY,EAAE,iBAAiB,MAAM;AAAA,IACzD,MAAM,QAAQ,SAAS;AAAA,EACxB;AAAA,EACA,MAAM,MAAM,MAAM,KAAK;AAAA,EACvB,OAAO;AAAA,IACN,QAAQ,UAAU,GAAG;AAAA,IACrB,OAAO;AAAA,IACP;AAAA,IACA,UAAU,IAAI;AAAA,EACf;AAAA;;;AC1GM,IAAM,UACZ;AAEM,SAAS,MAAM,CAAC,KAAyB;AAAA,EAC/C,MAAM,aACL,OAAO,IAAI,eAAe,WACtB,KAAK,MAAM,IAAI,UAAU,IAC1B,gBAAgB,IAAI,UAAU;AAAA,EAClC,MAAM,OAAkB;AAAA,IACvB,IAAI,IAAI;AAAA,IACR,MAAM,IAAI;AAAA,IACV;AAAA,IACA,MAAM,IAAI;AAAA,IACV,WAAW,IAAI;AAAA,IACf,eAAe,IAAI;AAAA,IACnB,UAAU,IAAI;AAAA,IACd,eAAe,IAAI;AAAA,EACpB;AAAA,EACA,IAAI,IAAI,gBAAgB,QAAQ,IAAI,qBAAqB;AAAA,IAAM,OAAO;AAAA,EACtE,OAAO;AAAA,OACH;AAAA,IACH,OAAO,EAAE,OAAO,IAAI,aAAa,WAAW,IAAI,iBAAiB;AAAA,EAClE;AAAA;AAIM,IAAM,SAAS,OAAU,YAC9B,MAAM;;;AClCR,IAAM,iBACL;AAGD,eAAsB,OAAU,CAC/B,KACA,IACa;AAAA,EACb,OAAQ,MAAM,IAAI,MAAM,OAAO,OAA0B;AAAA,IACxD,MAAM,GAAG,OAAO,cAAc;AAAA,IAC9B,OAAO,GAAG,EAAE;AAAA,GACZ;AAAA;AAIK,SAAS,OAAU,CACzB,KACA,OACA,SAAoB,CAAC,GACN;AAAA,EACf,OAAO,QAAQ,KAAK,CAAC,OAAO,OAAU,GAAG,OAAO,OAAO,MAAM,CAAC,CAAC;AAAA;;;ACjBzD,SAAS,UAAU;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,GAC0C;AAAA,EAC1C,OAAO;AAAA,IAEN;AAAA,MACC,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAehB,gBAAgB,sBAAsB;AAAA,MACtC,gBAAgB;AAAA,0CACuB;AAAA;AAAA;AAAA,IAGxC;AAAA,EACD;AAAA;AAID,SAAS,aAAa,CAAC,SAAiB,OAAqB;AAAA,EAC5D,IAAI,UAAU,OAAO;AAAA,IACpB,MAAM,IAAI,YACT,WACA,qCAAqC,oCAAoC,OAC1E;AAAA,EACD;AAAA;AAOD,eAAe,SAAS,CACvB,KACA,QAC8B;AAAA,EAC9B,OAAO,SAAS,MAAM,OACrB,IAAI,OAAO,iDAAiD;AAAA,IAC3D,OAAO;AAAA,EACR,CAAC,CACF;AAAA,EACA,IAAI,CAAC,OAAO;AAAA,IAAS;AAAA,EACrB,OAAO,OAAO,MAAM,OACnB,IAAI,OAAO,uBAAuB,OAAO,QAAQ,CAClD;AAAA,EACA,OAAO,KAAK,WAAW;AAAA;AAUxB,eAAsB,OAAO,CAC5B,QACA,QACgB;AAAA,EAChB,MAAM,MAAM,WAAW,MAAM;AAAA,EAC7B,MAAM,UAAU,MAAM,UAAU,QAAQ,MAAM;AAAA,EAC9C,IAAI,YAAY,WAAW;AAAA,IAC1B,cAAc,SAAS,IAAI,MAAM;AAAA,IACjC,IAAI,YAAY,IAAI;AAAA,MAAQ;AAAA,EAC7B;AAAA,EAGA,MAAM,QAAQ,QAAQ,OAAO,QAA2B;AAAA,IACvD,MAAM,IAAI,OAAO,sDAAsD;AAAA,MACtE,OAAO;AAAA,IACR,CAAC;AAAA,IACD,MAAM,IAAI,OACT,8BAA8B,OAAO,mCACtC;AAAA,IACA,OAAO,OAAO,MAAM,OACnB,IAAI,OAAO,uBAAuB,OAAO,QAAQ,CAClD;AAAA,IACA,MAAM,UAAU,KAAK,WAAW;AAAA,IAChC,cAAc,SAAS,IAAI,MAAM;AAAA,IACjC,WAAW,cAAc,IAAI,MAAM,OAAO,GAAG;AAAA,MAC5C,WAAW,aAAa;AAAA,QAAY,MAAM,IAAI,OAAO,SAAS;AAAA,IAC/D;AAAA,IACA,IAAI,QAAQ,WAAW;AAAA,MACtB,MAAM,IAAI,OACT,eAAe,OAAO,qCACtB,CAAC,IAAI,MAAM,CACZ;AAAA,IACD,EAAO,SAAI,UAAU,IAAI,QAAQ;AAAA,MAChC,MAAM,IAAI,OAAO,UAAU,OAAO,gCAAgC;AAAA,QACjE,IAAI;AAAA,MACL,CAAC;AAAA,IACF;AAAA,GACA;AAAA;;;AC/GK,SAAS,YAAY,GAAG,OAAO,YAAoB;AAAA,EACzD,OAAO;AAAA,IAEN,QAAQ;AAAA,iBACO;AAAA;AAAA;AAAA;AAAA,gBAID;AAAA,IAEd,UAAU,0CAA0C;AAAA,IACpD,OAAO,kCAAkC;AAAA,IACzC,KAAK,UAAU,gBAAgB;AAAA,IAC/B,MAAM,UAAU,gBAAgB;AAAA;AAAA,IAEhC,SAAS,uBAAuB;AAAA,IAMhC,OAAO,UAAU;AAAA,kCACe;AAAA;AAAA;AAAA;AAAA;AAAA,eAKnB;AAAA,IACb,OAAO,UAAU;AAAA;AAAA,IAGjB,MAAM,UAAU,gBAAgB;AAAA;AAAA,IAGhC,QAAQ,UAAU;AAAA;AAAA;AAAA;AAAA,IAKlB,MAAM,eAAe,iCAAiC;AAAA,IACtD,SAAS,UAAU;AAAA;AAAA,IAEnB,UAAU,UAAU;AAAA;AAAA;AAAA,EAGrB;AAAA;;;ACjBD,IAAM,YAAY,CAAC,UAClB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA;AAW/C,MAAM,mBAAyC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT;AAAA,EACA,UAAU;AAAA,EAEF,WAAW,GAAG,QAAQ,OAAO,QAAQ,YAAwB;AAAA,IACpE,KAAK,UAAU;AAAA,IACf,KAAK,SAAS;AAAA,IACd,KAAK,UAAU;AAAA,IACf,KAAK,YAAY;AAAA,IACjB,KAAK,KAAK,aAAa,MAAM;AAAA;AAAA,SAIvB,IAAI,CAAC,SAAwD;AAAA,IACnE,OAAO,IAAI,mBAAmB,QAAQ,OAAO,CAAC;AAAA;AAAA,EAQ/C,OAAO,GAAkB;AAAA,IACxB,IAAI,KAAK;AAAA,MAAS,OAAO,QAAQ,OAAO,OAAO,CAAC;AAAA,IAChD,KAAK,cAAc,QAAQ,KAAK,SAAS,KAAK,OAAO,EAAE,MAAM,CAAC,UAAU;AAAA,MACvE,KAAK,YAAY;AAAA,MACjB,IAAI,iBAAiB;AAAA,QAAY,MAAM;AAAA,MACvC,MAAM,IAAI,YACT,WACA,0CAA0C,OAAO,UAAU,KAAK,GAAG,KAAK,SAAS,GAClF;AAAA,KACA;AAAA,IACD,OAAO,KAAK;AAAA;AAAA,OAIP,MAAK,GAAkB;AAAA,IAC5B,IAAI,KAAK;AAAA,MAAS;AAAA,IAClB,KAAK,UAAU;AAAA,IACf,IAAI,KAAK;AAAA,MAAQ,MAAM,KAAK,QAAQ,MAAM;AAAA;AAAA,OAIrC,IAAI,GAA4B;AAAA,IACrC,IAAI,KAAK;AAAA,MAAS,MAAM,OAAO;AAAA,IAC/B,MAAM,KAAK,QAAQ;AAAA,IACnB,OAAO,KAAK;AAAA;AAAA,OAGP,KAAQ,CAAC,OAAe,SAAoB,CAAC,GAAiB;AAAA,IACnE,OAAO,QAAW,MAAM,KAAK,KAAK,GAAG,OAAO,OAAO,MAAM,CAAC;AAAA;AAAA,OAIrD,QAAW,CAAC,OAAe,SAAoB,CAAC,GAAiB;AAAA,IACtE,OAAO,QAAW,MAAM,KAAK,KAAK,GAAG,OAAO,MAAM;AAAA;AAAA,OAG7C,IAAG,CAAC,MAAoB,UAAsB,CAAC,GAAuB;AAAA,IAC3E,aAAa,IAAI;AAAA,IACjB,MAAM,MAAM,cAAc,QAAQ,QAAQ;AAAA,IAC1C,MAAM,QAAQ,QAAQ,OAAO,WAAW,GAAG,IAAI;AAAA,IAC/C,MAAM,SAAS;AAAA,MACd,MAAM;AAAA,MACN,MAAM;AAAA,MACN,KAAK,UAAU,MAAM,UAAU;AAAA,MAC/B,MAAM;AAAA,MACN,MAAM;AAAA,MACN,KAAK;AAAA,IACN;AAAA,IACA,MAAM,IAAI,KAAK;AAAA,IACf,IAAI,QAAQ,WAAW;AAAA,MACtB,MAAM,KAAK,SAAS,EAAE,QAAQ,MAAM;AAAA,MACpC,OAAO;AAAA,IACR;AAAA,IAEA,MAAM,QAAQ,MAAM,KAAK,KAAK,GAAG,OAAO,OAAO;AAAA,MAC9C,MAAM,GAAG,OAAO,EAAE,QAAQ;AAAA,MAC1B,OAAO,OAAO,MAAM,OAAsB,GAAG,OAAO,EAAE,KAAK,CAAC;AAAA,MAC5D,MAAM,IAAI,KAAK,KAAK;AAAA,MACpB,IAAI,KAAK,KAAK;AAAA,QACb,MAAM,IAAI,YACT,cACA,mBAAmB,oBACpB;AAAA,MACD;AAAA,MACA,MAAM,GAAG,OAAO,EAAE,QAAQ,MAAM;AAAA,KAChC;AAAA,IACD,OAAO;AAAA;AAAA,OAGF,IAAG,CAAC,IAA4C;AAAA,IACrD,IAAI,CAAC,WAAW,EAAE;AAAA,MAAG;AAAA,IACrB,OAAO,OAAO,MAAM,KAAK,MAAe,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC;AAAA,IACzD,OAAO,MAAM,OAAO,GAAG,IAAI;AAAA;AAAA,OAGtB,KAAI,CAAC,SAAkD;AAAA,IAC5D,QAAQ,QAAQ,UAAU,UAAU,OAAO;AAAA,IAC3C,MAAM,OAAO,MAAM,KAAK,MAAe,KAAK,GAAG,MAAM,CAAC,OAAO,MAAM,CAAC;AAAA,IACpE,OAAO,KAAK,IAAI,MAAM;AAAA;AAAA,OAGjB,MAAK,GAAoB;AAAA,IAC9B,OAAO,OAAO,MAAM,KAAK,MAAqB,KAAK,GAAG,KAAK;AAAA,IAC3D,OAAO,KAAK,KAAK;AAAA;AAAA,OAGZ,YAAW,CAAC,IAA6C;AAAA,IAC9D,IAAI,CAAC,WAAW,EAAE;AAAA,MAAG;AAAA,IACrB,OAAO,OAAO,MAAM,KAAK,MAA+B,KAAK,GAAG,SAAS;AAAA,MACxE;AAAA,IACD,CAAC;AAAA,IACD,OAAO,MAAM,IAAI,WAAW,IAAI,OAAO,IAAI;AAAA;AAAA,OAGtC,MAAK,CAAC,SAAuD;AAAA,IAClE,WAAW,OAAO;AAAA,IAClB,QAAQ,OAAO,KAAK,YAAY;AAAA,IAChC,OAAO,OAAO,MAAM,KAAK,SAAkB,KAAK,GAAG,OAAO;AAAA,MACzD;AAAA,MACA;AAAA,MACA,MAAM;AAAA,IACP,CAAC;AAAA,IACD,OAAO,MAAM,OAAO,GAAG,IAAI;AAAA;AAAA,OAGtB,MAAK,CAAC,IAAY,OAAe,WAAqC;AAAA,IAC3E,WAAW,KAAK;AAAA,IAChB,UAAU,aAAa,SAAS;AAAA,IAChC,IAAI,CAAC,WAAW,EAAE;AAAA,MAAG,OAAO;AAAA,IAC5B,MAAM,OAAO,MAAM,KAAK,SAAS,KAAK,GAAG,OAAO,CAAC,WAAW,IAAI,KAAK,CAAC;AAAA,IACtE,OAAO,KAAK,SAAS;AAAA;AAAA,OAGhB,SAAQ,CACb,IACA,OACA,QACiC;AAAA,IACjC,WAAW,KAAK;AAAA,IAChB,YAAY,MAAM;AAAA,IAClB,IAAI,CAAC,WAAW,EAAE;AAAA,MAAG;AAAA,IACrB,MAAM,IAAI,KAAK;AAAA,IACf,IAAI;AAAA,IACJ,MAAM,QAAQ,MAAM,KAAK,KAAK,GAAG,OAAO,OAAO;AAAA,MAC9C,OAAO,OAAO,MAAM,OAAgB,GAAG,OAAO,EAAE,MAAM,CAAC,IAAI,KAAK,CAAC,CAAC;AAAA,MAClE,IAAI,CAAC;AAAA,QAAK;AAAA,MACV,MAAM,OAAO,aAAa,OAAO,GAAG,GAAG,MAAM;AAAA,MAC7C,IAAI,OAAO,IAAI,GAAG;AAAA,QACjB,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC;AAAA,MAC7B,EAAO;AAAA,QACN,MAAM,GAAG,OAAO,EAAE,QAAQ;AAAA,UACzB;AAAA,UACA,KAAK,UAAU,KAAK,UAAU;AAAA,UAC9B,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,QACN,CAAC;AAAA;AAAA,MAEF,OAAO;AAAA,KACP;AAAA,IACD,OAAO;AAAA;AAAA,OAGF,WAAU,CAAC,IAAY,IAAY,OAAkC;AAAA,IAC1E,UAAU,MAAM,EAAE;AAAA,IAClB,IAAI,CAAC,WAAW,EAAE;AAAA,MAAG,OAAO;AAAA,IAC5B,IAAI,UAAU,WAAW;AAAA,MACxB,QAAQ,MAAM,KAAK,SAAS,KAAK,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,GAAG,SAAS;AAAA,IAClE;AAAA,IACA,WAAW,KAAK;AAAA,IAChB,QAAQ,MAAM,KAAK,SAAS,KAAK,GAAG,UAAU,CAAC,IAAI,IAAI,KAAK,CAAC,GAAG,SAAS;AAAA;AAAA,OAGpE,OAAM,CAAC,IAA4C;AAAA,IAExD,IAAI,CAAC,WAAW,EAAE;AAAA,MAAG;AAAA,IACrB,OAAO,OAAO,MAAM,KAAK,SAAkB,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC;AAAA,IAC7D,OAAO,MAAM,OAAO,GAAG,IAAI;AAAA;AAE7B;AAEA,IAAM,SAAS,MAAM,IAAI,YAAW,UAAU,2BAA2B;",
13
+ "debugId": "B46CC738D07AA2A964756E2164756E21",
13
14
  "names": []
14
15
  }
@@ -0,0 +1,6 @@
1
+ import type { PostgresClient, PostgresQueryable } from './options';
2
+ /** `fn` in a transaction at READ COMMITTED: every write of the store, its migration included, goes through here. */
3
+ export declare function writing<T>(sql: PostgresClient, fn: (tx: PostgresQueryable) => Promise<T>): Promise<T>;
4
+ /** One statement that writes, at READ COMMITTED; its rows. */
5
+ export declare function written<T>(sql: PostgresClient, query: string, values?: unknown[]): Promise<T[]>;
6
+ //# sourceMappingURL=isolation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isolation.d.ts","sourceRoot":"","sources":["../../src/postgres/isolation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAcnE,oHAAoH;AACpH,wBAAsB,OAAO,CAAC,CAAC,EAC9B,GAAG,EAAE,cAAc,EACnB,EAAE,EAAE,CAAC,EAAE,EAAE,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC,GACvC,OAAO,CAAC,CAAC,CAAC,CAKZ;AAED,8DAA8D;AAC9D,wBAAgB,OAAO,CAAC,CAAC,EACxB,GAAG,EAAE,cAAc,EACnB,KAAK,EAAE,MAAM,EACb,MAAM,GAAE,OAAO,EAAO,GACpB,OAAO,CAAC,CAAC,EAAE,CAAC,CAEd"}
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/postgres/schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAqB,MAAM,WAAW,CAAC;AAGnE;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,EAC1B,MAAM,EACN,KAAK,EACL,QAAQ,GACR,EAAE,MAAM,GAAG,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CA0BzC;AAgCD;;;;;;GAMG;AACH,wBAAsB,OAAO,CAC5B,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAiCf"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/postgres/schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,KAAK,EAAE,cAAc,EAAqB,MAAM,WAAW,CAAC;AAGnE;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,EAC1B,MAAM,EACN,KAAK,EACL,QAAQ,GACR,EAAE,MAAM,GAAG,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CA0BzC;AAgCD;;;;;;GAMG;AACH,wBAAsB,OAAO,CAC5B,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAmCf"}
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/postgres/store.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EACX,UAAU,EACV,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,gBAAgB,EAChB,MAAM,mBAAmB,CAAC;AAI3B,OAAO,KAAK,EAGX,yBAAyB,EACzB,MAAM,WAAW,CAAC;AAKnB,YAAY,EACX,cAAc,EACd,iBAAiB,EACjB,yBAAyB,GACzB,MAAM,WAAW,CAAC;AAKnB;;;;;;;;GAQG;AACH,qBAAa,kBAAmB,YAAW,UAAU;;IAQpD,OAAO;IAOP,gGAAgG;IAChG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,yBAAyB,GAAG,kBAAkB;IAInE;;;;OAIG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAaxB,mGAAmG;IAC7F,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBtB,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,SAAS,CAAC;IAkCrE,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAM/C,IAAI,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAMtD,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAKxB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAQxD,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAW5D,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQrE,QAAQ,CACb,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,aAAa,GACnB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IA2B3B,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUpE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;CAMxD"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/postgres/store.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EACX,UAAU,EACV,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,gBAAgB,EAChB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,KAAK,EAAkB,yBAAyB,EAAE,MAAM,WAAW,CAAC;AAK3E,YAAY,EACX,cAAc,EACd,iBAAiB,EACjB,yBAAyB,GACzB,MAAM,WAAW,CAAC;AAKnB;;;;;;;;GAQG;AACH,qBAAa,kBAAmB,YAAW,UAAU;;IASpD,OAAO;IAQP,gGAAgG;IAChG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,yBAAyB,GAAG,kBAAkB;IAInE;;;;OAIG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAaxB,mGAAmG;IAC7F,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBtB,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,SAAS,CAAC;IAiCrE,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAM/C,IAAI,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAMtD,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAKxB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAQxD,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAW5D,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQrE,QAAQ,CACb,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,aAAa,GACnB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IA0B3B,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUpE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;CAMxD"}
@@ -1,5 +1,6 @@
1
1
  import type { QueueItem } from '../contract/types';
2
2
  import type { Events } from './events';
3
+ import type { Lapse } from './lease';
3
4
  import type { KeyedLimiter } from './limiter';
4
5
  import { type NotifyContext } from './notify';
5
6
  export interface DeliveryContext extends NotifyContext {
@@ -9,12 +10,20 @@ export interface DeliveryContext extends NotifyContext {
9
10
  readonly stopping: () => boolean;
10
11
  /** The outcome is recorded: the lease needs no more renewal. */
11
12
  readonly recorded: () => void;
13
+ /**
14
+ * Whether the lease could have passed to another worker by `now`: a
15
+ * renewal found it taken, or its last expiry is past. `undefined` while
16
+ * it surely held.
17
+ */
18
+ readonly leaseLapsed: (now: number) => Promise<Lapse | undefined>;
12
19
  }
13
20
  /**
14
21
  * Delivers a claimed item: one session per recipient domain, at most
15
22
  * `perDomain` at once to each — none, and no slot taken, when its sender
16
23
  * is one `sendMail` would refuse — then the outcome recorded — which lets go
17
- * of the lease — then the events and the DSNs.
24
+ * of the lease — then the events and the DSNs. An item whose message the
25
+ * store no longer gives fails every pending recipient, said on the `error`
26
+ * event, its DSN without the original.
18
27
  */
19
28
  export declare function deliverItem(ctx: DeliveryContext, item: QueueItem): Promise<void>;
20
29
  //# sourceMappingURL=deliver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deliver.d.ts","sourceRoot":"","sources":["../../src/queue/deliver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,mBAAmB,CAAC;AAGpE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,KAAK,aAAa,EAAU,MAAM,UAAU,CAAC;AAKtD,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACrD,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC;IACjC,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;CAC9B;AA0FD;;;;;GAKG;AACH,wBAAsB,WAAW,CAChC,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,SAAS,GACb,OAAO,CAAC,IAAI,CAAC,CA8Cf"}
1
+ {"version":3,"file":"deliver.d.ts","sourceRoot":"","sources":["../../src/queue/deliver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,mBAAmB,CAAC;AAGpE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,KAAK,aAAa,EAAU,MAAM,UAAU,CAAC;AAKtD,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACrD,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC;IACjC,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;CAClE;AA8HD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAChC,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,SAAS,GACb,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
@@ -0,0 +1,41 @@
1
+ import type { QueueItem } from '../contract/types';
2
+ import type { NotifyContext } from './notify';
3
+ /**
4
+ * How a lease was lost. `taken`: a renewal found the item still in the
5
+ * store, held by another worker or by none. `expired`: the lease's last
6
+ * expiry passed, so another worker could claim it.
7
+ */
8
+ export type Lapse = 'taken' | 'expired';
9
+ /** What a worker knows of its lease on an item it delivers. */
10
+ export interface LeaseState {
11
+ readonly item: QueueItem;
12
+ /** The outcome is recorded, or a renewal was refused: no more renewals count. */
13
+ done: boolean;
14
+ /** The lease's last expiry this worker set: the claim's, then each renewal's. */
15
+ expiresAt: number;
16
+ /** A renewal was refused while the item was still in the store. */
17
+ taken: boolean;
18
+ /** The look a refused renewal takes at the item. */
19
+ looking: Promise<void>;
20
+ }
21
+ export declare function leaseOf(ctx: NotifyContext, item: QueueItem): LeaseState;
22
+ /**
23
+ * One renewal. A renewal that is held keeps its expiry, even one that
24
+ * lands after the outcome is recorded. One refused while the item is
25
+ * still there — held by another worker or by none — says so once, and
26
+ * ends the renewals; one refused for an item gone says nothing and ends
27
+ * them: a cancel, or another worker that finished it, which `lapsed` tells
28
+ * apart by the expiry. One that fails (the store busy, unreachable) says
29
+ * so, and the next one tries again: the lease may still be held.
30
+ * Resolves `false` once no more renewals are wanted.
31
+ */
32
+ export declare function renew(ctx: NotifyContext, lease: LeaseState): Promise<boolean>;
33
+ /**
34
+ * Whether the lease could have passed to another worker by `now`: a
35
+ * renewal found it taken, or its last expiry is past. `undefined` while
36
+ * it surely held, by this worker's clock.
37
+ */
38
+ export declare function lapsed(lease: LeaseState, now: number): Promise<Lapse | undefined>;
39
+ /** Resolves once the look a refused renewal took at the item is over. */
40
+ export declare const settled: (lease: LeaseState) => Promise<void>;
41
+ //# sourceMappingURL=lease.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lease.d.ts","sourceRoot":"","sources":["../../src/queue/lease.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C;;;;GAIG;AACH,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,SAAS,CAAC;AAExC,+DAA+D;AAC/D,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,iFAAiF;IACjF,IAAI,EAAE,OAAO,CAAC;IACd,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,KAAK,EAAE,OAAO,CAAC;IACf,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,GAAG,UAAU,CASvE;AAiBD;;;;;;;;;GASG;AACH,wBAAsB,KAAK,CAC1B,GAAG,EAAE,aAAa,EAClB,KAAK,EAAE,UAAU,GACf,OAAO,CAAC,OAAO,CAAC,CAmBlB;AAED;;;;GAIG;AACH,wBAAsB,MAAM,CAC3B,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,MAAM,GACT,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAI5B;AAED,yEAAyE;AACzE,eAAO,MAAM,OAAO,GAAI,OAAO,UAAU,KAAG,OAAO,CAAC,IAAI,CAAkB,CAAC"}
@@ -13,7 +13,8 @@ export interface NotifyContext {
13
13
  * recipients, from the null sender, so it never causes one of its own.
14
14
  * Nothing for an item from the null sender (RFC 5321 §4.5.5, RFC 3464
15
15
  * §2: a DSN is never sent about a DSN). It bypasses `maxItems`: a full
16
- * queue loses no bounce. A failure goes to the `error` event.
16
+ * queue loses no bounce. A failure goes to the `error` event. With no
17
+ * `message` — the store lost it — the DSN returns nothing of it.
17
18
  */
18
- export declare function notify(ctx: NotifyContext, item: QueueItem, message: Uint8Array, kind: DsnKind, recipients: readonly RecipientUpdate[], now: number): Promise<void>;
19
+ export declare function notify(ctx: NotifyContext, item: QueueItem, message: Uint8Array | undefined, kind: DsnKind, recipients: readonly RecipientUpdate[], now: number): Promise<void>;
19
20
  //# sourceMappingURL=notify.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"notify.d.ts","sourceRoot":"","sources":["../../src/queue/notify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAY,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAsB,MAAM,CAC3B,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,UAAU,EACnB,IAAI,EAAE,OAAO,EACb,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,GAAG,EAAE,MAAM,GACT,OAAO,CAAC,IAAI,CAAC,CAwCf"}
1
+ {"version":3,"file":"notify.d.ts","sourceRoot":"","sources":["../../src/queue/notify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAY,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,wBAAsB,MAAM,CAC3B,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,UAAU,GAAG,SAAS,EAC/B,IAAI,EAAE,OAAO,EACb,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,GAAG,EAAE,MAAM,GACT,OAAO,CAAC,IAAI,CAAC,CAwCf"}
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/queue/worker.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C;;;;;GAKG;AACH,qBAAa,MAAM;;gBAaN,GAAG,EAAE,aAAa;IAsE9B;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAgCnC,4FAA4F;IAC5F,IAAI,IAAI,IAAI;IAKZ,KAAK,IAAI,IAAI;IAqCb;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAa3B"}
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/queue/worker.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C;;;;;GAKG;AACH,qBAAa,MAAM;;gBAaN,GAAG,EAAE,aAAa;IAsD9B;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAgCnC,4FAA4F;IAC5F,IAAI,IAAI,IAAI;IAKZ,KAAK,IAAI,IAAI;IAqCb;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAa3B"}
@@ -0,0 +1,27 @@
1
+ import type { RedisQueueClient, RedisQueueStoreOptions } from './options';
2
+ /** The keys of one queue, each its prefix and a fixed name. */
3
+ export interface Keys {
4
+ readonly prefix: string;
5
+ /** Every item, scored by its next attempt: `list` and `count`. */
6
+ readonly items: string;
7
+ /** The items no lease holds, scored by their next attempt: what a claim takes first. */
8
+ readonly ready: string;
9
+ /** The leased items, scored by when their leases expire. */
10
+ readonly leases: string;
11
+ /** The counter that orders items equally due. */
12
+ readonly seq: string;
13
+ /** The layout version. */
14
+ readonly schema: string;
15
+ }
16
+ /** The client a store uses, and whether it opened it (and so closes it). */
17
+ export interface Connection {
18
+ readonly client: RedisQueueClient;
19
+ readonly owned: boolean;
20
+ readonly keys: Keys;
21
+ /** The URL's password, so an error that repeats it is masked; `''` for a given client. */
22
+ readonly password: string;
23
+ }
24
+ export declare function keysOf(value: unknown): Keys;
25
+ /** Checks the options and opens a client for a URL; connects to nothing yet. */
26
+ export declare function connect(options: RedisQueueStoreOptions): Connection;
27
+ //# sourceMappingURL=connect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../src/redis/connect.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAE1E,+DAA+D;AAC/D,MAAM,WAAW,IAAI;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kEAAkE;IAClE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,wFAAwF;IACxF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iDAAiD;IACjD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,0BAA0B;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB;AAED,4EAA4E;AAC5E,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,0FAA0F;IAC1F,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC1B;AAWD,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAe3C;AAiDD,gFAAgF;AAChF,wBAAgB,OAAO,CAAC,OAAO,EAAE,sBAAsB,GAAG,UAAU,CAkBnE"}
@@ -0,0 +1,3 @@
1
+ export type { RedisQueueClient, RedisQueueClientOptions, RedisQueueStoreOptions, RedisQueueUrlOptions, } from './options';
2
+ export { RedisQueueStore } from './store';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/redis/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,gBAAgB,EAChB,uBAAuB,EACvB,sBAAsB,EACtB,oBAAoB,GACpB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC"}