@bumail/queue 0.10.0 → 0.11.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 (46) hide show
  1. package/README.md +27 -1
  2. package/dist/chunks/{index-sz13a17b.js → index-t6q7zxgj.js} +14 -3
  3. package/dist/chunks/{index-sz13a17b.js.map → index-t6q7zxgj.js.map} +4 -4
  4. package/dist/contract/checks.d.ts +4 -0
  5. package/dist/contract/checks.d.ts.map +1 -1
  6. package/dist/contract/queue-store.d.ts +15 -7
  7. package/dist/contract/queue-store.d.ts.map +1 -1
  8. package/dist/contract/types.d.ts +5 -0
  9. package/dist/contract/types.d.ts.map +1 -1
  10. package/dist/errors.d.ts +3 -1
  11. package/dist/errors.d.ts.map +1 -1
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +64 -26
  15. package/dist/index.js.map +4 -4
  16. package/dist/memory/index.js +10 -6
  17. package/dist/memory/index.js.map +3 -3
  18. package/dist/memory/store.d.ts +2 -2
  19. package/dist/memory/store.d.ts.map +1 -1
  20. package/dist/postgres/complete.d.ts +13 -0
  21. package/dist/postgres/complete.d.ts.map +1 -0
  22. package/dist/postgres/index.js +85 -74
  23. package/dist/postgres/index.js.map +6 -5
  24. package/dist/postgres/store.d.ts +2 -2
  25. package/dist/postgres/store.d.ts.map +1 -1
  26. package/dist/queue/deliver.d.ts.map +1 -1
  27. package/dist/queue/notify.d.ts +35 -6
  28. package/dist/queue/notify.d.ts.map +1 -1
  29. package/dist/redis/complete.d.ts +11 -0
  30. package/dist/redis/complete.d.ts.map +1 -0
  31. package/dist/redis/index.js +133 -110
  32. package/dist/redis/index.js.map +7 -6
  33. package/dist/redis/scripts.d.ts +8 -5
  34. package/dist/redis/scripts.d.ts.map +1 -1
  35. package/dist/redis/store.d.ts +2 -2
  36. package/dist/redis/store.d.ts.map +1 -1
  37. package/dist/sqlite/index.js +29 -20
  38. package/dist/sqlite/index.js.map +5 -4
  39. package/dist/sqlite/insert.d.ts +5 -0
  40. package/dist/sqlite/insert.d.ts.map +1 -0
  41. package/dist/sqlite/store.d.ts +2 -2
  42. package/dist/sqlite/store.d.ts.map +1 -1
  43. package/docs/guide.md +29 -0
  44. package/docs/roadmap.md +36 -10
  45. package/docs/troubleshooting.md +64 -1
  46. package/package.json +4 -4
@@ -11,15 +11,94 @@ import {
11
11
  invalid,
12
12
  checkTime,
13
13
  checkOwner,
14
+ checkComplete,
14
15
  checkNewItem,
15
16
  checkMaxItems,
16
17
  checkClaim,
17
- checkResult,
18
18
  checkList,
19
19
  isDone,
20
20
  applyAttempt,
21
21
  newItem
22
- } from "../chunks/index-sz13a17b.js";
22
+ } from "../chunks/index-t6q7zxgj.js";
23
+
24
+ // src/postgres/rows.ts
25
+ var COLUMNS = "id, sender, recipients, size, created_at, next_attempt_at, attempts, delay_notified, lease_owner, lease_expires_at, dsn";
26
+ function itemOf(row) {
27
+ const recipients = typeof row.recipients === "string" ? JSON.parse(row.recipients) : structuredClone(row.recipients);
28
+ const item = {
29
+ id: row.id,
30
+ from: row.sender,
31
+ recipients,
32
+ size: row.size,
33
+ createdAt: row.created_at,
34
+ nextAttemptAt: row.next_attempt_at,
35
+ attempts: row.attempts,
36
+ delayNotified: row.delay_notified,
37
+ ...dsnParams(row.dsn)
38
+ };
39
+ if (row.lease_owner === null || row.lease_expires_at === null)
40
+ return item;
41
+ return {
42
+ ...item,
43
+ lease: { owner: row.lease_owner, expiresAt: row.lease_expires_at }
44
+ };
45
+ }
46
+ var rowsOf = async (pending) => await pending;
47
+
48
+ // src/postgres/isolation.ts
49
+ var READ_COMMITTED = "SET TRANSACTION ISOLATION LEVEL READ COMMITTED, READ WRITE";
50
+ async function writing(sql, fn) {
51
+ return await sql.begin(async (tx) => {
52
+ await tx.unsafe(READ_COMMITTED);
53
+ return fn(tx);
54
+ });
55
+ }
56
+ function written(sql, query, values = []) {
57
+ return writing(sql, (tx) => rowsOf(tx.unsafe(query, values)));
58
+ }
59
+
60
+ // src/postgres/complete.ts
61
+ var insertValues = (added, message) => [
62
+ added.id,
63
+ added.from,
64
+ JSON.stringify(added.recipients),
65
+ added.size,
66
+ added.createdAt,
67
+ message,
68
+ dsnColumn(added)
69
+ ];
70
+ async function complete(connected, q, id, owner, result, dsns) {
71
+ checkComplete(owner, result, dsns);
72
+ if (!isStorable(id))
73
+ return;
74
+ const sql = await connected();
75
+ let done;
76
+ await writing(sql, async (tx) => {
77
+ const [row] = await rowsOf(tx.unsafe(q.held, [id, owner]));
78
+ if (!row)
79
+ return;
80
+ const item = applyAttempt(itemOf(row), result);
81
+ if (isDone(item)) {
82
+ await tx.unsafe(q.drop, [id]);
83
+ } else {
84
+ await tx.unsafe(q.record, [
85
+ id,
86
+ JSON.stringify(item.recipients),
87
+ item.nextAttemptAt,
88
+ item.attempts,
89
+ item.delayNotified
90
+ ]);
91
+ }
92
+ const added = [];
93
+ for (const dsn of dsns) {
94
+ const made = newItem(crypto.randomUUID(), dsn);
95
+ await tx.unsafe(q.insert, insertValues(made, dsn.message));
96
+ added.push(made);
97
+ }
98
+ done = { item, dsns: added };
99
+ });
100
+ return done;
101
+ }
23
102
 
24
103
  // src/postgres/connect.ts
25
104
  var DEFAULT_PREFIX = "bumail_queue_";
@@ -87,42 +166,6 @@ function connect(options) {
87
166
  };
88
167
  }
89
168
 
90
- // src/postgres/rows.ts
91
- var COLUMNS = "id, sender, recipients, size, created_at, next_attempt_at, attempts, delay_notified, lease_owner, lease_expires_at, dsn";
92
- function itemOf(row) {
93
- const recipients = typeof row.recipients === "string" ? JSON.parse(row.recipients) : structuredClone(row.recipients);
94
- const item = {
95
- id: row.id,
96
- from: row.sender,
97
- recipients,
98
- size: row.size,
99
- createdAt: row.created_at,
100
- nextAttemptAt: row.next_attempt_at,
101
- attempts: row.attempts,
102
- delayNotified: row.delay_notified,
103
- ...dsnParams(row.dsn)
104
- };
105
- if (row.lease_owner === null || row.lease_expires_at === null)
106
- return item;
107
- return {
108
- ...item,
109
- lease: { owner: row.lease_owner, expiresAt: row.lease_expires_at }
110
- };
111
- }
112
- var rowsOf = async (pending) => await pending;
113
-
114
- // src/postgres/isolation.ts
115
- var READ_COMMITTED = "SET TRANSACTION ISOLATION LEVEL READ COMMITTED, READ WRITE";
116
- async function writing(sql, fn) {
117
- return await sql.begin(async (tx) => {
118
- await tx.unsafe(READ_COMMITTED);
119
- return fn(tx);
120
- });
121
- }
122
- function written(sql, query, values = []) {
123
- return writing(sql, (tx) => rowsOf(tx.unsafe(query, values)));
124
- }
125
-
126
169
  // src/postgres/schema.ts
127
170
  function migrations({
128
171
  prefix,
@@ -293,15 +336,7 @@ class PostgresQueueStore {
293
336
  checkNewItem(item);
294
337
  const max = checkMaxItems(options.maxItems);
295
338
  const added = newItem(crypto.randomUUID(), item);
296
- const values = [
297
- added.id,
298
- added.from,
299
- JSON.stringify(added.recipients),
300
- added.size,
301
- added.createdAt,
302
- item.message,
303
- dsnColumn(added)
304
- ];
339
+ const values = insertValues(added, item.message);
305
340
  const q = this.#q;
306
341
  if (max === undefined) {
307
342
  await this.#written(q.insert, values);
@@ -359,32 +394,8 @@ class PostgresQueueStore {
359
394
  const rows = await this.#written(this.#q.renew, [expiresAt, id, owner]);
360
395
  return rows.length > 0;
361
396
  }
362
- async complete(id, owner, result) {
363
- checkOwner(owner);
364
- checkResult(result);
365
- if (!isStorable(id))
366
- return;
367
- const q = this.#q;
368
- let done;
369
- await writing(await this.#sql(), async (tx) => {
370
- const [row] = await rowsOf(tx.unsafe(q.held, [id, owner]));
371
- if (!row)
372
- return;
373
- const item = applyAttempt(itemOf(row), result);
374
- if (isDone(item)) {
375
- await tx.unsafe(q.drop, [id]);
376
- } else {
377
- await tx.unsafe(q.record, [
378
- id,
379
- JSON.stringify(item.recipients),
380
- item.nextAttemptAt,
381
- item.attempts,
382
- item.delayNotified
383
- ]);
384
- }
385
- done = item;
386
- });
387
- return done;
397
+ async complete(id, owner, result, dsns) {
398
+ return complete(() => this.#sql(), this.#q, id, owner, result, dsns);
388
399
  }
389
400
  async reschedule(id, at, owner) {
390
401
  checkTime("at", at);
@@ -408,5 +419,5 @@ export {
408
419
  PostgresQueueStore
409
420
  };
410
421
 
411
- //# debugId=E11119E44742AD2264756E2164756E21
422
+ //# debugId=AA983FDFF9CB849964756E2164756E21
412
423
  //# sourceMappingURL=index.js.map
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "version": 3,
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"],
3
+ "sources": ["../src/postgres/rows.ts", "../src/postgres/isolation.ts", "../src/postgres/complete.ts", "../src/postgres/connect.ts", "../src/postgres/schema.ts", "../src/postgres/statements.ts", "../src/postgres/store.ts"],
4
4
  "sourcesContent": [
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
5
  "import { dsnParams } from '../contract/dsn-column';\nimport 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\t/** `jsonb`: parsed or not, depending on the client. */\n\treadonly dsn: string | { ret?: 'FULL' | 'HDRS'; envid?: string } | 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, dsn';\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\t...dsnParams(row.dsn),\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
6
  "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",
7
+ "import {\n\tapplyAttempt,\n\tcheckComplete,\n\tisDone,\n\tnewItem,\n} from '../contract/checks';\nimport { dsnColumn } from '../contract/dsn-column';\nimport type {\n\tAttemptResult,\n\tCompleted,\n\tNewQueueItem,\n\tQueueItem,\n} from '../contract/types';\nimport { isStorable } from '../text';\nimport { writing } from './isolation';\nimport type { PostgresClient } from './options';\nimport { type ItemRow, itemOf, rowsOf } from './rows';\nimport type { Statements } from './statements';\n\n/** The parameters of `insert` for `added`, whose message is `message`. */\nexport const insertValues = (added: QueueItem, message: Uint8Array) => [\n\tadded.id,\n\tadded.from,\n\tJSON.stringify(added.recipients),\n\tadded.size,\n\tadded.createdAt,\n\tmessage,\n\tdsnColumn(added),\n];\n\n/**\n * The outcome of an attempt and the DSNs it asks for, in one transaction:\n * a DSN that cannot be stored undoes the outcome too, and a lease lost\n * writes nothing. The DSNs get their ids here and go in, in order, with no\n * `maxItems` lock: a DSN is never refused for a full queue.\n */\nexport async function complete(\n\tconnected: () => Promise<PostgresClient>,\n\tq: Statements,\n\tid: string,\n\towner: string,\n\tresult: AttemptResult,\n\tdsns: readonly NewQueueItem[],\n): Promise<Completed | undefined> {\n\tcheckComplete(owner, result, dsns);\n\tif (!isStorable(id)) return undefined;\n\tconst sql = await connected();\n\tlet done: Completed | undefined;\n\tawait writing(sql, async (tx) => {\n\t\tconst [row] = await rowsOf<ItemRow>(tx.unsafe(q.held, [id, owner]));\n\t\tif (!row) return;\n\t\tconst item = applyAttempt(itemOf(row), result);\n\t\tif (isDone(item)) {\n\t\t\tawait tx.unsafe(q.drop, [id]);\n\t\t} else {\n\t\t\tawait tx.unsafe(q.record, [\n\t\t\t\tid,\n\t\t\t\tJSON.stringify(item.recipients),\n\t\t\t\titem.nextAttemptAt,\n\t\t\t\titem.attempts,\n\t\t\t\titem.delayNotified,\n\t\t\t]);\n\t\t}\n\t\tconst added: QueueItem[] = [];\n\t\tfor (const dsn of dsns) {\n\t\t\tconst made = newItem(crypto.randomUUID(), dsn);\n\t\t\tawait tx.unsafe(q.insert, insertValues(made, dsn.message));\n\t\t\tadded.push(made);\n\t\t}\n\t\tdone = { item, dsns: added };\n\t});\n\treturn done;\n}\n",
8
+ "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",
8
9
  "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\t// 2: the item's DSN parameters (RET, ENVID) as JSON; NULL for the rows of before.\n\t\t[`ALTER TABLE ${items} ADD COLUMN dsn jsonb`],\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",
9
10
  "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, $7 dsn (JSON or null): 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, dsn)\n\t\t\tVALUES ($1, $2, $3::text::jsonb, $4::int, $5::float8, $5::float8, 0, false,\n\t\t\t\t$7::text::jsonb)\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",
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 { dsnColumn } from '../contract/dsn-column';\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\tdsnColumn(added),\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"
11
+ "import {\n\tcheckClaim,\n\tcheckList,\n\tcheckMaxItems,\n\tcheckNewItem,\n\tcheckOwner,\n\tcheckTime,\n\tnewItem,\n} from '../contract/checks';\nimport type { QueueStore } from '../contract/queue-store';\nimport type {\n\tAddOptions,\n\tAttemptResult,\n\tClaimRequest,\n\tCompleted,\n\tNewQueueItem,\n\tQueueItem,\n\tQueueListOptions,\n} from '../contract/types';\nimport { QueueError } from '../errors';\nimport { masked } from '../masked';\nimport { isStorable } from '../text';\nimport { complete, insertValues } from './complete';\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 = insertValues(added, item.message);\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\tdsns: readonly NewQueueItem[],\n\t): Promise<Completed | undefined> {\n\t\treturn complete(() => this.#sql(), this.#q, id, owner, result, dsns);\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"
11
12
  ],
12
- "mappings": "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",
13
- "debugId": "E11119E44742AD2264756E2164756E21",
13
+ "mappings": "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",
14
+ "debugId": "AA983FDFF9CB849964756E2164756E21",
14
15
  "names": []
15
16
  }
@@ -1,5 +1,5 @@
1
1
  import type { QueueStore } from '../contract/queue-store';
2
- import type { AddOptions, AttemptResult, ClaimRequest, NewQueueItem, QueueItem, QueueListOptions } from '../contract/types';
2
+ import type { AddOptions, AttemptResult, ClaimRequest, Completed, NewQueueItem, QueueItem, QueueListOptions } from '../contract/types';
3
3
  import type { PostgresQueueStoreOptions } from './options';
4
4
  export type { PostgresClient, PostgresQueryable, PostgresQueueStoreOptions, } from './options';
5
5
  /**
@@ -31,7 +31,7 @@ export declare class PostgresQueueStore implements QueueStore {
31
31
  readMessage(id: string): Promise<Uint8Array | undefined>;
32
32
  claim(request: ClaimRequest): Promise<QueueItem | undefined>;
33
33
  renew(id: string, owner: string, expiresAt: number): Promise<boolean>;
34
- complete(id: string, owner: string, result: AttemptResult): Promise<QueueItem | undefined>;
34
+ complete(id: string, owner: string, result: AttemptResult, dsns: readonly NewQueueItem[]): Promise<Completed | undefined>;
35
35
  reschedule(id: string, at: number, owner?: string): Promise<boolean>;
36
36
  cancel(id: string): Promise<QueueItem | undefined>;
37
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/postgres/store.ts"],"names":[],"mappings":"AAaA,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;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;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
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/postgres/store.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EACX,UAAU,EACV,aAAa,EACb,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,SAAS,EACT,gBAAgB,EAChB,MAAM,mBAAmB,CAAC;AAO3B,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;IA0BrE,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,EACrB,IAAI,EAAE,SAAS,YAAY,EAAE,GAC3B,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAI3B,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 +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;AAIpE,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;AAGtD,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;AAiGD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAChC,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,SAAS,GACb,OAAO,CAAC,IAAI,CAAC,CAuCf"}
1
+ {"version":3,"file":"deliver.d.ts","sourceRoot":"","sources":["../../src/queue/deliver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,mBAAmB,CAAC;AAIpE,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,EAAU,KAAK,aAAa,EAAY,MAAM,UAAU,CAAC;AAGhE,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;AAiGD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAChC,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,SAAS,GACb,OAAO,CAAC,IAAI,CAAC,CAuCf"}
@@ -1,23 +1,52 @@
1
1
  import type { QueueStore } from '../contract/queue-store';
2
- import type { QueueItem, RecipientUpdate } from '../contract/types';
2
+ import type { Completed, NewQueueItem, QueueItem, RecipientUpdate } from '../contract/types';
3
3
  import { type DsnKind } from '../dsn/build';
4
4
  import type { Events } from './events';
5
5
  import type { Settings } from './settings';
6
+ import type { Settled } from './settle';
6
7
  export interface NotifyContext {
7
8
  readonly settings: Settings;
8
9
  readonly store: QueueStore;
9
10
  readonly events: Events;
10
11
  }
12
+ /** A DSN built for an item, ready to go to the store with `complete`, and what its `dsn` event says. */
13
+ export interface PendingDsn {
14
+ readonly item: NewQueueItem;
15
+ readonly kind: Exclude<DsnKind, 'delivered'>;
16
+ readonly to: string;
17
+ readonly recipients: readonly string[];
18
+ }
11
19
  /**
12
- * Enqueues a DSN (RFC 3464) back to the item's sender for those of these
20
+ * Builds the DSN (RFC 3464) back to the item's sender for those of these
13
21
  * recipients that asked for one of this kind (`NOTIFY`, RFC 3461 §4.1:
14
22
  * `NEVER`, or the events listed; failure and delay when absent), from the
15
23
  * null sender, so it never causes one of its own. `ret` and `envid` of the
16
24
  * item shape its content and name the original (RFC 3461 §4.3, §4.4).
17
25
  * Nothing for an item from the null sender (RFC 5321 §4.5.5, RFC 3464
18
- * §2: a DSN is never sent about a DSN). It bypasses `maxItems`: a full
19
- * queue loses no bounce. A failure goes to the `error` event. With no
20
- * `message` — the store lost it — the DSN returns nothing of it.
26
+ * §2: a DSN is never sent about a DSN). With no `message` — the store lost
27
+ * it — the DSN returns nothing of it. The store enqueues it, in the step
28
+ * that records the outcome (`complete`), bypassing `maxItems`: a full queue
29
+ * loses no bounce. One that cannot be built is left out and its error
30
+ * pushed to `failures`, for the caller to say once the outcome is recorded:
31
+ * the outcome is recorded all the same, `delayNotified` included.
32
+ */
33
+ export declare function dsnsFor(ctx: Pick<NotifyContext, 'settings'>, item: QueueItem, message: Uint8Array | undefined, kind: Exclude<DsnKind, 'delivered'>, recipients: readonly RecipientUpdate[], now: number, failures: unknown[]): PendingDsn[];
34
+ /**
35
+ * The DSNs an attempt's outcome calls for, in the order failed, relayed,
36
+ * delayed, and the errors of those that could not be built.
37
+ */
38
+ export declare function dsnsOf(ctx: Pick<NotifyContext, 'settings'>, item: QueueItem, message: Uint8Array | undefined, settled: Settled, now: number): {
39
+ pending: PendingDsn[];
40
+ failures: unknown[];
41
+ };
42
+ /**
43
+ * Tells the listeners each DSN the store inserted with the outcome, by the
44
+ * ids it gave, in the order given. A store written before `complete` took
45
+ * the DSNs answers with the bare item: that is said on the `error` event,
46
+ * and each DSN goes to `add` instead, as it did, with no step shared with
47
+ * the outcome. A store that answers the new shape but gives back fewer DSNs
48
+ * than asked (the stores here throw instead, and write nothing) has an
49
+ * `error` event for each one missing.
21
50
  */
22
- export declare function notify(ctx: NotifyContext, item: QueueItem, message: Uint8Array | undefined, kind: Exclude<DsnKind, 'delivered'>, recipients: readonly RecipientUpdate[], now: number): Promise<void>;
51
+ export declare function tellDsns(ctx: NotifyContext, item: QueueItem, pending: readonly PendingDsn[], completed: Completed): Promise<void>;
23
52
  //# 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,EAAc,SAAS,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAY,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AAEtD,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;AAwBD;;;;;;;;;;GAUG;AACH,wBAAsB,MAAM,CAC3B,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,UAAU,GAAG,SAAS,EAC/B,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,WAAW,CAAC,EACnC,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,GAAG,EAAE,MAAM,GACT,OAAO,CAAC,IAAI,CAAC,CAsDf"}
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,EACX,SAAS,EAET,YAAY,EACZ,SAAS,EACT,eAAe,EACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAY,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AAGtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,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;AAwBD,wGAAwG;AACxG,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC7C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CACtB,GAAG,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,EACpC,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,UAAU,GAAG,SAAS,EAC/B,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,WAAW,CAAC,EACnC,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,OAAO,EAAE,GACjB,UAAU,EAAE,CAkDd;AAED;;;GAGG;AACH,wBAAgB,MAAM,CACrB,GAAG,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,EACpC,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,UAAU,GAAG,SAAS,EAC/B,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,GACT;IAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IAAC,QAAQ,EAAE,OAAO,EAAE,CAAA;CAAE,CAgBhD;AAED;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAC7B,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,SAAS,UAAU,EAAE,EAC9B,SAAS,EAAE,SAAS,GAClB,OAAO,CAAC,IAAI,CAAC,CAuCf"}
@@ -0,0 +1,11 @@
1
+ import type { AttemptResult, Completed, NewQueueItem } from '../contract/types';
2
+ import type { Keys } from './connect';
3
+ import type { RedisQueueClient } from './options';
4
+ /**
5
+ * `QueueStore.complete` on Redis: the outcome, the lease let go of and
6
+ * the DSN items added by one `COMPLETE` script. Redis cannot roll back,
7
+ * so every check (the DSNs, the result, the owner) is done here, before
8
+ * the script; the DSN ids are made once, whatever the number of reads.
9
+ */
10
+ export declare function complete(connected: () => Promise<RedisQueueClient>, k: Keys, id: string, owner: string, result: AttemptResult, dsns: readonly NewQueueItem[]): Promise<Completed | undefined>;
11
+ //# sourceMappingURL=complete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../src/redis/complete.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EACT,YAAY,EAEZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAOlD;;;;;GAKG;AACH,wBAAsB,QAAQ,CAC7B,SAAS,EAAE,MAAM,OAAO,CAAC,gBAAgB,CAAC,EAC1C,CAAC,EAAE,IAAI,EACP,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,SAAS,YAAY,EAAE,GAC3B,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CA+BhC"}