Integration Runtime Layer
queue
Message queue — Upstash QStash (serverless), with an in-memory fallback for local dev and tests.
email247billing89ai-tasks14webhooks31
| Status | Job | Queue | Attempts | Duration | When |
|---|---|---|---|---|---|
| Processing | job_9f3a2c | ai-tasks | 1/3 | 412 ms | now |
| Success | job_8c41be | 1/3 | 184 ms | 12s ago | |
| Success | job_77d019 | billing | 1/3 | 76 ms | 48s ago |
| Failed | job_6b22f4 | webhooks | 3/3 | 5 012 ms | 1m ago |
| Pending | job_5a18ee | 2/3 | — | 2m ago | |
| Success | job_4e0b7c | billing | 1/3 | 221 ms | 3m ago |
Throughput
1,247
+8.2%
jobs/min
Success rate
99.4%
+0.3%
Last 60 min
Avg latency
184 ms
Healthy
In code
queue.ts
1import { getQueue, createJob } from "@nebutra/queue";
2
3// QStash in production; falls back to in-memory when no env is set.
4const queue = await getQueue();
5
6await queue.enqueue(
7 createJob("billing", "send-invoice", { orderId: order.id }, { tenantId }),
8);
9
10queue.registerHandler("billing", "send-invoice", async (job) => {
11 await sendInvoice(job.data.orderId);
12});More in nebutra.com
- admin-toolingSelf-serve operator dashboards — tenants, billing overrides, feature-flag flips — all gated by @nebutra/permissions.
- cacheTag-based cache with Redis, Upstash, or in-memory backend. Same get/set/invalidate(tags) for serverless and self-hosted.
- collabRealtime co-editing primitives — Yjs CRDT, WebSocket transport, presence cursors. The piece every multi-user app eventually needs.
- emailRender React Email templates, dispatch through Resend / SES / SMTP. One sendEmail(template, props, recipient) for every transactional flow.
- event-busIn-process pub/sub with cross-app fanout. Used by audit, billing, and notifications to react to commerce events without circular imports.
- integration-vaultPer-tenant credential store for OAuth integrations and API keys — Creem, Gmail OAuth, Notion API. KMS-wrapped, refresh-rotated.