← All @molecule/* packages · App templates
@molecule/api-queue-sqsProvider bond · queue · API (Node) · v1.0.2 · Apache-2.0
AWS SQS queue provider for molecule.dev
npm install @molecule/api-queue-sqsnpm · Source on GitHub · Implements @molecule/api-queue
@molecule/api-queue-sqs is a provider bond on the API (Node) side: it implements the queue core interface (@molecule/api-queue) with a concrete vendor or library behind it.
Your code calls the core; you wire this provider once at startup. Swapping vendors later is one line in that wiring, not a rewrite.
import { setProvider, send, subscribe } from '@molecule/api-queue'
import { provider } from '@molecule/api-queue-sqs'
setProvider(provider)
subscribe<{ userId: string }>('emails', async (message) => {
await deliver(message.body) // returning normally acks (deletes) the message
})
await send('emails', { body: { userId: 'u1' } })Works with: @molecule/api-bond, @molecule/api-queue, @molecule/api-secrets
Secrets: AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, SQS_ENDPOINT (optional)
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
AWS SQS queue provider for molecule.dev.
Uses AWS_REGION (default us-east-1) with the standard AWS credential
chain; set SQS_ENDPOINT to target LocalStack. Queue URLs are resolved
lazily on first operation — the queue must already exist (create it with
createQueue() or in AWS) or the first send/receive rejects with the AWS
QueueDoesNotExist error. Pass { autoCreateQueues: true } to
createProvider() to auto-create a standard queue on first use instead
(opt-in — unlike the memory/redis bonds, silently creating AWS resources
has cost/IAM implications, so it is never the default).
import { setProvider, send, subscribe } from '@molecule/api-queue'
import { provider } from '@molecule/api-queue-sqs'
setProvider(provider)
subscribe<{ userId: string }>('emails', async (message) => {
await deliver(message.body) // returning normally acks (deletes) the message
})
await send('emails', { body: { userId: 'u1' } })
provider
npm install @molecule/api-queue-sqs @aws-sdk/client-sqs @molecule/api-bond @molecule/api-proxy-agent @molecule/api-queue @molecule/api-secrets
QueueHandle for a named queue, providing send, receive, and subscribe operations.
interface Queue {
/**
* Queue name.
*/
name: string
/**
* Sends a message to the queue.
*/
send<T = unknown>(message: QueueMessage<T>): Promise<string>
/**
* Sends multiple messages to the queue.
*/
sendBatch?<T = unknown>(messages: QueueMessage<T>[]): Promise<string[]>
/**
* Receives messages from the queue.
*/
receive<T = unknown>(options?: ReceiveOptions): Promise<ReceivedMessage<T>[]>
/**
* Subscribes to messages from the queue.
* Returns a function to unsubscribe.
*/
subscribe<T = unknown>(handler: MessageHandler<T>, options?: ReceiveOptions): () => void
/**
* Gets the approximate number of messages in the queue.
*/
size?(): Promise<number>
/**
* Purges all messages from the queue.
*/
purge?(): Promise<void>
}
QueueCreateOptionsOptions for creating a new queue, including FIFO mode, timeouts, retention periods, and dead-letter queue configuration.
interface QueueCreateOptions {
/**
* Whether this is a FIFO queue.
*/
fifo?: boolean
/**
* Default visibility timeout in seconds.
*/
visibilityTimeout?: number
/**
* Message retention period in seconds.
*/
messageRetentionSeconds?: number
/**
* Maximum message size in bytes.
*/
maxMessageSize?: number
/**
* Dead letter queue configuration.
*/
deadLetterQueue?: {
name: string
maxReceiveCount: number
}
}
QueueMessageMessage to be sent to a queue.
interface QueueMessage<T = unknown> {
/**
* Message payload.
*/
body: T
/**
* Message ID (auto-generated if not provided).
*/
id?: string
/**
* Delay in seconds before the message becomes visible.
*/
delaySeconds?: number
/**
* Message attributes/headers.
*/
attributes?: Record<string, string | number | boolean>
/**
* Message group ID (for FIFO queues).
*/
groupId?: string
/**
* Deduplication ID (for FIFO queues).
*/
deduplicationId?: string
}
QueueProviderQueue provider interface that all queue bond packages must implement. Provides queue handle creation and optional queue management operations.
interface QueueProvider {
/**
* Gets or creates a queue by name.
*/
queue(name: string): Queue
/**
* Lists all available queues.
*/
listQueues?(): Promise<string[]>
/**
* Creates a new queue.
*/
createQueue?(name: string, options?: QueueCreateOptions): Promise<Queue>
/**
* Deletes a queue.
*/
deleteQueue?(name: string): Promise<void>
/**
* Closes all connections.
*/
close?(): Promise<void>
}
ReceivedMessageReceived message from a queue.
interface ReceivedMessage<T = unknown> {
/**
* Message ID.
*/
id: string
/**
* Message payload.
*/
body: T
/**
* Receipt handle for acknowledging the message.
*/
receiptHandle: string
/**
* Message attributes/headers.
*/
attributes?: Record<string, string | number | boolean>
/**
* Number of times this message has been received.
*/
receiveCount?: number
/**
* Timestamp when the message was sent.
*/
sentTimestamp?: Date
/**
* Acknowledges (deletes) the message from the queue.
*/
ack(): Promise<void>
/**
* Rejects the message (returns it to the queue).
*/
nack?(): Promise<void>
}
ReceiveOptionsOptions for receiving messages.
interface ReceiveOptions {
/**
* Maximum number of messages to receive.
*/
maxMessages?: number
/**
* Visibility timeout in seconds.
*/
visibilityTimeout?: number
/**
* Wait time in seconds for long polling.
*/
waitTimeSeconds?: number
}
SQSOptionsOptions for creating an SQS queue provider.
interface SQSOptions {
region?: string
accessKeyId?: string
secretAccessKey?: string
endpoint?: string
accountId?: string
/**
* When `true`, resolving a queue name that does not yet exist in AWS
* auto-creates a standard (non-FIFO) queue with default settings instead
* of rejecting with `QueueDoesNotExist` — matching the memory/redis
* bonds' "just works" first-send behavior. Off by default: unlike an
* in-process or self-hosted broker, silently creating AWS resources has
* cost and IAM-permission implications, so opting in is a deliberate
* choice. When off (the default), create the queue via `createQueue()`,
* the AWS console, or infrastructure-as-code before sending to it.
*/
autoCreateQueues?: boolean
}
MessageHandlerAsync callback invoked for each message received from a queue subscription.
type MessageHandler<T = unknown> = (message: ReceivedMessage<T>) => Promise<void>
createProvider(options)Creates an AWS SQS queue provider. Connects using AWS_REGION env var (default 'us-east-1'),
optional explicit credentials, and optional custom endpoint (e.g. for LocalStack).
function createProvider(options?: SQSOptions): QueueProvider
options — Optional AWS region, credentials, endpoint, and auto-create configuration. Falls back to environment variables.Returns: A QueueProvider that manages SQS queues. Queue URLs are resolved lazily on first operation.
providerLazily-initialized SQS queue provider proxy that creates the provider on first access.
const provider: QueueProvider
queueSqsSecretDefinitionsSecret definitions required by the SQS queue bond.
const queueSqsSecretDefinitions: SecretDefinition[]
Implements @molecule/api-queue interface.
Setup function to register this provider with the core interface:
import { setProvider } from '@molecule/api-queue'
import { provider } from '@molecule/api-queue-sqs'
export function setupQueueSqs(): void {
setProvider(provider)
}
Peer dependencies:
@molecule/api-bond ^1.0.1@molecule/api-queue ^1.0.1@molecule/api-secrets ^1.0.1AWS_REGION (required) — AWS region — default: us-east-1
us-east-1AWS_ACCESS_KEY_ID (required) — AWS access key ID
AKIA...AWS_SECRET_ACCESS_KEY (required) — AWS secret access key
SQS_ENDPOINT (optional) — SQS endpoint override
http://localhost:4566@aws-sdk/client-sqs@molecule/api-bond@molecule/api-proxy-agent@molecule/api-queue@molecule/api-secretsDelivery semantics (at-least-once — handlers must be idempotent):
createQueue(name, { deadLetterQueue: { name, maxReceiveCount } }).ack()/nack() settle at most once; nack() returns the message to the
queue immediately (visibility timeout 0) instead of waiting out the lease..fifo suffix (createQueue(name, { fifo: true })
appends it) and a groupId per message; a deduplicationId is derived
from the message id when not provided.delaySeconds is capped at 900 (15 minutes) by SQS itself.subscribe() retries a failed queue-URL resolution (bad region,
credentials not yet propagated, a QueueDoesNotExist race) with bounded
exponential backoff (1s → 30s) instead of logging once and leaving the
subscription permanently dead — it self-heals once the queue/credentials
become valid.HTTPS_PROXY is set. The AWS SDK v3
builds its own agent and reads no proxy variable, so on a host whose only
egress path is a proxy every queue operation used to fail with a bare
connection error. The client now gets a CONNECT-capable agent through its
own requestHandler hook (@molecule/api-proxy-agent, resolved against
SQS_ENDPOINT when set and the regional endpoint otherwise, so a LocalStack
endpoint in NO_PROXY keeps connecting directly). With no proxy configured
nothing is passed. Allowlist *.amazonaws.com on the proxy.Integration checklist — exercise the REAL behavior end-to-end (drive the app action that enqueues/consumes work in the live preview, no mocks), adapt each item to this app's actual screens/flows, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip:
send() returns a message
id immediately and the request/response does NOT block on the job. The #1
trap: the executor awaits the heavy work inline (defeating the queue);
confirm the triggering UI action returns quickly and the work happens in the
background.subscribe() consumer (a
MessageHandler) is wired and running, so the message's real side effect
(email sent, file processed, notification delivered — whatever the app does)
actually appears in the UI/data. A message enqueued with no worker wired is
the silent failure.ReceivedMessage.body the handler sees
equals the QueueMessage.body that was sent, with no dropped or renamed
fields.QueueCreateOptions.deadLetterQueue.maxReceiveCount, tracked via
receiveCount) or dead-lettered, never silently lost. Delivery is
at-least-once, so the handler is idempotent (dedupe on the job/record id) — a
redelivery must not double-charge or double-send.QueueMessage.groupId/fifo) or exactly-once delivery unless the
bonded provider actually guarantees it.body carries only the ids/refs the job
needs (never a secret or stale authority); the consumer re-loads and
re-scopes on the CURRENT data (owner id from body, re-checked server-side)
so one user's job cannot act on another user's resource.