@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
@@ -7,81 +7,15 @@ import {
7
7
  invalid,
8
8
  checkTime,
9
9
  checkOwner,
10
+ checkComplete,
10
11
  checkNewItem,
11
12
  checkMaxItems,
12
13
  checkClaim,
13
- checkResult,
14
14
  checkList,
15
15
  isDone,
16
16
  applyAttempt,
17
17
  newItem
18
- } from "../chunks/index-sz13a17b.js";
19
-
20
- // src/redis/connect.ts
21
- var DEFAULT_PREFIX = "bumail:queue:";
22
- var PREFIX = /^[a-z][a-z0-9_:.-]{0,39}$/;
23
- function keysOf(value) {
24
- const prefix = value ?? DEFAULT_PREFIX;
25
- if (typeof prefix !== "string" || !PREFIX.test(prefix)) {
26
- throw invalid(`keyPrefix must be lowercase letters, digits, '_', ':', '.' and '-', starting with a letter, at most 40 characters, not ${JSON.stringify(prefix)}`);
27
- }
28
- return {
29
- prefix,
30
- items: `${prefix}items`,
31
- ready: `${prefix}ready`,
32
- leases: `${prefix}leases`,
33
- seq: `${prefix}seq`,
34
- schema: `${prefix}schema`
35
- };
36
- }
37
- var NEEDS = "A Redis queue store needs client, a Bun.RedisClient, or url, a redis:// URL";
38
- var SCHEMES = [
39
- "redis:",
40
- "rediss:",
41
- "valkey:",
42
- "valkeys:",
43
- "redis+tls:",
44
- "redis+unix:",
45
- "redis+tls+unix:"
46
- ];
47
- function urlOf(value) {
48
- if (typeof value !== "string" && !(value instanceof URL))
49
- throw invalid(NEEDS);
50
- const url = URL.parse(String(value));
51
- if (url === null || !SCHEMES.includes(url.protocol))
52
- throw invalid(NEEDS);
53
- return url;
54
- }
55
- function clientFor(url) {
56
- try {
57
- return new Bun.RedisClient(url.href);
58
- } catch (error) {
59
- const reason = error instanceof Error ? error.message : String(error);
60
- throw invalid(`The URL in url cannot be opened: ${masked(reason, url.password)}`);
61
- }
62
- }
63
- var isClient = (value) => typeof value === "object" && value !== null && typeof value.send === "function" && typeof value.getBuffer === "function" && typeof value.close === "function";
64
- function connect(options) {
65
- if (typeof options !== "object" || options === null)
66
- throw invalid(NEEDS);
67
- const keys = keysOf(options.keyPrefix);
68
- const { client, url } = options;
69
- if (client !== undefined && url !== undefined) {
70
- throw invalid("A Redis queue store takes client or url, not both");
71
- }
72
- if (client !== undefined) {
73
- if (!isClient(client))
74
- throw invalid(NEEDS);
75
- return { client, owned: false, keys, password: "" };
76
- }
77
- const parsed = urlOf(url);
78
- return {
79
- client: clientFor(parsed),
80
- owned: true,
81
- keys,
82
- password: parsed.password
83
- };
84
- }
18
+ } from "../chunks/index-t6q7zxgj.js";
85
19
 
86
20
  // src/redis/items.ts
87
21
  function fieldsOf(reply) {
@@ -173,21 +107,27 @@ if found then return found end
173
107
  redis.call('SET', KEYS[1], ARGV[2])
174
108
  return ARGV[2]
175
109
  `);
176
- var ADD = script(`
110
+ var ADD_ITEM = `
111
+ local function addItem(base, seq)
112
+ local id, created = ARGV[base], ARGV[base + 4]
113
+ local member = string.format('%016d', seq) .. ':' .. id
114
+ redis.call('HSET', prefix .. 'item:' .. id, 'id', id, 'from', ARGV[base + 1],
115
+ 'recipients', ARGV[base + 2], 'size', ARGV[base + 3], 'created', created, 'next', created,
116
+ 'attempts', '0', 'delay', '0', 'rev', '0', 'member', member)
117
+ if ARGV[base + 7] ~= '' then redis.call('HSET', prefix .. 'item:' .. id, 'ret', ARGV[base + 7]) end
118
+ if ARGV[base + 8] ~= '' then redis.call('HSET', prefix .. 'item:' .. id, 'envid', ARGV[base + 8]) end
119
+ redis.call('SET', prefix .. 'message:' .. id, ARGV[base + 5])
120
+ redis.call('ZADD', KEYS[1], created, member)
121
+ redis.call('ZADD', KEYS[2], created, member)
122
+ end
123
+ `;
124
+ var ADD = script(`${ADD_ITEM}
177
125
  local max = tonumber(ARGV[8])
178
126
  if max then
179
127
  local n = redis.call('ZCARD', KEYS[1])
180
128
  if n >= max then return {'full', tostring(n)} end
181
129
  end
182
- local member = string.format('%016d', redis.call('INCR', KEYS[3])) .. ':' .. ARGV[2]
183
- redis.call('HSET', prefix .. 'item:' .. ARGV[2], 'id', ARGV[2], 'from', ARGV[3],
184
- 'recipients', ARGV[4], 'size', ARGV[5], 'created', ARGV[6], 'next', ARGV[6],
185
- 'attempts', '0', 'delay', '0', 'rev', '0', 'member', member)
186
- if ARGV[9] ~= '' then redis.call('HSET', prefix .. 'item:' .. ARGV[2], 'ret', ARGV[9]) end
187
- if ARGV[10] ~= '' then redis.call('HSET', prefix .. 'item:' .. ARGV[2], 'envid', ARGV[10]) end
188
- redis.call('SET', prefix .. 'message:' .. ARGV[2], ARGV[7])
189
- redis.call('ZADD', KEYS[1], ARGV[6], member)
190
- redis.call('ZADD', KEYS[2], ARGV[6], member)
130
+ addItem(2, redis.call('INCR', KEYS[3]))
191
131
  return {'ok'}
192
132
  `);
193
133
  var CLAIM = script(`${NEXT_OF}
@@ -223,24 +163,31 @@ redis.call('HSET', key, 'expires', ARGV[4])
223
163
  redis.call('ZADD', KEYS[1], ARGV[4], redis.call('HGET', key, 'member'))
224
164
  return 1
225
165
  `);
226
- var COMPLETE = script(`
166
+ var COMPLETE = script(`${ADD_ITEM}
227
167
  local key = prefix .. 'item:' .. ARGV[2]
228
168
  if redis.call('HGET', key, 'owner') ~= ARGV[3] then return 0 end
229
169
  if redis.call('HGET', key, 'rev') ~= ARGV[4] then return -1 end
230
170
  local member = redis.call('HGET', key, 'member')
171
+ local count = ARGV[5] == 'drop' and 6 or 10
172
+ local dsns = tonumber(ARGV[count])
173
+ -- The one command that can still fail, before the first write.
174
+ local last = dsns > 0 and redis.call('INCRBY', KEYS[4], dsns) or 0
231
175
  redis.call('ZREM', KEYS[3], member)
232
176
  if ARGV[5] == 'drop' then
233
177
  redis.call('ZREM', KEYS[1], member)
234
178
  redis.call('ZREM', KEYS[2], member)
235
179
  redis.call('DEL', key, prefix .. 'message:' .. ARGV[2])
236
- return 1
180
+ else
181
+ redis.call('HSET', key, 'recipients', ARGV[6], 'next', ARGV[7],
182
+ 'attempts', ARGV[8], 'delay', ARGV[9])
183
+ redis.call('HINCRBY', key, 'rev', 1)
184
+ redis.call('HDEL', key, 'owner', 'expires')
185
+ redis.call('ZADD', KEYS[1], ARGV[7], member)
186
+ redis.call('ZADD', KEYS[2], ARGV[7], member)
187
+ end
188
+ for i = 1, dsns do
189
+ addItem(count + 1 + (i - 1) * 9, last - dsns + i)
237
190
  end
238
- redis.call('HSET', key, 'recipients', ARGV[6], 'next', ARGV[7],
239
- 'attempts', ARGV[8], 'delay', ARGV[9])
240
- redis.call('HINCRBY', key, 'rev', 1)
241
- redis.call('HDEL', key, 'owner', 'expires')
242
- redis.call('ZADD', KEYS[1], ARGV[7], member)
243
- redis.call('ZADD', KEYS[2], ARGV[7], member)
244
191
  return 1
245
192
  `);
246
193
  var RESCHEDULE = script(`
@@ -301,6 +248,103 @@ async function checkLayout(client, keys) {
301
248
  }
302
249
  }
303
250
 
251
+ // src/redis/complete.ts
252
+ var MAX_READS = 8;
253
+ async function complete(connected, k, id, owner, result, dsns) {
254
+ checkComplete(owner, result, dsns);
255
+ if (!isId(id))
256
+ return;
257
+ const client = await connected();
258
+ const added = [];
259
+ const args = [`${dsns.length}`];
260
+ for (const dsn of dsns) {
261
+ const made = newItem(crypto.randomUUID(), dsn);
262
+ added.push(made);
263
+ args.push(...addArgs(made, dsn.message, undefined));
264
+ }
265
+ for (let read = 0;read < MAX_READS; read++) {
266
+ const fields = fieldsOf(await client.send("HGETALL", [`${k.prefix}item:${id}`]));
267
+ if (!fields || fields["owner"] !== owner)
268
+ return;
269
+ const rev = fields["rev"];
270
+ if (rev === undefined)
271
+ return;
272
+ const item = applyAttempt(itemOf(fields), result);
273
+ const done = Number(await run(client, COMPLETE, [k.items, k.ready, k.leases, k.seq], [k.prefix, id, owner, rev, ...outcomeOf(item), ...args]));
274
+ if (done === 1)
275
+ return { item, dsns: added };
276
+ if (done === 0)
277
+ return;
278
+ }
279
+ return;
280
+ }
281
+
282
+ // src/redis/connect.ts
283
+ var DEFAULT_PREFIX = "bumail:queue:";
284
+ var PREFIX = /^[a-z][a-z0-9_:.-]{0,39}$/;
285
+ function keysOf(value) {
286
+ const prefix = value ?? DEFAULT_PREFIX;
287
+ if (typeof prefix !== "string" || !PREFIX.test(prefix)) {
288
+ throw invalid(`keyPrefix must be lowercase letters, digits, '_', ':', '.' and '-', starting with a letter, at most 40 characters, not ${JSON.stringify(prefix)}`);
289
+ }
290
+ return {
291
+ prefix,
292
+ items: `${prefix}items`,
293
+ ready: `${prefix}ready`,
294
+ leases: `${prefix}leases`,
295
+ seq: `${prefix}seq`,
296
+ schema: `${prefix}schema`
297
+ };
298
+ }
299
+ var NEEDS = "A Redis queue store needs client, a Bun.RedisClient, or url, a redis:// URL";
300
+ var SCHEMES = [
301
+ "redis:",
302
+ "rediss:",
303
+ "valkey:",
304
+ "valkeys:",
305
+ "redis+tls:",
306
+ "redis+unix:",
307
+ "redis+tls+unix:"
308
+ ];
309
+ function urlOf(value) {
310
+ if (typeof value !== "string" && !(value instanceof URL))
311
+ throw invalid(NEEDS);
312
+ const url = URL.parse(String(value));
313
+ if (url === null || !SCHEMES.includes(url.protocol))
314
+ throw invalid(NEEDS);
315
+ return url;
316
+ }
317
+ function clientFor(url) {
318
+ try {
319
+ return new Bun.RedisClient(url.href);
320
+ } catch (error) {
321
+ const reason = error instanceof Error ? error.message : String(error);
322
+ throw invalid(`The URL in url cannot be opened: ${masked(reason, url.password)}`);
323
+ }
324
+ }
325
+ var isClient = (value) => typeof value === "object" && value !== null && typeof value.send === "function" && typeof value.getBuffer === "function" && typeof value.close === "function";
326
+ function connect(options) {
327
+ if (typeof options !== "object" || options === null)
328
+ throw invalid(NEEDS);
329
+ const keys = keysOf(options.keyPrefix);
330
+ const { client, url } = options;
331
+ if (client !== undefined && url !== undefined) {
332
+ throw invalid("A Redis queue store takes client or url, not both");
333
+ }
334
+ if (client !== undefined) {
335
+ if (!isClient(client))
336
+ throw invalid(NEEDS);
337
+ return { client, owned: false, keys, password: "" };
338
+ }
339
+ const parsed = urlOf(url);
340
+ return {
341
+ client: clientFor(parsed),
342
+ owned: true,
343
+ keys,
344
+ password: parsed.password
345
+ };
346
+ }
347
+
304
348
  // src/redis/store.ts
305
349
  class RedisQueueStore {
306
350
  #client;
@@ -398,28 +442,8 @@ class RedisQueueStore {
398
442
  const done = await this.#run(RENEW, [k.leases], [id, owner, time(expiresAt)]);
399
443
  return Number(done) === 1;
400
444
  }
401
- async complete(id, owner, result) {
402
- checkOwner(owner);
403
- checkResult(result);
404
- if (!isId(id))
405
- return;
406
- const k = this.#keys;
407
- const client = await this.#redis();
408
- for (let read = 0;read < MAX_READS; read++) {
409
- const fields = fieldsOf(await client.send("HGETALL", [`${k.prefix}item:${id}`]));
410
- if (!fields || fields["owner"] !== owner)
411
- return;
412
- const rev = fields["rev"];
413
- if (rev === undefined)
414
- return;
415
- const item = applyAttempt(itemOf(fields), result);
416
- const done = Number(await this.#run(COMPLETE, [k.items, k.ready, k.leases], [id, owner, rev, ...outcomeOf(item)]));
417
- if (done === 1)
418
- return item;
419
- if (done === 0)
420
- return;
421
- }
422
- return;
445
+ async complete(id, owner, result, dsns) {
446
+ return complete(() => this.#redis(), this.#keys, id, owner, result, dsns);
423
447
  }
424
448
  async reschedule(id, at, owner) {
425
449
  checkTime("at", at);
@@ -441,11 +465,10 @@ class RedisQueueStore {
441
465
  return fields ? itemOf(fields) : undefined;
442
466
  }
443
467
  }
444
- var MAX_READS = 8;
445
468
  var closed = () => new QueueError2("CLOSED", "The queue store is closed");
446
469
  export {
447
470
  RedisQueueStore
448
471
  };
449
472
 
450
- //# debugId=709817593E83454864756E2164756E21
473
+ //# debugId=D8069639A7F10A3F64756E2164756E21
451
474
  //# sourceMappingURL=index.js.map
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/redis/connect.ts", "../src/redis/items.ts", "../src/redis/scripts.ts", "../src/redis/run.ts", "../src/redis/store.ts"],
3
+ "sources": ["../src/redis/items.ts", "../src/redis/scripts.ts", "../src/redis/run.ts", "../src/redis/complete.ts", "../src/redis/connect.ts", "../src/redis/store.ts"],
4
4
  "sourcesContent": [
5
- "import { invalid } from '../errors';\nimport { masked } from '../masked';\nimport type { RedisQueueClient, RedisQueueStoreOptions } from './options';\n\n/** The keys of one queue, each its prefix and a fixed name. */\nexport interface Keys {\n\treadonly prefix: string;\n\t/** Every item, scored by its next attempt: `list` and `count`. */\n\treadonly items: string;\n\t/** The items no lease holds, scored by their next attempt: what a claim takes first. */\n\treadonly ready: string;\n\t/** The leased items, scored by when their leases expire. */\n\treadonly leases: string;\n\t/** The counter that orders items equally due. */\n\treadonly seq: string;\n\t/** The layout version. */\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: RedisQueueClient;\n\treadonly owned: boolean;\n\treadonly keys: Keys;\n\t/** The URL's password, so an error that repeats it is masked; `''` for a given client. */\n\treadonly password: string;\n}\n\nconst DEFAULT_PREFIX = 'bumail:queue:';\n\n/**\n * Nothing Redis reads specially: no `{`, so no Cluster hash tag; no `*`,\n * `?`, `[` or `\\`, so a `SCAN MATCH` on the prefix matches its keys only;\n * no space or control character.\n */\nconst PREFIX = /^[a-z][a-z0-9_:.-]{0,39}$/;\n\nexport function keysOf(value: unknown): Keys {\n\tconst prefix = value ?? DEFAULT_PREFIX;\n\tif (typeof prefix !== 'string' || !PREFIX.test(prefix)) {\n\t\tthrow invalid(\n\t\t\t`keyPrefix must be lowercase letters, digits, '_', ':', '.' and '-', starting with a letter, 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\tready: `${prefix}ready`,\n\t\tleases: `${prefix}leases`,\n\t\tseq: `${prefix}seq`,\n\t\tschema: `${prefix}schema`,\n\t};\n}\n\nconst NEEDS =\n\t'A Redis queue store needs client, a Bun.RedisClient, or url, a redis:// URL';\n\n/** The schemes `Bun.RedisClient` takes. */\nconst SCHEMES = [\n\t'redis:',\n\t'rediss:',\n\t'valkey:',\n\t'valkeys:',\n\t'redis+tls:',\n\t'redis+unix:',\n\t'redis+tls+unix:',\n];\n\n/** A Redis URL; never echoed, since it may hold a password. */\nfunction urlOf(value: unknown): URL {\n\tif (typeof value !== 'string' && !(value instanceof URL))\n\t\tthrow invalid(NEEDS);\n\tconst url = URL.parse(String(value));\n\tif (url === null || !SCHEMES.includes(url.protocol)) throw invalid(NEEDS);\n\treturn url;\n}\n\n/**\n * A client of the store's own for the URL. `Bun.RedisClient` refuses\n * some URLs at once (a database that is not a number): that is\n * `INVALID`, its reason kept and the password, should it be repeated,\n * masked.\n */\nfunction clientFor(url: URL): RedisQueueClient {\n\ttry {\n\t\treturn new Bun.RedisClient(url.href) as unknown as RedisQueueClient;\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 url cannot be opened: ${masked(reason, url.password)}`,\n\t\t);\n\t}\n}\n\nconst isClient = (value: unknown): value is RedisQueueClient =>\n\ttypeof value === 'object' &&\n\tvalue !== null &&\n\ttypeof (value as RedisQueueClient).send === 'function' &&\n\ttypeof (value as RedisQueueClient).getBuffer === 'function' &&\n\ttypeof (value as RedisQueueClient).close === 'function';\n\n/** Checks the options and opens a client for a URL; connects to nothing yet. */\nexport function connect(options: RedisQueueStoreOptions): Connection {\n\tif (typeof options !== 'object' || options === null) throw invalid(NEEDS);\n\tconst keys = keysOf(options.keyPrefix);\n\tconst { client, url } = options;\n\tif (client !== undefined && url !== undefined) {\n\t\tthrow invalid('A Redis queue store takes client or url, not both');\n\t}\n\tif (client !== undefined) {\n\t\tif (!isClient(client)) throw invalid(NEEDS);\n\t\treturn { client, owned: false, keys, password: '' };\n\t}\n\tconst parsed = urlOf(url);\n\treturn {\n\t\tclient: clientFor(parsed),\n\t\towned: true,\n\t\tkeys,\n\t\tpassword: parsed.password,\n\t};\n}\n",
6
5
  "import { isDone } from '../contract/checks';\nimport type { QueueItem, RecipientState } from '../contract/types';\n\n/** An item's hash, as `HGETALL` gives it: a map, or a script's flat list of names and values. */\nexport type Fields = Readonly<Record<string, string>>;\n\n/** A script's `HGETALL`, `[name, value, …]`, as a map; a map as it is. */\nexport function fieldsOf(reply: unknown): Fields | undefined {\n\tif (Array.isArray(reply)) {\n\t\tconst fields: Record<string, string> = {};\n\t\tfor (let i = 0; i + 1 < reply.length; i += 2) {\n\t\t\tfields[String(reply[i])] = String(reply[i + 1]);\n\t\t}\n\t\treturn fieldsOf(fields);\n\t}\n\tif (typeof reply !== 'object' || reply === null) return undefined;\n\t// No id: no item, whatever else a hash left half written holds.\n\treturn (reply as Fields)['id'] === undefined ? undefined : (reply as Fields);\n}\n\nconst field = (fields: Fields, name: string): string => fields[name] ?? '';\n\n/** `RET` and `ENVID`: absent from a hash written before they existed. */\nfunction dsnFields(fields: Fields): Pick<QueueItem, 'ret' | 'envid'> {\n\tconst { ret, envid } = fields;\n\treturn {\n\t\t...(ret === 'FULL' || ret === 'HDRS' ? { ret } : {}),\n\t\t...(envid ? { envid } : {}),\n\t};\n}\n\n/** The item a hash holds. Times are kept as JavaScript wrote them, so each reads back exactly. */\nexport function itemOf(fields: Fields): QueueItem {\n\tconst item: QueueItem = {\n\t\tid: field(fields, 'id'),\n\t\tfrom: field(fields, 'from'),\n\t\trecipients: JSON.parse(field(fields, 'recipients')) as RecipientState[],\n\t\tsize: Number(field(fields, 'size')),\n\t\tcreatedAt: Number(field(fields, 'created')),\n\t\tnextAttemptAt: Number(field(fields, 'next')),\n\t\tattempts: Number(field(fields, 'attempts')),\n\t\tdelayNotified: field(fields, 'delay') === '1',\n\t\t...dsnFields(fields),\n\t};\n\tconst owner = fields['owner'];\n\tconst expires = fields['expires'];\n\tif (owner === undefined || expires === undefined) return item;\n\treturn { ...item, lease: { owner, expiresAt: Number(expires) } };\n}\n\n/**\n * The ids a store makes, `crypto.randomUUID()`'s. Any other id is one no\n * item has, so no id a caller gives ever reaches a key but an item's.\n */\nconst ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;\n\nexport const isId = (id: unknown): id is string =>\n\ttypeof id === 'string' && ID.test(id);\n\n/** A time as a script takes it: the string JavaScript writes, which reads back exactly. */\nexport const time = (value: number) => String(value);\n\n/** What `COMPLETE` records of an attempt: the item dropped, or its new state. */\nexport const outcomeOf = (item: QueueItem): string[] =>\n\tisDone(item)\n\t\t? ['drop']\n\t\t: [\n\t\t\t\t'record',\n\t\t\t\tJSON.stringify(item.recipients),\n\t\t\t\ttime(item.nextAttemptAt),\n\t\t\t\t`${item.attempts}`,\n\t\t\t\titem.delayNotified ? '1' : '0',\n\t\t\t];\n\n/** The arguments of the `ADD` script, after the prefix: see `ADD`. */\nexport const addArgs = (\n\tadded: QueueItem,\n\tmessage: Uint8Array,\n\tmax: number | undefined,\n): (string | Uint8Array)[] => [\n\tadded.id,\n\tadded.from,\n\tJSON.stringify(added.recipients),\n\t`${added.size}`,\n\ttime(added.createdAt),\n\tmessage,\n\tmax === undefined ? '' : `${max}`,\n\tadded.ret ?? '',\n\tadded.envid ?? '',\n];\n",
7
- "/**\n * The Lua scripts a Redis store runs: each operation that writes is one\n * script, so Redis runs it whole, with no other command between its\n * steps. The fixed keys come as `KEYS`; an item's own keys are its\n * prefix (`ARGV[1]`), `item:` or `message:`, and its id.\n *\n * An item is a hash, `<prefix>item:<id>`; its message a string,\n * `<prefix>message:<id>`, written from the bytes given, as they are. Its\n * member in the sorted sets is its sequence number, sixteen digits, `:`,\n * and its id: Redis orders members of one score by their bytes, so items\n * equally due come oldest first. Times travel as the strings JavaScript\n * writes for them and are only compared here (`tonumber`), never written\n * back from Lua, so none loses a digit.\n */\n\n/** What every script starts with. */\nconst PRELUDE = `\nlocal prefix = ARGV[1]\nlocal function itemKey(member) return prefix .. 'item:' .. string.sub(member, 18) end\nlocal function seqOf(member) return tonumber(string.sub(member, 1, 16)) end\n`;\n\n/** For CLAIM: when an item's due time, or false when its hash is gone (evicted, deleted by hand). */\nconst NEXT_OF = `\nlocal function nextOf(member)\n\tlocal found = redis.call('HGET', itemKey(member), 'next')\n\tif found then return tonumber(found) end\n\t-- A member whose hash is gone is dropped, never leased.\n\tredis.call('ZREM', KEYS[1], member)\n\tredis.call('ZREM', KEYS[2], member)\n\tredis.call('ZREM', KEYS[3], member)\n\tredis.call('DEL', prefix .. 'message:' .. string.sub(member, 18))\n\treturn false\nend\n`;\n\n/** A script, and the SHA-1 `EVALSHA` names it by. */\nexport interface Script {\n\treadonly source: string;\n\treadonly sha: string;\n}\n\nconst script = (body: string): Script => {\n\tconst source = PRELUDE + body;\n\tconst sha = new Bun.CryptoHasher('sha1').update(source).digest('hex');\n\treturn { source, sha };\n};\n\n/**\n * KEYS schema; ARGV prefix, version. Writes the version on a new queue;\n * returns the one found.\n */\nexport const SCHEMA = script(`\nlocal found = redis.call('GET', KEYS[1])\nif found then return found end\nredis.call('SET', KEYS[1], ARGV[2])\nreturn ARGV[2]\n`);\n\n/**\n * KEYS items, ready, seq; ARGV prefix, id, from, recipients, size,\n * created, message, max (or ''), ret (or ''), envid (or ''). `{'full', n}` when `max` items are\n * there already, else `{'ok'}`.\n */\nexport const ADD = script(`\nlocal max = tonumber(ARGV[8])\nif max then\n\tlocal n = redis.call('ZCARD', KEYS[1])\n\tif n >= max then return {'full', tostring(n)} end\nend\nlocal member = string.format('%016d', redis.call('INCR', KEYS[3])) .. ':' .. ARGV[2]\nredis.call('HSET', prefix .. 'item:' .. ARGV[2], 'id', ARGV[2], 'from', ARGV[3],\n\t'recipients', ARGV[4], 'size', ARGV[5], 'created', ARGV[6], 'next', ARGV[6],\n\t'attempts', '0', 'delay', '0', 'rev', '0', 'member', member)\nif ARGV[9] ~= '' then redis.call('HSET', prefix .. 'item:' .. ARGV[2], 'ret', ARGV[9]) end\nif ARGV[10] ~= '' then redis.call('HSET', prefix .. 'item:' .. ARGV[2], 'envid', ARGV[10]) end\nredis.call('SET', prefix .. 'message:' .. ARGV[2], ARGV[7])\nredis.call('ZADD', KEYS[1], ARGV[6], member)\nredis.call('ZADD', KEYS[2], ARGV[6], member)\nreturn {'ok'}\n`);\n\n/**\n * KEYS ready, leases, items; ARGV prefix, owner, now, expiry. The\n * earliest due, then the oldest, of the items no lease holds and of those\n * whose lease expired, leased to the owner; its fields, or false. The\n * expired leases are read whole: there are as many as the leases a\n * crashed or stalled worker left behind, and the leased items an admin\n * moved later, until they are due.\n */\nexport const CLAIM = script(`${NEXT_OF}\nlocal now = tonumber(ARGV[3])\nlocal best, bestNext\nwhile best == nil do\n\tlocal first = redis.call('ZRANGEBYSCORE', KEYS[1], '-inf', ARGV[3], 'LIMIT', 0, 1)[1]\n\tif not first then break end\n\tlocal nextAt = nextOf(first)\n\tif nextAt then\n\t\tbest = first\n\t\tbestNext = nextAt\n\tend\nend\nfor _, member in ipairs(redis.call('ZRANGEBYSCORE', KEYS[2], '-inf', ARGV[3])) do\n\tlocal nextAt = nextOf(member)\n\tif nextAt and nextAt <= now and (best == nil or nextAt < bestNext\n\t\tor (nextAt == bestNext and seqOf(member) < seqOf(best))) then\n\t\tbest = member\n\t\tbestNext = nextAt\n\tend\nend\nif best == nil then return false end\nredis.call('ZREM', KEYS[1], best)\nredis.call('ZADD', KEYS[2], ARGV[4], best)\nredis.call('HSET', itemKey(best), 'owner', ARGV[2], 'expires', ARGV[4])\nreturn redis.call('HGETALL', itemKey(best))\n`);\n\n/** KEYS leases; ARGV prefix, id, owner, expiry. 1 while the owner holds the lease, else 0. */\nexport const RENEW = script(`\nlocal key = prefix .. 'item:' .. ARGV[2]\nif redis.call('HGET', key, 'owner') ~= ARGV[3] then return 0 end\nredis.call('HSET', key, 'expires', ARGV[4])\nredis.call('ZADD', KEYS[1], ARGV[4], redis.call('HGET', key, 'member'))\nreturn 1\n`);\n\n/**\n * KEYS items, ready, leases; ARGV prefix, id, owner, rev, then 'drop',\n * or 'record' and recipients, next, attempts, delay. 0 when the owner\n * does not hold the lease; -1 when another outcome was recorded since\n * the item was read at `rev`, to read it again; 1 once recorded, the\n * lease let go of, or the item and its message dropped.\n */\nexport const COMPLETE = script(`\nlocal key = prefix .. 'item:' .. ARGV[2]\nif redis.call('HGET', key, 'owner') ~= ARGV[3] then return 0 end\nif redis.call('HGET', key, 'rev') ~= ARGV[4] then return -1 end\nlocal member = redis.call('HGET', key, 'member')\nredis.call('ZREM', KEYS[3], member)\nif ARGV[5] == 'drop' then\n\tredis.call('ZREM', KEYS[1], member)\n\tredis.call('ZREM', KEYS[2], member)\n\tredis.call('DEL', key, prefix .. 'message:' .. ARGV[2])\n\treturn 1\nend\nredis.call('HSET', key, 'recipients', ARGV[6], 'next', ARGV[7],\n\t'attempts', ARGV[8], 'delay', ARGV[9])\nredis.call('HINCRBY', key, 'rev', 1)\nredis.call('HDEL', key, 'owner', 'expires')\nredis.call('ZADD', KEYS[1], ARGV[7], member)\nredis.call('ZADD', KEYS[2], ARGV[7], member)\nreturn 1\n`);\n\n/**\n * KEYS items, ready, leases; ARGV prefix, id, at, owner (or ''). With an\n * owner, only while it holds the lease, which it lets go of; without,\n * the lease stays. 1 when moved, else 0.\n */\nexport const RESCHEDULE = script(`\nlocal key = prefix .. 'item:' .. ARGV[2]\nlocal member = redis.call('HGET', key, 'member')\nif not member then return 0 end\nlocal owner = redis.call('HGET', key, 'owner')\nif ARGV[4] ~= '' then\n\tif owner ~= ARGV[4] then return 0 end\n\tredis.call('HDEL', key, 'owner', 'expires')\n\tredis.call('ZREM', KEYS[3], member)\n\towner = false\nend\nredis.call('HSET', key, 'next', ARGV[3])\nredis.call('ZADD', KEYS[1], ARGV[3], member)\nif not owner then redis.call('ZADD', KEYS[2], ARGV[3], member) end\nreturn 1\n`);\n\n/** KEYS items, ready, leases; ARGV prefix, id. The item's fields as it stood, or false; dropped with its message. */\nexport const CANCEL = script(`\nlocal key = prefix .. 'item:' .. ARGV[2]\nlocal fields = redis.call('HGETALL', key)\nif #fields == 0 then return false end\nlocal member = redis.call('HGET', key, 'member')\nredis.call('ZREM', KEYS[1], member)\nredis.call('ZREM', KEYS[2], member)\nredis.call('ZREM', KEYS[3], member)\nredis.call('DEL', key, prefix .. 'message:' .. ARGV[2])\nreturn fields\n`);\n\n/** KEYS items; ARGV prefix, first, last. A page of items, each its fields, in one read. */\nexport const LIST = script(`\nlocal out = {}\nfor _, member in ipairs(redis.call('ZRANGE', KEYS[1], ARGV[2], ARGV[3])) do\n\tout[#out + 1] = redis.call('HGETALL', itemKey(member))\nend\nreturn out\n`);\n",
6
+ "/**\n * The Lua scripts a Redis store runs: each operation that writes is one\n * script, so Redis runs it whole, with no other command between its\n * steps. The fixed keys come as `KEYS`; an item's own keys are its\n * prefix (`ARGV[1]`), `item:` or `message:`, and its id.\n *\n * An item is a hash, `<prefix>item:<id>`; its message a string,\n * `<prefix>message:<id>`, written from the bytes given, as they are. Its\n * member in the sorted sets is its sequence number, sixteen digits, `:`,\n * and its id: Redis orders members of one score by their bytes, so items\n * equally due come oldest first. Times travel as the strings JavaScript\n * writes for them and are only compared here (`tonumber`), never written\n * back from Lua, so none loses a digit.\n */\n\n/** What every script starts with. */\nconst PRELUDE = `\nlocal prefix = ARGV[1]\nlocal function itemKey(member) return prefix .. 'item:' .. string.sub(member, 18) end\nlocal function seqOf(member) return tonumber(string.sub(member, 1, 16)) end\n`;\n\n/** For CLAIM: when an item's due time, or false when its hash is gone (evicted, deleted by hand). */\nconst NEXT_OF = `\nlocal function nextOf(member)\n\tlocal found = redis.call('HGET', itemKey(member), 'next')\n\tif found then return tonumber(found) end\n\t-- A member whose hash is gone is dropped, never leased.\n\tredis.call('ZREM', KEYS[1], member)\n\tredis.call('ZREM', KEYS[2], member)\n\tredis.call('ZREM', KEYS[3], member)\n\tredis.call('DEL', prefix .. 'message:' .. string.sub(member, 18))\n\treturn false\nend\n`;\n\n/** A script, and the SHA-1 `EVALSHA` names it by. */\nexport interface Script {\n\treadonly source: string;\n\treadonly sha: string;\n}\n\nconst script = (body: string): Script => {\n\tconst source = PRELUDE + body;\n\tconst sha = new Bun.CryptoHasher('sha1').update(source).digest('hex');\n\treturn { source, sha };\n};\n\n/**\n * KEYS schema; ARGV prefix, version. Writes the version on a new queue;\n * returns the one found.\n */\nexport const SCHEMA = script(`\nlocal found = redis.call('GET', KEYS[1])\nif found then return found end\nredis.call('SET', KEYS[1], ARGV[2])\nreturn ARGV[2]\n`);\n\n/**\n * Writes one new item, its arguments from `ARGV[base]`: id, from,\n * recipients, size, created, message, max (or ''), ret (or ''), envid\n * (or ''). Only HSET, SET and ZADD: Redis has no rollback, so what can\n * fail is checked before the script runs. `max` is for the caller.\n */\nconst ADD_ITEM = `\nlocal function addItem(base, seq)\n\tlocal id, created = ARGV[base], ARGV[base + 4]\n\tlocal member = string.format('%016d', seq) .. ':' .. id\n\tredis.call('HSET', prefix .. 'item:' .. id, 'id', id, 'from', ARGV[base + 1],\n\t\t'recipients', ARGV[base + 2], 'size', ARGV[base + 3], 'created', created, 'next', created,\n\t\t'attempts', '0', 'delay', '0', 'rev', '0', 'member', member)\n\tif ARGV[base + 7] ~= '' then redis.call('HSET', prefix .. 'item:' .. id, 'ret', ARGV[base + 7]) end\n\tif ARGV[base + 8] ~= '' then redis.call('HSET', prefix .. 'item:' .. id, 'envid', ARGV[base + 8]) end\n\tredis.call('SET', prefix .. 'message:' .. id, ARGV[base + 5])\n\tredis.call('ZADD', KEYS[1], created, member)\n\tredis.call('ZADD', KEYS[2], created, member)\nend\n`;\n\n/**\n * KEYS items, ready, seq; ARGV prefix, id, from, recipients, size,\n * created, message, max (or ''), ret (or ''), envid (or ''). `{'full', n}` when `max` items are\n * there already, else `{'ok'}`.\n */\nexport const ADD = script(`${ADD_ITEM}\nlocal max = tonumber(ARGV[8])\nif max then\n\tlocal n = redis.call('ZCARD', KEYS[1])\n\tif n >= max then return {'full', tostring(n)} end\nend\naddItem(2, redis.call('INCR', KEYS[3]))\nreturn {'ok'}\n`);\n\n/**\n * KEYS ready, leases, items; ARGV prefix, owner, now, expiry. The\n * earliest due, then the oldest, of the items no lease holds and of those\n * whose lease expired, leased to the owner; its fields, or false. The\n * expired leases are read whole: there are as many as the leases a\n * crashed or stalled worker left behind, and the leased items an admin\n * moved later, until they are due.\n */\nexport const CLAIM = script(`${NEXT_OF}\nlocal now = tonumber(ARGV[3])\nlocal best, bestNext\nwhile best == nil do\n\tlocal first = redis.call('ZRANGEBYSCORE', KEYS[1], '-inf', ARGV[3], 'LIMIT', 0, 1)[1]\n\tif not first then break end\n\tlocal nextAt = nextOf(first)\n\tif nextAt then\n\t\tbest = first\n\t\tbestNext = nextAt\n\tend\nend\nfor _, member in ipairs(redis.call('ZRANGEBYSCORE', KEYS[2], '-inf', ARGV[3])) do\n\tlocal nextAt = nextOf(member)\n\tif nextAt and nextAt <= now and (best == nil or nextAt < bestNext\n\t\tor (nextAt == bestNext and seqOf(member) < seqOf(best))) then\n\t\tbest = member\n\t\tbestNext = nextAt\n\tend\nend\nif best == nil then return false end\nredis.call('ZREM', KEYS[1], best)\nredis.call('ZADD', KEYS[2], ARGV[4], best)\nredis.call('HSET', itemKey(best), 'owner', ARGV[2], 'expires', ARGV[4])\nreturn redis.call('HGETALL', itemKey(best))\n`);\n\n/** KEYS leases; ARGV prefix, id, owner, expiry. 1 while the owner holds the lease, else 0. */\nexport const RENEW = script(`\nlocal key = prefix .. 'item:' .. ARGV[2]\nif redis.call('HGET', key, 'owner') ~= ARGV[3] then return 0 end\nredis.call('HSET', key, 'expires', ARGV[4])\nredis.call('ZADD', KEYS[1], ARGV[4], redis.call('HGET', key, 'member'))\nreturn 1\n`);\n\n/**\n * KEYS items, ready, leases, seq; ARGV prefix, id, owner, rev, then\n * 'drop', or 'record' and recipients, next, attempts, delay; then the\n * number of DSN items and, for each, the arguments of `ADD` (its `max`\n * left empty: a DSN ignores the limit). 0 when the owner does not hold\n * the lease; -1 when another outcome was recorded since the item was\n * read at `rev`, to read it again, with nothing written; 1 once the\n * outcome is recorded, the lease let go of (or the item and its message\n * dropped) and the DSN items added, all in this one call.\n */\nexport const COMPLETE = script(`${ADD_ITEM}\nlocal key = prefix .. 'item:' .. ARGV[2]\nif redis.call('HGET', key, 'owner') ~= ARGV[3] then return 0 end\nif redis.call('HGET', key, 'rev') ~= ARGV[4] then return -1 end\nlocal member = redis.call('HGET', key, 'member')\nlocal count = ARGV[5] == 'drop' and 6 or 10\nlocal dsns = tonumber(ARGV[count])\n-- The one command that can still fail, before the first write.\nlocal last = dsns > 0 and redis.call('INCRBY', KEYS[4], dsns) or 0\nredis.call('ZREM', KEYS[3], member)\nif ARGV[5] == 'drop' then\n\tredis.call('ZREM', KEYS[1], member)\n\tredis.call('ZREM', KEYS[2], member)\n\tredis.call('DEL', key, prefix .. 'message:' .. ARGV[2])\nelse\n\tredis.call('HSET', key, 'recipients', ARGV[6], 'next', ARGV[7],\n\t\t'attempts', ARGV[8], 'delay', ARGV[9])\n\tredis.call('HINCRBY', key, 'rev', 1)\n\tredis.call('HDEL', key, 'owner', 'expires')\n\tredis.call('ZADD', KEYS[1], ARGV[7], member)\n\tredis.call('ZADD', KEYS[2], ARGV[7], member)\nend\nfor i = 1, dsns do\n\taddItem(count + 1 + (i - 1) * 9, last - dsns + i)\nend\nreturn 1\n`);\n\n/**\n * KEYS items, ready, leases; ARGV prefix, id, at, owner (or ''). With an\n * owner, only while it holds the lease, which it lets go of; without,\n * the lease stays. 1 when moved, else 0.\n */\nexport const RESCHEDULE = script(`\nlocal key = prefix .. 'item:' .. ARGV[2]\nlocal member = redis.call('HGET', key, 'member')\nif not member then return 0 end\nlocal owner = redis.call('HGET', key, 'owner')\nif ARGV[4] ~= '' then\n\tif owner ~= ARGV[4] then return 0 end\n\tredis.call('HDEL', key, 'owner', 'expires')\n\tredis.call('ZREM', KEYS[3], member)\n\towner = false\nend\nredis.call('HSET', key, 'next', ARGV[3])\nredis.call('ZADD', KEYS[1], ARGV[3], member)\nif not owner then redis.call('ZADD', KEYS[2], ARGV[3], member) end\nreturn 1\n`);\n\n/** KEYS items, ready, leases; ARGV prefix, id. The item's fields as it stood, or false; dropped with its message. */\nexport const CANCEL = script(`\nlocal key = prefix .. 'item:' .. ARGV[2]\nlocal fields = redis.call('HGETALL', key)\nif #fields == 0 then return false end\nlocal member = redis.call('HGET', key, 'member')\nredis.call('ZREM', KEYS[1], member)\nredis.call('ZREM', KEYS[2], member)\nredis.call('ZREM', KEYS[3], member)\nredis.call('DEL', key, prefix .. 'message:' .. ARGV[2])\nreturn fields\n`);\n\n/** KEYS items; ARGV prefix, first, last. A page of items, each its fields, in one read. */\nexport const LIST = script(`\nlocal out = {}\nfor _, member in ipairs(redis.call('ZRANGE', KEYS[1], ARGV[2], ARGV[3])) do\n\tout[#out + 1] = redis.call('HGETALL', itemKey(member))\nend\nreturn out\n`);\n",
8
7
  "import { QueueError } from '../errors';\nimport type { Keys } from './connect';\nimport type { RedisQueueClient } from './options';\nimport { SCHEMA, type Script } from './scripts';\n\n/** Redis no longer has the script: restarted, failed over, or `SCRIPT FLUSH`ed. */\nconst isNoScript = (error: unknown) =>\n\terror instanceof Error && error.message.startsWith('NOSCRIPT');\n\n/**\n * Runs a script by its SHA-1 (`EVALSHA`), or, when Redis does not have\n * it, by its source (`EVAL`), which also keeps it for the next call.\n * Either way Redis runs it whole.\n */\nexport async function run(\n\tclient: RedisQueueClient,\n\tscript: Script,\n\tkeys: string[],\n\targs: (string | Uint8Array)[],\n): Promise<unknown> {\n\tconst rest = [`${keys.length}`, ...keys, ...args];\n\ttry {\n\t\treturn await client.send('EVALSHA', [script.sha, ...rest]);\n\t} catch (error) {\n\t\tif (!isNoScript(error)) throw error;\n\t\treturn client.send('EVAL', [script.source, ...rest]);\n\t}\n}\n\n/** The layout of the keys; a change is a new version, and a newer one is refused. */\nconst LAYOUT = 1;\n\n/** Reads the layout version, writing it on a new queue; a newer one is `INVALID`. */\nexport async function checkLayout(\n\tclient: RedisQueueClient,\n\tkeys: Keys,\n): Promise<void> {\n\tconst found = Number(\n\t\tawait run(client, SCHEMA, [keys.schema], [keys.prefix, `${LAYOUT}`]),\n\t);\n\tif (!Number.isInteger(found) || found < 1) {\n\t\tthrow new QueueError(\n\t\t\t'INVALID',\n\t\t\t`The key ${keys.schema} does not hold a layout version: is the prefix another application's?`,\n\t\t);\n\t}\n\tif (found > LAYOUT) {\n\t\tthrow new QueueError(\n\t\t\t'INVALID',\n\t\t\t`The database is at schema version ${found}, newer than this store's ${LAYOUT}`,\n\t\t);\n\t}\n}\n",
9
- "import {\n\tapplyAttempt,\n\tcheckClaim,\n\tcheckList,\n\tcheckMaxItems,\n\tcheckNewItem,\n\tcheckOwner,\n\tcheckResult,\n\tcheckTime,\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 Keys } from './connect';\nimport { addArgs, fieldsOf, isId, itemOf, outcomeOf, time } from './items';\nimport type { RedisQueueClient, RedisQueueStoreOptions } from './options';\nimport { checkLayout, run } from './run';\nimport {\n\tADD,\n\tCANCEL,\n\tCLAIM,\n\tCOMPLETE,\n\tLIST,\n\tRENEW,\n\tRESCHEDULE,\n\ttype Script,\n} from './scripts';\n\n/**\n * A `QueueStore` on Redis through Bun's own `Bun.RedisClient`: several\n * instances, on one machine or many, share one queue. Every operation\n * that writes is one Lua script, which Redis runs whole, so two\n * instances never take the same item. The due items are in sorted sets,\n * each item a hash, its message a string written byte for byte. One\n * Redis, or a primary with replicas — not Redis Cluster.\n */\nexport class RedisQueueStore implements QueueStore {\n\treadonly #client: RedisQueueClient;\n\treadonly #owned: boolean;\n\treadonly #keys: Keys;\n\treadonly #password: string;\n\t#ready: Promise<void> | undefined;\n\t#closed = false;\n\n\tprivate constructor({ client, owned, keys, password }: Connection) {\n\t\tthis.#client = client;\n\t\tthis.#owned = owned;\n\t\tthis.#keys = keys;\n\t\tthis.#password = password;\n\t}\n\n\t/** Checks the options; connects to nothing until the first call. What is wrong is `INVALID`. */\n\tstatic open(options: RedisQueueStoreOptions): RedisQueueStore {\n\t\treturn new RedisQueueStore(connect(options));\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/**\n\t * Reads the layout version, writing it on a new queue; once per\n\t * store. A failure is `INVALID`, and the next call tries again.\n\t */\n\t#setUp(): Promise<void> {\n\t\tthis.#ready ??= checkLayout(this.#client, this.#keys).catch((error) => {\n\t\t\tthis.#ready = undefined;\n\t\t\tif (error instanceof QueueError) throw error;\n\t\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new QueueError(\n\t\t\t\t'INVALID',\n\t\t\t\t`The Redis queue cannot be set up: ${masked(reason, this.#password)}`,\n\t\t\t);\n\t\t});\n\t\treturn this.#ready;\n\t}\n\n\t/** The client, once the layout is checked; `CLOSED` after `close()`. */\n\tasync #redis(): Promise<RedisQueueClient> {\n\t\tif (this.#closed) throw closed();\n\t\tawait this.#setUp();\n\t\treturn this.#client;\n\t}\n\n\tasync #run(script: Script, keys: string[], args: (string | Uint8Array)[]) {\n\t\tconst client = await this.#redis();\n\t\treturn run(client, script, keys, [this.#keys.prefix, ...args]);\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 k = this.#keys;\n\t\tconst reply = (await this.#run(\n\t\t\tADD,\n\t\t\t[k.items, k.ready, k.seq],\n\t\t\taddArgs(added, item.message, max),\n\t\t)) as string[];\n\t\tif (reply[0] === 'full') {\n\t\t\tthrow new QueueError(\n\t\t\t\t'QUEUE_FULL',\n\t\t\t\t`The queue holds ${reply[1]} items, its limit`,\n\t\t\t);\n\t\t}\n\t\treturn added;\n\t}\n\n\tasync get(id: string): Promise<QueueItem | undefined> {\n\t\tif (!isId(id)) return undefined;\n\t\tconst client = await this.#redis();\n\t\tconst fields = fieldsOf(\n\t\t\tawait client.send('HGETALL', [`${this.#keys.prefix}item:${id}`]),\n\t\t);\n\t\treturn fields ? itemOf(fields) : undefined;\n\t}\n\n\tasync list(options?: QueueListOptions): Promise<QueueItem[]> {\n\t\tconst { offset, limit } = checkList(options);\n\t\tconst pages = (await this.#run(\n\t\t\tLIST,\n\t\t\t[this.#keys.items],\n\t\t\t[`${offset}`, `${offset + limit - 1}`],\n\t\t)) as unknown[];\n\t\treturn pages.flatMap((reply) => {\n\t\t\tconst fields = fieldsOf(reply);\n\t\t\treturn fields ? [itemOf(fields)] : [];\n\t\t});\n\t}\n\n\tasync count(): Promise<number> {\n\t\tconst client = await this.#redis();\n\t\treturn Number(await client.send('ZCARD', [this.#keys.items]));\n\t}\n\n\tasync readMessage(id: string): Promise<Uint8Array | undefined> {\n\t\tif (!isId(id)) return undefined;\n\t\tconst client = await this.#redis();\n\t\tconst bytes = await client.getBuffer(`${this.#keys.prefix}message:${id}`);\n\t\treturn bytes === null ? undefined : new Uint8Array(bytes);\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 k = this.#keys;\n\t\tconst fields = fieldsOf(\n\t\t\tawait this.#run(\n\t\t\t\tCLAIM,\n\t\t\t\t[k.ready, k.leases, k.items],\n\t\t\t\t[owner, time(now), time(now + leaseMs)],\n\t\t\t),\n\t\t);\n\t\treturn fields ? itemOf(fields) : 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 (!isId(id)) return false;\n\t\tconst k = this.#keys;\n\t\tconst done = await this.#run(\n\t\t\tRENEW,\n\t\t\t[k.leases],\n\t\t\t[id, owner, time(expiresAt)],\n\t\t);\n\t\treturn Number(done) === 1;\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 (!isId(id)) return undefined;\n\t\tconst k = this.#keys;\n\t\tconst client = await this.#redis();\n\t\tfor (let read = 0; read < MAX_READS; read++) {\n\t\t\tconst fields = fieldsOf(\n\t\t\t\tawait client.send('HGETALL', [`${k.prefix}item:${id}`]),\n\t\t\t);\n\t\t\tif (!fields || fields['owner'] !== owner) return undefined;\n\t\t\tconst rev = fields['rev']; // none: damaged by hand, nothing recorded\n\t\t\tif (rev === undefined) return undefined;\n\t\t\tconst item = applyAttempt(itemOf(fields), result);\n\t\t\tconst done = Number(\n\t\t\t\tawait this.#run(\n\t\t\t\t\tCOMPLETE,\n\t\t\t\t\t[k.items, k.ready, k.leases],\n\t\t\t\t\t[id, owner, rev, ...outcomeOf(item)],\n\t\t\t\t),\n\t\t\t);\n\t\t\tif (done === 1) return item;\n\t\t\tif (done === 0) return undefined;\n\t\t}\n\t\treturn undefined; // outrun MAX_READS times: told as a lease lost\n\t}\n\n\tasync reschedule(id: string, at: number, owner?: string): Promise<boolean> {\n\t\tcheckTime('at', at);\n\t\t// As PostgreSQL: an id no store could hold is unknown before the owner is checked.\n\t\tif (!isStorable(id)) return false;\n\t\tif (owner !== undefined) checkOwner(owner);\n\t\tif (!isId(id)) return false;\n\t\tconst k = this.#keys;\n\t\tconst done = await this.#run(\n\t\t\tRESCHEDULE,\n\t\t\t[k.items, k.ready, k.leases],\n\t\t\t[id, time(at), owner ?? ''],\n\t\t);\n\t\treturn Number(done) === 1;\n\t}\n\n\tasync cancel(id: string): Promise<QueueItem | undefined> {\n\t\tif (!isId(id)) return undefined;\n\t\tconst k = this.#keys;\n\t\tconst fields = fieldsOf(\n\t\t\tawait this.#run(CANCEL, [k.items, k.ready, k.leases], [id]),\n\t\t);\n\t\treturn fields ? itemOf(fields) : undefined;\n\t}\n}\n\n/** How often `complete` reads an item, another outcome recorded since each read. */\nconst MAX_READS = 8;\n\nconst closed = () => new QueueError('CLOSED', 'The queue store is closed');\n"
8
+ "import { applyAttempt, checkComplete, newItem } from '../contract/checks';\nimport type {\n\tAttemptResult,\n\tCompleted,\n\tNewQueueItem,\n\tQueueItem,\n} from '../contract/types';\nimport type { Keys } from './connect';\nimport { addArgs, fieldsOf, isId, itemOf, outcomeOf } from './items';\nimport type { RedisQueueClient } from './options';\nimport { run } from './run';\nimport { COMPLETE } from './scripts';\n\n/** How often `complete` reads an item, another outcome recorded since each read. */\nconst MAX_READS = 8;\n\n/**\n * `QueueStore.complete` on Redis: the outcome, the lease let go of and\n * the DSN items added by one `COMPLETE` script. Redis cannot roll back,\n * so every check (the DSNs, the result, the owner) is done here, before\n * the script; the DSN ids are made once, whatever the number of reads.\n */\nexport async function complete(\n\tconnected: () => Promise<RedisQueueClient>,\n\tk: Keys,\n\tid: string,\n\towner: string,\n\tresult: AttemptResult,\n\tdsns: readonly NewQueueItem[],\n): Promise<Completed | undefined> {\n\tcheckComplete(owner, result, dsns);\n\tif (!isId(id)) return undefined;\n\tconst client = await connected();\n\tconst added: QueueItem[] = [];\n\tconst args: (string | Uint8Array)[] = [`${dsns.length}`];\n\tfor (const dsn of dsns) {\n\t\tconst made = newItem(crypto.randomUUID(), dsn);\n\t\tadded.push(made);\n\t\targs.push(...addArgs(made, dsn.message, undefined));\n\t}\n\tfor (let read = 0; read < MAX_READS; read++) {\n\t\tconst fields = fieldsOf(\n\t\t\tawait client.send('HGETALL', [`${k.prefix}item:${id}`]),\n\t\t);\n\t\tif (!fields || fields['owner'] !== owner) return undefined;\n\t\tconst rev = fields['rev']; // none: damaged by hand, nothing recorded\n\t\tif (rev === undefined) return undefined;\n\t\tconst item = applyAttempt(itemOf(fields), result);\n\t\tconst done = Number(\n\t\t\tawait run(\n\t\t\t\tclient,\n\t\t\t\tCOMPLETE,\n\t\t\t\t[k.items, k.ready, k.leases, k.seq],\n\t\t\t\t[k.prefix, id, owner, rev, ...outcomeOf(item), ...args],\n\t\t\t),\n\t\t);\n\t\tif (done === 1) return { item, dsns: added };\n\t\tif (done === 0) return undefined;\n\t}\n\treturn undefined; // outrun MAX_READS times: told as a lease lost\n}\n",
9
+ "import { invalid } from '../errors';\nimport { masked } from '../masked';\nimport type { RedisQueueClient, RedisQueueStoreOptions } from './options';\n\n/** The keys of one queue, each its prefix and a fixed name. */\nexport interface Keys {\n\treadonly prefix: string;\n\t/** Every item, scored by its next attempt: `list` and `count`. */\n\treadonly items: string;\n\t/** The items no lease holds, scored by their next attempt: what a claim takes first. */\n\treadonly ready: string;\n\t/** The leased items, scored by when their leases expire. */\n\treadonly leases: string;\n\t/** The counter that orders items equally due. */\n\treadonly seq: string;\n\t/** The layout version. */\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: RedisQueueClient;\n\treadonly owned: boolean;\n\treadonly keys: Keys;\n\t/** The URL's password, so an error that repeats it is masked; `''` for a given client. */\n\treadonly password: string;\n}\n\nconst DEFAULT_PREFIX = 'bumail:queue:';\n\n/**\n * Nothing Redis reads specially: no `{`, so no Cluster hash tag; no `*`,\n * `?`, `[` or `\\`, so a `SCAN MATCH` on the prefix matches its keys only;\n * no space or control character.\n */\nconst PREFIX = /^[a-z][a-z0-9_:.-]{0,39}$/;\n\nexport function keysOf(value: unknown): Keys {\n\tconst prefix = value ?? DEFAULT_PREFIX;\n\tif (typeof prefix !== 'string' || !PREFIX.test(prefix)) {\n\t\tthrow invalid(\n\t\t\t`keyPrefix must be lowercase letters, digits, '_', ':', '.' and '-', starting with a letter, 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\tready: `${prefix}ready`,\n\t\tleases: `${prefix}leases`,\n\t\tseq: `${prefix}seq`,\n\t\tschema: `${prefix}schema`,\n\t};\n}\n\nconst NEEDS =\n\t'A Redis queue store needs client, a Bun.RedisClient, or url, a redis:// URL';\n\n/** The schemes `Bun.RedisClient` takes. */\nconst SCHEMES = [\n\t'redis:',\n\t'rediss:',\n\t'valkey:',\n\t'valkeys:',\n\t'redis+tls:',\n\t'redis+unix:',\n\t'redis+tls+unix:',\n];\n\n/** A Redis URL; never echoed, since it may hold a password. */\nfunction urlOf(value: unknown): URL {\n\tif (typeof value !== 'string' && !(value instanceof URL))\n\t\tthrow invalid(NEEDS);\n\tconst url = URL.parse(String(value));\n\tif (url === null || !SCHEMES.includes(url.protocol)) throw invalid(NEEDS);\n\treturn url;\n}\n\n/**\n * A client of the store's own for the URL. `Bun.RedisClient` refuses\n * some URLs at once (a database that is not a number): that is\n * `INVALID`, its reason kept and the password, should it be repeated,\n * masked.\n */\nfunction clientFor(url: URL): RedisQueueClient {\n\ttry {\n\t\treturn new Bun.RedisClient(url.href) as unknown as RedisQueueClient;\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 url cannot be opened: ${masked(reason, url.password)}`,\n\t\t);\n\t}\n}\n\nconst isClient = (value: unknown): value is RedisQueueClient =>\n\ttypeof value === 'object' &&\n\tvalue !== null &&\n\ttypeof (value as RedisQueueClient).send === 'function' &&\n\ttypeof (value as RedisQueueClient).getBuffer === 'function' &&\n\ttypeof (value as RedisQueueClient).close === 'function';\n\n/** Checks the options and opens a client for a URL; connects to nothing yet. */\nexport function connect(options: RedisQueueStoreOptions): Connection {\n\tif (typeof options !== 'object' || options === null) throw invalid(NEEDS);\n\tconst keys = keysOf(options.keyPrefix);\n\tconst { client, url } = options;\n\tif (client !== undefined && url !== undefined) {\n\t\tthrow invalid('A Redis queue store takes client or url, not both');\n\t}\n\tif (client !== undefined) {\n\t\tif (!isClient(client)) throw invalid(NEEDS);\n\t\treturn { client, owned: false, keys, password: '' };\n\t}\n\tconst parsed = urlOf(url);\n\treturn {\n\t\tclient: clientFor(parsed),\n\t\towned: true,\n\t\tkeys,\n\t\tpassword: parsed.password,\n\t};\n}\n",
10
+ "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 } from './complete';\nimport { type Connection, connect, type Keys } from './connect';\nimport { addArgs, fieldsOf, isId, itemOf, time } from './items';\nimport type { RedisQueueClient, RedisQueueStoreOptions } from './options';\nimport { checkLayout, run } from './run';\nimport {\n\tADD,\n\tCANCEL,\n\tCLAIM,\n\tLIST,\n\tRENEW,\n\tRESCHEDULE,\n\ttype Script,\n} from './scripts';\n\n/**\n * A `QueueStore` on Redis through Bun's own `Bun.RedisClient`: several\n * instances, on one machine or many, share one queue. Every operation\n * that writes is one Lua script, which Redis runs whole, so two\n * instances never take the same item. The due items are in sorted sets,\n * each item a hash, its message a string written byte for byte. One\n * Redis, or a primary with replicas — not Redis Cluster.\n */\nexport class RedisQueueStore implements QueueStore {\n\treadonly #client: RedisQueueClient;\n\treadonly #owned: boolean;\n\treadonly #keys: Keys;\n\treadonly #password: string;\n\t#ready: Promise<void> | undefined;\n\t#closed = false;\n\n\tprivate constructor({ client, owned, keys, password }: Connection) {\n\t\tthis.#client = client;\n\t\tthis.#owned = owned;\n\t\tthis.#keys = keys;\n\t\tthis.#password = password;\n\t}\n\n\t/** Checks the options; connects to nothing until the first call. What is wrong is `INVALID`. */\n\tstatic open(options: RedisQueueStoreOptions): RedisQueueStore {\n\t\treturn new RedisQueueStore(connect(options));\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/**\n\t * Reads the layout version, writing it on a new queue; once per\n\t * store. A failure is `INVALID`, and the next call tries again.\n\t */\n\t#setUp(): Promise<void> {\n\t\tthis.#ready ??= checkLayout(this.#client, this.#keys).catch((error) => {\n\t\t\tthis.#ready = undefined;\n\t\t\tif (error instanceof QueueError) throw error;\n\t\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new QueueError(\n\t\t\t\t'INVALID',\n\t\t\t\t`The Redis queue cannot be set up: ${masked(reason, this.#password)}`,\n\t\t\t);\n\t\t});\n\t\treturn this.#ready;\n\t}\n\n\t/** The client, once the layout is checked; `CLOSED` after `close()`. */\n\tasync #redis(): Promise<RedisQueueClient> {\n\t\tif (this.#closed) throw closed();\n\t\tawait this.#setUp();\n\t\treturn this.#client;\n\t}\n\n\tasync #run(script: Script, keys: string[], args: (string | Uint8Array)[]) {\n\t\tconst client = await this.#redis();\n\t\treturn run(client, script, keys, [this.#keys.prefix, ...args]);\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 k = this.#keys;\n\t\tconst reply = (await this.#run(\n\t\t\tADD,\n\t\t\t[k.items, k.ready, k.seq],\n\t\t\taddArgs(added, item.message, max),\n\t\t)) as string[];\n\t\tif (reply[0] === 'full') {\n\t\t\tthrow new QueueError(\n\t\t\t\t'QUEUE_FULL',\n\t\t\t\t`The queue holds ${reply[1]} items, its limit`,\n\t\t\t);\n\t\t}\n\t\treturn added;\n\t}\n\n\tasync get(id: string): Promise<QueueItem | undefined> {\n\t\tif (!isId(id)) return undefined;\n\t\tconst client = await this.#redis();\n\t\tconst fields = fieldsOf(\n\t\t\tawait client.send('HGETALL', [`${this.#keys.prefix}item:${id}`]),\n\t\t);\n\t\treturn fields ? itemOf(fields) : undefined;\n\t}\n\n\tasync list(options?: QueueListOptions): Promise<QueueItem[]> {\n\t\tconst { offset, limit } = checkList(options);\n\t\tconst pages = (await this.#run(\n\t\t\tLIST,\n\t\t\t[this.#keys.items],\n\t\t\t[`${offset}`, `${offset + limit - 1}`],\n\t\t)) as unknown[];\n\t\treturn pages.flatMap((reply) => {\n\t\t\tconst fields = fieldsOf(reply);\n\t\t\treturn fields ? [itemOf(fields)] : [];\n\t\t});\n\t}\n\n\tasync count(): Promise<number> {\n\t\tconst client = await this.#redis();\n\t\treturn Number(await client.send('ZCARD', [this.#keys.items]));\n\t}\n\n\tasync readMessage(id: string): Promise<Uint8Array | undefined> {\n\t\tif (!isId(id)) return undefined;\n\t\tconst client = await this.#redis();\n\t\tconst bytes = await client.getBuffer(`${this.#keys.prefix}message:${id}`);\n\t\treturn bytes === null ? undefined : new Uint8Array(bytes);\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 k = this.#keys;\n\t\tconst fields = fieldsOf(\n\t\t\tawait this.#run(\n\t\t\t\tCLAIM,\n\t\t\t\t[k.ready, k.leases, k.items],\n\t\t\t\t[owner, time(now), time(now + leaseMs)],\n\t\t\t),\n\t\t);\n\t\treturn fields ? itemOf(fields) : 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 (!isId(id)) return false;\n\t\tconst k = this.#keys;\n\t\tconst done = await this.#run(\n\t\t\tRENEW,\n\t\t\t[k.leases],\n\t\t\t[id, owner, time(expiresAt)],\n\t\t);\n\t\treturn Number(done) === 1;\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.#redis(), this.#keys, 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\t// As PostgreSQL: an id no store could hold is unknown before the owner is checked.\n\t\tif (!isStorable(id)) return false;\n\t\tif (owner !== undefined) checkOwner(owner);\n\t\tif (!isId(id)) return false;\n\t\tconst k = this.#keys;\n\t\tconst done = await this.#run(\n\t\t\tRESCHEDULE,\n\t\t\t[k.items, k.ready, k.leases],\n\t\t\t[id, time(at), owner ?? ''],\n\t\t);\n\t\treturn Number(done) === 1;\n\t}\n\n\tasync cancel(id: string): Promise<QueueItem | undefined> {\n\t\tif (!isId(id)) return undefined;\n\t\tconst k = this.#keys;\n\t\tconst fields = fieldsOf(\n\t\t\tawait this.#run(CANCEL, [k.items, k.ready, k.leases], [id]),\n\t\t);\n\t\treturn fields ? itemOf(fields) : 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": "709817593E83454864756E2164756E21",
12
+ "mappings": "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",
13
+ "debugId": "D8069639A7F10A3F64756E2164756E21",
13
14
  "names": []
14
15
  }
@@ -40,11 +40,14 @@ export declare const CLAIM: Script;
40
40
  /** KEYS leases; ARGV prefix, id, owner, expiry. 1 while the owner holds the lease, else 0. */
41
41
  export declare const RENEW: Script;
42
42
  /**
43
- * KEYS items, ready, leases; ARGV prefix, id, owner, rev, then 'drop',
44
- * or 'record' and recipients, next, attempts, delay. 0 when the owner
45
- * does not hold the lease; -1 when another outcome was recorded since
46
- * the item was read at `rev`, to read it again; 1 once recorded, the
47
- * lease let go of, or the item and its message dropped.
43
+ * KEYS items, ready, leases, seq; ARGV prefix, id, owner, rev, then
44
+ * 'drop', or 'record' and recipients, next, attempts, delay; then the
45
+ * number of DSN items and, for each, the arguments of `ADD` (its `max`
46
+ * left empty: a DSN ignores the limit). 0 when the owner does not hold
47
+ * the lease; -1 when another outcome was recorded since the item was
48
+ * read at `rev`, to read it again, with nothing written; 1 once the
49
+ * outcome is recorded, the lease let go of (or the item and its message
50
+ * dropped) and the DSN items added, all in this one call.
48
51
  */
49
52
  export declare const COMPLETE: Script;
50
53
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"scripts.d.ts","sourceRoot":"","sources":["../../src/redis/scripts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAuBH,qDAAqD;AACrD,MAAM,WAAW,MAAM;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACrB;AAQD;;;GAGG;AACH,eAAO,MAAM,MAAM,QAKjB,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,GAAG,QAgBd,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,KAAK,QAyBhB,CAAC;AAEH,8FAA8F;AAC9F,eAAO,MAAM,KAAK,QAMhB,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,QAmBnB,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,UAAU,QAerB,CAAC;AAEH,qHAAqH;AACrH,eAAO,MAAM,MAAM,QAUjB,CAAC;AAEH,2FAA2F;AAC3F,eAAO,MAAM,IAAI,QAMf,CAAC"}
1
+ {"version":3,"file":"scripts.d.ts","sourceRoot":"","sources":["../../src/redis/scripts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAuBH,qDAAqD;AACrD,MAAM,WAAW,MAAM;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACrB;AAQD;;;GAGG;AACH,eAAO,MAAM,MAAM,QAKjB,CAAC;AAuBH;;;;GAIG;AACH,eAAO,MAAM,GAAG,QAQd,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,KAAK,QAyBhB,CAAC;AAEH,8FAA8F;AAC9F,eAAO,MAAM,KAAK,QAMhB,CAAC;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,QAAQ,QA0BnB,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,UAAU,QAerB,CAAC;AAEH,qHAAqH;AACrH,eAAO,MAAM,MAAM,QAUjB,CAAC;AAEH,2FAA2F;AAC3F,eAAO,MAAM,IAAI,QAMf,CAAC"}
@@ -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 { RedisQueueStoreOptions } from './options';
4
4
  /**
5
5
  * A `QueueStore` on Redis through Bun's own `Bun.RedisClient`: several
@@ -23,7 +23,7 @@ export declare class RedisQueueStore implements QueueStore {
23
23
  readMessage(id: string): Promise<Uint8Array | undefined>;
24
24
  claim(request: ClaimRequest): Promise<QueueItem | undefined>;
25
25
  renew(id: string, owner: string, expiresAt: number): Promise<boolean>;
26
- complete(id: string, owner: string, result: AttemptResult): Promise<QueueItem | undefined>;
26
+ complete(id: string, owner: string, result: AttemptResult, dsns: readonly NewQueueItem[]): Promise<Completed | undefined>;
27
27
  reschedule(id: string, at: number, owner?: string): Promise<boolean>;
28
28
  cancel(id: string): Promise<QueueItem | undefined>;
29
29
  }
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/redis/store.ts"],"names":[],"mappings":"AAWA,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,EAAoB,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAa1E;;;;;;;GAOG;AACH,qBAAa,eAAgB,YAAW,UAAU;;IAQjD,OAAO;IAOP,gGAAgG;IAChG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe;IAI7D,mGAAmG;IAC7F,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmCtB,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,SAAS,CAAC;IAmBrE,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAS/C,IAAI,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAatD,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAKxB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAOxD,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAc5D,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAarE,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;IAepE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;CAQxD"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/redis/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,EAAoB,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAY1E;;;;;;;GAOG;AACH,qBAAa,eAAgB,YAAW,UAAU;;IAQjD,OAAO;IAOP,gGAAgG;IAChG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe;IAI7D,mGAAmG;IAC7F,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmCtB,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,SAAS,CAAC;IAmBrE,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAS/C,IAAI,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAatD,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAKxB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAOxD,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAc5D,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAarE,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;IAepE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;CAQxD"}
@@ -6,15 +6,32 @@ import {
6
6
  QueueError2,
7
7
  checkTime,
8
8
  checkOwner,
9
+ checkComplete,
9
10
  checkNewItem,
10
11
  checkMaxItems,
11
12
  checkClaim,
12
- checkResult,
13
13
  checkList,
14
14
  isDone,
15
15
  applyAttempt,
16
16
  newItem
17
- } from "../chunks/index-sz13a17b.js";
17
+ } from "../chunks/index-t6q7zxgj.js";
18
+
19
+ // src/sqlite/insert.ts
20
+ function insertItem(db, added, message) {
21
+ db.query(`INSERT INTO items (id, sender, recipients, size, created_at,
22
+ next_attempt_at, attempts, delay_notified, dsn)
23
+ VALUES ($id, $sender, $recipients, $size, $created_at,
24
+ $next_attempt_at, 0, 0, $dsn)`).run({
25
+ id: added.id,
26
+ sender: added.from,
27
+ recipients: JSON.stringify(added.recipients),
28
+ size: added.size,
29
+ created_at: added.createdAt,
30
+ next_attempt_at: added.nextAttemptAt,
31
+ dsn: dsnColumn(added)
32
+ });
33
+ db.query("INSERT INTO messages (item_id, content) VALUES (?, ?)").run(added.id, message);
34
+ }
18
35
 
19
36
  // src/sqlite/open.ts
20
37
  import { Database } from "bun:sqlite";
@@ -195,19 +212,7 @@ class SqliteQueueStore {
195
212
  throw new QueueError2("QUEUE_FULL", `The queue holds ${n} items, its limit`);
196
213
  }
197
214
  }
198
- db.query(`INSERT INTO items (id, sender, recipients, size, created_at,
199
- next_attempt_at, attempts, delay_notified, dsn)
200
- VALUES ($id, $sender, $recipients, $size, $created_at,
201
- $next_attempt_at, 0, 0, $dsn)`).run({
202
- id: added.id,
203
- sender: added.from,
204
- recipients: JSON.stringify(added.recipients),
205
- size: added.size,
206
- created_at: added.createdAt,
207
- next_attempt_at: added.nextAttemptAt,
208
- dsn: dsnColumn(added)
209
- });
210
- db.query("INSERT INTO messages (item_id, content) VALUES (?, ?)").run(added.id, item.message);
215
+ insertItem(db, added, item.message);
211
216
  }).immediate();
212
217
  return added;
213
218
  }
@@ -246,9 +251,8 @@ class SqliteQueueStore {
246
251
  const { changes } = this.#open.query("UPDATE items SET lease_expires_at = ? WHERE id = ? AND lease_owner = ?").run(expiresAt, id, owner);
247
252
  return changes > 0;
248
253
  }
249
- async complete(id, owner, result) {
250
- checkOwner(owner);
251
- checkResult(result);
254
+ async complete(id, owner, result, dsns) {
255
+ checkComplete(owner, result, dsns);
252
256
  const db = this.#open;
253
257
  return db.transaction(() => {
254
258
  const row = this.#row(id, owner);
@@ -260,7 +264,12 @@ class SqliteQueueStore {
260
264
  } else {
261
265
  this.#write(item);
262
266
  }
263
- return item;
267
+ const added = dsns.map((dsn) => {
268
+ const stored = newItem(crypto.randomUUID(), dsn);
269
+ insertItem(db, stored, dsn.message);
270
+ return stored;
271
+ });
272
+ return { item, dsns: added };
264
273
  }).immediate();
265
274
  }
266
275
  async reschedule(id, at, owner) {
@@ -289,5 +298,5 @@ export {
289
298
  SqliteQueueStore
290
299
  };
291
300
 
292
- //# debugId=92D7A7C42951038864756E2164756E21
301
+ //# debugId=69534685BB7970EA64756E2164756E21
293
302
  //# sourceMappingURL=index.js.map