runlater-js 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # runlater-js
2
2
 
3
- Official Node.js SDK for [Runlater](https://runlater.eu) — delayed tasks, cron jobs, and reliable webhooks for any Node.js app. No Redis. No infrastructure. Just HTTP.
3
+ Official Node.js SDK for [Runlater](https://runlater.eu) — delayed tasks, cron jobs, message queues, and reliable webhooks for any Node.js app. No Redis. No infrastructure. Just HTTP.
4
4
 
5
5
  [Documentation](https://runlater.eu/docs) | [Dashboard](https://runlater.eu) | [npm](https://www.npmjs.com/package/runlater-js)
6
6
 
@@ -63,7 +63,7 @@ const result = await rl.send("https://myapp.com/api/webhook", {
63
63
  body: { key: "value" }, // automatically JSON-serialized
64
64
  retries: 5, // default: server default
65
65
  timeout: 30000, // ms, default: 30000
66
- queue: "emails", // optional: serialize execution within a queue
66
+ lane: "emails", // optional: serialize execution within a lane
67
67
  callback: "https://myapp.com/api/on-complete", // optional: receive result
68
68
  })
69
69
  // => { task_id, execution_id, status, scheduled_for }
@@ -129,6 +129,62 @@ const executions = await rl.tasks.executions("task-id")
129
129
  await rl.tasks.delete("task-id")
130
130
  ```
131
131
 
132
+ ### Message queues
133
+
134
+ Produce and consume messages with at-least-once delivery, visibility timeout, and dead-letter support.
135
+
136
+ ```js
137
+ // Create a queue
138
+ const queue = await rl.queues.create({
139
+ name: "order-events",
140
+ visibility_timeout_seconds: 30,
141
+ max_receives: 5,
142
+ })
143
+
144
+ // Enqueue a message
145
+ await rl.queues.enqueue("order-events", { orderId: 123, action: "process" })
146
+
147
+ // Enqueue multiple messages
148
+ await rl.queues.enqueueBatch("order-events", [
149
+ { orderId: 124, action: "process" },
150
+ { orderId: 125, action: "process" },
151
+ ])
152
+
153
+ // Receive messages (long-polling supported)
154
+ const messages = await rl.queues.receive("order-events", { max: 5, wait: 10 })
155
+
156
+ for (const msg of messages) {
157
+ // Process the message...
158
+ console.log(msg.body)
159
+
160
+ // Acknowledge when done
161
+ await rl.queues.ack("order-events", msg.receipt_handle)
162
+ }
163
+
164
+ // Nack a message to release it back to the queue
165
+ await rl.queues.nack("order-events", msg.receipt_handle)
166
+
167
+ // Batch acknowledge
168
+ await rl.queues.ackBatch("order-events", ["receipt_1", "receipt_2"])
169
+
170
+ // Get queue stats
171
+ const stats = await rl.queues.stats("order-events")
172
+ // => { available, locked, completed, dead, total, avg_time_in_queue_seconds, avg_processing_time_seconds }
173
+
174
+ // List all queues
175
+ const queues = await rl.queues.list()
176
+
177
+ // Pause / resume
178
+ await rl.queues.pause("order-events")
179
+ await rl.queues.resume("order-events")
180
+
181
+ // Browse messages
182
+ const msgs = await rl.queues.messages("order-events", { status: "available", limit: 10 })
183
+
184
+ // Delete a queue
185
+ await rl.queues.delete("order-events")
186
+ ```
187
+
132
188
  ### Monitors (dead man's switch)
133
189
 
134
190
  ```js
package/dist/index.d.mts CHANGED
@@ -8,7 +8,7 @@ interface SendOptions {
8
8
  body?: unknown;
9
9
  retries?: number;
10
10
  timeout?: number;
11
- queue?: string;
11
+ lane?: string;
12
12
  callback?: string;
13
13
  idempotencyKey?: string;
14
14
  on_failure_url?: string;
@@ -31,7 +31,7 @@ interface CronOptions {
31
31
  body?: unknown;
32
32
  timeout?: number;
33
33
  retries?: number;
34
- queue?: string;
34
+ lane?: string;
35
35
  callback?: string;
36
36
  enabled?: boolean;
37
37
  on_failure_url?: string;
@@ -126,7 +126,7 @@ interface Task {
126
126
  timeout_ms: number;
127
127
  retry_attempts: number;
128
128
  callback_url: string | null;
129
- queue: string | null;
129
+ lane: string | null;
130
130
  notify_on_failure: boolean | null;
131
131
  notify_on_recovery: boolean | null;
132
132
  on_failure_url: string | null;
@@ -149,7 +149,7 @@ interface Execution {
149
149
  script_logs: string[];
150
150
  }
151
151
  interface ListOptions {
152
- queue?: string;
152
+ lane?: string;
153
153
  limit?: number;
154
154
  offset?: number;
155
155
  }
@@ -184,10 +184,16 @@ interface Monitor {
184
184
  inserted_at: string;
185
185
  updated_at: string;
186
186
  }
187
- interface BatchOptions {
187
+ interface BatchTask {
188
188
  url: string;
189
- queue: string;
190
- items: unknown[];
189
+ method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
190
+ headers?: Record<string, string>;
191
+ body?: unknown;
192
+ name?: string;
193
+ }
194
+ interface BatchOptions {
195
+ lane: string;
196
+ tasks: BatchTask[];
191
197
  method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
192
198
  headers?: Record<string, string>;
193
199
  run_at?: string | Date;
@@ -197,11 +203,11 @@ interface BatchOptions {
197
203
  callback?: string;
198
204
  }
199
205
  interface BatchResponse {
200
- queue: string;
206
+ lane: string;
201
207
  created: number;
202
208
  scheduled_for: string;
203
209
  }
204
- interface CancelQueueResponse {
210
+ interface CancelLaneResponse {
205
211
  cancelled: number;
206
212
  }
207
213
  interface UpdateTaskOptions {
@@ -215,7 +221,7 @@ interface UpdateTaskOptions {
215
221
  timeout_ms?: number;
216
222
  retry_attempts?: number;
217
223
  callback_url?: string;
218
- queue?: string;
224
+ lane?: string;
219
225
  enabled?: boolean;
220
226
  notify_on_failure?: boolean | null;
221
227
  notify_on_recovery?: boolean | null;
@@ -283,7 +289,7 @@ interface Endpoint {
283
289
  enabled: boolean;
284
290
  paused: boolean;
285
291
  retry_attempts: number;
286
- use_queue: boolean;
292
+ use_lane: boolean;
287
293
  notify_on_failure: boolean | null;
288
294
  notify_on_recovery: boolean | null;
289
295
  on_failure_url: string | null;
@@ -300,7 +306,7 @@ interface CreateEndpointOptions {
300
306
  name: string;
301
307
  forward_urls: string[];
302
308
  retry_attempts?: number;
303
- use_queue?: boolean;
309
+ use_lane?: boolean;
304
310
  enabled?: boolean;
305
311
  forward_headers?: Record<string, string>;
306
312
  forward_body?: string;
@@ -312,7 +318,7 @@ interface UpdateEndpointOptions {
312
318
  name?: string;
313
319
  forward_urls?: string[];
314
320
  retry_attempts?: number;
315
- use_queue?: boolean;
321
+ use_lane?: boolean;
316
322
  enabled?: boolean;
317
323
  forward_headers?: Record<string, string>;
318
324
  forward_body?: string;
@@ -329,6 +335,59 @@ interface InboundEvent {
329
335
  lua_rejected: boolean;
330
336
  lua_logs: string[];
331
337
  }
338
+ interface MessageQueue {
339
+ id: string;
340
+ name: string;
341
+ slug: string;
342
+ visibility_timeout_seconds: number;
343
+ max_receives: number;
344
+ paused: boolean;
345
+ inserted_at: string;
346
+ updated_at: string;
347
+ }
348
+ interface CreateMessageQueueOptions {
349
+ name: string;
350
+ visibility_timeout_seconds?: number;
351
+ max_receives?: number;
352
+ }
353
+ interface UpdateMessageQueueOptions {
354
+ name?: string;
355
+ visibility_timeout_seconds?: number;
356
+ max_receives?: number;
357
+ }
358
+ interface MqMessage {
359
+ id: string;
360
+ body: unknown;
361
+ status: string;
362
+ receipt_handle: string | null;
363
+ receive_count: number;
364
+ locked_until: string | null;
365
+ first_received_at: string | null;
366
+ completed_at: string | null;
367
+ inserted_at: string;
368
+ }
369
+ interface MqStats {
370
+ available: number;
371
+ locked: number;
372
+ completed: number;
373
+ dead: number;
374
+ total: number;
375
+ avg_time_in_queue_seconds: number | null;
376
+ avg_processing_time_seconds: number | null;
377
+ }
378
+ interface MqReceiveOptions {
379
+ max?: number;
380
+ wait?: number;
381
+ }
382
+ interface MqListMessagesOptions {
383
+ status?: string;
384
+ limit?: number;
385
+ offset?: number;
386
+ }
387
+ interface MqBatchAckResponse {
388
+ acknowledged: number;
389
+ failed: number;
390
+ }
332
391
  declare class RunlaterError extends Error {
333
392
  status: number;
334
393
  code: string;
@@ -342,6 +401,7 @@ declare class Runlater {
342
401
  monitors: Monitors;
343
402
  endpoints: Endpoints;
344
403
  schedules: Schedules;
404
+ queues: MessageQueues;
345
405
  constructor(options: RunlaterOptions | string);
346
406
  /**
347
407
  * Send a request immediately with reliable delivery and retries.
@@ -423,36 +483,36 @@ declare class Tasks {
423
483
  update(id: string, options: UpdateTaskOptions): Promise<Task>;
424
484
  executions(id: string, limit?: number): Promise<Execution[]>;
425
485
  /**
426
- * Create many tasks at once with shared configuration.
486
+ * Create many tasks at once. Each task defines its own URL and can
487
+ * optionally override method, headers, body, and name. Top-level
488
+ * settings serve as defaults.
427
489
  *
428
- * Each item in the array becomes the request body for one task.
429
- * All tasks share the same URL, method, headers, timing, and queue.
430
- * Use the queue name with `cancelQueue()` to cancel them as a group.
490
+ * Use the lane name with `cancelLane()` to cancel them as a group.
431
491
  *
432
492
  * ```js
433
493
  * await rl.tasks.batch({
434
- * url: "https://myapp.com/api/send-email",
435
- * queue: "march-newsletter",
494
+ * lane: "march-newsletter",
495
+ * method: "POST",
436
496
  * run_at: "2026-03-01T09:00:00Z",
437
- * items: [
438
- * { to: "user1@example.com", name: "Alice" },
439
- * { to: "user2@example.com", name: "Bob" },
497
+ * tasks: [
498
+ * { url: "https://myapp.com/api/send-email", body: { to: "alice@example.com" } },
499
+ * { url: "https://myapp.com/api/send-sms", body: { to: "+1234567890" } },
440
500
  * ]
441
501
  * })
442
502
  * ```
443
503
  */
444
504
  batch(options: BatchOptions): Promise<BatchResponse>;
445
505
  /**
446
- * Cancel all tasks in a queue.
506
+ * Cancel all tasks in a lane.
447
507
  *
448
- * Soft-deletes every task in the queue and removes their pending executions.
508
+ * Soft-deletes every task in the lane and removes their pending executions.
449
509
  *
450
510
  * ```js
451
- * const { cancelled } = await rl.tasks.cancelQueue("march-newsletter")
511
+ * const { cancelled } = await rl.tasks.cancelLane("march-newsletter")
452
512
  * console.log(`Cancelled ${cancelled} tasks`)
453
513
  * ```
454
514
  */
455
- cancelQueue(queue: string): Promise<CancelQueueResponse>;
515
+ cancelLane(lane: string): Promise<CancelLaneResponse>;
456
516
  }
457
517
  declare class Schedules {
458
518
  private client;
@@ -489,5 +549,43 @@ declare class Endpoints {
489
549
  pause(id: string): Promise<Endpoint>;
490
550
  resume(id: string): Promise<Endpoint>;
491
551
  }
552
+ declare class MessageQueues {
553
+ private client;
554
+ constructor(client: Runlater);
555
+ /** List all message queues. */
556
+ list(): Promise<MessageQueue[]>;
557
+ /** Create a new message queue. */
558
+ create(options: CreateMessageQueueOptions): Promise<MessageQueue>;
559
+ /** Get a message queue by slug. */
560
+ get(slug: string): Promise<MessageQueue>;
561
+ /** Update a message queue. */
562
+ update(slug: string, options: UpdateMessageQueueOptions): Promise<MessageQueue>;
563
+ /** Delete a message queue. */
564
+ delete(slug: string): Promise<void>;
565
+ /** Get queue statistics. */
566
+ stats(slug: string): Promise<MqStats>;
567
+ /** Enqueue a single message. */
568
+ enqueue(slug: string, body: unknown): Promise<MqMessage>;
569
+ /** Enqueue multiple messages at once. */
570
+ enqueueBatch(slug: string, messages: unknown[]): Promise<{
571
+ enqueued: number;
572
+ }>;
573
+ /** Receive messages from the queue. */
574
+ receive(slug: string, options?: MqReceiveOptions): Promise<MqMessage[]>;
575
+ /** Acknowledge (complete) a message by receipt handle. */
576
+ ack(slug: string, receiptHandle: string): Promise<void>;
577
+ /** Nack (release) a message back to the queue. */
578
+ nack(slug: string, receiptHandle: string): Promise<void>;
579
+ /** Acknowledge multiple messages at once. */
580
+ ackBatch(slug: string, receiptHandles: string[]): Promise<MqBatchAckResponse>;
581
+ /** List messages in the queue with optional filtering. */
582
+ messages(slug: string, options?: MqListMessagesOptions): Promise<MqMessage[]>;
583
+ /** Get a specific message by ID. */
584
+ getMessage(slug: string, id: string): Promise<MqMessage>;
585
+ /** Pause the queue. */
586
+ pause(slug: string): Promise<MessageQueue>;
587
+ /** Resume a paused queue. */
588
+ resume(slug: string): Promise<MessageQueue>;
589
+ }
492
590
 
493
- export { type BatchOptions, type BatchResponse, type CancelQueueResponse, type CreateEndpointOptions, type CreateMonitorOptions, type CreateScheduleOptions, type CronOptions, type CronResponse, type DelayOptions, type Endpoint, type Execution, type InboundEvent, type ListOptions, type ListResponse, type Monitor, type Ping, type PingResponse, Runlater, RunlaterError, type RunlaterOptions, type Schedule, type ScheduleOptions, type SendOptions, type SyncOptions, type SyncResponse, type Task, type TaskResponse, type TriggerResponse, type UpdateEndpointOptions, type UpdateMonitorOptions, type UpdateScheduleOptions, type UpdateTaskOptions };
591
+ export { type BatchOptions, type BatchResponse, type BatchTask, type CancelLaneResponse, type CreateEndpointOptions, type CreateMessageQueueOptions, type CreateMonitorOptions, type CreateScheduleOptions, type CronOptions, type CronResponse, type DelayOptions, type Endpoint, type Execution, type InboundEvent, type ListOptions, type ListResponse, type MessageQueue, type Monitor, type MqBatchAckResponse, type MqListMessagesOptions, type MqMessage, type MqReceiveOptions, type MqStats, type Ping, type PingResponse, Runlater, RunlaterError, type RunlaterOptions, type Schedule, type ScheduleOptions, type SendOptions, type SyncOptions, type SyncResponse, type Task, type TaskResponse, type TriggerResponse, type UpdateEndpointOptions, type UpdateMessageQueueOptions, type UpdateMonitorOptions, type UpdateScheduleOptions, type UpdateTaskOptions };
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ interface SendOptions {
8
8
  body?: unknown;
9
9
  retries?: number;
10
10
  timeout?: number;
11
- queue?: string;
11
+ lane?: string;
12
12
  callback?: string;
13
13
  idempotencyKey?: string;
14
14
  on_failure_url?: string;
@@ -31,7 +31,7 @@ interface CronOptions {
31
31
  body?: unknown;
32
32
  timeout?: number;
33
33
  retries?: number;
34
- queue?: string;
34
+ lane?: string;
35
35
  callback?: string;
36
36
  enabled?: boolean;
37
37
  on_failure_url?: string;
@@ -126,7 +126,7 @@ interface Task {
126
126
  timeout_ms: number;
127
127
  retry_attempts: number;
128
128
  callback_url: string | null;
129
- queue: string | null;
129
+ lane: string | null;
130
130
  notify_on_failure: boolean | null;
131
131
  notify_on_recovery: boolean | null;
132
132
  on_failure_url: string | null;
@@ -149,7 +149,7 @@ interface Execution {
149
149
  script_logs: string[];
150
150
  }
151
151
  interface ListOptions {
152
- queue?: string;
152
+ lane?: string;
153
153
  limit?: number;
154
154
  offset?: number;
155
155
  }
@@ -184,10 +184,16 @@ interface Monitor {
184
184
  inserted_at: string;
185
185
  updated_at: string;
186
186
  }
187
- interface BatchOptions {
187
+ interface BatchTask {
188
188
  url: string;
189
- queue: string;
190
- items: unknown[];
189
+ method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
190
+ headers?: Record<string, string>;
191
+ body?: unknown;
192
+ name?: string;
193
+ }
194
+ interface BatchOptions {
195
+ lane: string;
196
+ tasks: BatchTask[];
191
197
  method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
192
198
  headers?: Record<string, string>;
193
199
  run_at?: string | Date;
@@ -197,11 +203,11 @@ interface BatchOptions {
197
203
  callback?: string;
198
204
  }
199
205
  interface BatchResponse {
200
- queue: string;
206
+ lane: string;
201
207
  created: number;
202
208
  scheduled_for: string;
203
209
  }
204
- interface CancelQueueResponse {
210
+ interface CancelLaneResponse {
205
211
  cancelled: number;
206
212
  }
207
213
  interface UpdateTaskOptions {
@@ -215,7 +221,7 @@ interface UpdateTaskOptions {
215
221
  timeout_ms?: number;
216
222
  retry_attempts?: number;
217
223
  callback_url?: string;
218
- queue?: string;
224
+ lane?: string;
219
225
  enabled?: boolean;
220
226
  notify_on_failure?: boolean | null;
221
227
  notify_on_recovery?: boolean | null;
@@ -283,7 +289,7 @@ interface Endpoint {
283
289
  enabled: boolean;
284
290
  paused: boolean;
285
291
  retry_attempts: number;
286
- use_queue: boolean;
292
+ use_lane: boolean;
287
293
  notify_on_failure: boolean | null;
288
294
  notify_on_recovery: boolean | null;
289
295
  on_failure_url: string | null;
@@ -300,7 +306,7 @@ interface CreateEndpointOptions {
300
306
  name: string;
301
307
  forward_urls: string[];
302
308
  retry_attempts?: number;
303
- use_queue?: boolean;
309
+ use_lane?: boolean;
304
310
  enabled?: boolean;
305
311
  forward_headers?: Record<string, string>;
306
312
  forward_body?: string;
@@ -312,7 +318,7 @@ interface UpdateEndpointOptions {
312
318
  name?: string;
313
319
  forward_urls?: string[];
314
320
  retry_attempts?: number;
315
- use_queue?: boolean;
321
+ use_lane?: boolean;
316
322
  enabled?: boolean;
317
323
  forward_headers?: Record<string, string>;
318
324
  forward_body?: string;
@@ -329,6 +335,59 @@ interface InboundEvent {
329
335
  lua_rejected: boolean;
330
336
  lua_logs: string[];
331
337
  }
338
+ interface MessageQueue {
339
+ id: string;
340
+ name: string;
341
+ slug: string;
342
+ visibility_timeout_seconds: number;
343
+ max_receives: number;
344
+ paused: boolean;
345
+ inserted_at: string;
346
+ updated_at: string;
347
+ }
348
+ interface CreateMessageQueueOptions {
349
+ name: string;
350
+ visibility_timeout_seconds?: number;
351
+ max_receives?: number;
352
+ }
353
+ interface UpdateMessageQueueOptions {
354
+ name?: string;
355
+ visibility_timeout_seconds?: number;
356
+ max_receives?: number;
357
+ }
358
+ interface MqMessage {
359
+ id: string;
360
+ body: unknown;
361
+ status: string;
362
+ receipt_handle: string | null;
363
+ receive_count: number;
364
+ locked_until: string | null;
365
+ first_received_at: string | null;
366
+ completed_at: string | null;
367
+ inserted_at: string;
368
+ }
369
+ interface MqStats {
370
+ available: number;
371
+ locked: number;
372
+ completed: number;
373
+ dead: number;
374
+ total: number;
375
+ avg_time_in_queue_seconds: number | null;
376
+ avg_processing_time_seconds: number | null;
377
+ }
378
+ interface MqReceiveOptions {
379
+ max?: number;
380
+ wait?: number;
381
+ }
382
+ interface MqListMessagesOptions {
383
+ status?: string;
384
+ limit?: number;
385
+ offset?: number;
386
+ }
387
+ interface MqBatchAckResponse {
388
+ acknowledged: number;
389
+ failed: number;
390
+ }
332
391
  declare class RunlaterError extends Error {
333
392
  status: number;
334
393
  code: string;
@@ -342,6 +401,7 @@ declare class Runlater {
342
401
  monitors: Monitors;
343
402
  endpoints: Endpoints;
344
403
  schedules: Schedules;
404
+ queues: MessageQueues;
345
405
  constructor(options: RunlaterOptions | string);
346
406
  /**
347
407
  * Send a request immediately with reliable delivery and retries.
@@ -423,36 +483,36 @@ declare class Tasks {
423
483
  update(id: string, options: UpdateTaskOptions): Promise<Task>;
424
484
  executions(id: string, limit?: number): Promise<Execution[]>;
425
485
  /**
426
- * Create many tasks at once with shared configuration.
486
+ * Create many tasks at once. Each task defines its own URL and can
487
+ * optionally override method, headers, body, and name. Top-level
488
+ * settings serve as defaults.
427
489
  *
428
- * Each item in the array becomes the request body for one task.
429
- * All tasks share the same URL, method, headers, timing, and queue.
430
- * Use the queue name with `cancelQueue()` to cancel them as a group.
490
+ * Use the lane name with `cancelLane()` to cancel them as a group.
431
491
  *
432
492
  * ```js
433
493
  * await rl.tasks.batch({
434
- * url: "https://myapp.com/api/send-email",
435
- * queue: "march-newsletter",
494
+ * lane: "march-newsletter",
495
+ * method: "POST",
436
496
  * run_at: "2026-03-01T09:00:00Z",
437
- * items: [
438
- * { to: "user1@example.com", name: "Alice" },
439
- * { to: "user2@example.com", name: "Bob" },
497
+ * tasks: [
498
+ * { url: "https://myapp.com/api/send-email", body: { to: "alice@example.com" } },
499
+ * { url: "https://myapp.com/api/send-sms", body: { to: "+1234567890" } },
440
500
  * ]
441
501
  * })
442
502
  * ```
443
503
  */
444
504
  batch(options: BatchOptions): Promise<BatchResponse>;
445
505
  /**
446
- * Cancel all tasks in a queue.
506
+ * Cancel all tasks in a lane.
447
507
  *
448
- * Soft-deletes every task in the queue and removes their pending executions.
508
+ * Soft-deletes every task in the lane and removes their pending executions.
449
509
  *
450
510
  * ```js
451
- * const { cancelled } = await rl.tasks.cancelQueue("march-newsletter")
511
+ * const { cancelled } = await rl.tasks.cancelLane("march-newsletter")
452
512
  * console.log(`Cancelled ${cancelled} tasks`)
453
513
  * ```
454
514
  */
455
- cancelQueue(queue: string): Promise<CancelQueueResponse>;
515
+ cancelLane(lane: string): Promise<CancelLaneResponse>;
456
516
  }
457
517
  declare class Schedules {
458
518
  private client;
@@ -489,5 +549,43 @@ declare class Endpoints {
489
549
  pause(id: string): Promise<Endpoint>;
490
550
  resume(id: string): Promise<Endpoint>;
491
551
  }
552
+ declare class MessageQueues {
553
+ private client;
554
+ constructor(client: Runlater);
555
+ /** List all message queues. */
556
+ list(): Promise<MessageQueue[]>;
557
+ /** Create a new message queue. */
558
+ create(options: CreateMessageQueueOptions): Promise<MessageQueue>;
559
+ /** Get a message queue by slug. */
560
+ get(slug: string): Promise<MessageQueue>;
561
+ /** Update a message queue. */
562
+ update(slug: string, options: UpdateMessageQueueOptions): Promise<MessageQueue>;
563
+ /** Delete a message queue. */
564
+ delete(slug: string): Promise<void>;
565
+ /** Get queue statistics. */
566
+ stats(slug: string): Promise<MqStats>;
567
+ /** Enqueue a single message. */
568
+ enqueue(slug: string, body: unknown): Promise<MqMessage>;
569
+ /** Enqueue multiple messages at once. */
570
+ enqueueBatch(slug: string, messages: unknown[]): Promise<{
571
+ enqueued: number;
572
+ }>;
573
+ /** Receive messages from the queue. */
574
+ receive(slug: string, options?: MqReceiveOptions): Promise<MqMessage[]>;
575
+ /** Acknowledge (complete) a message by receipt handle. */
576
+ ack(slug: string, receiptHandle: string): Promise<void>;
577
+ /** Nack (release) a message back to the queue. */
578
+ nack(slug: string, receiptHandle: string): Promise<void>;
579
+ /** Acknowledge multiple messages at once. */
580
+ ackBatch(slug: string, receiptHandles: string[]): Promise<MqBatchAckResponse>;
581
+ /** List messages in the queue with optional filtering. */
582
+ messages(slug: string, options?: MqListMessagesOptions): Promise<MqMessage[]>;
583
+ /** Get a specific message by ID. */
584
+ getMessage(slug: string, id: string): Promise<MqMessage>;
585
+ /** Pause the queue. */
586
+ pause(slug: string): Promise<MessageQueue>;
587
+ /** Resume a paused queue. */
588
+ resume(slug: string): Promise<MessageQueue>;
589
+ }
492
590
 
493
- export { type BatchOptions, type BatchResponse, type CancelQueueResponse, type CreateEndpointOptions, type CreateMonitorOptions, type CreateScheduleOptions, type CronOptions, type CronResponse, type DelayOptions, type Endpoint, type Execution, type InboundEvent, type ListOptions, type ListResponse, type Monitor, type Ping, type PingResponse, Runlater, RunlaterError, type RunlaterOptions, type Schedule, type ScheduleOptions, type SendOptions, type SyncOptions, type SyncResponse, type Task, type TaskResponse, type TriggerResponse, type UpdateEndpointOptions, type UpdateMonitorOptions, type UpdateScheduleOptions, type UpdateTaskOptions };
591
+ export { type BatchOptions, type BatchResponse, type BatchTask, type CancelLaneResponse, type CreateEndpointOptions, type CreateMessageQueueOptions, type CreateMonitorOptions, type CreateScheduleOptions, type CronOptions, type CronResponse, type DelayOptions, type Endpoint, type Execution, type InboundEvent, type ListOptions, type ListResponse, type MessageQueue, type Monitor, type MqBatchAckResponse, type MqListMessagesOptions, type MqMessage, type MqReceiveOptions, type MqStats, type Ping, type PingResponse, Runlater, RunlaterError, type RunlaterOptions, type Schedule, type ScheduleOptions, type SendOptions, type SyncOptions, type SyncResponse, type Task, type TaskResponse, type TriggerResponse, type UpdateEndpointOptions, type UpdateMessageQueueOptions, type UpdateMonitorOptions, type UpdateScheduleOptions, type UpdateTaskOptions };
package/dist/index.js CHANGED
@@ -46,6 +46,7 @@ var Runlater = class {
46
46
  monitors;
47
47
  endpoints;
48
48
  schedules;
49
+ queues;
49
50
  constructor(options) {
50
51
  if (typeof options === "string") {
51
52
  this.apiKey = options;
@@ -58,6 +59,7 @@ var Runlater = class {
58
59
  this.monitors = new Monitors(this);
59
60
  this.endpoints = new Endpoints(this);
60
61
  this.schedules = new Schedules(this);
62
+ this.queues = new MessageQueues(this);
61
63
  }
62
64
  /**
63
65
  * Send a request immediately with reliable delivery and retries.
@@ -142,7 +144,7 @@ var Runlater = class {
142
144
  body: options.body != null ? JSON.stringify(options.body) : void 0,
143
145
  timeout_ms: options.timeout,
144
146
  retry_attempts: options.retries,
145
- queue: options.queue,
147
+ lane: options.lane,
146
148
  callback_url: options.callback,
147
149
  enabled: options.enabled,
148
150
  script: options.script
@@ -175,7 +177,7 @@ var Runlater = class {
175
177
  body: t.body != null ? JSON.stringify(t.body) : void 0,
176
178
  timeout_ms: t.timeout,
177
179
  retry_attempts: t.retries,
178
- queue: t.queue,
180
+ lane: t.lane,
179
181
  callback_url: t.callback,
180
182
  enabled: t.enabled,
181
183
  script: t.script
@@ -210,7 +212,7 @@ var Runlater = class {
210
212
  body: options.body != null ? JSON.stringify(options.body) : void 0,
211
213
  timeout_ms: options.timeout,
212
214
  retry_attempts: options.retries,
213
- queue: options.queue,
215
+ lane: options.lane,
214
216
  callback_url: options.callback,
215
217
  script: options.script,
216
218
  debounce: options.debounce != null ? formatDelay(options.debounce) : void 0,
@@ -222,7 +224,7 @@ var Runlater = class {
222
224
  const headers = {
223
225
  Authorization: `Bearer ${this.apiKey}`,
224
226
  "Content-Type": "application/json",
225
- "User-Agent": "runlater-js/0.1.0"
227
+ "User-Agent": "runlater-js/0.12.0"
226
228
  };
227
229
  if (options.idempotencyKey) {
228
230
  headers["Idempotency-Key"] = options.idempotencyKey;
@@ -253,7 +255,7 @@ var Tasks = class {
253
255
  }
254
256
  async list(options = {}) {
255
257
  const params = new URLSearchParams();
256
- if (options.queue != null) params.set("queue", options.queue);
258
+ if (options.lane != null) params.set("lane", options.lane);
257
259
  if (options.limit != null) params.set("limit", String(options.limit));
258
260
  if (options.offset != null) params.set("offset", String(options.offset));
259
261
  const query = params.toString();
@@ -287,29 +289,34 @@ var Tasks = class {
287
289
  return res.data;
288
290
  }
289
291
  /**
290
- * Create many tasks at once with shared configuration.
292
+ * Create many tasks at once. Each task defines its own URL and can
293
+ * optionally override method, headers, body, and name. Top-level
294
+ * settings serve as defaults.
291
295
  *
292
- * Each item in the array becomes the request body for one task.
293
- * All tasks share the same URL, method, headers, timing, and queue.
294
- * Use the queue name with `cancelQueue()` to cancel them as a group.
296
+ * Use the lane name with `cancelLane()` to cancel them as a group.
295
297
  *
296
298
  * ```js
297
299
  * await rl.tasks.batch({
298
- * url: "https://myapp.com/api/send-email",
299
- * queue: "march-newsletter",
300
+ * lane: "march-newsletter",
301
+ * method: "POST",
300
302
  * run_at: "2026-03-01T09:00:00Z",
301
- * items: [
302
- * { to: "user1@example.com", name: "Alice" },
303
- * { to: "user2@example.com", name: "Bob" },
303
+ * tasks: [
304
+ * { url: "https://myapp.com/api/send-email", body: { to: "alice@example.com" } },
305
+ * { url: "https://myapp.com/api/send-sms", body: { to: "+1234567890" } },
304
306
  * ]
305
307
  * })
306
308
  * ```
307
309
  */
308
310
  async batch(options) {
309
311
  const body = {
310
- url: options.url,
311
- queue: options.queue,
312
- items: options.items,
312
+ lane: options.lane,
313
+ tasks: options.tasks.map((t) => ({
314
+ url: t.url,
315
+ method: t.method,
316
+ headers: t.headers,
317
+ body: t.body != null ? typeof t.body === "string" ? t.body : JSON.stringify(t.body) : void 0,
318
+ name: t.name
319
+ })),
313
320
  method: options.method ?? "POST",
314
321
  headers: options.headers,
315
322
  timeout_ms: options.timeout,
@@ -328,19 +335,19 @@ var Tasks = class {
328
335
  return res.data;
329
336
  }
330
337
  /**
331
- * Cancel all tasks in a queue.
338
+ * Cancel all tasks in a lane.
332
339
  *
333
- * Soft-deletes every task in the queue and removes their pending executions.
340
+ * Soft-deletes every task in the lane and removes their pending executions.
334
341
  *
335
342
  * ```js
336
- * const { cancelled } = await rl.tasks.cancelQueue("march-newsletter")
343
+ * const { cancelled } = await rl.tasks.cancelLane("march-newsletter")
337
344
  * console.log(`Cancelled ${cancelled} tasks`)
338
345
  * ```
339
346
  */
340
- async cancelQueue(queue) {
347
+ async cancelLane(lane) {
341
348
  const res = await this.client.request(
342
349
  "DELETE",
343
- `/tasks?queue=${encodeURIComponent(queue)}`
350
+ `/tasks?lane=${encodeURIComponent(lane)}`
344
351
  );
345
352
  return res.data;
346
353
  }
@@ -499,6 +506,126 @@ var Endpoints = class {
499
506
  return res.data;
500
507
  }
501
508
  };
509
+ var MessageQueues = class {
510
+ constructor(client) {
511
+ this.client = client;
512
+ }
513
+ /** List all message queues. */
514
+ async list() {
515
+ const res = await this.client.request("GET", "/mq");
516
+ return res.data;
517
+ }
518
+ /** Create a new message queue. */
519
+ async create(options) {
520
+ const res = await this.client.request("POST", "/mq", {
521
+ body: options
522
+ });
523
+ return res.data;
524
+ }
525
+ /** Get a message queue by slug. */
526
+ async get(slug) {
527
+ const res = await this.client.request("GET", `/mq/${slug}`);
528
+ return res.data;
529
+ }
530
+ /** Update a message queue. */
531
+ async update(slug, options) {
532
+ const res = await this.client.request("PATCH", `/mq/${slug}`, {
533
+ body: options
534
+ });
535
+ return res.data;
536
+ }
537
+ /** Delete a message queue. */
538
+ async delete(slug) {
539
+ await this.client.request("DELETE", `/mq/${slug}`);
540
+ }
541
+ /** Get queue statistics. */
542
+ async stats(slug) {
543
+ const res = await this.client.request("GET", `/mq/${slug}/stats`);
544
+ return res.data;
545
+ }
546
+ /** Enqueue a single message. */
547
+ async enqueue(slug, body) {
548
+ const res = await this.client.request("POST", `/mq/${slug}/messages`, {
549
+ body: { body }
550
+ });
551
+ return res.data;
552
+ }
553
+ /** Enqueue multiple messages at once. */
554
+ async enqueueBatch(slug, messages) {
555
+ const res = await this.client.request(
556
+ "POST",
557
+ `/mq/${slug}/messages/batch`,
558
+ { body: { messages } }
559
+ );
560
+ return res.data;
561
+ }
562
+ /** Receive messages from the queue. */
563
+ async receive(slug, options = {}) {
564
+ const params = new URLSearchParams();
565
+ if (options.max != null) params.set("max", String(options.max));
566
+ if (options.wait != null) params.set("wait", String(options.wait));
567
+ const query = params.toString();
568
+ const res = await this.client.request(
569
+ "GET",
570
+ `/mq/${slug}/receive${query ? `?${query}` : ""}`
571
+ );
572
+ return res.data;
573
+ }
574
+ /** Acknowledge (complete) a message by receipt handle. */
575
+ async ack(slug, receiptHandle) {
576
+ await this.client.request("DELETE", `/mq/${slug}/ack/${receiptHandle}`);
577
+ }
578
+ /** Nack (release) a message back to the queue. */
579
+ async nack(slug, receiptHandle) {
580
+ await this.client.request("POST", `/mq/${slug}/nack/${receiptHandle}`);
581
+ }
582
+ /** Acknowledge multiple messages at once. */
583
+ async ackBatch(slug, receiptHandles) {
584
+ const res = await this.client.request(
585
+ "POST",
586
+ `/mq/${slug}/ack/batch`,
587
+ { body: { receipt_handles: receiptHandles } }
588
+ );
589
+ return res.data;
590
+ }
591
+ /** List messages in the queue with optional filtering. */
592
+ async messages(slug, options = {}) {
593
+ const params = new URLSearchParams();
594
+ if (options.status != null) params.set("status", options.status);
595
+ if (options.limit != null) params.set("limit", String(options.limit));
596
+ if (options.offset != null) params.set("offset", String(options.offset));
597
+ const query = params.toString();
598
+ const res = await this.client.request(
599
+ "GET",
600
+ `/mq/${slug}/messages${query ? `?${query}` : ""}`
601
+ );
602
+ return res.data;
603
+ }
604
+ /** Get a specific message by ID. */
605
+ async getMessage(slug, id) {
606
+ const res = await this.client.request(
607
+ "GET",
608
+ `/mq/${slug}/messages/${id}`
609
+ );
610
+ return res.data;
611
+ }
612
+ /** Pause the queue. */
613
+ async pause(slug) {
614
+ const res = await this.client.request(
615
+ "POST",
616
+ `/mq/${slug}/pause`
617
+ );
618
+ return res.data;
619
+ }
620
+ /** Resume a paused queue. */
621
+ async resume(slug) {
622
+ const res = await this.client.request(
623
+ "POST",
624
+ `/mq/${slug}/resume`
625
+ );
626
+ return res.data;
627
+ }
628
+ };
502
629
  function formatDelay(delay) {
503
630
  if (typeof delay === "number") return `${delay}s`;
504
631
  return delay;
package/dist/index.mjs CHANGED
@@ -19,6 +19,7 @@ var Runlater = class {
19
19
  monitors;
20
20
  endpoints;
21
21
  schedules;
22
+ queues;
22
23
  constructor(options) {
23
24
  if (typeof options === "string") {
24
25
  this.apiKey = options;
@@ -31,6 +32,7 @@ var Runlater = class {
31
32
  this.monitors = new Monitors(this);
32
33
  this.endpoints = new Endpoints(this);
33
34
  this.schedules = new Schedules(this);
35
+ this.queues = new MessageQueues(this);
34
36
  }
35
37
  /**
36
38
  * Send a request immediately with reliable delivery and retries.
@@ -115,7 +117,7 @@ var Runlater = class {
115
117
  body: options.body != null ? JSON.stringify(options.body) : void 0,
116
118
  timeout_ms: options.timeout,
117
119
  retry_attempts: options.retries,
118
- queue: options.queue,
120
+ lane: options.lane,
119
121
  callback_url: options.callback,
120
122
  enabled: options.enabled,
121
123
  script: options.script
@@ -148,7 +150,7 @@ var Runlater = class {
148
150
  body: t.body != null ? JSON.stringify(t.body) : void 0,
149
151
  timeout_ms: t.timeout,
150
152
  retry_attempts: t.retries,
151
- queue: t.queue,
153
+ lane: t.lane,
152
154
  callback_url: t.callback,
153
155
  enabled: t.enabled,
154
156
  script: t.script
@@ -183,7 +185,7 @@ var Runlater = class {
183
185
  body: options.body != null ? JSON.stringify(options.body) : void 0,
184
186
  timeout_ms: options.timeout,
185
187
  retry_attempts: options.retries,
186
- queue: options.queue,
188
+ lane: options.lane,
187
189
  callback_url: options.callback,
188
190
  script: options.script,
189
191
  debounce: options.debounce != null ? formatDelay(options.debounce) : void 0,
@@ -195,7 +197,7 @@ var Runlater = class {
195
197
  const headers = {
196
198
  Authorization: `Bearer ${this.apiKey}`,
197
199
  "Content-Type": "application/json",
198
- "User-Agent": "runlater-js/0.1.0"
200
+ "User-Agent": "runlater-js/0.12.0"
199
201
  };
200
202
  if (options.idempotencyKey) {
201
203
  headers["Idempotency-Key"] = options.idempotencyKey;
@@ -226,7 +228,7 @@ var Tasks = class {
226
228
  }
227
229
  async list(options = {}) {
228
230
  const params = new URLSearchParams();
229
- if (options.queue != null) params.set("queue", options.queue);
231
+ if (options.lane != null) params.set("lane", options.lane);
230
232
  if (options.limit != null) params.set("limit", String(options.limit));
231
233
  if (options.offset != null) params.set("offset", String(options.offset));
232
234
  const query = params.toString();
@@ -260,29 +262,34 @@ var Tasks = class {
260
262
  return res.data;
261
263
  }
262
264
  /**
263
- * Create many tasks at once with shared configuration.
265
+ * Create many tasks at once. Each task defines its own URL and can
266
+ * optionally override method, headers, body, and name. Top-level
267
+ * settings serve as defaults.
264
268
  *
265
- * Each item in the array becomes the request body for one task.
266
- * All tasks share the same URL, method, headers, timing, and queue.
267
- * Use the queue name with `cancelQueue()` to cancel them as a group.
269
+ * Use the lane name with `cancelLane()` to cancel them as a group.
268
270
  *
269
271
  * ```js
270
272
  * await rl.tasks.batch({
271
- * url: "https://myapp.com/api/send-email",
272
- * queue: "march-newsletter",
273
+ * lane: "march-newsletter",
274
+ * method: "POST",
273
275
  * run_at: "2026-03-01T09:00:00Z",
274
- * items: [
275
- * { to: "user1@example.com", name: "Alice" },
276
- * { to: "user2@example.com", name: "Bob" },
276
+ * tasks: [
277
+ * { url: "https://myapp.com/api/send-email", body: { to: "alice@example.com" } },
278
+ * { url: "https://myapp.com/api/send-sms", body: { to: "+1234567890" } },
277
279
  * ]
278
280
  * })
279
281
  * ```
280
282
  */
281
283
  async batch(options) {
282
284
  const body = {
283
- url: options.url,
284
- queue: options.queue,
285
- items: options.items,
285
+ lane: options.lane,
286
+ tasks: options.tasks.map((t) => ({
287
+ url: t.url,
288
+ method: t.method,
289
+ headers: t.headers,
290
+ body: t.body != null ? typeof t.body === "string" ? t.body : JSON.stringify(t.body) : void 0,
291
+ name: t.name
292
+ })),
286
293
  method: options.method ?? "POST",
287
294
  headers: options.headers,
288
295
  timeout_ms: options.timeout,
@@ -301,19 +308,19 @@ var Tasks = class {
301
308
  return res.data;
302
309
  }
303
310
  /**
304
- * Cancel all tasks in a queue.
311
+ * Cancel all tasks in a lane.
305
312
  *
306
- * Soft-deletes every task in the queue and removes their pending executions.
313
+ * Soft-deletes every task in the lane and removes their pending executions.
307
314
  *
308
315
  * ```js
309
- * const { cancelled } = await rl.tasks.cancelQueue("march-newsletter")
316
+ * const { cancelled } = await rl.tasks.cancelLane("march-newsletter")
310
317
  * console.log(`Cancelled ${cancelled} tasks`)
311
318
  * ```
312
319
  */
313
- async cancelQueue(queue) {
320
+ async cancelLane(lane) {
314
321
  const res = await this.client.request(
315
322
  "DELETE",
316
- `/tasks?queue=${encodeURIComponent(queue)}`
323
+ `/tasks?lane=${encodeURIComponent(lane)}`
317
324
  );
318
325
  return res.data;
319
326
  }
@@ -472,6 +479,126 @@ var Endpoints = class {
472
479
  return res.data;
473
480
  }
474
481
  };
482
+ var MessageQueues = class {
483
+ constructor(client) {
484
+ this.client = client;
485
+ }
486
+ /** List all message queues. */
487
+ async list() {
488
+ const res = await this.client.request("GET", "/mq");
489
+ return res.data;
490
+ }
491
+ /** Create a new message queue. */
492
+ async create(options) {
493
+ const res = await this.client.request("POST", "/mq", {
494
+ body: options
495
+ });
496
+ return res.data;
497
+ }
498
+ /** Get a message queue by slug. */
499
+ async get(slug) {
500
+ const res = await this.client.request("GET", `/mq/${slug}`);
501
+ return res.data;
502
+ }
503
+ /** Update a message queue. */
504
+ async update(slug, options) {
505
+ const res = await this.client.request("PATCH", `/mq/${slug}`, {
506
+ body: options
507
+ });
508
+ return res.data;
509
+ }
510
+ /** Delete a message queue. */
511
+ async delete(slug) {
512
+ await this.client.request("DELETE", `/mq/${slug}`);
513
+ }
514
+ /** Get queue statistics. */
515
+ async stats(slug) {
516
+ const res = await this.client.request("GET", `/mq/${slug}/stats`);
517
+ return res.data;
518
+ }
519
+ /** Enqueue a single message. */
520
+ async enqueue(slug, body) {
521
+ const res = await this.client.request("POST", `/mq/${slug}/messages`, {
522
+ body: { body }
523
+ });
524
+ return res.data;
525
+ }
526
+ /** Enqueue multiple messages at once. */
527
+ async enqueueBatch(slug, messages) {
528
+ const res = await this.client.request(
529
+ "POST",
530
+ `/mq/${slug}/messages/batch`,
531
+ { body: { messages } }
532
+ );
533
+ return res.data;
534
+ }
535
+ /** Receive messages from the queue. */
536
+ async receive(slug, options = {}) {
537
+ const params = new URLSearchParams();
538
+ if (options.max != null) params.set("max", String(options.max));
539
+ if (options.wait != null) params.set("wait", String(options.wait));
540
+ const query = params.toString();
541
+ const res = await this.client.request(
542
+ "GET",
543
+ `/mq/${slug}/receive${query ? `?${query}` : ""}`
544
+ );
545
+ return res.data;
546
+ }
547
+ /** Acknowledge (complete) a message by receipt handle. */
548
+ async ack(slug, receiptHandle) {
549
+ await this.client.request("DELETE", `/mq/${slug}/ack/${receiptHandle}`);
550
+ }
551
+ /** Nack (release) a message back to the queue. */
552
+ async nack(slug, receiptHandle) {
553
+ await this.client.request("POST", `/mq/${slug}/nack/${receiptHandle}`);
554
+ }
555
+ /** Acknowledge multiple messages at once. */
556
+ async ackBatch(slug, receiptHandles) {
557
+ const res = await this.client.request(
558
+ "POST",
559
+ `/mq/${slug}/ack/batch`,
560
+ { body: { receipt_handles: receiptHandles } }
561
+ );
562
+ return res.data;
563
+ }
564
+ /** List messages in the queue with optional filtering. */
565
+ async messages(slug, options = {}) {
566
+ const params = new URLSearchParams();
567
+ if (options.status != null) params.set("status", options.status);
568
+ if (options.limit != null) params.set("limit", String(options.limit));
569
+ if (options.offset != null) params.set("offset", String(options.offset));
570
+ const query = params.toString();
571
+ const res = await this.client.request(
572
+ "GET",
573
+ `/mq/${slug}/messages${query ? `?${query}` : ""}`
574
+ );
575
+ return res.data;
576
+ }
577
+ /** Get a specific message by ID. */
578
+ async getMessage(slug, id) {
579
+ const res = await this.client.request(
580
+ "GET",
581
+ `/mq/${slug}/messages/${id}`
582
+ );
583
+ return res.data;
584
+ }
585
+ /** Pause the queue. */
586
+ async pause(slug) {
587
+ const res = await this.client.request(
588
+ "POST",
589
+ `/mq/${slug}/pause`
590
+ );
591
+ return res.data;
592
+ }
593
+ /** Resume a paused queue. */
594
+ async resume(slug) {
595
+ const res = await this.client.request(
596
+ "POST",
597
+ `/mq/${slug}/resume`
598
+ );
599
+ return res.data;
600
+ }
601
+ };
475
602
  function formatDelay(delay) {
476
603
  if (typeof delay === "number") return `${delay}s`;
477
604
  return delay;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "runlater-js",
3
- "version": "0.10.0",
4
- "description": "Delayed tasks, cron jobs, and reliable webhooks. No infrastructure required.",
3
+ "version": "0.12.0",
4
+ "description": "Delayed tasks, cron jobs, message queues, and reliable webhooks. No infrastructure required.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
7
7
  "types": "./dist/index.d.ts",