lonnymq 0.0.1 → 0.0.2

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/dist/index.cjs CHANGED
@@ -1,20 +1,21 @@
1
- var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=Object.prototype.hasOwnProperty;var q=new WeakMap,j=(e)=>{var n=q.get(e),_;if(n)return n;if(n=g({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function")K(e).map((c)=>!Y.call(n,c)&&g(n,c,{get:()=>e[c],enumerable:!(_=Q(e,c))||_.enumerable}));return q.set(e,n),n};var Z=(e,n)=>{for(var _ in n)g(e,_,{get:n[_],enumerable:!0,configurable:!0,set:(c)=>n[_]=()=>c})};var oe={};Z(oe,{Queue:()=>p,MessageDequeueCommand:()=>l,MessageDeleteCommand:()=>d,MessageDeferCommand:()=>h,MessageCreateCommand:()=>i,ChannelPolicySetCommand:()=>o,ChannelPolicyClearCommand:()=>E});module.exports=j(oe);var s=(e)=>({nodeType:"VALUE",value:e}),t=(e)=>({nodeType:"REF",value:e}),ee=(e)=>({nodeType:"RAW",value:e}),ne=(e)=>{return`'${e.replace(/'/g,"''")}'`},te=(e)=>{if(e===null)return"NULL";else if(typeof e==="string")return ne(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 throw new Error(`Unsupported value type: ${typeof e}`)},_e=(e)=>{return`"${e.replace(/"/g,'""')}"`},se=(e)=>{if(e.nodeType==="VALUE")return te(e.value);else if(e.nodeType==="REF")return _e(e.value);else if(e.nodeType==="RAW")return e.value;else throw new Error("Unsupported SQL node type")};var a=(e,...n)=>{let _=[];for(let c=0;c<e.length;c+=1)if(_.push(e[c]),c<n.length)_.push(se(n[c]));return ee(_.join(""))};class E{schema;channelName;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.createdAt=new Date}sortKeyGet(){return JSON.stringify([this.channelName,null,this.createdAt.toISOString()])}async execute(e){await e.query(a`
1
+ var{defineProperty:S,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=Object.prototype.hasOwnProperty;var q=new WeakMap,j=(e)=>{var n=q.get(e),_;if(n)return n;if(n=S({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function")K(e).map((c)=>!Y.call(n,c)&&S(n,c,{get:()=>e[c],enumerable:!(_=Q(e,c))||_.enumerable}));return q.set(e,n),n};var Z=(e,n)=>{for(var _ in n)S(e,_,{get:n[_],enumerable:!0,configurable:!0,set:(c)=>n[_]=()=>c})};var oe={};Z(oe,{Queue:()=>p,MessageDequeueCommand:()=>u,MessageDeleteCommand:()=>h,MessageDeferCommand:()=>N,MessageCreateCommand:()=>i,ChannelPolicySetCommand:()=>o,ChannelPolicyClearCommand:()=>E});module.exports=j(oe);var s=(e)=>({nodeType:"VALUE",value:e}),t=(e)=>({nodeType:"REF",value:e}),ee=(e)=>({nodeType:"RAW",value:e}),ne=(e)=>{return`'${e.replace(/'/g,"''")}'`},te=(e)=>{if(e===null)return"NULL";else if(typeof e==="string")return ne(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}`)},_e=(e)=>{return`"${e.replace(/"/g,'""')}"`},se=(e)=>{if(e.nodeType==="VALUE")return te(e.value);else if(e.nodeType==="REF")return _e(e.value);else if(e.nodeType==="RAW")return e.value;else throw new Error("Unsupported SQL node type")};var a=(e,...n)=>{let _=[];for(let c=0;c<e.length;c+=1)if(_.push(e[c]),c<n.length)_.push(se(n[c]));return ee(_.join(""))};class E{schema;channelName;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.createdAt=new Date}sortKeyGet(){return JSON.stringify([this.channelName,null,this.createdAt.toISOString()])}async execute(e){await e.query(a`
2
2
  SELECT 1 FROM ${t(this.schema)}."channel_policy_clear"(
3
3
  ${s(this.channelName)}
4
4
  )
5
- `.value)}}class o{schema;channelName;maxSize;maxConcurrency;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.maxConcurrency=e.maxConcurrency===null?null:Math.max(0,e.maxConcurrency),this.maxSize=e.maxSize===null?null:Math.max(0,e.maxSize),this.createdAt=new Date}sortKeyGet(){return JSON.stringify([this.channelName,null,this.createdAt.toISOString()])}async execute(e){await e.query(a`
5
+ `.value)}}class o{schema;channelName;maxSize;maxConcurrency;releaseIntervalMs;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName;let n=e.maxConcurrency??null;this.maxConcurrency=n!==null?Math.max(0,n):null;let _=e.maxSize??null;this.maxSize=_!==null?Math.max(0,_):null;let c=e.releaseIntervalMs??null;this.releaseIntervalMs=c!==null?Math.max(0,c):null,this.createdAt=new Date}sortKeyGet(){return JSON.stringify([this.channelName,null,this.createdAt.toISOString()])}async execute(e){await e.query(a`
6
6
  SELECT 1 FROM ${t(this.schema)}."channel_policy_set"(
7
7
  ${s(this.channelName)},
8
- ${s(this.maxSize)}::BIGINT,
9
- ${s(this.maxConcurrency)}::BIGINT
8
+ ${s(this.maxSize)}::INTEGER,
9
+ ${s(this.maxConcurrency)}::INTEGER,
10
+ ${s(this.releaseIntervalMs)}::INTEGER
10
11
  )
11
- `.value)}}var R=(e)=>{return e*1000},ae=(e)=>{return R(e*60)},I=(e)=>{return ae(e*60)},C=(e)=>{return I(e*24)};var $=require("node:crypto");class F{value;constructor(e){this.value=e}toString(e){return $.createHash("sha256").update(e).update(this.value).digest("base64").replace(/=/g,"")}}var N=new F("WAKE"),T=C(1000),M=!1,S=R(0),B=I(1);var A=require("path"),__filename="/home/runner/work/lonnymq/lonnymq/src/core/path.ts",ce=A.dirname(A.dirname(__filename)),re=new RegExp(`^${ce}/`),r=(e)=>{return e.replace(re,"")};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/04-function-message-create.ts";var G={name:r(__filename),sql:(e)=>{return[a`
12
+ `.value)}}var g=(e)=>{return e*1000},ae=(e)=>{return g(e*60)},I=(e)=>{return ae(e*60)},C=(e)=>{return I(e*24)};var $=require("node:crypto");class F{value;constructor(e){this.value=e}toString(e){return $.createHash("sha256").update(e).update(this.value).digest("base64").replace(/=/g,"")}}var T=new F("WAKE"),d=C(1000),M=!1,R=g(0),G=I(1);var O=require("path"),__filename="/home/runner/work/lonnymq/lonnymq/src/core/path.ts",ce=O.dirname(O.dirname(__filename)),re=new RegExp(`^${ce}/`),r=(e)=>{return e.replace(re,"")};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/04-function-message-create.ts";var B={name:r(__filename),sql:(e)=>{return[a`
12
13
  CREATE FUNCTION ${t(e.schema)}."message_create" (
13
14
  p_channel_name TEXT,
14
15
  p_name TEXT,
15
16
  p_content TEXT,
16
- p_lock_ms BIGINT,
17
- p_delay_ms BIGINT
17
+ p_lock_ms INTEGER,
18
+ p_delay_ms INTEGER
18
19
  ) RETURNS JSONB AS $$
19
20
  DECLARE
20
21
  v_now TIMESTAMP;
@@ -27,7 +28,8 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
27
28
 
28
29
  SELECT
29
30
  "max_size",
30
- "max_concurrency"
31
+ "max_concurrency",
32
+ "release_interval_ms"
31
33
  FROM ${t(e.schema)}."channel_policy"
32
34
  WHERE "name" = p_channel_name
33
35
  FOR SHARE
@@ -39,6 +41,7 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
39
41
  "current_concurrency",
40
42
  "max_size",
41
43
  "max_concurrency",
44
+ "release_interval_ms",
42
45
  "message_next_id",
43
46
  "message_next_dequeue_after"
44
47
  ) VALUES (
@@ -47,6 +50,7 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
47
50
  0,
48
51
  v_channel_policy."max_size",
49
52
  v_channel_policy."max_concurrency",
53
+ v_channel_policy."release_interval_ms",
50
54
  NULL,
51
55
  NULL
52
56
  ) ON CONFLICT ("name")
@@ -119,20 +123,20 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
119
123
  );
120
124
  END;
121
125
  $$ LANGUAGE plpgsql;
122
- `]}};class i{schema;channelName;name;content;lockMs;delayMs;createdAt;constructor(e){let n=e.name??null,_=e.lockMs===void 0?B:Math.max(0,e.lockMs),c;if(e.priority)c=-T;else c=e.delayMs===void 0?S:Math.max(0,e.delayMs);this.schema=e.schema,this.channelName=e.channelName,this.content=e.content,this.name=n,this.lockMs=_,this.delayMs=c,this.createdAt=new Date}async execute(e){let n=await e.query(a`
126
+ `]}};class i{schema;channelName;name;content;lockMs;delayMs;createdAt;constructor(e){let n=e.name??null,_=e.lockMs===void 0?G:Math.max(0,e.lockMs),c;if(e.priority)c=-d;else c=e.delayMs===void 0?R:Math.max(0,e.delayMs);this.schema=e.schema,this.channelName=e.channelName,this.content=e.content,this.name=n,this.lockMs=_,this.delayMs=c,this.createdAt=new Date}async execute(e){let n=await e.query(a`
123
127
  SELECT ${t(this.schema)}."message_create"(
124
128
  ${s(this.channelName)},
125
129
  ${s(this.name)},
126
130
  ${s(this.content)},
127
- ${s(this.lockMs)}::BIGINT,
128
- ${s(this.delayMs)}::BIGINT
131
+ ${s(this.lockMs)}::INTEGER,
132
+ ${s(this.delayMs)}::INTEGER
129
133
  ) AS "result"
130
- `.value).then((_)=>_.rows[0].result);if(n.result_code===1)return{resultType:"MESSAGE_DROPPED"};else if(n.result_code===2)return{resultType:"MESSAGE_DEDUPLICATED",id:n.id};else if(n.result_code===0)return{resultType:"MESSAGE_CREATED",id:n.id};else throw new Error("Unexpected result")}}var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/05-function-message-dequeue.ts";var P={name:r(__filename),sql:(e)=>{return[a`
134
+ `.value).then((_)=>_.rows[0].result);if(n.result_code===1)return{resultType:"MESSAGE_DROPPED"};else if(n.result_code===2)return{resultType:"MESSAGE_DEDUPLICATED",id:BigInt(n.id)};else if(n.result_code===0)return{resultType:"MESSAGE_CREATED",id:BigInt(n.id)};else throw new Error("Unexpected result")}}var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/05-function-message-dequeue.ts";var P={name:r(__filename),sql:(e)=>{return[a`
131
135
  CREATE FUNCTION ${t(e.schema)}."message_dequeue" ()
132
136
  RETURNS JSONB AS $$
133
137
  DECLARE
134
138
  v_now TIMESTAMP;
135
- v_dequeue_id UUID;
139
+ v_dequeue_nonce UUID;
136
140
  v_channel_state RECORD;
137
141
  v_message_locked RECORD;
138
142
  v_retry_after TIMESTAMP;
@@ -141,7 +145,7 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
141
145
  v_message_next_dequeue_after TIMESTAMP;
142
146
  BEGIN
143
147
  v_now := NOW();
144
- v_dequeue_id := GEN_RANDOM_UUID();
148
+ v_dequeue_nonce := GEN_RANDOM_UUID();
145
149
 
146
150
  SELECT
147
151
  "id",
@@ -164,7 +168,7 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
164
168
  UPDATE ${t(e.schema)}."message" SET
165
169
  "num_attempts" = v_message_locked."num_attempts" + 1,
166
170
  "dequeue_after" = v_now + (v_message_locked."lock_ms" * INTERVAL '1 millisecond'),
167
- "dequeue_id" = v_dequeue_id
171
+ "dequeue_nonce" = v_dequeue_nonce
168
172
  WHERE "id" = v_message_locked."id";
169
173
 
170
174
  PERFORM ${t(e.schema)}."wake"(v_message_locked."lock_ms");
@@ -175,7 +179,7 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
175
179
  'channel_name', v_message_locked.channel_name,
176
180
  'state', v_message_locked.state,
177
181
  'name', v_message_locked.name,
178
- 'dequeue_id', v_dequeue_id,
182
+ 'dequeue_nonce', v_dequeue_nonce,
179
183
  'content', v_message_locked.content,
180
184
  'num_attempts', v_message_locked.num_attempts
181
185
  );
@@ -184,6 +188,7 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
184
188
  SELECT
185
189
  "id",
186
190
  "name",
191
+ "release_interval_ms",
187
192
  "message_next_id",
188
193
  "message_next_dequeue_after",
189
194
  "current_concurrency"
@@ -223,7 +228,7 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
223
228
  UPDATE ${t(e.schema)}."message" SET
224
229
  "is_locked" = TRUE,
225
230
  "num_attempts" = v_message_dequeue."num_attempts" + 1,
226
- "dequeue_id" = v_dequeue_id,
231
+ "dequeue_nonce" = v_dequeue_nonce,
227
232
  "dequeue_after" = v_now + (v_message_dequeue."lock_ms" * INTERVAL '1 millisecond')
228
233
  WHERE "id" = v_message_dequeue."id";
229
234
 
@@ -242,7 +247,7 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
242
247
  IF v_message_next_dequeue."id" IS NOT NULL THEN
243
248
  v_message_next_dequeue_after := GREATEST(
244
249
  v_message_next_dequeue."dequeue_after",
245
- v_now
250
+ v_now + (COALESCE(v_channel_state."release_interval_ms", 0) * INTERVAL '1 millisecond')
246
251
  );
247
252
 
248
253
  UPDATE ${t(e.schema)}."channel_state" SET
@@ -263,29 +268,30 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
263
268
  'id', v_message_dequeue.id,
264
269
  'channel_name', v_message_dequeue.channel_name,
265
270
  'state', v_message_dequeue.state,
266
- 'dequeue_id', v_dequeue_id,
271
+ 'dequeue_nonce', v_dequeue_nonce,
267
272
  'name', v_message_dequeue.name,
268
273
  'content', v_message_dequeue.content,
269
274
  'num_attempts', v_message_dequeue.num_attempts
270
275
  );
271
276
  END;
272
277
  $$ LANGUAGE plpgsql;
273
- `]}};class l{schema;constructor(e){this.schema=e.schema}async execute(e){let n=await e.query(a`
278
+ `]}};class u{schema;constructor(e){this.schema=e.schema}async execute(e){let n=await e.query(a`
274
279
  SELECT ${t(this.schema)}."message_dequeue"() AS "result"
275
- `.value).then((_)=>_.rows[0].result);if(n.result_code===0)return{resultType:"MESSAGE_NOT_AVAILABLE",retryMs:n.retry_ms};else if(n.result_code===1)return{resultType:"MESSAGE_DEQUEUED",message:{id:n.id,channelName:n.channel_name,name:n.name,content:n.content,dequeueId:n.dequeue_id,state:n.state,numAttempts:n.num_attempts,lockMs:n.lock_ms}};else throw new Error("Unexpected dequeue result")}}var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/06-function-message-delete.ts";var k={name:r(__filename),sql:(e)=>{return[a`
280
+ `.value).then((_)=>_.rows[0].result);if(n.result_code===0)return{resultType:"MESSAGE_NOT_AVAILABLE",retryMs:n.retry_ms};else if(n.result_code===1)return{resultType:"MESSAGE_DEQUEUED",message:{id:BigInt(n.id),channelName:n.channel_name,name:n.name,content:n.content,dequeueNonce:n.dequeue_nonce,state:n.state,numAttempts:n.num_attempts}};else throw new Error("Unexpected dequeue result")}}var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/06-function-message-delete.ts";var H={name:r(__filename),sql:(e)=>{return[a`
276
281
  CREATE FUNCTION ${t(e.schema)}."message_delete" (
277
- p_id UUID,
278
- p_dequeue_id UUID
282
+ p_id BIGINT,
283
+ p_dequeue_nonce UUID
279
284
  )
280
285
  RETURNS JSONB AS $$
281
286
  DECLARE
287
+ v_channel_policy RECORD;
282
288
  v_channel_state RECORD;
283
289
  v_message RECORD;
284
290
  BEGIN
285
291
  SELECT
286
292
  "id",
287
293
  "channel_name",
288
- "dequeue_id"
294
+ "dequeue_nonce"
289
295
  FROM ${t(e.schema)}."message"
290
296
  WHERE "id" = p_id
291
297
  FOR UPDATE
@@ -295,12 +301,19 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
295
301
  RETURN JSONB_BUILD_OBJECT(
296
302
  'result_code', ${s(0)}
297
303
  );
298
- ELSEIF v_message."dequeue_id" != p_dequeue_id THEN
304
+ ELSEIF v_message."dequeue_nonce" != p_dequeue_nonce THEN
299
305
  RETURN JSONB_BUILD_OBJECT(
300
306
  'result_code', ${s(1)}
301
307
  );
302
308
  END IF;
303
309
 
310
+ SELECT
311
+ "id"
312
+ FROM ${t(e.schema)}."channel_policy"
313
+ WHERE "name" = v_message."channel_name"
314
+ FOR SHARE
315
+ INTO v_channel_policy;
316
+
304
317
  SELECT
305
318
  "id",
306
319
  "current_size",
@@ -310,7 +323,7 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
310
323
  FOR UPDATE
311
324
  INTO v_channel_state;
312
325
 
313
- IF v_channel_state."current_size" = 1 THEN
326
+ IF v_channel_policy."id" IS NULL AND v_channel_state."current_size" = 1 THEN
314
327
  DELETE FROM ${t(e.schema)}."channel_state"
315
328
  WHERE "id" = v_channel_state."id";
316
329
  ELSE
@@ -328,15 +341,15 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
328
341
  );
329
342
  END;
330
343
  $$ LANGUAGE plpgsql;
331
- `]}};class d{schema;id;dequeueId;constructor(e){this.schema=e.schema,this.id=e.id,this.dequeueId=e.dequeueId}async execute(e){let n=await e.query(a`
344
+ `]}};class h{schema;id;dequeueNonce;constructor(e){this.schema=e.schema,this.id=e.id,this.dequeueNonce=e.dequeueNonce}async execute(e){let n=await e.query(a`
332
345
  SELECT ${t(this.schema)}."message_delete"( ${s(this.id)},
333
- ${s(this.dequeueId)}
346
+ ${s(this.dequeueNonce)}
334
347
  ) AS "result"
335
348
  `.value).then((_)=>_.rows[0].result);if(n.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(n.result_code===1)return{resultType:"STATE_INVALID"};else if(n.result_code===2)return{resultType:"MESSAGE_DELETED"};else throw new Error("Unexpected result")}}var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/07-function-message-defer.ts";var b={name:r(__filename),sql:(e)=>{return[a`
336
349
  CREATE FUNCTION ${t(e.schema)}."message_defer" (
337
- p_id UUID,
338
- p_dequeue_id UUID,
339
- p_delay_ms BIGINT,
350
+ p_id BIGINT,
351
+ p_dequeue_nonce UUID,
352
+ p_delay_ms INTEGER,
340
353
  p_state TEXT
341
354
  )
342
355
  RETURNS JSONB AS $$
@@ -348,7 +361,7 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
348
361
  SELECT
349
362
  "id",
350
363
  "channel_name",
351
- "dequeue_id"
364
+ "dequeue_nonce"
352
365
  FROM ${t(e.schema)}."message"
353
366
  WHERE "id" = p_id
354
367
  FOR UPDATE
@@ -358,7 +371,7 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
358
371
  RETURN JSONB_BUILD_OBJECT(
359
372
  'result_code', ${s(0)}
360
373
  );
361
- ELSEIF v_message."dequeue_id" != p_dequeue_id THEN
374
+ ELSEIF v_message."dequeue_nonce" != p_dequeue_nonce THEN
362
375
  RETURN JSONB_BUILD_OBJECT(
363
376
  'result_code', ${s(1)}
364
377
  );
@@ -403,35 +416,37 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
403
416
  );
404
417
  END;
405
418
  $$ LANGUAGE plpgsql;
406
- `]}};class h{schema;id;dequeueId;delayMs;state;constructor(e){let n;if(e.priority)n=-T;else n=e.delayMs===void 0?S:Math.max(0,e.delayMs);this.schema=e.schema,this.id=e.id,this.dequeueId=e.dequeueId,this.delayMs=n,this.state=e.state??null}async execute(e){let n=await e.query(a`
419
+ `]}};class N{schema;id;dequeueNonce;delayMs;state;constructor(e){let n;if(e.priority)n=-d;else n=e.delayMs===void 0?R:Math.max(0,e.delayMs);this.schema=e.schema,this.id=e.id,this.dequeueNonce=e.dequeueNonce,this.delayMs=n,this.state=e.state??null}async execute(e){let n=await e.query(a`
407
420
  SELECT ${t(this.schema)}."message_defer"(
408
421
  ${s(this.id)},
409
- ${s(this.dequeueId)},
410
- ${s(this.delayMs)}::BIGINT,
422
+ ${s(this.dequeueNonce)},
423
+ ${s(this.delayMs)},
411
424
  ${s(this.state)}
412
425
  ) AS "result"
413
- `.value).then((_)=>_.rows[0].result);if(n.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(n.result_code===1)return{resultType:"STATE_INVALID"};else if(n.result_code===2)return{resultType:"MESSAGE_DEFERRED"};else throw new Error("Unexpected result")}}var H=(e)=>{let n=e.split(`
414
- `),_=Number.MAX_SAFE_INTEGER;for(let c of n){if(c.trim().length===0)continue;let u=c.search(/\S/);_=Math.min(_,u)}return n.map((c)=>c.slice(_)).join(`
426
+ `.value).then((_)=>_.rows[0].result);if(n.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(n.result_code===1)return{resultType:"STATE_INVALID"};else if(n.result_code===2)return{resultType:"MESSAGE_DEFERRED"};else throw new Error("Unexpected result")}}var k=(e)=>{let n=e.split(`
427
+ `),_=Number.MAX_SAFE_INTEGER;for(let c of n){if(c.trim().length===0)continue;let l=c.search(/\S/);_=Math.min(_,l)}return n.map((c)=>c.slice(_)).join(`
415
428
  `).trim()};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/00-table-channel-policy.ts",z={name:r(__filename),sql:(e)=>{return[a`
416
429
  CREATE TABLE ${t(e.schema)}."channel_policy" (
417
- "id" UUID NOT NULL DEFAULT GEN_RANDOM_UUID(),
430
+ "id" BIGSERIAL NOT NULL,
418
431
  "name" TEXT NOT NULL,
419
- "max_size" BIGINT,
420
- "max_concurrency" BIGINT,
432
+ "max_size" INTEGER,
433
+ "max_concurrency" INTEGER,
434
+ "release_interval_ms" INTEGER,
421
435
  PRIMARY KEY ("id")
422
436
  );
423
437
  `,a`
424
438
  CREATE UNIQUE INDEX "channel_policy_name_ux"
425
439
  ON ${t(e.schema)}."channel_policy" ("name");
426
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/01-table-channel-state.ts",w={name:r(__filename),sql:(e)=>{return[a`
440
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/01-table-channel-state.ts",W={name:r(__filename),sql:(e)=>{return[a`
427
441
  CREATE TABLE ${t(e.schema)}."channel_state" (
428
- "id" UUID NOT NULL DEFAULT GEN_RANDOM_UUID(),
442
+ "id" BIGSERIAL NOT NULL,
429
443
  "name" TEXT NOT NULL,
430
- "max_size" BIGINT,
431
- "max_concurrency" BIGINT,
432
- "current_size" BIGINT NOT NULL,
433
- "current_concurrency" BIGINT NOT NULL,
434
- "message_next_id" UUID,
444
+ "max_size" INTEGER,
445
+ "max_concurrency" INTEGER,
446
+ "release_interval_ms" INTEGER,
447
+ "current_size" INTEGER NOT NULL,
448
+ "current_concurrency" INTEGER NOT NULL,
449
+ "message_next_id" BIGINT,
435
450
  "message_next_dequeue_after" TIMESTAMP,
436
451
  PRIMARY KEY ("id")
437
452
  );
@@ -444,19 +459,18 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
444
459
  "message_next_dequeue_after" ASC
445
460
  ) WHERE "message_next_id" IS NOT NULL
446
461
  AND ("max_concurrency" IS NULL OR "current_concurrency" < "max_concurrency");
447
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/02-table-message.ts",W={name:r(__filename),sql:(e)=>{return[a`
462
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/02-table-message.ts",w={name:r(__filename),sql:(e)=>{return[a`
448
463
  CREATE TABLE ${t(e.schema)}."message" (
449
- "id" UUID NOT NULL DEFAULT GEN_RANDOM_UUID(),
464
+ "id" BIGSERIAL NOT NULL,
450
465
  "channel_name" TEXT NOT NULL,
451
- "dequeue_id" UUID,
466
+ "dequeue_nonce" UUID,
452
467
  "name" TEXT,
453
468
  "content" TEXT NOT NULL,
454
469
  "state" TEXT,
455
- "lock_ms" BIGINT NOT NULL,
470
+ "lock_ms" INTEGER NOT NULL,
456
471
  "is_locked" BOOLEAN NOT NULL DEFAULT FALSE,
457
- "num_attempts" BIGINT NOT NULL DEFAULT 0,
472
+ "num_attempts" INTEGER NOT NULL DEFAULT 0,
458
473
  "dequeue_after" TIMESTAMP NOT NULL,
459
- "sweep_after" TIMESTAMP,
460
474
  PRIMARY KEY ("id")
461
475
  );
462
476
  `,a`
@@ -476,9 +490,9 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
476
490
  ON ${t(e.schema)}."message" (
477
491
  "dequeue_after" ASC
478
492
  ) WHERE "is_locked";
479
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/03-function-wake.ts",J={name:r(__filename),sql:(e)=>{let n=N.toString(e.schema);return[a`
493
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/03-function-wake.ts",J={name:r(__filename),sql:(e)=>{let n=T.toString(e.schema);return[a`
480
494
  CREATE FUNCTION ${t(e.schema)}."wake" (
481
- p_delay_ms BIGINT
495
+ p_delay_ms INTEGER
482
496
  ) RETURNS VOID AS $$
483
497
  BEGIN
484
498
  IF ${s(e.useWake)} THEN
@@ -489,25 +503,30 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
489
503
  `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/08-function-channel-policy-set.ts",V={name:r(__filename),sql:(e)=>{return[a`
490
504
  CREATE FUNCTION ${t(e.schema)}."channel_policy_set" (
491
505
  p_name TEXT,
492
- p_max_size BIGINT,
493
- p_max_concurrency BIGINT
506
+ p_max_size INTEGER,
507
+ p_max_concurrency INTEGER,
508
+ p_release_interval_ms INTEGER
494
509
  ) RETURNS VOID AS $$
495
510
  BEGIN
496
511
  INSERT INTO ${t(e.schema)}."channel_policy" (
497
512
  "name",
498
513
  "max_size",
499
- "max_concurrency"
514
+ "max_concurrency",
515
+ "release_interval_ms"
500
516
  ) VALUES (
501
517
  p_name,
502
518
  p_max_size,
503
- p_max_concurrency
519
+ p_max_concurrency,
520
+ p_release_interval_ms
504
521
  ) ON CONFLICT ("name") DO UPDATE SET
505
522
  "max_size" = EXCLUDED."max_size",
506
- "max_concurrency" = EXCLUDED."max_concurrency";
523
+ "max_concurrency" = EXCLUDED."max_concurrency",
524
+ "release_interval_ms" = EXCLUDED."release_interval_ms";
507
525
 
508
526
  UPDATE ${t(e.schema)}."channel_state" SET
509
527
  "max_size" = p_max_size,
510
- "max_concurrency" = p_max_concurrency
528
+ "max_concurrency" = p_max_concurrency,
529
+ "release_interval_ms" = p_release_interval_ms
511
530
  WHERE "name" = p_name;
512
531
 
513
532
  PERFORM ${t(e.schema)}."wake"(0);
@@ -517,16 +536,32 @@ var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=
517
536
  CREATE FUNCTION ${t(e.schema)}."channel_policy_clear" (
518
537
  p_name TEXT
519
538
  ) RETURNS VOID AS $$
539
+ DECLARE
540
+ v_channel_state RECORD;
520
541
  BEGIN
521
542
  DELETE FROM ${t(e.schema)}."channel_policy"
522
543
  WHERE "name" = p_name;
523
544
 
524
- UPDATE ${t(e.schema)}."channel_state" SET
525
- "max_size" = NULL,
526
- "max_concurrency" = NULL
527
- WHERE "name" = p_name;
545
+ SELECT
546
+ "id",
547
+ "current_size"
548
+ FROM ${t(e.schema)}."channel_state"
549
+ WHERE "name" = p_name
550
+ FOR UPDATE
551
+ INTO v_channel_state;
552
+
553
+ IF v_channel_state."current_size" = 0 THEN
554
+ DELETE FROM ${t(e.schema)}."channel_state"
555
+ WHERE "id" = v_channel_state."id";
556
+ ELSE
557
+ UPDATE ${t(e.schema)}."channel_state" SET
558
+ "max_size" = NULL,
559
+ "max_concurrency" = NULL,
560
+ "release_interval_ms" = NULL
561
+ WHERE "name" = p_name;
562
+ END IF;
528
563
 
529
564
  PERFORM ${t(e.schema)}."wake"(0);
530
565
  END;
531
566
  $$ LANGUAGE plpgsql;
532
- `]}};class m{value;isSet;constructor(){this.isSet=!1,this.value=null}get(){return this.isSet?{resultType:"RESULT_SET",value:this.value}:{resultType:"RESULT_NOT_SET"}}set(e){this.isSet=!0,this.value=e}}class O{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}create(e){let n=new i({schema:this.schema,channelName:this.channelName,name:e.name,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs,priority:e.priority}),_=new m;return this.registerFn({sortKey:JSON.stringify([n.channelName,n.name,n.createdAt.toISOString()]),execute:(c)=>n.execute(c).then((u)=>_.set(u))}),_}}class D{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}set(e){let n=new o({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,maxSize:e.maxSize}),_=new m;return this.registerFn({sortKey:JSON.stringify([n.channelName,null,n.createdAt.toISOString()]),execute:(c)=>n.execute(c).then((u)=>_.set(u))}),_}clear(){let e=new E({schema:this.schema,channelName:this.channelName}),n=new m;return this.registerFn({sortKey:JSON.stringify([e.channelName,null,e.createdAt.toISOString()]),execute:(_)=>e.execute(_).then((c)=>n.set(c))}),n}}class U{policy;message;constructor(e){this.message=new O(e),this.policy=new D(e)}}var Ee=(e,n)=>{return e.sortKey.localeCompare(n.sortKey)};class y{commands;schema;constructor(e){this.commands=[],this.schema=e.schema}channel(e){return new U({schema:this.schema,channelName:e,registerFn:(n)=>{this.commands.push(n)}})}async execute(e){for(let n of this.commands.sort(Ee))await n.execute(e.databaseClient)}}class L{schema;channelName;constructor(e){this.schema=e.schema,this.channelName=e.channelName}async create(e){return new i({schema:this.schema,channelName:this.channelName,name:e.name,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs,priority:e.priority}).execute(e.databaseClient)}}class x{schema;channelName;constructor(e){this.schema=e.schema,this.channelName=e.channelName}set(e){return new o({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,maxSize:e.maxSize}).execute(e.databaseClient)}clear(e){return new E({schema:this.schema,channelName:this.channelName}).execute(e.databaseClient)}}class v{policy;message;constructor(e){this.message=new L({schema:e.schema,channelName:e.channelName}),this.policy=new x({schema:e.schema,channelName:e.channelName})}}class f{schema;id;channelName;name;content;dequeueId;state;numAttempts;lockMs;constructor(e){this.schema=e.schema,this.id=e.id,this.channelName=e.channelName,this.dequeueId=e.dequeueId,this.name=e.name,this.content=e.content,this.state=e.state,this.numAttempts=e.numAttempts,this.lockMs=e.lockMs}async defer(e){return new h({schema:this.schema,id:this.id,dequeueId:this.dequeueId,delayMs:e.delayMs,state:e.state,priority:e.priority}).execute(e.databaseClient)}async delete(e){return new d({schema:this.schema,id:this.id,dequeueId:this.dequeueId}).execute(e.databaseClient)}}class p{schema;constructor(e){this.schema=e}async dequeue(e){let _=await new l({schema:this.schema}).execute(e.databaseClient);if(_.resultType==="MESSAGE_DEQUEUED")return{resultType:"MESSAGE_DEQUEUED",message:new f({schema:this.schema,id:_.message.id,dequeueId:_.message.dequeueId,channelName:_.message.channelName,name:_.message.name,content:_.message.content,state:_.message.state,numAttempts:_.message.numAttempts,lockMs:_.message.lockMs})};else return _}channel(e){return new v({schema:this.schema,channelName:e})}batch(){return new y({schema:this.schema})}migrations(e){return[z,w,W,J,G,P,k,b,V,X].map((n)=>({name:n.name,sql:n.sql({schema:this.schema,useWake:e.useWake??M}).map((_)=>H(_.value))})).sort((n,_)=>n.name.localeCompare(_.name))}wakeChannel(){return N.toString(this.schema)}}
567
+ `]}};class m{value;isSet;constructor(){this.isSet=!1,this.value=null}get(){return this.isSet?{resultType:"RESULT_SET",value:this.value}:{resultType:"RESULT_NOT_SET"}}set(e){this.isSet=!0,this.value=e}}class A{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}create(e){let n=new i({schema:this.schema,channelName:this.channelName,name:e.name,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs,priority:e.priority}),_=new m;return this.registerFn({sortKey:JSON.stringify([n.channelName,n.name,n.createdAt.toISOString()]),execute:(c)=>n.execute(c).then((l)=>_.set(l))}),_}}class L{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}set(e){let n=new o({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,maxSize:e.maxSize,releaseIntervalMs:e.releaseIntervalMs}),_=new m;return this.registerFn({sortKey:JSON.stringify([n.channelName,null,n.createdAt.toISOString()]),execute:(c)=>n.execute(c).then((l)=>_.set(l))}),_}clear(){let e=new E({schema:this.schema,channelName:this.channelName}),n=new m;return this.registerFn({sortKey:JSON.stringify([e.channelName,null,e.createdAt.toISOString()]),execute:(_)=>e.execute(_).then((c)=>n.set(c))}),n}}class y{policy;message;constructor(e){this.message=new A(e),this.policy=new L(e)}}var Ee=(e,n)=>{return e.sortKey.localeCompare(n.sortKey)};class v{commands;schema;constructor(e){this.commands=[],this.schema=e.schema}channel(e){return new y({schema:this.schema,channelName:e,registerFn:(n)=>{this.commands.push(n)}})}async execute(e){for(let n of this.commands.sort(Ee))await n.execute(e.databaseClient)}}class D{schema;channelName;constructor(e){this.schema=e.schema,this.channelName=e.channelName}async create(e){return new i({schema:this.schema,channelName:this.channelName,name:e.name,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs,priority:e.priority}).execute(e.databaseClient)}}class x{schema;channelName;constructor(e){this.schema=e.schema,this.channelName=e.channelName}set(e){return new o({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,maxSize:e.maxSize,releaseIntervalMs:e.releaseIntervalMs}).execute(e.databaseClient)}clear(e){return new E({schema:this.schema,channelName:this.channelName}).execute(e.databaseClient)}}class U{policy;message;constructor(e){this.message=new D({schema:e.schema,channelName:e.channelName}),this.policy=new x({schema:e.schema,channelName:e.channelName})}}class f{schema;id;channelName;name;content;dequeueNonce;state;numAttempts;constructor(e){this.schema=e.schema,this.id=e.id,this.channelName=e.channelName,this.dequeueNonce=e.dequeueNonce,this.name=e.name,this.content=e.content,this.state=e.state,this.numAttempts=e.numAttempts}async defer(e){return new N({schema:this.schema,id:this.id,dequeueNonce:this.dequeueNonce,delayMs:e.delayMs,state:e.state,priority:e.priority}).execute(e.databaseClient)}async delete(e){return new h({schema:this.schema,id:this.id,dequeueNonce:this.dequeueNonce}).execute(e.databaseClient)}}class p{schema;constructor(e){this.schema=e}async dequeue(e){let _=await new u({schema:this.schema}).execute(e.databaseClient);if(_.resultType==="MESSAGE_DEQUEUED")return{resultType:"MESSAGE_DEQUEUED",message:new f({schema:this.schema,id:_.message.id,dequeueNonce:_.message.dequeueNonce,channelName:_.message.channelName,name:_.message.name,content:_.message.content,state:_.message.state,numAttempts:_.message.numAttempts})};else return _}channel(e){return new U({schema:this.schema,channelName:e})}batch(){return new v({schema:this.schema})}migrations(e){return[z,W,w,J,B,P,H,b,V,X].map((n)=>({name:n.name,sql:n.sql({schema:this.schema,useWake:e.useWake??M}).map((_)=>k(_.value))})).sort((n,_)=>n.name.localeCompare(_.name))}wakeChannel(){return T.toString(this.schema)}}
package/dist/index.d.ts CHANGED
@@ -35,23 +35,25 @@ export declare class ChannelPolicySetCommand {
35
35
  readonly channelName: string;
36
36
  readonly maxSize: number | null;
37
37
  readonly maxConcurrency: number | null;
38
+ readonly releaseIntervalMs: number | null;
38
39
  readonly createdAt: Date;
39
40
  constructor(params: {
40
41
  schema: string;
41
42
  channelName: string;
42
- maxSize: number | null;
43
- maxConcurrency: number | null;
43
+ maxSize?: number | null;
44
+ maxConcurrency?: number | null;
45
+ releaseIntervalMs?: number | null;
44
46
  });
45
47
  sortKeyGet(): string;
46
48
  execute(databaseClient: DatabaseClient): Promise<void>;
47
49
  }
48
50
  export type MessageCreateCommandResultMessageCreated = {
49
51
  resultType: "MESSAGE_CREATED";
50
- id: string;
52
+ id: bigint;
51
53
  };
52
54
  export type MessageCreateCommandResultMessageDeduplicated = {
53
55
  resultType: "MESSAGE_DEDUPLICATED";
54
- id: string;
56
+ id: bigint;
55
57
  };
56
58
  export type MessageCreateCommandResultMessageDropped = {
57
59
  resultType: "MESSAGE_DROPPED";
@@ -79,14 +81,13 @@ export declare class MessageCreateCommand {
79
81
  export type MessageDequeueCommandResultMessageDequeued = {
80
82
  resultType: "MESSAGE_DEQUEUED";
81
83
  message: {
82
- id: string;
84
+ id: bigint;
83
85
  channelName: string;
84
86
  name: string | null;
85
87
  content: string;
86
- dequeueId: string;
88
+ dequeueNonce: string;
87
89
  state: string | null;
88
90
  numAttempts: number;
89
- lockMs: number;
90
91
  };
91
92
  };
92
93
  export type MessageDequeueCommandResultMessageNotAvailable = {
@@ -113,12 +114,12 @@ export type MessageDeleteCommandResultMessageDeleted = {
113
114
  export type MessageDeleteCommandResult = MessageDeleteCommandResultMessageNotFound | MessageDeleteCommandResultStateInvalid | MessageDeleteCommandResultMessageDeleted;
114
115
  export declare class MessageDeleteCommand {
115
116
  readonly schema: string;
116
- readonly id: string;
117
- readonly dequeueId: string;
117
+ readonly id: bigint;
118
+ readonly dequeueNonce: string;
118
119
  constructor(params: {
119
120
  schema: string;
120
- id: string;
121
- dequeueId: string;
121
+ id: bigint;
122
+ dequeueNonce: string;
122
123
  });
123
124
  execute(databaseClient: DatabaseClient): Promise<MessageDeleteCommandResult>;
124
125
  }
@@ -134,14 +135,14 @@ export type MessageDeferCommandResultMessageDeferred = {
134
135
  export type MessageDeferCommandResult = MessageDeferCommandResultMessageNotFound | MessageDeferCommandResultStateInvalid | MessageDeferCommandResultMessageDeferred;
135
136
  export declare class MessageDeferCommand {
136
137
  readonly schema: string;
137
- readonly id: string;
138
- readonly dequeueId: string;
138
+ readonly id: bigint;
139
+ readonly dequeueNonce: string;
139
140
  readonly delayMs: number;
140
141
  readonly state: string | null;
141
142
  constructor(params: {
142
143
  schema: string;
143
- id: string;
144
- dequeueId: string;
144
+ id: bigint;
145
+ dequeueNonce: string;
145
146
  delayMs?: number;
146
147
  state?: string | null;
147
148
  priority?: boolean;
@@ -175,8 +176,9 @@ export declare class QueueBatchChannelPolicy {
175
176
  registerFn: BatchedCommandRegisterFn;
176
177
  });
177
178
  set(params: {
178
- maxConcurrency: number | null;
179
- maxSize: number | null;
179
+ maxConcurrency?: number | null;
180
+ maxSize?: number | null;
181
+ releaseIntervalMs?: number | null;
180
182
  }): Deferred<void>;
181
183
  clear(): Deferred<void>;
182
184
  }
@@ -230,8 +232,9 @@ export declare class QueueChannelPolicy {
230
232
  });
231
233
  set(params: {
232
234
  databaseClient: DatabaseClient;
233
- maxConcurrency: number | null;
234
- maxSize: number | null;
235
+ maxConcurrency?: number | null;
236
+ maxSize?: number | null;
237
+ releaseIntervalMs?: number | null;
235
238
  }): Promise<void>;
236
239
  clear(params: {
237
240
  databaseClient: DatabaseClient;
@@ -247,24 +250,22 @@ export declare class QueueChannel {
247
250
  }
248
251
  export declare class QueueMessage {
249
252
  private readonly schema;
250
- readonly id: string;
253
+ readonly id: bigint;
251
254
  readonly channelName: string;
252
255
  readonly name: string | null;
253
256
  readonly content: string;
254
- readonly dequeueId: string;
257
+ readonly dequeueNonce: string;
255
258
  readonly state: string | null;
256
259
  readonly numAttempts: number;
257
- readonly lockMs: number;
258
260
  constructor(params: {
259
261
  schema: string;
260
- id: string;
261
- dequeueId: string;
262
+ id: bigint;
263
+ dequeueNonce: string;
262
264
  channelName: string;
263
265
  name: string | null;
264
266
  content: string;
265
267
  state: string | null;
266
268
  numAttempts: number;
267
- lockMs: number;
268
269
  });
269
270
  defer(params: {
270
271
  databaseClient: DatabaseClient;
package/dist/index.js CHANGED
@@ -1,20 +1,21 @@
1
- var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=>({nodeType:"RAW",value:e}),V=(e)=>{return`'${e.replace(/'/g,"''")}'`},X=(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 throw new Error(`Unsupported value type: ${typeof e}`)},K=(e)=>{return`"${e.replace(/"/g,'""')}"`},Q=(e)=>{if(e.nodeType==="VALUE")return X(e.value);else if(e.nodeType==="REF")return K(e.value);else if(e.nodeType==="RAW")return e.value;else throw new Error("Unsupported SQL node type")};var a=(e,...t)=>{let _=[];for(let c=0;c<e.length;c+=1)if(_.push(e[c]),c<t.length)_.push(Q(t[c]));return J(_.join(""))};class E{schema;channelName;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.createdAt=new Date}sortKeyGet(){return JSON.stringify([this.channelName,null,this.createdAt.toISOString()])}async execute(e){await e.query(a`
1
+ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=>({nodeType:"RAW",value:e}),V=(e)=>{return`'${e.replace(/'/g,"''")}'`},X=(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}`)},K=(e)=>{return`"${e.replace(/"/g,'""')}"`},Q=(e)=>{if(e.nodeType==="VALUE")return X(e.value);else if(e.nodeType==="REF")return K(e.value);else if(e.nodeType==="RAW")return e.value;else throw new Error("Unsupported SQL node type")};var a=(e,...t)=>{let _=[];for(let c=0;c<e.length;c+=1)if(_.push(e[c]),c<t.length)_.push(Q(t[c]));return J(_.join(""))};class E{schema;channelName;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.createdAt=new Date}sortKeyGet(){return JSON.stringify([this.channelName,null,this.createdAt.toISOString()])}async execute(e){await e.query(a`
2
2
  SELECT 1 FROM ${n(this.schema)}."channel_policy_clear"(
3
3
  ${s(this.channelName)}
4
4
  )
5
- `.value)}}class o{schema;channelName;maxSize;maxConcurrency;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.maxConcurrency=e.maxConcurrency===null?null:Math.max(0,e.maxConcurrency),this.maxSize=e.maxSize===null?null:Math.max(0,e.maxSize),this.createdAt=new Date}sortKeyGet(){return JSON.stringify([this.channelName,null,this.createdAt.toISOString()])}async execute(e){await e.query(a`
5
+ `.value)}}class o{schema;channelName;maxSize;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 _=e.maxSize??null;this.maxSize=_!==null?Math.max(0,_):null;let c=e.releaseIntervalMs??null;this.releaseIntervalMs=c!==null?Math.max(0,c):null,this.createdAt=new Date}sortKeyGet(){return JSON.stringify([this.channelName,null,this.createdAt.toISOString()])}async execute(e){await e.query(a`
6
6
  SELECT 1 FROM ${n(this.schema)}."channel_policy_set"(
7
7
  ${s(this.channelName)},
8
- ${s(this.maxSize)}::BIGINT,
9
- ${s(this.maxConcurrency)}::BIGINT
8
+ ${s(this.maxSize)}::INTEGER,
9
+ ${s(this.maxConcurrency)}::INTEGER,
10
+ ${s(this.releaseIntervalMs)}::INTEGER
10
11
  )
11
- `.value)}}var g=(e)=>{return e*1000},Y=(e)=>{return g(e*60)},R=(e)=>{return Y(e*60)},v=(e)=>{return R(e*24)};import{createHash as j}from"node:crypto";class f{value;constructor(e){this.value=e}toString(e){return j("sha256").update(e).update(this.value).digest("base64").replace(/=/g,"")}}var l=new f("WAKE"),d=v(1000),p=!1,h=g(0),q=R(1);import{dirname as C}from"path";var __filename="/home/runner/work/lonnymq/lonnymq/src/core/path.ts",Z=C(C(__filename)),ee=new RegExp(`^${Z}/`),r=(e)=>{return e.replace(ee,"")};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/04-function-message-create.ts";var $={name:r(__filename),sql:(e)=>{return[a`
12
+ `.value)}}var S=(e)=>{return e*1000},Y=(e)=>{return S(e*60)},g=(e)=>{return Y(e*60)},U=(e)=>{return g(e*24)};import{createHash as j}from"node:crypto";class f{value;constructor(e){this.value=e}toString(e){return j("sha256").update(e).update(this.value).digest("base64").replace(/=/g,"")}}var u=new f("WAKE"),h=U(1000),p=!1,N=S(0),q=g(1);import{dirname as C}from"path";var __filename="/home/runner/work/lonnymq/lonnymq/src/core/path.ts",Z=C(C(__filename)),ee=new RegExp(`^${Z}/`),r=(e)=>{return e.replace(ee,"")};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/04-function-message-create.ts";var $={name:r(__filename),sql:(e)=>{return[a`
12
13
  CREATE FUNCTION ${n(e.schema)}."message_create" (
13
14
  p_channel_name TEXT,
14
15
  p_name TEXT,
15
16
  p_content TEXT,
16
- p_lock_ms BIGINT,
17
- p_delay_ms BIGINT
17
+ p_lock_ms INTEGER,
18
+ p_delay_ms INTEGER
18
19
  ) RETURNS JSONB AS $$
19
20
  DECLARE
20
21
  v_now TIMESTAMP;
@@ -27,7 +28,8 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
27
28
 
28
29
  SELECT
29
30
  "max_size",
30
- "max_concurrency"
31
+ "max_concurrency",
32
+ "release_interval_ms"
31
33
  FROM ${n(e.schema)}."channel_policy"
32
34
  WHERE "name" = p_channel_name
33
35
  FOR SHARE
@@ -39,6 +41,7 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
39
41
  "current_concurrency",
40
42
  "max_size",
41
43
  "max_concurrency",
44
+ "release_interval_ms",
42
45
  "message_next_id",
43
46
  "message_next_dequeue_after"
44
47
  ) VALUES (
@@ -47,6 +50,7 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
47
50
  0,
48
51
  v_channel_policy."max_size",
49
52
  v_channel_policy."max_concurrency",
53
+ v_channel_policy."release_interval_ms",
50
54
  NULL,
51
55
  NULL
52
56
  ) ON CONFLICT ("name")
@@ -119,20 +123,20 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
119
123
  );
120
124
  END;
121
125
  $$ LANGUAGE plpgsql;
122
- `]}};class i{schema;channelName;name;content;lockMs;delayMs;createdAt;constructor(e){let t=e.name??null,_=e.lockMs===void 0?q:Math.max(0,e.lockMs),c;if(e.priority)c=-d;else c=e.delayMs===void 0?h:Math.max(0,e.delayMs);this.schema=e.schema,this.channelName=e.channelName,this.content=e.content,this.name=t,this.lockMs=_,this.delayMs=c,this.createdAt=new Date}async execute(e){let t=await e.query(a`
126
+ `]}};class i{schema;channelName;name;content;lockMs;delayMs;createdAt;constructor(e){let t=e.name??null,_=e.lockMs===void 0?q:Math.max(0,e.lockMs),c;if(e.priority)c=-h;else c=e.delayMs===void 0?N:Math.max(0,e.delayMs);this.schema=e.schema,this.channelName=e.channelName,this.content=e.content,this.name=t,this.lockMs=_,this.delayMs=c,this.createdAt=new Date}async execute(e){let t=await e.query(a`
123
127
  SELECT ${n(this.schema)}."message_create"(
124
128
  ${s(this.channelName)},
125
129
  ${s(this.name)},
126
130
  ${s(this.content)},
127
- ${s(this.lockMs)}::BIGINT,
128
- ${s(this.delayMs)}::BIGINT
131
+ ${s(this.lockMs)}::INTEGER,
132
+ ${s(this.delayMs)}::INTEGER
129
133
  ) AS "result"
130
- `.value).then((_)=>_.rows[0].result);if(t.result_code===1)return{resultType:"MESSAGE_DROPPED"};else if(t.result_code===2)return{resultType:"MESSAGE_DEDUPLICATED",id:t.id};else if(t.result_code===0)return{resultType:"MESSAGE_CREATED",id:t.id};else throw new Error("Unexpected result")}}var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/05-function-message-dequeue.ts";var F={name:r(__filename),sql:(e)=>{return[a`
134
+ `.value).then((_)=>_.rows[0].result);if(t.result_code===1)return{resultType:"MESSAGE_DROPPED"};else if(t.result_code===2)return{resultType:"MESSAGE_DEDUPLICATED",id:BigInt(t.id)};else if(t.result_code===0)return{resultType:"MESSAGE_CREATED",id:BigInt(t.id)};else throw new Error("Unexpected result")}}var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/05-function-message-dequeue.ts";var F={name:r(__filename),sql:(e)=>{return[a`
131
135
  CREATE FUNCTION ${n(e.schema)}."message_dequeue" ()
132
136
  RETURNS JSONB AS $$
133
137
  DECLARE
134
138
  v_now TIMESTAMP;
135
- v_dequeue_id UUID;
139
+ v_dequeue_nonce UUID;
136
140
  v_channel_state RECORD;
137
141
  v_message_locked RECORD;
138
142
  v_retry_after TIMESTAMP;
@@ -141,7 +145,7 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
141
145
  v_message_next_dequeue_after TIMESTAMP;
142
146
  BEGIN
143
147
  v_now := NOW();
144
- v_dequeue_id := GEN_RANDOM_UUID();
148
+ v_dequeue_nonce := GEN_RANDOM_UUID();
145
149
 
146
150
  SELECT
147
151
  "id",
@@ -164,7 +168,7 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
164
168
  UPDATE ${n(e.schema)}."message" SET
165
169
  "num_attempts" = v_message_locked."num_attempts" + 1,
166
170
  "dequeue_after" = v_now + (v_message_locked."lock_ms" * INTERVAL '1 millisecond'),
167
- "dequeue_id" = v_dequeue_id
171
+ "dequeue_nonce" = v_dequeue_nonce
168
172
  WHERE "id" = v_message_locked."id";
169
173
 
170
174
  PERFORM ${n(e.schema)}."wake"(v_message_locked."lock_ms");
@@ -175,7 +179,7 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
175
179
  'channel_name', v_message_locked.channel_name,
176
180
  'state', v_message_locked.state,
177
181
  'name', v_message_locked.name,
178
- 'dequeue_id', v_dequeue_id,
182
+ 'dequeue_nonce', v_dequeue_nonce,
179
183
  'content', v_message_locked.content,
180
184
  'num_attempts', v_message_locked.num_attempts
181
185
  );
@@ -184,6 +188,7 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
184
188
  SELECT
185
189
  "id",
186
190
  "name",
191
+ "release_interval_ms",
187
192
  "message_next_id",
188
193
  "message_next_dequeue_after",
189
194
  "current_concurrency"
@@ -223,7 +228,7 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
223
228
  UPDATE ${n(e.schema)}."message" SET
224
229
  "is_locked" = TRUE,
225
230
  "num_attempts" = v_message_dequeue."num_attempts" + 1,
226
- "dequeue_id" = v_dequeue_id,
231
+ "dequeue_nonce" = v_dequeue_nonce,
227
232
  "dequeue_after" = v_now + (v_message_dequeue."lock_ms" * INTERVAL '1 millisecond')
228
233
  WHERE "id" = v_message_dequeue."id";
229
234
 
@@ -242,7 +247,7 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
242
247
  IF v_message_next_dequeue."id" IS NOT NULL THEN
243
248
  v_message_next_dequeue_after := GREATEST(
244
249
  v_message_next_dequeue."dequeue_after",
245
- v_now
250
+ v_now + (COALESCE(v_channel_state."release_interval_ms", 0) * INTERVAL '1 millisecond')
246
251
  );
247
252
 
248
253
  UPDATE ${n(e.schema)}."channel_state" SET
@@ -263,29 +268,30 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
263
268
  'id', v_message_dequeue.id,
264
269
  'channel_name', v_message_dequeue.channel_name,
265
270
  'state', v_message_dequeue.state,
266
- 'dequeue_id', v_dequeue_id,
271
+ 'dequeue_nonce', v_dequeue_nonce,
267
272
  'name', v_message_dequeue.name,
268
273
  'content', v_message_dequeue.content,
269
274
  'num_attempts', v_message_dequeue.num_attempts
270
275
  );
271
276
  END;
272
277
  $$ LANGUAGE plpgsql;
273
- `]}};class N{schema;constructor(e){this.schema=e.schema}async execute(e){let t=await e.query(a`
278
+ `]}};class T{schema;constructor(e){this.schema=e.schema}async execute(e){let t=await e.query(a`
274
279
  SELECT ${n(this.schema)}."message_dequeue"() AS "result"
275
- `.value).then((_)=>_.rows[0].result);if(t.result_code===0)return{resultType:"MESSAGE_NOT_AVAILABLE",retryMs:t.retry_ms};else if(t.result_code===1)return{resultType:"MESSAGE_DEQUEUED",message:{id:t.id,channelName:t.channel_name,name:t.name,content:t.content,dequeueId:t.dequeue_id,state:t.state,numAttempts:t.num_attempts,lockMs:t.lock_ms}};else throw new Error("Unexpected dequeue result")}}var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/06-function-message-delete.ts";var M={name:r(__filename),sql:(e)=>{return[a`
280
+ `.value).then((_)=>_.rows[0].result);if(t.result_code===0)return{resultType:"MESSAGE_NOT_AVAILABLE",retryMs:t.retry_ms};else if(t.result_code===1)return{resultType:"MESSAGE_DEQUEUED",message:{id:BigInt(t.id),channelName:t.channel_name,name:t.name,content:t.content,dequeueNonce:t.dequeue_nonce,state:t.state,numAttempts:t.num_attempts}};else throw new Error("Unexpected dequeue result")}}var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/06-function-message-delete.ts";var M={name:r(__filename),sql:(e)=>{return[a`
276
281
  CREATE FUNCTION ${n(e.schema)}."message_delete" (
277
- p_id UUID,
278
- p_dequeue_id UUID
282
+ p_id BIGINT,
283
+ p_dequeue_nonce UUID
279
284
  )
280
285
  RETURNS JSONB AS $$
281
286
  DECLARE
287
+ v_channel_policy RECORD;
282
288
  v_channel_state RECORD;
283
289
  v_message RECORD;
284
290
  BEGIN
285
291
  SELECT
286
292
  "id",
287
293
  "channel_name",
288
- "dequeue_id"
294
+ "dequeue_nonce"
289
295
  FROM ${n(e.schema)}."message"
290
296
  WHERE "id" = p_id
291
297
  FOR UPDATE
@@ -295,12 +301,19 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
295
301
  RETURN JSONB_BUILD_OBJECT(
296
302
  'result_code', ${s(0)}
297
303
  );
298
- ELSEIF v_message."dequeue_id" != p_dequeue_id THEN
304
+ ELSEIF v_message."dequeue_nonce" != p_dequeue_nonce THEN
299
305
  RETURN JSONB_BUILD_OBJECT(
300
306
  'result_code', ${s(1)}
301
307
  );
302
308
  END IF;
303
309
 
310
+ SELECT
311
+ "id"
312
+ FROM ${n(e.schema)}."channel_policy"
313
+ WHERE "name" = v_message."channel_name"
314
+ FOR SHARE
315
+ INTO v_channel_policy;
316
+
304
317
  SELECT
305
318
  "id",
306
319
  "current_size",
@@ -310,7 +323,7 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
310
323
  FOR UPDATE
311
324
  INTO v_channel_state;
312
325
 
313
- IF v_channel_state."current_size" = 1 THEN
326
+ IF v_channel_policy."id" IS NULL AND v_channel_state."current_size" = 1 THEN
314
327
  DELETE FROM ${n(e.schema)}."channel_state"
315
328
  WHERE "id" = v_channel_state."id";
316
329
  ELSE
@@ -328,15 +341,15 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
328
341
  );
329
342
  END;
330
343
  $$ LANGUAGE plpgsql;
331
- `]}};class T{schema;id;dequeueId;constructor(e){this.schema=e.schema,this.id=e.id,this.dequeueId=e.dequeueId}async execute(e){let t=await e.query(a`
344
+ `]}};class d{schema;id;dequeueNonce;constructor(e){this.schema=e.schema,this.id=e.id,this.dequeueNonce=e.dequeueNonce}async execute(e){let t=await e.query(a`
332
345
  SELECT ${n(this.schema)}."message_delete"( ${s(this.id)},
333
- ${s(this.dequeueId)}
346
+ ${s(this.dequeueNonce)}
334
347
  ) AS "result"
335
- `.value).then((_)=>_.rows[0].result);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")}}var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/07-function-message-defer.ts";var B={name:r(__filename),sql:(e)=>{return[a`
348
+ `.value).then((_)=>_.rows[0].result);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")}}var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/07-function-message-defer.ts";var G={name:r(__filename),sql:(e)=>{return[a`
336
349
  CREATE FUNCTION ${n(e.schema)}."message_defer" (
337
- p_id UUID,
338
- p_dequeue_id UUID,
339
- p_delay_ms BIGINT,
350
+ p_id BIGINT,
351
+ p_dequeue_nonce UUID,
352
+ p_delay_ms INTEGER,
340
353
  p_state TEXT
341
354
  )
342
355
  RETURNS JSONB AS $$
@@ -348,7 +361,7 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
348
361
  SELECT
349
362
  "id",
350
363
  "channel_name",
351
- "dequeue_id"
364
+ "dequeue_nonce"
352
365
  FROM ${n(e.schema)}."message"
353
366
  WHERE "id" = p_id
354
367
  FOR UPDATE
@@ -358,7 +371,7 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
358
371
  RETURN JSONB_BUILD_OBJECT(
359
372
  'result_code', ${s(0)}
360
373
  );
361
- ELSEIF v_message."dequeue_id" != p_dequeue_id THEN
374
+ ELSEIF v_message."dequeue_nonce" != p_dequeue_nonce THEN
362
375
  RETURN JSONB_BUILD_OBJECT(
363
376
  'result_code', ${s(1)}
364
377
  );
@@ -403,35 +416,37 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
403
416
  );
404
417
  END;
405
418
  $$ LANGUAGE plpgsql;
406
- `]}};class S{schema;id;dequeueId;delayMs;state;constructor(e){let t;if(e.priority)t=-d;else t=e.delayMs===void 0?h:Math.max(0,e.delayMs);this.schema=e.schema,this.id=e.id,this.dequeueId=e.dequeueId,this.delayMs=t,this.state=e.state??null}async execute(e){let t=await e.query(a`
419
+ `]}};class R{schema;id;dequeueNonce;delayMs;state;constructor(e){let t;if(e.priority)t=-h;else t=e.delayMs===void 0?N:Math.max(0,e.delayMs);this.schema=e.schema,this.id=e.id,this.dequeueNonce=e.dequeueNonce,this.delayMs=t,this.state=e.state??null}async execute(e){let t=await e.query(a`
407
420
  SELECT ${n(this.schema)}."message_defer"(
408
421
  ${s(this.id)},
409
- ${s(this.dequeueId)},
410
- ${s(this.delayMs)}::BIGINT,
422
+ ${s(this.dequeueNonce)},
423
+ ${s(this.delayMs)},
411
424
  ${s(this.state)}
412
425
  ) AS "result"
413
- `.value).then((_)=>_.rows[0].result);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")}}var G=(e)=>{let t=e.split(`
414
- `),_=Number.MAX_SAFE_INTEGER;for(let c of t){if(c.trim().length===0)continue;let u=c.search(/\S/);_=Math.min(_,u)}return t.map((c)=>c.slice(_)).join(`
426
+ `.value).then((_)=>_.rows[0].result);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")}}var B=(e)=>{let t=e.split(`
427
+ `),_=Number.MAX_SAFE_INTEGER;for(let c of t){if(c.trim().length===0)continue;let l=c.search(/\S/);_=Math.min(_,l)}return t.map((c)=>c.slice(_)).join(`
415
428
  `).trim()};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/00-table-channel-policy.ts",P={name:r(__filename),sql:(e)=>{return[a`
416
429
  CREATE TABLE ${n(e.schema)}."channel_policy" (
417
- "id" UUID NOT NULL DEFAULT GEN_RANDOM_UUID(),
430
+ "id" BIGSERIAL NOT NULL,
418
431
  "name" TEXT NOT NULL,
419
- "max_size" BIGINT,
420
- "max_concurrency" BIGINT,
432
+ "max_size" INTEGER,
433
+ "max_concurrency" INTEGER,
434
+ "release_interval_ms" INTEGER,
421
435
  PRIMARY KEY ("id")
422
436
  );
423
437
  `,a`
424
438
  CREATE UNIQUE INDEX "channel_policy_name_ux"
425
439
  ON ${n(e.schema)}."channel_policy" ("name");
426
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/01-table-channel-state.ts",k={name:r(__filename),sql:(e)=>{return[a`
440
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/01-table-channel-state.ts",H={name:r(__filename),sql:(e)=>{return[a`
427
441
  CREATE TABLE ${n(e.schema)}."channel_state" (
428
- "id" UUID NOT NULL DEFAULT GEN_RANDOM_UUID(),
442
+ "id" BIGSERIAL NOT NULL,
429
443
  "name" TEXT NOT NULL,
430
- "max_size" BIGINT,
431
- "max_concurrency" BIGINT,
432
- "current_size" BIGINT NOT NULL,
433
- "current_concurrency" BIGINT NOT NULL,
434
- "message_next_id" UUID,
444
+ "max_size" INTEGER,
445
+ "max_concurrency" INTEGER,
446
+ "release_interval_ms" INTEGER,
447
+ "current_size" INTEGER NOT NULL,
448
+ "current_concurrency" INTEGER NOT NULL,
449
+ "message_next_id" BIGINT,
435
450
  "message_next_dequeue_after" TIMESTAMP,
436
451
  PRIMARY KEY ("id")
437
452
  );
@@ -446,17 +461,16 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
446
461
  AND ("max_concurrency" IS NULL OR "current_concurrency" < "max_concurrency");
447
462
  `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/02-table-message.ts",b={name:r(__filename),sql:(e)=>{return[a`
448
463
  CREATE TABLE ${n(e.schema)}."message" (
449
- "id" UUID NOT NULL DEFAULT GEN_RANDOM_UUID(),
464
+ "id" BIGSERIAL NOT NULL,
450
465
  "channel_name" TEXT NOT NULL,
451
- "dequeue_id" UUID,
466
+ "dequeue_nonce" UUID,
452
467
  "name" TEXT,
453
468
  "content" TEXT NOT NULL,
454
469
  "state" TEXT,
455
- "lock_ms" BIGINT NOT NULL,
470
+ "lock_ms" INTEGER NOT NULL,
456
471
  "is_locked" BOOLEAN NOT NULL DEFAULT FALSE,
457
- "num_attempts" BIGINT NOT NULL DEFAULT 0,
472
+ "num_attempts" INTEGER NOT NULL DEFAULT 0,
458
473
  "dequeue_after" TIMESTAMP NOT NULL,
459
- "sweep_after" TIMESTAMP,
460
474
  PRIMARY KEY ("id")
461
475
  );
462
476
  `,a`
@@ -476,9 +490,9 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
476
490
  ON ${n(e.schema)}."message" (
477
491
  "dequeue_after" ASC
478
492
  ) WHERE "is_locked";
479
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/03-function-wake.ts",H={name:r(__filename),sql:(e)=>{let t=l.toString(e.schema);return[a`
493
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/03-function-wake.ts",k={name:r(__filename),sql:(e)=>{let t=u.toString(e.schema);return[a`
480
494
  CREATE FUNCTION ${n(e.schema)}."wake" (
481
- p_delay_ms BIGINT
495
+ p_delay_ms INTEGER
482
496
  ) RETURNS VOID AS $$
483
497
  BEGIN
484
498
  IF ${s(e.useWake)} THEN
@@ -489,44 +503,65 @@ var s=(e)=>({nodeType:"VALUE",value:e}),n=(e)=>({nodeType:"REF",value:e}),J=(e)=
489
503
  `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/08-function-channel-policy-set.ts",z={name:r(__filename),sql:(e)=>{return[a`
490
504
  CREATE FUNCTION ${n(e.schema)}."channel_policy_set" (
491
505
  p_name TEXT,
492
- p_max_size BIGINT,
493
- p_max_concurrency BIGINT
506
+ p_max_size INTEGER,
507
+ p_max_concurrency INTEGER,
508
+ p_release_interval_ms INTEGER
494
509
  ) RETURNS VOID AS $$
495
510
  BEGIN
496
511
  INSERT INTO ${n(e.schema)}."channel_policy" (
497
512
  "name",
498
513
  "max_size",
499
- "max_concurrency"
514
+ "max_concurrency",
515
+ "release_interval_ms"
500
516
  ) VALUES (
501
517
  p_name,
502
518
  p_max_size,
503
- p_max_concurrency
519
+ p_max_concurrency,
520
+ p_release_interval_ms
504
521
  ) ON CONFLICT ("name") DO UPDATE SET
505
522
  "max_size" = EXCLUDED."max_size",
506
- "max_concurrency" = EXCLUDED."max_concurrency";
523
+ "max_concurrency" = EXCLUDED."max_concurrency",
524
+ "release_interval_ms" = EXCLUDED."release_interval_ms";
507
525
 
508
526
  UPDATE ${n(e.schema)}."channel_state" SET
509
527
  "max_size" = p_max_size,
510
- "max_concurrency" = p_max_concurrency
528
+ "max_concurrency" = p_max_concurrency,
529
+ "release_interval_ms" = p_release_interval_ms
511
530
  WHERE "name" = p_name;
512
531
 
513
532
  PERFORM ${n(e.schema)}."wake"(0);
514
533
  END;
515
534
  $$ LANGUAGE plpgsql;
516
- `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/09-function-channel-policy-clear.ts",w={name:r(__filename),sql:(e)=>{return[a`
535
+ `]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/09-function-channel-policy-clear.ts",W={name:r(__filename),sql:(e)=>{return[a`
517
536
  CREATE FUNCTION ${n(e.schema)}."channel_policy_clear" (
518
537
  p_name TEXT
519
538
  ) RETURNS VOID AS $$
539
+ DECLARE
540
+ v_channel_state RECORD;
520
541
  BEGIN
521
542
  DELETE FROM ${n(e.schema)}."channel_policy"
522
543
  WHERE "name" = p_name;
523
544
 
524
- UPDATE ${n(e.schema)}."channel_state" SET
525
- "max_size" = NULL,
526
- "max_concurrency" = NULL
527
- WHERE "name" = p_name;
545
+ SELECT
546
+ "id",
547
+ "current_size"
548
+ FROM ${n(e.schema)}."channel_state"
549
+ WHERE "name" = p_name
550
+ FOR UPDATE
551
+ INTO v_channel_state;
552
+
553
+ IF v_channel_state."current_size" = 0 THEN
554
+ DELETE FROM ${n(e.schema)}."channel_state"
555
+ WHERE "id" = v_channel_state."id";
556
+ ELSE
557
+ UPDATE ${n(e.schema)}."channel_state" SET
558
+ "max_size" = NULL,
559
+ "max_concurrency" = NULL,
560
+ "release_interval_ms" = NULL
561
+ WHERE "name" = p_name;
562
+ END IF;
528
563
 
529
564
  PERFORM ${n(e.schema)}."wake"(0);
530
565
  END;
531
566
  $$ LANGUAGE plpgsql;
532
- `]}};class m{value;isSet;constructor(){this.isSet=!1,this.value=null}get(){return this.isSet?{resultType:"RESULT_SET",value:this.value}:{resultType:"RESULT_NOT_SET"}}set(e){this.isSet=!0,this.value=e}}class I{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}create(e){let t=new i({schema:this.schema,channelName:this.channelName,name:e.name,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs,priority:e.priority}),_=new m;return this.registerFn({sortKey:JSON.stringify([t.channelName,t.name,t.createdAt.toISOString()]),execute:(c)=>t.execute(c).then((u)=>_.set(u))}),_}}class A{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}set(e){let t=new o({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,maxSize:e.maxSize}),_=new m;return this.registerFn({sortKey:JSON.stringify([t.channelName,null,t.createdAt.toISOString()]),execute:(c)=>t.execute(c).then((u)=>_.set(u))}),_}clear(){let e=new E({schema:this.schema,channelName:this.channelName}),t=new m;return this.registerFn({sortKey:JSON.stringify([e.channelName,null,e.createdAt.toISOString()]),execute:(_)=>e.execute(_).then((c)=>t.set(c))}),t}}class O{policy;message;constructor(e){this.message=new I(e),this.policy=new A(e)}}var ne=(e,t)=>{return e.sortKey.localeCompare(t.sortKey)};class D{commands;schema;constructor(e){this.commands=[],this.schema=e.schema}channel(e){return new O({schema:this.schema,channelName:e,registerFn:(t)=>{this.commands.push(t)}})}async execute(e){for(let t of this.commands.sort(ne))await t.execute(e.databaseClient)}}class U{schema;channelName;constructor(e){this.schema=e.schema,this.channelName=e.channelName}async create(e){return new i({schema:this.schema,channelName:this.channelName,name:e.name,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs,priority:e.priority}).execute(e.databaseClient)}}class y{schema;channelName;constructor(e){this.schema=e.schema,this.channelName=e.channelName}set(e){return new o({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,maxSize:e.maxSize}).execute(e.databaseClient)}clear(e){return new E({schema:this.schema,channelName:this.channelName}).execute(e.databaseClient)}}class L{policy;message;constructor(e){this.message=new U({schema:e.schema,channelName:e.channelName}),this.policy=new y({schema:e.schema,channelName:e.channelName})}}class x{schema;id;channelName;name;content;dequeueId;state;numAttempts;lockMs;constructor(e){this.schema=e.schema,this.id=e.id,this.channelName=e.channelName,this.dequeueId=e.dequeueId,this.name=e.name,this.content=e.content,this.state=e.state,this.numAttempts=e.numAttempts,this.lockMs=e.lockMs}async defer(e){return new S({schema:this.schema,id:this.id,dequeueId:this.dequeueId,delayMs:e.delayMs,state:e.state,priority:e.priority}).execute(e.databaseClient)}async delete(e){return new T({schema:this.schema,id:this.id,dequeueId:this.dequeueId}).execute(e.databaseClient)}}class W{schema;constructor(e){this.schema=e}async dequeue(e){let _=await new N({schema:this.schema}).execute(e.databaseClient);if(_.resultType==="MESSAGE_DEQUEUED")return{resultType:"MESSAGE_DEQUEUED",message:new x({schema:this.schema,id:_.message.id,dequeueId:_.message.dequeueId,channelName:_.message.channelName,name:_.message.name,content:_.message.content,state:_.message.state,numAttempts:_.message.numAttempts,lockMs:_.message.lockMs})};else return _}channel(e){return new L({schema:this.schema,channelName:e})}batch(){return new D({schema:this.schema})}migrations(e){return[P,k,b,H,$,F,M,B,z,w].map((t)=>({name:t.name,sql:t.sql({schema:this.schema,useWake:e.useWake??p}).map((_)=>G(_.value))})).sort((t,_)=>t.name.localeCompare(_.name))}wakeChannel(){return l.toString(this.schema)}}export{W as Queue,N as MessageDequeueCommand,T as MessageDeleteCommand,S as MessageDeferCommand,i as MessageCreateCommand,o as ChannelPolicySetCommand,E as ChannelPolicyClearCommand};
567
+ `]}};class m{value;isSet;constructor(){this.isSet=!1,this.value=null}get(){return this.isSet?{resultType:"RESULT_SET",value:this.value}:{resultType:"RESULT_NOT_SET"}}set(e){this.isSet=!0,this.value=e}}class I{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}create(e){let t=new i({schema:this.schema,channelName:this.channelName,name:e.name,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs,priority:e.priority}),_=new m;return this.registerFn({sortKey:JSON.stringify([t.channelName,t.name,t.createdAt.toISOString()]),execute:(c)=>t.execute(c).then((l)=>_.set(l))}),_}}class O{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}set(e){let t=new o({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,maxSize:e.maxSize,releaseIntervalMs:e.releaseIntervalMs}),_=new m;return this.registerFn({sortKey:JSON.stringify([t.channelName,null,t.createdAt.toISOString()]),execute:(c)=>t.execute(c).then((l)=>_.set(l))}),_}clear(){let e=new E({schema:this.schema,channelName:this.channelName}),t=new m;return this.registerFn({sortKey:JSON.stringify([e.channelName,null,e.createdAt.toISOString()]),execute:(_)=>e.execute(_).then((c)=>t.set(c))}),t}}class A{policy;message;constructor(e){this.message=new I(e),this.policy=new O(e)}}var ne=(e,t)=>{return e.sortKey.localeCompare(t.sortKey)};class L{commands;schema;constructor(e){this.commands=[],this.schema=e.schema}channel(e){return new A({schema:this.schema,channelName:e,registerFn:(t)=>{this.commands.push(t)}})}async execute(e){for(let t of this.commands.sort(ne))await t.execute(e.databaseClient)}}class y{schema;channelName;constructor(e){this.schema=e.schema,this.channelName=e.channelName}async create(e){return new i({schema:this.schema,channelName:this.channelName,name:e.name,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs,priority:e.priority}).execute(e.databaseClient)}}class v{schema;channelName;constructor(e){this.schema=e.schema,this.channelName=e.channelName}set(e){return new o({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,maxSize:e.maxSize,releaseIntervalMs:e.releaseIntervalMs}).execute(e.databaseClient)}clear(e){return new E({schema:this.schema,channelName:this.channelName}).execute(e.databaseClient)}}class D{policy;message;constructor(e){this.message=new y({schema:e.schema,channelName:e.channelName}),this.policy=new v({schema:e.schema,channelName:e.channelName})}}class x{schema;id;channelName;name;content;dequeueNonce;state;numAttempts;constructor(e){this.schema=e.schema,this.id=e.id,this.channelName=e.channelName,this.dequeueNonce=e.dequeueNonce,this.name=e.name,this.content=e.content,this.state=e.state,this.numAttempts=e.numAttempts}async defer(e){return new R({schema:this.schema,id:this.id,dequeueNonce:this.dequeueNonce,delayMs:e.delayMs,state:e.state,priority:e.priority}).execute(e.databaseClient)}async delete(e){return new d({schema:this.schema,id:this.id,dequeueNonce:this.dequeueNonce}).execute(e.databaseClient)}}class w{schema;constructor(e){this.schema=e}async dequeue(e){let _=await new T({schema:this.schema}).execute(e.databaseClient);if(_.resultType==="MESSAGE_DEQUEUED")return{resultType:"MESSAGE_DEQUEUED",message:new x({schema:this.schema,id:_.message.id,dequeueNonce:_.message.dequeueNonce,channelName:_.message.channelName,name:_.message.name,content:_.message.content,state:_.message.state,numAttempts:_.message.numAttempts})};else return _}channel(e){return new D({schema:this.schema,channelName:e})}batch(){return new L({schema:this.schema})}migrations(e){return[P,H,b,k,$,F,M,G,z,W].map((t)=>({name:t.name,sql:t.sql({schema:this.schema,useWake:e.useWake??p}).map((_)=>B(_.value))})).sort((t,_)=>t.name.localeCompare(_.name))}wakeChannel(){return u.toString(this.schema)}}export{w as Queue,T as MessageDequeueCommand,d as MessageDeleteCommand,R as MessageDeferCommand,i as MessageCreateCommand,o as ChannelPolicySetCommand,E as ChannelPolicyClearCommand};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lonnymq",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -24,4 +24,4 @@
24
24
  "peerDependencies": {
25
25
  "typescript": "^5.0.0"
26
26
  }
27
- }
27
+ }