lonnymq 0.0.19 → 0.0.20

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.
package/README.md CHANGED
@@ -5,12 +5,11 @@ A high-performance, multi-tenant PostgreSQL message queue implementation for Nod
5
5
  ## Features
6
6
 
7
7
  - High throughput message processing
8
- - Multi-tenant concurrency and capacity constraints
8
+ - Multi-tenant concurrency and rate limits
9
9
  - Durable message processing with automatic recovery
10
10
  - Flexible message processing retries and deferrals
11
- - Message deduplication
12
11
  - Queue operations as part of *existing* database transactions
13
- - Database client agnostic
12
+ - Database client agnostic with optional adapters
14
13
  - Granular events via PostgreSQL `NOTIFY`
15
14
  - Zero dependencies
16
15
 
@@ -34,22 +33,18 @@ for (const migration of queue.migrations()) {
34
33
 
35
34
  // Create messages
36
35
  for (let ix = 0; ix < 500; ix += 1) {
37
- await queue
38
- .channel("myChannel")
39
- .message
40
- .create({
41
- content: Buffer.from("Hello"),
42
- databaseClient,
43
- })
36
+ await queue.message.create({
37
+ databaseClient,
38
+ content: Buffer.from("Hello"),
39
+ lockMs: 30_000
40
+ })
44
41
  }
45
42
 
46
43
  // Process messages
47
44
  while (true) {
48
45
  const dequeueResult = await queue.dequeue({ databaseClient })
49
46
  if (dequeueResult.resultType === "MESSAGE_NOT_AVAILABLE") {
50
- const sleepMs = Math.min(1000, dequeueResult.retryMs ?? 5000)
51
- await new Promise(resolve => setTimeout(resolve, sleepMs))
52
- continue
47
+ break
53
48
  }
54
49
 
55
50
  console.log(dequeueResult.message.content.toString())
@@ -90,7 +85,7 @@ try {
90
85
 
91
86
  Channels provide LonnyMQ's multi-tenancy support. They can be considered lightweight sub-queues that are read from in round-robin fashion. There is no performance penalty for using large numbers of channels, so they can be assigned on a highly granular basis (e.g., per-user) to ensure work is scheduled fairly.
92
87
 
93
- Channels can be configured with concurrency, capacity, and rate limits by setting their "channel policy":
88
+ Channels can be configured with concurrency and rate limits by setting their "channel policy":
94
89
 
95
90
  ```typescript
96
91
  await queue
@@ -99,7 +94,6 @@ await queue
99
94
  .set({
100
95
  databaseClient,
101
96
  maxConcurrency: 1,
102
- maxSize: 100,
103
97
  releaseIntervalMs: 1000
104
98
  })
105
99
 
@@ -112,7 +106,18 @@ await queue
112
106
 
113
107
  ## Message Creation
114
108
 
115
- You can add a message to the queue and assign it to a particular channel using the `create` function:
109
+ You can add a message to the queue using the `create` function. By default, messages are assigned to a random channel, ensuring fair distribution:
110
+
111
+ ```typescript
112
+ await queue.message.create({
113
+ databaseClient,
114
+ content: Buffer.from("Hello, world"),
115
+ lockMs: 30000,
116
+ delayMs: 5000
117
+ })
118
+ ```
119
+
120
+ If you need to assign messages to specific channels (for example, to take advantage of concurrency or rate limiting features), you can specify the channel explicitly:
116
121
 
117
122
  ```typescript
118
123
  await queue
@@ -121,25 +126,27 @@ await queue
121
126
  .create({
122
127
  databaseClient,
123
128
  content: Buffer.from("Hello, world"),
124
- name: "optional-dedup-key",
125
- lockMs: 30000, // 30 seconds
126
- delayMs: 5000 // 5 second delay
129
+ lockMs: 30000,
130
+ delayMs: 5000
127
131
  })
128
132
  ```
129
133
 
130
- The `name` argument can be provided for deduplication purposes: if a message that has *never* been dequeued exists with the same name within the same channel, no new message will be created.
134
+ The `lockMs` parameter is required and specifies how long a message will remain exclusively locked after being dequeued. While locked, the message is **not available** for subsequent `dequeue()` calls, preventing duplicate processing. If your process crashes or takes longer than expected, the message will automatically become available for dequeue again after the lock expires.
135
+
136
+ The `delayMs` parameter is optional and allows you to delay when the message becomes available for processing.
131
137
 
132
138
  ## Message Processing
133
139
 
134
140
  Messages can be fetched for processing by calling `dequeue` on the `Queue` - this locks the message. Once processing is complete, messages must be "finalized" via **deletion** or **deferral** (for further processing in the future).
135
141
 
136
142
  ```typescript
143
+ const dequeueResult = await queue.dequeue({ databaseClient })
137
144
 
138
145
  if (dequeueResult.resultType === "MESSAGE_DEQUEUED") {
139
146
  const { message } = dequeueResult
140
147
  console.log(`Processing message: ${message.id}`)
141
148
  console.log(`Content: ${message.content.toString()}`)
142
- console.log(`Attempts: ${message.numAttempts}`)
149
+ console.log(`State: ${message.state?.toString()}`)
143
150
 
144
151
  try {
145
152
  // Process the message...
@@ -148,18 +155,61 @@ if (dequeueResult.resultType === "MESSAGE_DEQUEUED") {
148
155
  // Delete on success
149
156
  await message.delete({ databaseClient })
150
157
  } catch (error) {
151
- // Defer for retry with updated state
152
- await message.defer({
153
- databaseClient,
154
- delayMs: 30000, // Retry in 30 seconds
155
- state: Buffer.from(JSON.stringify({ error: error.message }))
156
- })
158
+ if (message.numAttempts >= 5) {
159
+ // Too many retries, delete permanently
160
+ await message.delete({ databaseClient })
161
+ } else {
162
+ // Defer for retry with exponential backoff and updated state
163
+ const backoffMs = Math.pow(2, message.numAttempts) * 1000
164
+ await message.defer({
165
+ databaseClient,
166
+ delayMs: backoffMs,
167
+ state: Buffer.from(JSON.stringify({
168
+ error: error.message,
169
+ lastAttempt: new Date().toISOString()
170
+ }))
171
+ })
172
+ }
157
173
  }
174
+ } else {
175
+ console.log("No messages available")
158
176
  }
159
177
  ```
160
178
 
161
179
  When deferring a message, you can optionally specify `delayMs` and `state` arguments. The `delayMs` parameter tells the queue how long to wait before making the message available for reprocessing, and `state` allows you to "save your work" and implement durable and/or repeating/scheduled tasks.
162
180
 
181
+ **Note:** The above shows just one processing pattern (defer on failure with retry limits). You have complete flexibility in how you handle message processing - you might delete messages immediately, defer them unconditionally, implement different retry strategies based on error types, or use the message metadata (attempts, state, channel) to make sophisticated routing decisions.
182
+
183
+ ### Message Heartbeats
184
+
185
+ For long-running message processing, you can use the heartbeat functionality to extend the lock time beyond the initial `lockMs` value. This is useful when you need to process a message for longer than originally anticipated but want to keep a shorter default lock time for faster recovery.
186
+
187
+ ```typescript
188
+ const dequeueResult = await queue.dequeue({ databaseClient })
189
+
190
+ if (dequeueResult.resultType === "MESSAGE_DEQUEUED") {
191
+ const { message } = dequeueResult
192
+
193
+ // Start a long-running process
194
+ const intervalId = setInterval(async () => {
195
+ // Send heartbeat every 10 seconds to keep the message locked
196
+ await message.heartbeat({ databaseClient })
197
+ }, 10000)
198
+
199
+ try {
200
+ // Process the message (this might take a long time)
201
+ await longRunningProcessMessage(message.content)
202
+ await message.delete({ databaseClient })
203
+ } catch (error) {
204
+ await message.defer({ databaseClient, delayMs: 30000 })
205
+ } finally {
206
+ clearInterval(intervalId)
207
+ }
208
+ }
209
+ ```
210
+
211
+ Heartbeats reset the unlock time to the current time plus the original `lockMs` value.
212
+
163
213
  ### Graceful Shutdowns and Message Recovery
164
214
 
165
215
  If your program ends unexpectedly, messages that are currently being processed may become "orphaned" in a locked state - causing channel blockages and reducing throughput. To mitigate this problem, it's essential that you shut down gracefully by catching unhandled exceptions and signals (i.e., `SIGINT`/`SIGTERM`) and finalize all outstanding messages before exiting.
@@ -206,7 +256,7 @@ client.on("notification", (msg) => {
206
256
 
207
257
  ### Waiting for Job Completion
208
258
 
209
- The `MESSAGE_DELETED` event can be used to create coordination patterns where one part of your application waits for an unrelated job to complete. By listening for deletion events on specific channels or message names, you can implement blocking operations that wait for background work to finish.
259
+ The `MESSAGE_DELETED` event can be used to create coordination patterns where one part of your application waits for an unrelated job to complete. By listening for deletion events on specific message IDs, you can implement blocking operations that wait for background work to finish.
210
260
 
211
261
  ```typescript
212
262
  const client = await databaseClient.connect()
@@ -217,9 +267,7 @@ const wait = (messageId: string) : Promise<void> => {
217
267
  const handler = (msg) => {
218
268
  if (msg.channel === "EVENTS") {
219
269
  const event = queueEventDecode(msg.payload as string)
220
- if (event.eventType === "MESSAGE_DELETED" &&
221
- event.channelName === "background-jobs" &&
222
- event.messageName === messageId) {
270
+ if (event.eventType === "MESSAGE_DELETED" && event.id === messageId) {
223
271
  client.off("notification", handler)
224
272
  resolve()
225
273
  }
@@ -234,7 +282,7 @@ await wait(messageId)
234
282
 
235
283
  ## Deadlocks
236
284
 
237
- If all queue actions are isolated to their own transaction, there is zero risk of deadlocks occurring. That being said, it is *possible* to safely bulk-perform the following actions within a single transaction if we ensure they are performed in a consistent lexicographical ordering with respect to channel name and message name (if provided):
285
+ If all queue actions are isolated to their own transaction, there is zero risk of deadlocks occurring. That being said, it is *possible* to safely bulk-perform the following actions within a single transaction if we ensure they are performed in a consistent lexicographical ordering with respect to channel name:
238
286
 
239
287
  - Message create
240
288
  - Channel policy set
@@ -245,38 +293,43 @@ Beyond the actions specified above, it is manifestly **unsafe** to bulk-perform
245
293
  - Message dequeue
246
294
  - Message defer
247
295
  - Message delete
296
+ - Message heartbeat
248
297
 
249
298
  ## Batching Operations
250
299
 
251
300
  When you need to perform multiple safe operations (message creation and channel policy changes) within a single transaction, LonnyMQ provides a batching mechanism that automatically handles proper ordering to prevent deadlocks.
252
301
 
253
- The batch interface mirrors the main queue interface - you call `queue.batch()` to create a batch, then use the same `.channel(name).message.create()` and `.channel(name).policy.set/clear()` methods you're already familiar with. The key difference is that batch operations are queued up and don't execute immediately.
254
-
255
- The batch system ensures that all operations are executed in a consistent lexicographical order based on channel name and message name, eliminating the possibility of deadlocks when multiple workers are performing bulk operations simultaneously.
302
+ The batch interface mirrors a subset of the queue interface, supporting only the operations that are safe to perform together: message creation and channel policy management.
256
303
 
257
304
  ```typescript
258
305
  const batch = queue.batch()
259
306
 
260
- batch.channel("user-123").message.create({
261
- content: Buffer.from("Welcome email")
307
+ // Create messages (assigned to random channels)
308
+ batch.message.create({
309
+ content: Buffer.from("Welcome email"),
310
+ lockMs: 30000
262
311
  })
263
312
 
264
- batch.channel("user-123").policy.set({
265
- maxConcurrency: 5,
266
- maxSize: 1000,
267
- releaseIntervalMs: 100
313
+ // Create messages on specific channels
314
+ batch.channel("user-notifications").message.create({
315
+ content: Buffer.from("User signup notification"),
316
+ lockMs: 60000
268
317
  })
269
318
 
270
- batch.channel("notifications").message.create({
271
- content: Buffer.from("Daily digest"),
272
- name: "daily-digest-2025-08-29"
319
+ // Set channel policies
320
+ batch.channel("high-priority").policy.set({
321
+ maxConcurrency: 5,
322
+ releaseIntervalMs: 100
273
323
  })
274
324
 
325
+ // Clear channel policies
275
326
  batch.channel("analytics").policy.clear()
276
327
 
277
328
  await batch.execute({ databaseClient })
278
329
  ```
279
330
 
331
+ The batch system ensures all operations are executed in a consistent lexicographical order, eliminating the possibility of deadlocks when multiple workers are performing bulk operations simultaneously.
332
+
280
333
  ## Database Clients
281
334
 
282
335
  LonnyMQ is designed to be database client agnostic, requiring only a minimal interface that most PostgreSQL clients already implement. Your database client must provide a single `query` method with this signature:
@@ -287,4 +340,25 @@ interface DatabaseClient {
287
340
  rows: Array<Record<string, unknown>>
288
341
  }>
289
342
  }
343
+ ```
344
+
345
+ ### Database Client Adapters
346
+
347
+ For database clients that don't match the expected interface exactly, LonnyMQ provides an adapter system to improve the developer experience. You can provide an adapter function when creating a Queue:
348
+
349
+ ```typescript
350
+ import { Queue } from "lonnymq"
351
+ import { Pool } from "pg"
352
+
353
+ const customClient = new SomeOtherPostgresClient()
354
+ const queue = new Queue({
355
+ schema: "lonny",
356
+ adaptor: (client) => ({
357
+ query: async (sql, params) => {
358
+ // Adapt the client's interface to match DatabaseClient
359
+ const result = await client.executeQuery(sql, params)
360
+ return { rows: result.data }
361
+ }
362
+ })
363
+ })
290
364
  ```
package/dist/index.cjs CHANGED
@@ -1,14 +1,14 @@
1
- var{defineProperty:N,getOwnPropertyNames:Q,getOwnPropertyDescriptor:V}=Object,W=Object.prototype.hasOwnProperty;var C=new WeakMap,Y=(e)=>{var t=C.get(e),a;if(t)return t;if(t=N({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function")Q(e).map((r)=>!W.call(t,r)&&N(t,r,{get:()=>e[r],enumerable:!(a=V(e,r))||a.enumerable}));return C.set(e,t),t};var z=(e,t)=>{for(var a in t)N(e,a,{get:t[a],enumerable:!0,configurable:!0,set:(r)=>t[a]=()=>r})};var le={};z(le,{queueEventDecode:()=>O,Queue:()=>L,MessageHeartbeatCommand:()=>d,MessageDequeueCommand:()=>m,MessageDeleteCommand:()=>i,MessageDeferCommand:()=>u,MessageCreateCommand:()=>l,ChannelPolicySetCommand:()=>c,ChannelPolicyClearCommand:()=>o});module.exports=Y(le);var U=(e)=>{return e*1000};var T=U(0);var O=(e)=>{let t=JSON.parse(e);if(t.type===0)return{eventType:"MESSAGE_CREATED",id:t.id,delayMs:t.delay_ms};else if(t.type===1)return{eventType:"MESSAGE_DELETED",id:t.id};else if(t.type===2)return{eventType:"MESSAGE_DEFERRED",id:t.id,delayMs:t.delay_ms};else throw new Error("Unknown event type")};var _=(e)=>({nodeType:"VALUE",value:e}),s=(e)=>({nodeType:"REF",value:e}),X=(e)=>({nodeType:"RAW",value:e}),J=(e)=>{return`'${e.replace(/'/g,"''")}'`},K=(e)=>{if(e===null)return"NULL";else if(typeof e==="string")return J(e);else if(typeof e==="number")return e.toString();else if(typeof e==="boolean")return e?"TRUE":"FALSE";else if(e instanceof Date)return`'${e.toISOString()}'`;else if(typeof e==="bigint")return e.toString();else throw new Error(`Unsupported value type: ${typeof e}`)},j=(e)=>{return`"${e.replace(/"/g,'""')}"`},Z=(e)=>{if(e.nodeType==="VALUE")return K(e.value);else if(e.nodeType==="REF")return j(e.value);else if(e.nodeType==="RAW")return e.value;else throw new Error("Unsupported SQL node type")};var n=(e,...t)=>{let a=[];for(let r=0;r<e.length;r+=1)if(a.push(e[r]),r<t.length)a.push(Z(t[r]));return X(a.join(""))};class o{schema;channelName;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.createdAt=new Date}async execute(e){await e.query(n`
1
+ var{defineProperty:h,getOwnPropertyNames:z,getOwnPropertyDescriptor:J}=Object,X=Object.prototype.hasOwnProperty;var U=new WeakMap,K=(e)=>{var t=U.get(e),n;if(t)return t;if(t=h({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function")z(e).map((r)=>!X.call(t,r)&&h(t,r,{get:()=>e[r],enumerable:!(n=J(e,r))||n.enumerable}));return U.set(e,t),t};var j=(e,t)=>{for(var n in t)h(e,n,{get:t[n],enumerable:!0,configurable:!0,set:(r)=>t[n]=()=>r})};var de={};j(de,{queueEventDecode:()=>f,Queue:()=>C,MessageHeartbeatCommand:()=>d,MessageDequeueCommand:()=>m,MessageDeleteCommand:()=>i,MessageDeferCommand:()=>u,MessageCreateCommand:()=>o,ChannelPolicySetCommand:()=>l,ChannelPolicyClearCommand:()=>c});module.exports=K(de);var O=(e)=>{return e*1000};var T=O(0);var f=(e)=>{let t=JSON.parse(e);if(t.type===0)return{eventType:"MESSAGE_CREATED",id:t.id,delayMs:t.delay_ms};else if(t.type===1)return{eventType:"MESSAGE_DELETED",id:t.id};else if(t.type===2)return{eventType:"MESSAGE_DEFERRED",id:t.id,delayMs:t.delay_ms};else throw new Error("Unknown event type")};var _=(e)=>({nodeType:"VALUE",value:e}),s=(e)=>({nodeType:"REF",value:e}),Z=(e)=>({nodeType:"RAW",value:e}),ee=(e)=>{return`'${e.replace(/'/g,"''")}'`},te=(e)=>{if(e===null)return"NULL";else if(typeof e==="string")return ee(e);else if(typeof e==="number")return e.toString();else if(typeof e==="boolean")return e?"TRUE":"FALSE";else if(e instanceof Date)return`'${e.toISOString()}'`;else if(typeof e==="bigint")return e.toString();else throw new Error(`Unsupported value type: ${typeof e}`)},se=(e)=>{return`"${e.replace(/"/g,'""')}"`},ne=(e)=>{if(e.nodeType==="VALUE")return te(e.value);else if(e.nodeType==="REF")return se(e.value);else if(e.nodeType==="RAW")return e.value;else throw new Error("Unsupported SQL node type")};var a=(e,...t)=>{let n=[];for(let r=0;r<e.length;r+=1)if(n.push(e[r]),r<t.length)n.push(ne(t[r]));return Z(n.join(""))};class c{schema;channelName;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.createdAt=new Date}async execute(e){await e.query(a`
2
2
  SELECT 1 FROM ${s(this.schema)}."channel_policy_clear"(
3
3
  $1
4
4
  )
5
- `.value,[this.channelName])}}class c{schema;channelName;maxConcurrency;releaseIntervalMs;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName;let t=e.maxConcurrency??null;this.maxConcurrency=t!==null?Math.max(0,t):null;let a=e.releaseIntervalMs??null;this.releaseIntervalMs=a!==null?Math.max(0,a):null,this.createdAt=new Date}async execute(e){await e.query(n`
5
+ `.value,[this.channelName])}}class l{schema;channelName;maxConcurrency;releaseIntervalMs;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName;let t=e.maxConcurrency??null;this.maxConcurrency=t!==null?Math.max(0,t):null;let n=e.releaseIntervalMs??null;this.releaseIntervalMs=n!==null?Math.max(0,n):null,this.createdAt=new Date}async execute(e){await e.query(a`
6
6
  SELECT 1 FROM ${s(this.schema)}."channel_policy_set"(
7
7
  $1,
8
8
  $2::INTEGER,
9
9
  $3::INTEGER
10
10
  )
11
- `.value,[this.channelName,this.maxConcurrency,this.releaseIntervalMs])}}var f=require("node:crypto");class l{schema;channelName;content;lockMs;id;delayMs;createdAt;constructor(e){let t=Math.max(0,e.lockMs),a=e.delayMs===void 0?T:e.delayMs;this.id=f.randomUUID(),this.schema=e.schema,this.channelName=e.channelName,this.content=e.content,this.lockMs=t,this.delayMs=a,this.createdAt=new Date}async execute(e){await e.query(n`
11
+ `.value,[this.channelName,this.maxConcurrency,this.releaseIntervalMs])}}var F=require("crypto"),x=()=>{return F.randomBytes(16).toString("base64url")};var G=require("node:crypto");class o{schema;channelName;content;lockMs;id;delayMs;createdAt;constructor(e){let t=Math.max(0,e.lockMs),n=e.delayMs===void 0?T:e.delayMs;this.id=G.randomUUID(),this.schema=e.schema,this.channelName=e.channelName??x(),this.content=e.content,this.lockMs=t,this.delayMs=n,this.createdAt=new Date}async execute(e){await e.query(a`
12
12
  SELECT 1 FROM ${s(this.schema)}."message_create"(
13
13
  $1,
14
14
  $2,
@@ -16,33 +16,33 @@ var{defineProperty:N,getOwnPropertyNames:Q,getOwnPropertyDescriptor:V}=Object,W=
16
16
  $4::BIGINT,
17
17
  $5::BIGINT
18
18
  )
19
- `.value,[this.id,this.channelName,this.content,this.lockMs,this.delayMs])}}class m{schema;constructor(e){this.schema=e.schema}async execute(e){let t=await e.query(n`
19
+ `.value,[this.id,this.channelName,this.content,this.lockMs,this.delayMs])}}class m{schema;constructor(e){this.schema=e.schema}async execute(e){let t=await e.query(a`
20
20
  SELECT
21
21
  result_code,
22
22
  metadata,
23
23
  content,
24
24
  state
25
25
  FROM ${s(this.schema)}."message_dequeue"()
26
- `.value,[]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_AVAILABLE",retryMs:t.metadata.retry_ms};else if(t.result_code===1)return{resultType:"MESSAGE_DEQUEUED",message:{id:t.metadata.id,channelName:t.metadata.channel_name,isUnlocked:t.metadata.is_unlocked,content:t.content,state:t.state,numAttempts:t.metadata.num_attempts}};else throw new Error("Unexpected dequeue result")}}class i{schema;id;numAttempts;constructor(e){this.schema=e.schema,this.id=e.id,this.numAttempts=e.numAttempts}async execute(e){let t=await e.query(n`
26
+ `.value,[]).then((n)=>n.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_AVAILABLE",retryMs:t.metadata.retry_ms};else if(t.result_code===1)return{resultType:"MESSAGE_DEQUEUED",message:{id:t.metadata.id,channelName:t.metadata.channel_name,isUnlocked:t.metadata.is_unlocked,content:t.content,state:t.state,numAttempts:t.metadata.num_attempts}};else throw new Error("Unexpected dequeue result")}}class i{schema;id;numAttempts;constructor(e){this.schema=e.schema,this.id=e.id,this.numAttempts=e.numAttempts}async execute(e){let t=await e.query(a`
27
27
  SELECT * FROM ${s(this.schema)}."message_delete"(
28
28
  $1,
29
29
  $2::BIGINT
30
30
  )
31
- `.value,[this.id,this.numAttempts]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(t.result_code===1)return{resultType:"STATE_INVALID"};else if(t.result_code===2)return{resultType:"MESSAGE_DELETED"};else throw new Error("Unexpected result")}}class u{schema;id;numAttempts;delayMs;state;constructor(e){let t=e.delayMs===void 0?T:e.delayMs;this.schema=e.schema,this.numAttempts=e.numAttempts,this.id=e.id,this.delayMs=t,this.state=e.state??null}async execute(e){let t=await e.query(n`
31
+ `.value,[this.id,this.numAttempts]).then((n)=>n.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(t.result_code===1)return{resultType:"STATE_INVALID"};else if(t.result_code===2)return{resultType:"MESSAGE_DELETED"};else throw new Error("Unexpected result")}}class u{schema;id;numAttempts;delayMs;state;constructor(e){let t=e.delayMs===void 0?T:e.delayMs;this.schema=e.schema,this.numAttempts=e.numAttempts,this.id=e.id,this.delayMs=t,this.state=e.state??null}async execute(e){let t=await e.query(a`
32
32
  SELECT * FROM ${s(this.schema)}."message_defer"(
33
33
  $1,
34
34
  $2::BIGINT,
35
35
  $3::BIGINT,
36
36
  $4
37
37
  )
38
- `.value,[this.id,this.numAttempts,this.delayMs,this.state]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(t.result_code===1)return{resultType:"STATE_INVALID"};else if(t.result_code===2)return{resultType:"MESSAGE_DEFERRED"};else throw new Error("Unexpected result")}}class d{schema;id;numAttempts;constructor(e){this.schema=e.schema,this.numAttempts=e.numAttempts,this.id=e.id}async execute(e){let t=await e.query(n`
38
+ `.value,[this.id,this.numAttempts,this.delayMs,this.state]).then((n)=>n.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(t.result_code===1)return{resultType:"STATE_INVALID"};else if(t.result_code===2)return{resultType:"MESSAGE_DEFERRED"};else throw new Error("Unexpected result")}}class d{schema;id;numAttempts;constructor(e){this.schema=e.schema,this.numAttempts=e.numAttempts,this.id=e.id}async execute(e){let t=await e.query(a`
39
39
  SELECT * FROM ${s(this.schema)}."message_heartbeat"(
40
40
  $1,
41
41
  $2::BIGINT
42
42
  )
43
- `.value,[this.id,this.numAttempts]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(t.result_code===1)return{resultType:"MESSAGE_STATE_INVALID"};else if(t.result_code===2)return{resultType:"MESSAGE_HEARTBEATED"};else throw new Error("Unexpected result")}}var F=(e)=>{let t=e.split(`
44
- `),a=Number.MAX_SAFE_INTEGER;for(let r of t){if(r.trim().length===0)continue;let h=r.search(/\S/);a=Math.min(a,h)}return t.map((r)=>r.slice(a)).join(`
45
- `).trim()};var R=require("path"),__filename="/home/runner/work/lonnymq/lonnymq/src/core/path.ts",ae=R.dirname(R.dirname(__filename)),re=new RegExp(`^${ae}/`),E=(e)=>{return e.replace(re,"")};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/00-table-channel-policy.ts",G={name:E(__filename),sql:(e)=>{return[n`
43
+ `.value,[this.id,this.numAttempts]).then((n)=>n.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(t.result_code===1)return{resultType:"MESSAGE_STATE_INVALID"};else if(t.result_code===2)return{resultType:"MESSAGE_HEARTBEATED"};else throw new Error("Unexpected result")}}var q=(e)=>{let t=e.split(`
44
+ `),n=Number.MAX_SAFE_INTEGER;for(let r of t){if(r.trim().length===0)continue;let Y=r.search(/\S/);n=Math.min(n,Y)}return t.map((r)=>r.slice(n)).join(`
45
+ `).trim()};var g=require("path"),__filename="/home/runner/work/lonnymq/lonnymq/src/core/path.ts",oe=g.dirname(g.dirname(__filename)),ce=new RegExp(`^${oe}/`),E=(e)=>{return e.replace(ce,"")};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/00-table-channel-policy.ts",$={name:E(__filename),sql:(e)=>{return[a`
46
46
  CREATE TABLE ${s(e.schema)}."channel_policy" (
47
47
  "id" UUID NOT NULL DEFAULT GEN_RANDOM_UUID(),
48
48
  "name" TEXT NOT NULL,
@@ -51,10 +51,10 @@ var{defineProperty:N,getOwnPropertyNames:Q,getOwnPropertyDescriptor:V}=Object,W=
51
51
  "created_at" TIMESTAMP NOT NULL,
52
52
  PRIMARY KEY ("id")
53
53
  );
54
- `,n`
54
+ `,a`
55
55
  CREATE UNIQUE INDEX "channel_policy_name_ux"
56
56
  ON ${s(e.schema)}."channel_policy" ("name");
57
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/01-table-channel-state.ts",x={name:E(__filename),sql:(e)=>{return[n`
57
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/01-table-channel-state.ts",b={name:E(__filename),sql:(e)=>{return[a`
58
58
  CREATE TABLE ${s(e.schema)}."channel_state" (
59
59
  "id" UUID NOT NULL DEFAULT GEN_RANDOM_UUID(),
60
60
  "name" TEXT NOT NULL,
@@ -70,16 +70,16 @@ var{defineProperty:N,getOwnPropertyNames:Q,getOwnPropertyDescriptor:V}=Object,W=
70
70
  "created_at" TIMESTAMP NOT NULL,
71
71
  PRIMARY KEY ("id")
72
72
  );
73
- `,n`
73
+ `,a`
74
74
  CREATE UNIQUE INDEX "channel_state_name_ux"
75
75
  ON ${s(e.schema)}."channel_state" ("name");
76
- `,n`
76
+ `,a`
77
77
  CREATE INDEX "channel_state_dequeue_ix"
78
78
  ON ${s(e.schema)}."channel_state" (
79
79
  "active_next_at" ASC
80
80
  ) WHERE "message_id" IS NOT NULL
81
81
  AND ("max_concurrency" IS NULL OR "current_concurrency" < "max_concurrency");
82
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/02-table-message.ts",q={name:E(__filename),sql:(e)=>{return[n`
82
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/02-table-message.ts",B={name:E(__filename),sql:(e)=>{return[a`
83
83
  CREATE TABLE ${s(e.schema)}."message" (
84
84
  "id" UUID NOT NULL,
85
85
  "channel_name" TEXT NOT NULL,
@@ -94,19 +94,19 @@ var{defineProperty:N,getOwnPropertyNames:Q,getOwnPropertyDescriptor:V}=Object,W=
94
94
  "created_at" TIMESTAMP NOT NULL,
95
95
  PRIMARY KEY ("id")
96
96
  );
97
- `,n`
97
+ `,a`
98
98
  CREATE INDEX "message_dequeue_ix"
99
99
  ON ${s(e.schema)}."message" (
100
100
  "channel_name",
101
101
  "dequeue_at" ASC,
102
102
  "seq_no" ASC
103
103
  ) WHERE NOT "is_locked";
104
- `,n`
104
+ `,a`
105
105
  CREATE INDEX "message_locked_dequeue_ix"
106
106
  ON ${s(e.schema)}."message" (
107
107
  "unlock_at" ASC
108
108
  ) WHERE "is_locked";
109
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/03-function-message-create.ts",$={name:E(__filename),sql:(e)=>{return[n`
109
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/03-function-message-create.ts",k={name:E(__filename),sql:(e)=>{return[a`
110
110
  CREATE FUNCTION ${s(e.schema)}."message_create" (
111
111
  p_id UUID,
112
112
  p_channel_name TEXT,
@@ -217,7 +217,7 @@ var{defineProperty:N,getOwnPropertyNames:Q,getOwnPropertyDescriptor:V}=Object,W=
217
217
  END IF;
218
218
  END;
219
219
  $$ LANGUAGE plpgsql;
220
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/04-function-message-dequeue.ts",_e=(e)=>n`
220
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/04-function-message-dequeue.ts",le=(e)=>a`
221
221
  SELECT
222
222
  "message"."id",
223
223
  "message"."state",
@@ -230,7 +230,7 @@ var{defineProperty:N,getOwnPropertyNames:Q,getOwnPropertyDescriptor:V}=Object,W=
230
230
  WHERE "is_locked"
231
231
  AND "unlock_at" <= ${e.now}
232
232
  ORDER BY "unlock_at" ASC
233
- `,Ee=(e)=>n`
233
+ `,me=(e)=>a`
234
234
  SELECT
235
235
  "channel_state"."id",
236
236
  "channel_state"."name",
@@ -243,7 +243,7 @@ var{defineProperty:N,getOwnPropertyNames:Q,getOwnPropertyDescriptor:V}=Object,W=
243
243
  WHERE "message_id" IS NOT NULL
244
244
  AND ("max_concurrency" IS NULL OR "current_concurrency" < "max_concurrency")
245
245
  ORDER BY "active_next_at" ASC
246
- `,oe=(e)=>n`
246
+ `,ie=(e)=>a`
247
247
  SELECT
248
248
  "message"."id",
249
249
  "message"."dequeue_at",
@@ -252,7 +252,7 @@ var{defineProperty:N,getOwnPropertyNames:Q,getOwnPropertyDescriptor:V}=Object,W=
252
252
  WHERE NOT "is_locked"
253
253
  AND "channel_name" = ${e.channelName}
254
254
  ORDER BY "dequeue_at" ASC, "seq_no" ASC
255
- `,b={name:E(__filename),sql:(e)=>{let t=_e({now:n`v_now`,schema:e.schema}),a=oe({channelName:n`v_channel_state."name"`,schema:e.schema}),r=Ee({schema:e.schema});return[n`
255
+ `,w={name:E(__filename),sql:(e)=>{let t=le({now:a`v_now`,schema:e.schema}),n=ie({channelName:a`v_channel_state."name"`,schema:e.schema}),r=me({schema:e.schema});return[a`
256
256
  CREATE FUNCTION ${s(e.schema)}."message_dequeue" ()
257
257
  RETURNS TABLE (
258
258
  result_code INTEGER,
@@ -337,7 +337,7 @@ var{defineProperty:N,getOwnPropertyNames:Q,getOwnPropertyDescriptor:V}=Object,W=
337
337
  "unlock_at" = v_now + (v_message_dequeue."lock_ms" * INTERVAL '1 millisecond')
338
338
  WHERE "id" = v_message_dequeue."id";
339
339
 
340
- ${a}
340
+ ${n}
341
341
  LIMIT 1
342
342
  INTO v_message_next;
343
343
 
@@ -374,7 +374,7 @@ var{defineProperty:N,getOwnPropertyNames:Q,getOwnPropertyDescriptor:V}=Object,W=
374
374
  RETURN;
375
375
  END;
376
376
  $$ LANGUAGE plpgsql;
377
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/05-function-message-delete.ts",B={name:E(__filename),sql:(e)=>{return[n`
377
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/05-function-message-delete.ts",H={name:E(__filename),sql:(e)=>{return[a`
378
378
  CREATE FUNCTION ${s(e.schema)}."message_delete" (
379
379
  p_id UUID,
380
380
  p_num_attempts BIGINT
@@ -451,7 +451,7 @@ var{defineProperty:N,getOwnPropertyNames:Q,getOwnPropertyDescriptor:V}=Object,W=
451
451
  RETURN;
452
452
  END;
453
453
  $$ LANGUAGE plpgsql;
454
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/06-function-message-defer.ts",P={name:E(__filename),sql:(e)=>{return[n`
454
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/06-function-message-defer.ts",P={name:E(__filename),sql:(e)=>{return[a`
455
455
  CREATE FUNCTION ${s(e.schema)}."message_defer" (
456
456
  p_id UUID,
457
457
  p_num_attempts BIGINT,
@@ -547,7 +547,7 @@ var{defineProperty:N,getOwnPropertyNames:Q,getOwnPropertyDescriptor:V}=Object,W=
547
547
  RETURN;
548
548
  END;
549
549
  $$ LANGUAGE plpgsql;
550
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/07-function-message-heartbeat.ts",w={name:E(__filename),sql:(e)=>{return[n`
550
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/07-function-message-heartbeat.ts",Q={name:E(__filename),sql:(e)=>{return[a`
551
551
  CREATE FUNCTION ${s(e.schema)}."message_heartbeat" (
552
552
  p_id UUID,
553
553
  p_num_attempts BIGINT
@@ -590,7 +590,7 @@ var{defineProperty:N,getOwnPropertyNames:Q,getOwnPropertyDescriptor:V}=Object,W=
590
590
  RETURN;
591
591
  END;
592
592
  $$ LANGUAGE plpgsql;
593
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/08-function-channel-policy-clear.ts",H={name:E(__filename),sql:(e)=>{return[n`
593
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/08-function-channel-policy-clear.ts",V={name:E(__filename),sql:(e)=>{return[a`
594
594
  CREATE FUNCTION ${s(e.schema)}."channel_policy_clear" (
595
595
  p_name TEXT
596
596
  ) RETURNS VOID AS $$
@@ -619,7 +619,7 @@ var{defineProperty:N,getOwnPropertyNames:Q,getOwnPropertyDescriptor:V}=Object,W=
619
619
  END IF;
620
620
  END;
621
621
  $$ LANGUAGE plpgsql;
622
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/09-function-channel-policy-set.ts",k={name:E(__filename),sql:(e)=>{return[n`
622
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/09-function-channel-policy-set.ts",W={name:E(__filename),sql:(e)=>{return[a`
623
623
  CREATE FUNCTION ${s(e.schema)}."channel_policy_set" (
624
624
  p_name TEXT,
625
625
  p_max_concurrency INTEGER,
@@ -650,4 +650,4 @@ var{defineProperty:N,getOwnPropertyNames:Q,getOwnPropertyDescriptor:V}=Object,W=
650
650
  WHERE "name" = p_name;
651
651
  END;
652
652
  $$ LANGUAGE plpgsql;
653
- `]}};class S{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}create(e){let t=new l({schema:this.schema,channelName:this.channelName,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs}),a=new Promise((r)=>{this.registerFn({sortKey:JSON.stringify([t.channelName,t.createdAt.toISOString()]),execute:(h)=>t.execute(h).then(()=>r())})});return{messageId:t.id,promise:a}}}class A{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}set(e){let t=new c({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,releaseIntervalMs:e.releaseIntervalMs});this.registerFn({sortKey:JSON.stringify([t.channelName,t.createdAt.toISOString()]),execute:async(a)=>{await t.execute(a)}})}clear(){let e=new o({schema:this.schema,channelName:this.channelName});this.registerFn({sortKey:JSON.stringify([e.channelName,e.createdAt.toISOString()]),execute:async(t)=>{await e.execute(t)}})}}class p{policy;message;constructor(e){this.message=new S(e),this.policy=new A(e)}}var ce=(e,t)=>{return e.sortKey.localeCompare(t.sortKey)};class D{commands;schema;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.commands=[]}channel(e){return new p({schema:this.schema,channelName:e,registerFn:(t)=>{this.commands.push(t)}})}async execute(e){let t=this.adaptor(e.databaseClient);for(let a of this.commands.sort(ce))await a.execute(t)}}class y{schema;channelName;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.channelName=e.channelName}create(e){let t=this.adaptor(e.databaseClient);return new l({schema:this.schema,channelName:this.channelName,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs}).execute(t)}}class M{schema;adaptor;channelName;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.channelName=e.channelName}set(e){let t=this.adaptor(e.databaseClient);return new c({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,releaseIntervalMs:e.releaseIntervalMs}).execute(t)}clear(e){let t=this.adaptor(e.databaseClient);return new o({schema:this.schema,channelName:this.channelName}).execute(t)}}class v{policy;message;constructor(e){this.message=new y({schema:e.schema,adaptor:e.adaptor,channelName:e.channelName}),this.policy=new M({schema:e.schema,adaptor:e.adaptor,channelName:e.channelName})}}class I{schema;adaptor;id;isUnlocked;channelName;content;state;numAttempts;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.id=e.id,this.channelName=e.channelName,this.isUnlocked=e.isUnlocked,this.content=e.content,this.state=e.state,this.numAttempts=e.numAttempts}async defer(e){let t=this.adaptor(e.databaseClient);return new u({schema:this.schema,id:this.id,numAttempts:this.numAttempts,delayMs:e.delayMs,state:e.state}).execute(t)}async delete(e){let t=this.adaptor(e.databaseClient);return new i({schema:this.schema,numAttempts:this.numAttempts,id:this.id}).execute(t)}async heartbeat(e){let t=this.adaptor(e.databaseClient);return new d({schema:this.schema,id:this.id,numAttempts:this.numAttempts}).execute(t)}}class L{schema;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor?e.adaptor:(t)=>t}async dequeue(e){let t=new m({schema:this.schema}),a=this.adaptor(e.databaseClient),r=await t.execute(a);if(r.resultType==="MESSAGE_DEQUEUED")return{resultType:"MESSAGE_DEQUEUED",message:new I({schema:this.schema,adaptor:this.adaptor,id:r.message.id,channelName:r.message.channelName,isUnlocked:r.message.isUnlocked,content:r.message.content,state:r.message.state,numAttempts:r.message.numAttempts})};else return r}channel(e){return new v({adaptor:this.adaptor,schema:this.schema,channelName:e})}batch(){return new D({schema:this.schema,adaptor:this.adaptor})}migrations(e={}){return[G,x,q,$,b,B,P,w,k,H].sort((t,a)=>t.name.localeCompare(a.name)).flatMap((t)=>t.sql({schema:this.schema,eventChannel:e.eventChannel??null})).map((t)=>F(t.value))}}
653
+ `]}};class S{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}create(e){let t=new o({schema:this.schema,channelName:this.channelName,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs});return this.registerFn({sortKey:JSON.stringify([t.channelName,t.createdAt.toISOString()]),execute:(n)=>t.execute(n)}),{messageId:t.id}}}class R{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}set(e){let t=new l({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,releaseIntervalMs:e.releaseIntervalMs});this.registerFn({sortKey:JSON.stringify([t.channelName,t.createdAt.toISOString()]),execute:async(n)=>{await t.execute(n)}})}clear(){let e=new c({schema:this.schema,channelName:this.channelName});this.registerFn({sortKey:JSON.stringify([e.channelName,e.createdAt.toISOString()]),execute:async(t)=>{await e.execute(t)}})}}class A{policy;message;constructor(e){this.message=new S(e),this.policy=new R(e)}}class p{schema;registerFn;constructor(e){this.schema=e.schema,this.registerFn=e.registerFn}create(e){let t=new o({schema:this.schema,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs});return this.registerFn({sortKey:JSON.stringify([t.channelName,t.createdAt.toISOString()]),execute:(n)=>t.execute(n)}),{messageId:t.id,channelName:t.channelName}}}var ue=(e,t)=>{return e.sortKey.localeCompare(t.sortKey)};class D{commands;schema;adaptor;message;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.commands=[],this.message=new p({schema:this.schema,registerFn:(t)=>this.commands.push(t)})}channel(e){return new A({schema:this.schema,channelName:e,registerFn:(t)=>this.commands.push(t)})}async execute(e){let t=this.adaptor(e.databaseClient);for(let n of this.commands.sort(ue))await n.execute(t)}}class y{schema;channelName;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.channelName=e.channelName}async create(e){let t=this.adaptor(e.databaseClient),n=new o({schema:this.schema,channelName:this.channelName,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs});return await n.execute(t),{messageId:n.id}}}class M{schema;adaptor;channelName;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.channelName=e.channelName}set(e){let t=this.adaptor(e.databaseClient);return new l({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,releaseIntervalMs:e.releaseIntervalMs}).execute(t)}clear(e){let t=this.adaptor(e.databaseClient);return new c({schema:this.schema,channelName:this.channelName}).execute(t)}}class v{policy;message;constructor(e){this.message=new y({schema:e.schema,adaptor:e.adaptor,channelName:e.channelName}),this.policy=new M({schema:e.schema,adaptor:e.adaptor,channelName:e.channelName})}}class I{schema;adaptor;id;isUnlocked;channelName;content;state;numAttempts;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.id=e.id,this.channelName=e.channelName,this.isUnlocked=e.isUnlocked,this.content=e.content,this.state=e.state,this.numAttempts=e.numAttempts}async defer(e){let t=this.adaptor(e.databaseClient);return new u({schema:this.schema,id:this.id,numAttempts:this.numAttempts,delayMs:e.delayMs,state:e.state}).execute(t)}async delete(e){let t=this.adaptor(e.databaseClient);return new i({schema:this.schema,numAttempts:this.numAttempts,id:this.id}).execute(t)}async heartbeat(e){let t=this.adaptor(e.databaseClient);return new d({schema:this.schema,id:this.id,numAttempts:this.numAttempts}).execute(t)}}class L{schema;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor}async create(e){let t=this.adaptor(e.databaseClient),n=new o({schema:this.schema,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs});return await n.execute(t),{messageId:n.id,channelName:n.channelName}}}class C{schema;adaptor;message;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor?e.adaptor:(t)=>t,this.message=new L({schema:this.schema,adaptor:this.adaptor})}async dequeue(e){let t=new m({schema:this.schema}),n=this.adaptor(e.databaseClient),r=await t.execute(n);if(r.resultType==="MESSAGE_DEQUEUED")return{resultType:"MESSAGE_DEQUEUED",message:new I({schema:this.schema,adaptor:this.adaptor,id:r.message.id,channelName:r.message.channelName,isUnlocked:r.message.isUnlocked,content:r.message.content,state:r.message.state,numAttempts:r.message.numAttempts})};else return r}channel(e){return new v({adaptor:this.adaptor,schema:this.schema,channelName:e})}batch(){return new D({schema:this.schema,adaptor:this.adaptor})}migrations(e={}){return[$,b,B,k,w,H,P,Q,W,V].sort((t,n)=>t.name.localeCompare(n.name)).flatMap((t)=>t.sql({schema:this.schema,eventChannel:e.eventChannel??null})).map((t)=>q(t.value))}}
package/dist/index.d.ts CHANGED
@@ -62,7 +62,7 @@ export declare class MessageCreateCommand {
62
62
  readonly createdAt: Date;
63
63
  constructor(params: {
64
64
  schema: string;
65
- channelName: string;
65
+ channelName?: string;
66
66
  content: Buffer;
67
67
  lockMs: number;
68
68
  delayMs?: number;
@@ -159,11 +159,7 @@ export declare class MessageHeartbeatCommand {
159
159
  });
160
160
  execute(databaseClient: DatabaseClient): Promise<MessageHeartbeatCommandResult>;
161
161
  }
162
- export type QueueBatchChannelMessageCreateResult = {
163
- messageId: string;
164
- promise: Promise<void>;
165
- };
166
- export declare class QueueBatchChannelMessage {
162
+ export declare class QueueBatchChannelMessageModule {
167
163
  private readonly schema;
168
164
  private readonly channelName;
169
165
  private readonly registerFn;
@@ -173,13 +169,14 @@ export declare class QueueBatchChannelMessage {
173
169
  registerFn: BatchedCommandRegisterFn;
174
170
  });
175
171
  create(params: {
176
- name?: string;
177
172
  lockMs: number;
178
173
  content: Buffer;
179
174
  delayMs?: number;
180
- }): QueueBatchChannelMessageCreateResult;
175
+ }): {
176
+ messageId: string;
177
+ };
181
178
  }
182
- export declare class QueueBatchChannelPolicy {
179
+ export declare class QueueBatchChannelPolicyModule {
183
180
  private readonly schema;
184
181
  private readonly channelName;
185
182
  private readonly registerFn;
@@ -194,15 +191,31 @@ export declare class QueueBatchChannelPolicy {
194
191
  }): void;
195
192
  clear(): void;
196
193
  }
197
- export declare class QueueBatchChannel {
198
- readonly policy: QueueBatchChannelPolicy;
199
- readonly message: QueueBatchChannelMessage;
194
+ export declare class QueueBatchChannelModule {
195
+ readonly policy: QueueBatchChannelPolicyModule;
196
+ readonly message: QueueBatchChannelMessageModule;
200
197
  constructor(params: {
201
198
  schema: string;
202
199
  registerFn: BatchedCommandRegisterFn;
203
200
  channelName: string;
204
201
  });
205
202
  }
203
+ export declare class QueueBatchMessageModule {
204
+ private readonly schema;
205
+ private readonly registerFn;
206
+ constructor(params: {
207
+ schema: string;
208
+ registerFn: BatchedCommandRegisterFn;
209
+ });
210
+ create(params: {
211
+ lockMs: number;
212
+ content: Buffer;
213
+ delayMs?: number;
214
+ }): {
215
+ messageId: string;
216
+ channelName: string;
217
+ };
218
+ }
206
219
  export type BatchedCommand = {
207
220
  sortKey: string;
208
221
  execute: (databaseClient: DatabaseClient) => Promise<void>;
@@ -212,16 +225,17 @@ export declare class QueueBatch<T> {
212
225
  private readonly commands;
213
226
  private readonly schema;
214
227
  private readonly adaptor;
228
+ readonly message: QueueBatchMessageModule;
215
229
  constructor(params: {
216
230
  schema: string;
217
231
  adaptor: DatabaseClientAdaptor<T>;
218
232
  });
219
- channel(channelName: string): QueueBatchChannel;
233
+ channel(channelName: string): QueueBatchChannelModule;
220
234
  execute(params: {
221
235
  databaseClient: T;
222
236
  }): Promise<void>;
223
237
  }
224
- export declare class QueueChannelMessage<T> {
238
+ export declare class QueueChannelMessageModule<T> {
225
239
  private readonly schema;
226
240
  private readonly channelName;
227
241
  private readonly adaptor;
@@ -232,13 +246,14 @@ export declare class QueueChannelMessage<T> {
232
246
  });
233
247
  create(params: {
234
248
  databaseClient: T;
235
- name?: string;
236
249
  lockMs: number;
237
250
  content: Buffer;
238
251
  delayMs?: number;
239
- }): Promise<void>;
252
+ }): Promise<{
253
+ messageId: string;
254
+ }>;
240
255
  }
241
- export declare class QueueChannelPolicy<T> {
256
+ export declare class QueueChannelPolicyModule<T> {
242
257
  private readonly schema;
243
258
  private readonly adaptor;
244
259
  private readonly channelName;
@@ -256,9 +271,9 @@ export declare class QueueChannelPolicy<T> {
256
271
  databaseClient: T;
257
272
  }): Promise<void>;
258
273
  }
259
- export declare class QueueChannel<T> {
260
- readonly policy: QueueChannelPolicy<T>;
261
- readonly message: QueueChannelMessage<T>;
274
+ export declare class QueueChannelModule<T> {
275
+ readonly policy: QueueChannelPolicyModule<T>;
276
+ readonly message: QueueChannelMessageModule<T>;
262
277
  constructor(params: {
263
278
  schema: string;
264
279
  adaptor: DatabaseClientAdaptor<T>;
@@ -296,6 +311,23 @@ export declare class QueueMessage<T> {
296
311
  databaseClient: T;
297
312
  }): Promise<MessageHeartbeatCommandResult>;
298
313
  }
314
+ export declare class QueueMessageModule<T> {
315
+ private readonly schema;
316
+ private readonly adaptor;
317
+ constructor(params: {
318
+ schema: string;
319
+ adaptor: DatabaseClientAdaptor<T>;
320
+ });
321
+ create(params: {
322
+ databaseClient: T;
323
+ lockMs: number;
324
+ content: Buffer;
325
+ delayMs?: number;
326
+ }): Promise<{
327
+ messageId: string;
328
+ channelName: string;
329
+ }>;
330
+ }
299
331
  export type MessageDequeueResult<T> = {
300
332
  resultType: "MESSAGE_NOT_AVAILABLE";
301
333
  retryMs: number | null;
@@ -313,11 +345,12 @@ export type QueueParams<T> = T extends DatabaseClient ? {
313
345
  export declare class Queue<T = DatabaseClient> {
314
346
  private readonly schema;
315
347
  private readonly adaptor;
348
+ readonly message: QueueMessageModule<T>;
316
349
  constructor(params: QueueParams<T>);
317
350
  dequeue(params: {
318
351
  databaseClient: T;
319
352
  }): Promise<MessageDequeueResult<T>>;
320
- channel(channelName: string): QueueChannel<T>;
353
+ channel(channelName: string): QueueChannelModule<T>;
321
354
  batch(): QueueBatch<T>;
322
355
  migrations(params?: {
323
356
  eventChannel?: string;
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
- var v=(e)=>{return e*1000};var m=v(0);var P=(e)=>{let t=JSON.parse(e);if(t.type===0)return{eventType:"MESSAGE_CREATED",id:t.id,delayMs:t.delay_ms};else if(t.type===1)return{eventType:"MESSAGE_DELETED",id:t.id};else if(t.type===2)return{eventType:"MESSAGE_DEFERRED",id:t.id,delayMs:t.delay_ms};else throw new Error("Unknown event type")};var r=(e)=>({nodeType:"VALUE",value:e}),s=(e)=>({nodeType:"REF",value:e}),w=(e)=>({nodeType:"RAW",value:e}),H=(e)=>{return`'${e.replace(/'/g,"''")}'`},k=(e)=>{if(e===null)return"NULL";else if(typeof e==="string")return H(e);else if(typeof e==="number")return e.toString();else if(typeof e==="boolean")return e?"TRUE":"FALSE";else if(e instanceof Date)return`'${e.toISOString()}'`;else if(typeof e==="bigint")return e.toString();else throw new Error(`Unsupported value type: ${typeof e}`)},Q=(e)=>{return`"${e.replace(/"/g,'""')}"`},V=(e)=>{if(e.nodeType==="VALUE")return k(e.value);else if(e.nodeType==="REF")return Q(e.value);else if(e.nodeType==="RAW")return e.value;else throw new Error("Unsupported SQL node type")};var n=(e,...t)=>{let a=[];for(let _=0;_<e.length;_+=1)if(a.push(e[_]),_<t.length)a.push(V(t[_]));return w(a.join(""))};class o{schema;channelName;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.createdAt=new Date}async execute(e){await e.query(n`
1
+ var I=(e)=>{return e*1000};var m=I(0);var P=(e)=>{let t=JSON.parse(e);if(t.type===0)return{eventType:"MESSAGE_CREATED",id:t.id,delayMs:t.delay_ms};else if(t.type===1)return{eventType:"MESSAGE_DELETED",id:t.id};else if(t.type===2)return{eventType:"MESSAGE_DEFERRED",id:t.id,delayMs:t.delay_ms};else throw new Error("Unknown event type")};var r=(e)=>({nodeType:"VALUE",value:e}),s=(e)=>({nodeType:"REF",value:e}),Q=(e)=>({nodeType:"RAW",value:e}),V=(e)=>{return`'${e.replace(/'/g,"''")}'`},W=(e)=>{if(e===null)return"NULL";else if(typeof e==="string")return V(e);else if(typeof e==="number")return e.toString();else if(typeof e==="boolean")return e?"TRUE":"FALSE";else if(e instanceof Date)return`'${e.toISOString()}'`;else if(typeof e==="bigint")return e.toString();else throw new Error(`Unsupported value type: ${typeof e}`)},Y=(e)=>{return`"${e.replace(/"/g,'""')}"`},z=(e)=>{if(e.nodeType==="VALUE")return W(e.value);else if(e.nodeType==="REF")return Y(e.value);else if(e.nodeType==="RAW")return e.value;else throw new Error("Unsupported SQL node type")};var n=(e,...t)=>{let a=[];for(let _=0;_<e.length;_+=1)if(a.push(e[_]),_<t.length)a.push(z(t[_]));return Q(a.join(""))};class c{schema;channelName;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.createdAt=new Date}async execute(e){await e.query(n`
2
2
  SELECT 1 FROM ${s(this.schema)}."channel_policy_clear"(
3
3
  $1
4
4
  )
5
- `.value,[this.channelName])}}class c{schema;channelName;maxConcurrency;releaseIntervalMs;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName;let t=e.maxConcurrency??null;this.maxConcurrency=t!==null?Math.max(0,t):null;let a=e.releaseIntervalMs??null;this.releaseIntervalMs=a!==null?Math.max(0,a):null,this.createdAt=new Date}async execute(e){await e.query(n`
5
+ `.value,[this.channelName])}}class l{schema;channelName;maxConcurrency;releaseIntervalMs;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName;let t=e.maxConcurrency??null;this.maxConcurrency=t!==null?Math.max(0,t):null;let a=e.releaseIntervalMs??null;this.releaseIntervalMs=a!==null?Math.max(0,a):null,this.createdAt=new Date}async execute(e){await e.query(n`
6
6
  SELECT 1 FROM ${s(this.schema)}."channel_policy_set"(
7
7
  $1,
8
8
  $2::INTEGER,
9
9
  $3::INTEGER
10
10
  )
11
- `.value,[this.channelName,this.maxConcurrency,this.releaseIntervalMs])}}import{randomUUID as W}from"node:crypto";class l{schema;channelName;content;lockMs;id;delayMs;createdAt;constructor(e){let t=Math.max(0,e.lockMs),a=e.delayMs===void 0?m:e.delayMs;this.id=W(),this.schema=e.schema,this.channelName=e.channelName,this.content=e.content,this.lockMs=t,this.delayMs=a,this.createdAt=new Date}async execute(e){await e.query(n`
11
+ `.value,[this.channelName,this.maxConcurrency,this.releaseIntervalMs])}}import{randomBytes as J}from"crypto";var L=()=>{return J(16).toString("base64url")};import{randomUUID as X}from"node:crypto";class o{schema;channelName;content;lockMs;id;delayMs;createdAt;constructor(e){let t=Math.max(0,e.lockMs),a=e.delayMs===void 0?m:e.delayMs;this.id=X(),this.schema=e.schema,this.channelName=e.channelName??L(),this.content=e.content,this.lockMs=t,this.delayMs=a,this.createdAt=new Date}async execute(e){await e.query(n`
12
12
  SELECT 1 FROM ${s(this.schema)}."message_create"(
13
13
  $1,
14
14
  $2,
@@ -40,9 +40,9 @@ var v=(e)=>{return e*1000};var m=v(0);var P=(e)=>{let t=JSON.parse(e);if(t.type=
40
40
  $1,
41
41
  $2::BIGINT
42
42
  )
43
- `.value,[this.id,this.numAttempts]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(t.result_code===1)return{resultType:"MESSAGE_STATE_INVALID"};else if(t.result_code===2)return{resultType:"MESSAGE_HEARTBEATED"};else throw new Error("Unexpected result")}}var I=(e)=>{let t=e.split(`
44
- `),a=Number.MAX_SAFE_INTEGER;for(let _ of t){if(_.trim().length===0)continue;let h=_.search(/\S/);a=Math.min(a,h)}return t.map((_)=>_.slice(a)).join(`
45
- `).trim()};import{dirname as L}from"path";var __filename="/home/runner/work/lonnymq/lonnymq/src/core/path.ts",K=L(L(__filename)),j=new RegExp(`^${K}/`),E=(e)=>{return e.replace(j,"")};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/00-table-channel-policy.ts",C={name:E(__filename),sql:(e)=>{return[n`
43
+ `.value,[this.id,this.numAttempts]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(t.result_code===1)return{resultType:"MESSAGE_STATE_INVALID"};else if(t.result_code===2)return{resultType:"MESSAGE_HEARTBEATED"};else throw new Error("Unexpected result")}}var C=(e)=>{let t=e.split(`
44
+ `),a=Number.MAX_SAFE_INTEGER;for(let _ of t){if(_.trim().length===0)continue;let H=_.search(/\S/);a=Math.min(a,H)}return t.map((_)=>_.slice(a)).join(`
45
+ `).trim()};import{dirname as U}from"path";var __filename="/home/runner/work/lonnymq/lonnymq/src/core/path.ts",te=U(U(__filename)),se=new RegExp(`^${te}/`),E=(e)=>{return e.replace(se,"")};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/00-table-channel-policy.ts",O={name:E(__filename),sql:(e)=>{return[n`
46
46
  CREATE TABLE ${s(e.schema)}."channel_policy" (
47
47
  "id" UUID NOT NULL DEFAULT GEN_RANDOM_UUID(),
48
48
  "name" TEXT NOT NULL,
@@ -54,7 +54,7 @@ var v=(e)=>{return e*1000};var m=v(0);var P=(e)=>{let t=JSON.parse(e);if(t.type=
54
54
  `,n`
55
55
  CREATE UNIQUE INDEX "channel_policy_name_ux"
56
56
  ON ${s(e.schema)}."channel_policy" ("name");
57
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/01-table-channel-state.ts",U={name:E(__filename),sql:(e)=>{return[n`
57
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/01-table-channel-state.ts",f={name:E(__filename),sql:(e)=>{return[n`
58
58
  CREATE TABLE ${s(e.schema)}."channel_state" (
59
59
  "id" UUID NOT NULL DEFAULT GEN_RANDOM_UUID(),
60
60
  "name" TEXT NOT NULL,
@@ -79,7 +79,7 @@ var v=(e)=>{return e*1000};var m=v(0);var P=(e)=>{let t=JSON.parse(e);if(t.type=
79
79
  "active_next_at" ASC
80
80
  ) WHERE "message_id" IS NOT NULL
81
81
  AND ("max_concurrency" IS NULL OR "current_concurrency" < "max_concurrency");
82
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/02-table-message.ts",O={name:E(__filename),sql:(e)=>{return[n`
82
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/02-table-message.ts",F={name:E(__filename),sql:(e)=>{return[n`
83
83
  CREATE TABLE ${s(e.schema)}."message" (
84
84
  "id" UUID NOT NULL,
85
85
  "channel_name" TEXT NOT NULL,
@@ -106,7 +106,7 @@ var v=(e)=>{return e*1000};var m=v(0);var P=(e)=>{let t=JSON.parse(e);if(t.type=
106
106
  ON ${s(e.schema)}."message" (
107
107
  "unlock_at" ASC
108
108
  ) WHERE "is_locked";
109
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/03-function-message-create.ts",f={name:E(__filename),sql:(e)=>{return[n`
109
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/03-function-message-create.ts",x={name:E(__filename),sql:(e)=>{return[n`
110
110
  CREATE FUNCTION ${s(e.schema)}."message_create" (
111
111
  p_id UUID,
112
112
  p_channel_name TEXT,
@@ -217,7 +217,7 @@ var v=(e)=>{return e*1000};var m=v(0);var P=(e)=>{let t=JSON.parse(e);if(t.type=
217
217
  END IF;
218
218
  END;
219
219
  $$ LANGUAGE plpgsql;
220
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/04-function-message-dequeue.ts",Z=(e)=>n`
220
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/04-function-message-dequeue.ts",ne=(e)=>n`
221
221
  SELECT
222
222
  "message"."id",
223
223
  "message"."state",
@@ -230,7 +230,7 @@ var v=(e)=>{return e*1000};var m=v(0);var P=(e)=>{let t=JSON.parse(e);if(t.type=
230
230
  WHERE "is_locked"
231
231
  AND "unlock_at" <= ${e.now}
232
232
  ORDER BY "unlock_at" ASC
233
- `,ee=(e)=>n`
233
+ `,ae=(e)=>n`
234
234
  SELECT
235
235
  "channel_state"."id",
236
236
  "channel_state"."name",
@@ -243,7 +243,7 @@ var v=(e)=>{return e*1000};var m=v(0);var P=(e)=>{let t=JSON.parse(e);if(t.type=
243
243
  WHERE "message_id" IS NOT NULL
244
244
  AND ("max_concurrency" IS NULL OR "current_concurrency" < "max_concurrency")
245
245
  ORDER BY "active_next_at" ASC
246
- `,te=(e)=>n`
246
+ `,re=(e)=>n`
247
247
  SELECT
248
248
  "message"."id",
249
249
  "message"."dequeue_at",
@@ -252,7 +252,7 @@ var v=(e)=>{return e*1000};var m=v(0);var P=(e)=>{let t=JSON.parse(e);if(t.type=
252
252
  WHERE NOT "is_locked"
253
253
  AND "channel_name" = ${e.channelName}
254
254
  ORDER BY "dequeue_at" ASC, "seq_no" ASC
255
- `,F={name:E(__filename),sql:(e)=>{let t=Z({now:n`v_now`,schema:e.schema}),a=te({channelName:n`v_channel_state."name"`,schema:e.schema}),_=ee({schema:e.schema});return[n`
255
+ `,G={name:E(__filename),sql:(e)=>{let t=ne({now:n`v_now`,schema:e.schema}),a=re({channelName:n`v_channel_state."name"`,schema:e.schema}),_=ae({schema:e.schema});return[n`
256
256
  CREATE FUNCTION ${s(e.schema)}."message_dequeue" ()
257
257
  RETURNS TABLE (
258
258
  result_code INTEGER,
@@ -374,7 +374,7 @@ var v=(e)=>{return e*1000};var m=v(0);var P=(e)=>{let t=JSON.parse(e);if(t.type=
374
374
  RETURN;
375
375
  END;
376
376
  $$ LANGUAGE plpgsql;
377
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/05-function-message-delete.ts",G={name:E(__filename),sql:(e)=>{return[n`
377
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/05-function-message-delete.ts",q={name:E(__filename),sql:(e)=>{return[n`
378
378
  CREATE FUNCTION ${s(e.schema)}."message_delete" (
379
379
  p_id UUID,
380
380
  p_num_attempts BIGINT
@@ -451,7 +451,7 @@ var v=(e)=>{return e*1000};var m=v(0);var P=(e)=>{let t=JSON.parse(e);if(t.type=
451
451
  RETURN;
452
452
  END;
453
453
  $$ LANGUAGE plpgsql;
454
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/06-function-message-defer.ts",x={name:E(__filename),sql:(e)=>{return[n`
454
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/06-function-message-defer.ts",$={name:E(__filename),sql:(e)=>{return[n`
455
455
  CREATE FUNCTION ${s(e.schema)}."message_defer" (
456
456
  p_id UUID,
457
457
  p_num_attempts BIGINT,
@@ -547,7 +547,7 @@ var v=(e)=>{return e*1000};var m=v(0);var P=(e)=>{let t=JSON.parse(e);if(t.type=
547
547
  RETURN;
548
548
  END;
549
549
  $$ LANGUAGE plpgsql;
550
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/07-function-message-heartbeat.ts",q={name:E(__filename),sql:(e)=>{return[n`
550
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/07-function-message-heartbeat.ts",b={name:E(__filename),sql:(e)=>{return[n`
551
551
  CREATE FUNCTION ${s(e.schema)}."message_heartbeat" (
552
552
  p_id UUID,
553
553
  p_num_attempts BIGINT
@@ -590,7 +590,7 @@ var v=(e)=>{return e*1000};var m=v(0);var P=(e)=>{let t=JSON.parse(e);if(t.type=
590
590
  RETURN;
591
591
  END;
592
592
  $$ LANGUAGE plpgsql;
593
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/08-function-channel-policy-clear.ts",$={name:E(__filename),sql:(e)=>{return[n`
593
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/08-function-channel-policy-clear.ts",B={name:E(__filename),sql:(e)=>{return[n`
594
594
  CREATE FUNCTION ${s(e.schema)}."channel_policy_clear" (
595
595
  p_name TEXT
596
596
  ) RETURNS VOID AS $$
@@ -619,7 +619,7 @@ var v=(e)=>{return e*1000};var m=v(0);var P=(e)=>{let t=JSON.parse(e);if(t.type=
619
619
  END IF;
620
620
  END;
621
621
  $$ LANGUAGE plpgsql;
622
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/09-function-channel-policy-set.ts",b={name:E(__filename),sql:(e)=>{return[n`
622
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/09-function-channel-policy-set.ts",k={name:E(__filename),sql:(e)=>{return[n`
623
623
  CREATE FUNCTION ${s(e.schema)}."channel_policy_set" (
624
624
  p_name TEXT,
625
625
  p_max_concurrency INTEGER,
@@ -650,4 +650,4 @@ var v=(e)=>{return e*1000};var m=v(0);var P=(e)=>{let t=JSON.parse(e);if(t.type=
650
650
  WHERE "name" = p_name;
651
651
  END;
652
652
  $$ LANGUAGE plpgsql;
653
- `]}};class g{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}create(e){let t=new l({schema:this.schema,channelName:this.channelName,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs}),a=new Promise((_)=>{this.registerFn({sortKey:JSON.stringify([t.channelName,t.createdAt.toISOString()]),execute:(h)=>t.execute(h).then(()=>_())})});return{messageId:t.id,promise:a}}}class R{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}set(e){let t=new c({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,releaseIntervalMs:e.releaseIntervalMs});this.registerFn({sortKey:JSON.stringify([t.channelName,t.createdAt.toISOString()]),execute:async(a)=>{await t.execute(a)}})}clear(){let e=new o({schema:this.schema,channelName:this.channelName});this.registerFn({sortKey:JSON.stringify([e.channelName,e.createdAt.toISOString()]),execute:async(t)=>{await e.execute(t)}})}}class S{policy;message;constructor(e){this.message=new g(e),this.policy=new R(e)}}var se=(e,t)=>{return e.sortKey.localeCompare(t.sortKey)};class A{commands;schema;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.commands=[]}channel(e){return new S({schema:this.schema,channelName:e,registerFn:(t)=>{this.commands.push(t)}})}async execute(e){let t=this.adaptor(e.databaseClient);for(let a of this.commands.sort(se))await a.execute(t)}}class p{schema;channelName;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.channelName=e.channelName}create(e){let t=this.adaptor(e.databaseClient);return new l({schema:this.schema,channelName:this.channelName,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs}).execute(t)}}class D{schema;adaptor;channelName;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.channelName=e.channelName}set(e){let t=this.adaptor(e.databaseClient);return new c({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,releaseIntervalMs:e.releaseIntervalMs}).execute(t)}clear(e){let t=this.adaptor(e.databaseClient);return new o({schema:this.schema,channelName:this.channelName}).execute(t)}}class y{policy;message;constructor(e){this.message=new p({schema:e.schema,adaptor:e.adaptor,channelName:e.channelName}),this.policy=new D({schema:e.schema,adaptor:e.adaptor,channelName:e.channelName})}}class M{schema;adaptor;id;isUnlocked;channelName;content;state;numAttempts;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.id=e.id,this.channelName=e.channelName,this.isUnlocked=e.isUnlocked,this.content=e.content,this.state=e.state,this.numAttempts=e.numAttempts}async defer(e){let t=this.adaptor(e.databaseClient);return new d({schema:this.schema,id:this.id,numAttempts:this.numAttempts,delayMs:e.delayMs,state:e.state}).execute(t)}async delete(e){let t=this.adaptor(e.databaseClient);return new u({schema:this.schema,numAttempts:this.numAttempts,id:this.id}).execute(t)}async heartbeat(e){let t=this.adaptor(e.databaseClient);return new T({schema:this.schema,id:this.id,numAttempts:this.numAttempts}).execute(t)}}class B{schema;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor?e.adaptor:(t)=>t}async dequeue(e){let t=new i({schema:this.schema}),a=this.adaptor(e.databaseClient),_=await t.execute(a);if(_.resultType==="MESSAGE_DEQUEUED")return{resultType:"MESSAGE_DEQUEUED",message:new M({schema:this.schema,adaptor:this.adaptor,id:_.message.id,channelName:_.message.channelName,isUnlocked:_.message.isUnlocked,content:_.message.content,state:_.message.state,numAttempts:_.message.numAttempts})};else return _}channel(e){return new y({adaptor:this.adaptor,schema:this.schema,channelName:e})}batch(){return new A({schema:this.schema,adaptor:this.adaptor})}migrations(e={}){return[C,U,O,f,F,G,x,q,b,$].sort((t,a)=>t.name.localeCompare(a.name)).flatMap((t)=>t.sql({schema:this.schema,eventChannel:e.eventChannel??null})).map((t)=>I(t.value))}}export{P as queueEventDecode,B as Queue,T as MessageHeartbeatCommand,i as MessageDequeueCommand,u as MessageDeleteCommand,d as MessageDeferCommand,l as MessageCreateCommand,c as ChannelPolicySetCommand,o as ChannelPolicyClearCommand};
653
+ `]}};class N{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}create(e){let t=new o({schema:this.schema,channelName:this.channelName,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs});return this.registerFn({sortKey:JSON.stringify([t.channelName,t.createdAt.toISOString()]),execute:(a)=>t.execute(a)}),{messageId:t.id}}}class g{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}set(e){let t=new l({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,releaseIntervalMs:e.releaseIntervalMs});this.registerFn({sortKey:JSON.stringify([t.channelName,t.createdAt.toISOString()]),execute:async(a)=>{await t.execute(a)}})}clear(){let e=new c({schema:this.schema,channelName:this.channelName});this.registerFn({sortKey:JSON.stringify([e.channelName,e.createdAt.toISOString()]),execute:async(t)=>{await e.execute(t)}})}}class S{policy;message;constructor(e){this.message=new N(e),this.policy=new g(e)}}class R{schema;registerFn;constructor(e){this.schema=e.schema,this.registerFn=e.registerFn}create(e){let t=new o({schema:this.schema,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs});return this.registerFn({sortKey:JSON.stringify([t.channelName,t.createdAt.toISOString()]),execute:(a)=>t.execute(a)}),{messageId:t.id,channelName:t.channelName}}}var _e=(e,t)=>{return e.sortKey.localeCompare(t.sortKey)};class A{commands;schema;adaptor;message;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.commands=[],this.message=new R({schema:this.schema,registerFn:(t)=>this.commands.push(t)})}channel(e){return new S({schema:this.schema,channelName:e,registerFn:(t)=>this.commands.push(t)})}async execute(e){let t=this.adaptor(e.databaseClient);for(let a of this.commands.sort(_e))await a.execute(t)}}class p{schema;channelName;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.channelName=e.channelName}async create(e){let t=this.adaptor(e.databaseClient),a=new o({schema:this.schema,channelName:this.channelName,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs});return await a.execute(t),{messageId:a.id}}}class D{schema;adaptor;channelName;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.channelName=e.channelName}set(e){let t=this.adaptor(e.databaseClient);return new l({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,releaseIntervalMs:e.releaseIntervalMs}).execute(t)}clear(e){let t=this.adaptor(e.databaseClient);return new c({schema:this.schema,channelName:this.channelName}).execute(t)}}class y{policy;message;constructor(e){this.message=new p({schema:e.schema,adaptor:e.adaptor,channelName:e.channelName}),this.policy=new D({schema:e.schema,adaptor:e.adaptor,channelName:e.channelName})}}class M{schema;adaptor;id;isUnlocked;channelName;content;state;numAttempts;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.id=e.id,this.channelName=e.channelName,this.isUnlocked=e.isUnlocked,this.content=e.content,this.state=e.state,this.numAttempts=e.numAttempts}async defer(e){let t=this.adaptor(e.databaseClient);return new d({schema:this.schema,id:this.id,numAttempts:this.numAttempts,delayMs:e.delayMs,state:e.state}).execute(t)}async delete(e){let t=this.adaptor(e.databaseClient);return new u({schema:this.schema,numAttempts:this.numAttempts,id:this.id}).execute(t)}async heartbeat(e){let t=this.adaptor(e.databaseClient);return new T({schema:this.schema,id:this.id,numAttempts:this.numAttempts}).execute(t)}}class v{schema;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor}async create(e){let t=this.adaptor(e.databaseClient),a=new o({schema:this.schema,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs});return await a.execute(t),{messageId:a.id,channelName:a.channelName}}}class w{schema;adaptor;message;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor?e.adaptor:(t)=>t,this.message=new v({schema:this.schema,adaptor:this.adaptor})}async dequeue(e){let t=new i({schema:this.schema}),a=this.adaptor(e.databaseClient),_=await t.execute(a);if(_.resultType==="MESSAGE_DEQUEUED")return{resultType:"MESSAGE_DEQUEUED",message:new M({schema:this.schema,adaptor:this.adaptor,id:_.message.id,channelName:_.message.channelName,isUnlocked:_.message.isUnlocked,content:_.message.content,state:_.message.state,numAttempts:_.message.numAttempts})};else return _}channel(e){return new y({adaptor:this.adaptor,schema:this.schema,channelName:e})}batch(){return new A({schema:this.schema,adaptor:this.adaptor})}migrations(e={}){return[O,f,F,x,G,q,$,b,k,B].sort((t,a)=>t.name.localeCompare(a.name)).flatMap((t)=>t.sql({schema:this.schema,eventChannel:e.eventChannel??null})).map((t)=>C(t.value))}}export{P as queueEventDecode,w as Queue,T as MessageHeartbeatCommand,i as MessageDequeueCommand,u as MessageDeleteCommand,d as MessageDeferCommand,o as MessageCreateCommand,l as ChannelPolicySetCommand,c as ChannelPolicyClearCommand};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lonnymq",
3
- "version": "0.0.19",
3
+ "version": "0.0.20",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {