@molecule/api-queue-memory 1.0.0 → 1.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/README.md +502 -0
- package/package.json +6 -5
package/README.md
ADDED
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
AUTO-GENERATED — DO NOT EDIT THIS FILE.
|
|
3
|
+
Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
|
|
4
|
+
Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
|
|
5
|
+
To change this document, edit the module-level JSDoc in src/index.ts.
|
|
6
|
+
Generated: 2026-08-04T01:48:59.969Z
|
|
7
|
+
-->
|
|
8
|
+
|
|
9
|
+
# @molecule/api-queue-memory
|
|
10
|
+
|
|
11
|
+
> **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
|
|
12
|
+
> It is written to be read by coding agents as much as by people, and is generated from this
|
|
13
|
+
> package's source — edit `src/index.ts` JSDoc, not this file.
|
|
14
|
+
|
|
15
|
+
In-memory queue provider for molecule.dev.
|
|
16
|
+
|
|
17
|
+
A zero-dependency, zero-configuration, in-process queue provider for
|
|
18
|
+
development and testing — no broker, no credentials, no environment
|
|
19
|
+
variables. Implements the full `@molecule/api-queue` contract with
|
|
20
|
+
SQS-style semantics: named queues, at-least-once delivery via visibility
|
|
21
|
+
leases, delayed messages (`delaySeconds`), redelivery on subscriber
|
|
22
|
+
handler failure or `nack()`, a bounded delivery cap with optional
|
|
23
|
+
dead-letter routing, FIFO group ordering + deduplication, long-polling
|
|
24
|
+
`receive()`, and `maxMessages`-bounded subscriber concurrency.
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { setProvider, queue } from '@molecule/api-queue'
|
|
30
|
+
import { provider } from '@molecule/api-queue-memory'
|
|
31
|
+
|
|
32
|
+
setProvider(provider) // no configuration, no env vars
|
|
33
|
+
|
|
34
|
+
const emails = queue('emails')
|
|
35
|
+
const unsubscribe = emails.subscribe(async (message) => {
|
|
36
|
+
await deliver(message.body)
|
|
37
|
+
await message.ack() // handler success also auto-acks
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
await emails.send({ body: { to: 'a@b.c' } })
|
|
41
|
+
await emails.send({ body: { to: 'later@b.c' }, delaySeconds: 60 })
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Type
|
|
45
|
+
|
|
46
|
+
`provider`
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install @molecule/api-queue-memory @molecule/api-bond @molecule/api-queue
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## API
|
|
55
|
+
|
|
56
|
+
### Interfaces
|
|
57
|
+
|
|
58
|
+
#### `MemoryQueueConfig`
|
|
59
|
+
|
|
60
|
+
Internal configuration for a single in-memory queue instance, resolved by
|
|
61
|
+
the provider from `MemoryQueueOptions` and per-queue `QueueCreateOptions`.
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
interface MemoryQueueConfig {
|
|
65
|
+
/**
|
|
66
|
+
* Default visibility timeout in seconds for leases without an explicit
|
|
67
|
+
* `ReceiveOptions.visibilityTimeout`.
|
|
68
|
+
*/
|
|
69
|
+
defaultVisibilityTimeoutSeconds: number
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Maximum deliveries before dead-lettering/dropping. Overridden per queue
|
|
73
|
+
* by `deadLetterQueue.maxReceiveCount` when a dead-letter queue is set.
|
|
74
|
+
*/
|
|
75
|
+
maxReceiveCount: number
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Delay in seconds before redelivery after an explicit `nack()`.
|
|
79
|
+
*/
|
|
80
|
+
redeliveryDelaySeconds: number
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Delay in seconds before redelivery after an uncaught `subscribe()`
|
|
84
|
+
* handler failure.
|
|
85
|
+
*/
|
|
86
|
+
handlerFailureRedeliveryDelaySeconds: number
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Whether this queue enforces FIFO semantics (per-`groupId` ordered,
|
|
90
|
+
* head-of-line-blocking delivery plus `deduplicationId` deduplication).
|
|
91
|
+
*/
|
|
92
|
+
fifo: boolean
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Optional retention period in seconds; messages older than this are
|
|
96
|
+
* discarded when next scanned.
|
|
97
|
+
*/
|
|
98
|
+
messageRetentionSeconds?: number
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Optional dead-letter queue for messages exceeding the delivery cap.
|
|
102
|
+
*/
|
|
103
|
+
deadLetterQueue?: QueueCreateOptions['deadLetterQueue']
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Resolves another queue by name — used to route dead-lettered messages.
|
|
107
|
+
*/
|
|
108
|
+
resolveQueue: (name: string) => Queue
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
#### `MemoryQueueHandle`
|
|
113
|
+
|
|
114
|
+
Handle pairing a `Queue` with the internal lifecycle control the provider
|
|
115
|
+
uses to shut it down (`close()` is not part of the core `Queue` interface).
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
interface MemoryQueueHandle {
|
|
119
|
+
/**
|
|
120
|
+
* The in-memory queue implementation.
|
|
121
|
+
*/
|
|
122
|
+
queue: Queue
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Stops all timers, resolves pending long-polls with `[]`, discards all
|
|
126
|
+
* messages and subscribers, and rejects further sends.
|
|
127
|
+
*/
|
|
128
|
+
close(): void
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### `MemoryQueueOptions`
|
|
133
|
+
|
|
134
|
+
Options for creating an in-memory queue provider.
|
|
135
|
+
|
|
136
|
+
All options have working defaults — the provider is fully functional with
|
|
137
|
+
zero configuration and zero environment variables.
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
interface MemoryQueueOptions {
|
|
141
|
+
/**
|
|
142
|
+
* Default visibility timeout in seconds applied to received/dispatched
|
|
143
|
+
* messages when `ReceiveOptions.visibilityTimeout` is not given.
|
|
144
|
+
* A leased (in-flight) message whose lease expires without an `ack()`
|
|
145
|
+
* becomes visible again and is redelivered (at-least-once delivery).
|
|
146
|
+
* Defaults to `30`.
|
|
147
|
+
*/
|
|
148
|
+
visibilityTimeoutSeconds?: number
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Maximum number of times a message may be delivered before it is routed
|
|
152
|
+
* to the queue's dead-letter queue (when configured via
|
|
153
|
+
* `QueueCreateOptions.deadLetterQueue`) or dropped with an error log.
|
|
154
|
+
* Mirrors the Redis bond's `attempts: 3`. Defaults to `3`.
|
|
155
|
+
*/
|
|
156
|
+
maxReceiveCount?: number
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Delay in seconds before a message is redelivered after an explicit
|
|
160
|
+
* `nack()` (a pull `receive()` consumer's deliberate "put this back now").
|
|
161
|
+
* Defaults to `0` (immediate redelivery) — an explicit `nack()` is a
|
|
162
|
+
* caller decision that should be honored right away, not throttled.
|
|
163
|
+
*/
|
|
164
|
+
redeliveryDelaySeconds?: number
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Delay in seconds before a message is redelivered after an UNCAUGHT
|
|
168
|
+
* `subscribe()` handler failure (a thrown error) — distinct from
|
|
169
|
+
* `redeliveryDelaySeconds` because a throw is an unplanned failure (e.g. a
|
|
170
|
+
* downstream 503) that deserves a real retry window, mirroring the Redis
|
|
171
|
+
* bond's `attempts: 3, backoff: { type: 'exponential', delay: 1000 }`.
|
|
172
|
+
* Defaults to `1`. With the default `maxReceiveCount` of `3`, a
|
|
173
|
+
* `redeliveryDelaySeconds` of `0` would burn all delivery attempts within
|
|
174
|
+
* milliseconds and drop the message with no real chance for a transient
|
|
175
|
+
* downstream failure to recover — this option exists so "retry" means a
|
|
176
|
+
* few real seconds apart, not a hot loop.
|
|
177
|
+
*/
|
|
178
|
+
handlerFailureRedeliveryDelaySeconds?: number
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
#### `Queue`
|
|
183
|
+
|
|
184
|
+
Handle for a named queue, providing send, receive, and subscribe operations.
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
interface Queue {
|
|
188
|
+
/**
|
|
189
|
+
* Queue name.
|
|
190
|
+
*/
|
|
191
|
+
name: string
|
|
192
|
+
/**
|
|
193
|
+
* Sends a message to the queue.
|
|
194
|
+
*/
|
|
195
|
+
send<T = unknown>(message: QueueMessage<T>): Promise<string>
|
|
196
|
+
/**
|
|
197
|
+
* Sends multiple messages to the queue.
|
|
198
|
+
*/
|
|
199
|
+
sendBatch?<T = unknown>(messages: QueueMessage<T>[]): Promise<string[]>
|
|
200
|
+
/**
|
|
201
|
+
* Receives messages from the queue.
|
|
202
|
+
*/
|
|
203
|
+
receive<T = unknown>(options?: ReceiveOptions): Promise<ReceivedMessage<T>[]>
|
|
204
|
+
/**
|
|
205
|
+
* Subscribes to messages from the queue.
|
|
206
|
+
* Returns a function to unsubscribe.
|
|
207
|
+
*/
|
|
208
|
+
subscribe<T = unknown>(handler: MessageHandler<T>, options?: ReceiveOptions): () => void
|
|
209
|
+
/**
|
|
210
|
+
* Gets the approximate number of messages in the queue.
|
|
211
|
+
*/
|
|
212
|
+
size?(): Promise<number>
|
|
213
|
+
/**
|
|
214
|
+
* Purges all messages from the queue.
|
|
215
|
+
*/
|
|
216
|
+
purge?(): Promise<void>
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
#### `QueueCreateOptions`
|
|
221
|
+
|
|
222
|
+
Options for creating a new queue, including FIFO mode, timeouts,
|
|
223
|
+
retention periods, and dead-letter queue configuration.
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
interface QueueCreateOptions {
|
|
227
|
+
/**
|
|
228
|
+
* Whether this is a FIFO queue.
|
|
229
|
+
*/
|
|
230
|
+
fifo?: boolean
|
|
231
|
+
/**
|
|
232
|
+
* Default visibility timeout in seconds.
|
|
233
|
+
*/
|
|
234
|
+
visibilityTimeout?: number
|
|
235
|
+
/**
|
|
236
|
+
* Message retention period in seconds.
|
|
237
|
+
*/
|
|
238
|
+
messageRetentionSeconds?: number
|
|
239
|
+
/**
|
|
240
|
+
* Maximum message size in bytes.
|
|
241
|
+
*/
|
|
242
|
+
maxMessageSize?: number
|
|
243
|
+
/**
|
|
244
|
+
* Dead letter queue configuration.
|
|
245
|
+
*/
|
|
246
|
+
deadLetterQueue?: {
|
|
247
|
+
name: string
|
|
248
|
+
maxReceiveCount: number
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### `QueueMessage`
|
|
254
|
+
|
|
255
|
+
Message to be sent to a queue.
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
interface QueueMessage<T = unknown> {
|
|
259
|
+
/**
|
|
260
|
+
* Message payload.
|
|
261
|
+
*/
|
|
262
|
+
body: T
|
|
263
|
+
/**
|
|
264
|
+
* Message ID (auto-generated if not provided).
|
|
265
|
+
*/
|
|
266
|
+
id?: string
|
|
267
|
+
/**
|
|
268
|
+
* Delay in seconds before the message becomes visible.
|
|
269
|
+
*/
|
|
270
|
+
delaySeconds?: number
|
|
271
|
+
/**
|
|
272
|
+
* Message attributes/headers.
|
|
273
|
+
*/
|
|
274
|
+
attributes?: Record<string, string | number | boolean>
|
|
275
|
+
/**
|
|
276
|
+
* Message group ID (for FIFO queues).
|
|
277
|
+
*/
|
|
278
|
+
groupId?: string
|
|
279
|
+
/**
|
|
280
|
+
* Deduplication ID (for FIFO queues).
|
|
281
|
+
*/
|
|
282
|
+
deduplicationId?: string
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
#### `QueueProvider`
|
|
287
|
+
|
|
288
|
+
Queue provider interface that all queue bond packages must implement.
|
|
289
|
+
Provides queue handle creation and optional queue management operations.
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
interface QueueProvider {
|
|
293
|
+
/**
|
|
294
|
+
* Gets or creates a queue by name.
|
|
295
|
+
*/
|
|
296
|
+
queue(name: string): Queue
|
|
297
|
+
/**
|
|
298
|
+
* Lists all available queues.
|
|
299
|
+
*/
|
|
300
|
+
listQueues?(): Promise<string[]>
|
|
301
|
+
/**
|
|
302
|
+
* Creates a new queue.
|
|
303
|
+
*/
|
|
304
|
+
createQueue?(name: string, options?: QueueCreateOptions): Promise<Queue>
|
|
305
|
+
/**
|
|
306
|
+
* Deletes a queue.
|
|
307
|
+
*/
|
|
308
|
+
deleteQueue?(name: string): Promise<void>
|
|
309
|
+
/**
|
|
310
|
+
* Closes all connections.
|
|
311
|
+
*/
|
|
312
|
+
close?(): Promise<void>
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
#### `ReceivedMessage`
|
|
317
|
+
|
|
318
|
+
Received message from a queue.
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
interface ReceivedMessage<T = unknown> {
|
|
322
|
+
/**
|
|
323
|
+
* Message ID.
|
|
324
|
+
*/
|
|
325
|
+
id: string
|
|
326
|
+
/**
|
|
327
|
+
* Message payload.
|
|
328
|
+
*/
|
|
329
|
+
body: T
|
|
330
|
+
/**
|
|
331
|
+
* Receipt handle for acknowledging the message.
|
|
332
|
+
*/
|
|
333
|
+
receiptHandle: string
|
|
334
|
+
/**
|
|
335
|
+
* Message attributes/headers.
|
|
336
|
+
*/
|
|
337
|
+
attributes?: Record<string, string | number | boolean>
|
|
338
|
+
/**
|
|
339
|
+
* Number of times this message has been received.
|
|
340
|
+
*/
|
|
341
|
+
receiveCount?: number
|
|
342
|
+
/**
|
|
343
|
+
* Timestamp when the message was sent.
|
|
344
|
+
*/
|
|
345
|
+
sentTimestamp?: Date
|
|
346
|
+
/**
|
|
347
|
+
* Acknowledges (deletes) the message from the queue.
|
|
348
|
+
*/
|
|
349
|
+
ack(): Promise<void>
|
|
350
|
+
/**
|
|
351
|
+
* Rejects the message (returns it to the queue).
|
|
352
|
+
*/
|
|
353
|
+
nack?(): Promise<void>
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
#### `ReceiveOptions`
|
|
358
|
+
|
|
359
|
+
Options for receiving messages.
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
interface ReceiveOptions {
|
|
363
|
+
/**
|
|
364
|
+
* Maximum number of messages to receive.
|
|
365
|
+
*/
|
|
366
|
+
maxMessages?: number
|
|
367
|
+
/**
|
|
368
|
+
* Visibility timeout in seconds.
|
|
369
|
+
*/
|
|
370
|
+
visibilityTimeout?: number
|
|
371
|
+
/**
|
|
372
|
+
* Wait time in seconds for long polling.
|
|
373
|
+
*/
|
|
374
|
+
waitTimeSeconds?: number
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Types
|
|
379
|
+
|
|
380
|
+
#### `MessageHandler`
|
|
381
|
+
|
|
382
|
+
Async callback invoked for each message received from a queue subscription.
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
type MessageHandler<T = unknown> = (message: ReceivedMessage<T>) => Promise<void>
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Functions
|
|
389
|
+
|
|
390
|
+
#### `createProvider(options)`
|
|
391
|
+
|
|
392
|
+
Creates an in-memory queue provider. Queues are created implicitly on first
|
|
393
|
+
access (like the Redis bond) or explicitly via `createQueue()` with FIFO,
|
|
394
|
+
visibility-timeout, retention, and dead-letter options. All state lives in
|
|
395
|
+
this process and is lost on restart.
|
|
396
|
+
|
|
397
|
+
```typescript
|
|
398
|
+
function createProvider(options?: MemoryQueueOptions): QueueProvider
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
- `options` — Optional delivery defaults (visibility timeout, delivery cap, nack redelivery delay, handler-failure redelivery delay). Everything defaults sensibly — no configuration is required.
|
|
402
|
+
|
|
403
|
+
**Returns:** A `QueueProvider` backed by in-process queues.
|
|
404
|
+
|
|
405
|
+
### Constants
|
|
406
|
+
|
|
407
|
+
#### `provider`
|
|
408
|
+
|
|
409
|
+
Lazily-initialized in-memory queue provider proxy that creates the provider on first access.
|
|
410
|
+
|
|
411
|
+
```typescript
|
|
412
|
+
const provider: QueueProvider
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## Core Interface
|
|
416
|
+
|
|
417
|
+
Implements `@molecule/api-queue` interface.
|
|
418
|
+
|
|
419
|
+
## Bond Wiring
|
|
420
|
+
|
|
421
|
+
Setup function to register this provider with the core interface:
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
import { setProvider } from '@molecule/api-queue'
|
|
425
|
+
import { provider } from '@molecule/api-queue-memory'
|
|
426
|
+
|
|
427
|
+
export function setupQueueMemory(): void {
|
|
428
|
+
setProvider(provider)
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Injection Notes
|
|
433
|
+
|
|
434
|
+
### Requirements
|
|
435
|
+
|
|
436
|
+
Peer dependencies:
|
|
437
|
+
|
|
438
|
+
- `@molecule/api-bond` ^1.0.1
|
|
439
|
+
- `@molecule/api-queue` ^1.0.1
|
|
440
|
+
|
|
441
|
+
### Runtime Dependencies
|
|
442
|
+
|
|
443
|
+
- `@molecule/api-bond`
|
|
444
|
+
- `@molecule/api-queue`
|
|
445
|
+
|
|
446
|
+
Single-process and DEV-ONLY. Messages live in this process's memory: there
|
|
447
|
+
is NO persistence (everything is lost on restart) and NO cross-instance
|
|
448
|
+
delivery, so it must not be used for multi-instance production — swap in
|
|
449
|
+
`@molecule/api-queue-redis`, `@molecule/api-queue-rabbitmq`, or
|
|
450
|
+
`@molecule/api-queue-sqs` for production workloads. Delivery is
|
|
451
|
+
at-least-once: a message whose visibility lease expires without `ack()` is
|
|
452
|
+
redelivered (with an incremented `receiveCount`), and a message delivered
|
|
453
|
+
more than `maxReceiveCount` times (default 3) is routed to the queue's
|
|
454
|
+
dead-letter queue when one was configured via `createQueue()` — otherwise
|
|
455
|
+
it is dropped with an error log. Message bodies are `structuredClone`d on
|
|
456
|
+
send and per delivery (like a real broker's serialization), so bodies must
|
|
457
|
+
be structured-cloneable and post-send mutations never leak to consumers.
|
|
458
|
+
`QueueCreateOptions.maxMessageSize` is not enforced (nothing is
|
|
459
|
+
serialized). `close()` clears all timers, resolves pending long-polls with
|
|
460
|
+
`[]`, and stops all delivery.
|
|
461
|
+
|
|
462
|
+
Two distinct redelivery delays (both `MemoryQueueOptions`, provider-wide):
|
|
463
|
+
an explicit `nack()` redelivers per `redeliveryDelaySeconds` (default `0`
|
|
464
|
+
— a deliberate caller decision, honored immediately), while an UNCAUGHT
|
|
465
|
+
`subscribe()` handler throw redelivers per
|
|
466
|
+
`handlerFailureRedeliveryDelaySeconds` (default `1` — an unplanned failure
|
|
467
|
+
gets a real retry window instead of burning all `maxReceiveCount` attempts
|
|
468
|
+
within milliseconds, mirroring the Redis bond's `attempts: 3, backoff:
|
|
469
|
+
{ type: 'exponential', delay: 1000 }`).
|
|
470
|
+
|
|
471
|
+
## E2E Tests
|
|
472
|
+
|
|
473
|
+
Integration checklist — exercise the REAL behavior end-to-end (drive the app
|
|
474
|
+
action that enqueues/consumes work in the live preview, no mocks), adapt each
|
|
475
|
+
item to this app's actual screens/flows, and check every box off one by one. A
|
|
476
|
+
box you can't check is an integration bug to fix — not a skip:
|
|
477
|
+
|
|
478
|
+
- [ ] The action that enqueues work responds fast — `send()` returns a message
|
|
479
|
+
id immediately and the request/response does NOT block on the job. The #1
|
|
480
|
+
trap: the executor awaits the heavy work inline (defeating the queue);
|
|
481
|
+
confirm the triggering UI action returns quickly and the work happens in the
|
|
482
|
+
background.
|
|
483
|
+
- [ ] The enqueued job actually RUNS — a `subscribe()` consumer (a
|
|
484
|
+
`MessageHandler`) is wired and running, so the message's real side effect
|
|
485
|
+
(email sent, file processed, notification delivered — whatever the app does)
|
|
486
|
+
actually appears in the UI/data. A message enqueued with no worker wired is
|
|
487
|
+
the silent failure.
|
|
488
|
+
- [ ] Payload round-trips intact — the `ReceivedMessage.body` the handler sees
|
|
489
|
+
equals the `QueueMessage.body` that was sent, with no dropped or renamed
|
|
490
|
+
fields.
|
|
491
|
+
- [ ] Failure is handled — a handler that throws is redelivered (up to
|
|
492
|
+
`QueueCreateOptions.deadLetterQueue.maxReceiveCount`, tracked via
|
|
493
|
+
`receiveCount`) or dead-lettered, never silently lost. Delivery is
|
|
494
|
+
at-least-once, so the handler is idempotent (dedupe on the job/record id) — a
|
|
495
|
+
redelivery must not double-charge or double-send.
|
|
496
|
+
- [ ] Ordering/concurrency is not assumed — the app does not rely on strict
|
|
497
|
+
FIFO (`QueueMessage.groupId`/`fifo`) or exactly-once delivery unless the
|
|
498
|
+
bonded provider actually guarantees it.
|
|
499
|
+
- [ ] Least-authority payloads — the `body` carries only the ids/refs the job
|
|
500
|
+
needs (never a secret or stale authority); the consumer re-loads and
|
|
501
|
+
re-scopes on the CURRENT data (owner id from `body`, re-checked server-side)
|
|
502
|
+
so one user's job cannot act on another user's resource.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@molecule/api-queue-memory",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "In-memory queue provider for molecule.dev.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
|
-
"dist"
|
|
20
|
+
"dist",
|
|
21
|
+
"README.md"
|
|
21
22
|
],
|
|
22
23
|
"keywords": [
|
|
23
24
|
"molecule",
|
|
@@ -27,13 +28,13 @@
|
|
|
27
28
|
],
|
|
28
29
|
"license": "Apache-2.0",
|
|
29
30
|
"peerDependencies": {
|
|
30
|
-
"@molecule/api-bond": "^1.0.
|
|
31
|
-
"@molecule/api-queue": "^1.0.
|
|
31
|
+
"@molecule/api-bond": "^1.0.1",
|
|
32
|
+
"@molecule/api-queue": "^1.0.1"
|
|
32
33
|
},
|
|
33
34
|
"devDependencies": {
|
|
34
35
|
"@types/node": "26.1.2",
|
|
35
36
|
"typescript": "6.0.3",
|
|
36
|
-
"vitest": "4.1.
|
|
37
|
+
"vitest": "4.1.11"
|
|
37
38
|
},
|
|
38
39
|
"repository": {
|
|
39
40
|
"type": "git",
|