@capixjs/transport-queue 0.1.0-alpha.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Capix Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,159 @@
1
+ # @capixjs/transport-queue
2
+
3
+ Queue transport for [Capix](https://github.com/capix/capix). Process background jobs by routing queue messages to capability resolvers — no HTTP, no WebSocket, just workers consuming from a queue adapter.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @capixjs/core @capixjs/transport-queue zod
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import { createServer } from '@capixjs/core';
15
+ import { queueTransport, MemoryQueueAdapter, createQueueClient } from '@capixjs/transport-queue';
16
+ import { buildContext, capabilities } from './capabilities.js';
17
+
18
+ const adapter = new MemoryQueueAdapter();
19
+ const jobQueue = createQueueClient(adapter, 'jobs');
20
+
21
+ createServer({
22
+ context: buildContext,
23
+ capabilities,
24
+ transports: [
25
+ queueTransport({ queues: ['jobs'], adapter }),
26
+ ],
27
+ }).start();
28
+
29
+ // Enqueue a job from anywhere in your application:
30
+ await jobQueue.enqueue('jobs.processOrder', { orderId: '123' });
31
+ ```
32
+
33
+ ## Adapters
34
+
35
+ ### `MemoryQueueAdapter`
36
+
37
+ In-process queue, suitable for development and testing. Jobs are not persisted — they are lost if the process restarts.
38
+
39
+ ```ts
40
+ import { MemoryQueueAdapter } from '@capixjs/transport-queue';
41
+ const adapter = new MemoryQueueAdapter();
42
+ ```
43
+
44
+ ### BullMQ adapter (Redis)
45
+
46
+ ```ts
47
+ import { Queue, Worker } from 'bullmq';
48
+ import type { QueueAdapter, QueueMessage } from '@capixjs/transport-queue';
49
+
50
+ class BullMQAdapter implements QueueAdapter {
51
+ private workers = new Map<string, Worker>();
52
+ private queues = new Map<string, Queue>();
53
+
54
+ async start(queue: string, handler: (msg: QueueMessage) => Promise<unknown>): Promise<void> {
55
+ const worker = new Worker(queue, async (job) => handler(job.data as QueueMessage), {
56
+ connection: { host: 'localhost', port: 6379 },
57
+ });
58
+ this.workers.set(queue, worker);
59
+ }
60
+
61
+ async enqueue(queue: string, msg: QueueMessage): Promise<void> {
62
+ if (!this.queues.has(queue)) {
63
+ this.queues.set(queue, new Queue(queue, { connection: { host: 'localhost', port: 6379 } }));
64
+ }
65
+ await this.queues.get(queue)!.add(msg.capability, msg);
66
+ }
67
+
68
+ async stop(): Promise<void> {
69
+ await Promise.all([
70
+ ...[...this.workers.values()].map((w) => w.close()),
71
+ ...[...this.queues.values()].map((q) => q.close()),
72
+ ]);
73
+ }
74
+ }
75
+ ```
76
+
77
+ ### Custom adapters
78
+
79
+ Implement the `QueueAdapter` interface to connect to SQS, Faktory, or any queue system:
80
+
81
+ ```ts
82
+ import type { QueueAdapter, QueueMessage } from '@capixjs/transport-queue';
83
+
84
+ class BullMQAdapter implements QueueAdapter {
85
+ async start(queue: string, handler: (msg: QueueMessage) => Promise<unknown>): Promise<void> {
86
+ // Subscribe to the BullMQ queue and call handler for each job
87
+ }
88
+ async enqueue(queue: string, msg: QueueMessage): Promise<void> {
89
+ // Add job to BullMQ queue
90
+ }
91
+ async stop(): Promise<void> {
92
+ // Drain and close connections
93
+ }
94
+ }
95
+ ```
96
+
97
+ ## `createQueueClient`
98
+
99
+ Creates a typed client for enqueueing jobs:
100
+
101
+ ```ts
102
+ const jobQueue = createQueueClient(adapter, 'jobs');
103
+
104
+ // Enqueue with capability name and input
105
+ const jobId = await jobQueue.enqueue('jobs.sendEmail', { to: 'user@example.com' });
106
+ ```
107
+
108
+ ## Queue transport vs HTTP
109
+
110
+ The queue transport invokes capabilities through the same execution engine as REST and WebSocket — guards run, input is validated, context is built. The key difference: the caller is the queue adapter, not an HTTP client.
111
+
112
+ ```ts
113
+ // jobs-only capabilities never exposed over HTTP
114
+ createServer({
115
+ context: buildContext,
116
+ transports: [
117
+ restTransport({ port: 3000, capabilities: publicCaps }),
118
+ queueTransport({ queues: ['jobs'], adapter, capabilities: jobCaps }),
119
+ ],
120
+ });
121
+ ```
122
+
123
+ ## Options
124
+
125
+ | Option | Type | Description |
126
+ |--------|------|-------------|
127
+ | `queues` | `string[]` | Queue names to listen on |
128
+ | `adapter` | `QueueAdapter` | Queue backend implementation |
129
+ | `capabilities` | `GroupTree` | Per-transport capability registry (optional) |
130
+
131
+ ## Message format
132
+
133
+ The wire format is the `QueueMessage` type. Any system that can enqueue a JSON object to your queue can trigger Capix capabilities:
134
+
135
+ ```ts
136
+ type QueueMessage = {
137
+ capability: string; // dot-path, e.g. 'jobs.processOrder'
138
+ input: unknown; // passed to the capability's input validator
139
+ };
140
+ ```
141
+
142
+ ## Security note
143
+
144
+ The queue transport does **not** enforce authentication by default. Jobs arrive with a minimal context (just `requestId`) — there is no `Authorization` header. Guards using `ctx.user` will always see `null` for queue-originated jobs unless you explicitly populate the user field in your context builder by reading from the job input or a service account.
145
+
146
+ For queue jobs that should run with service-account privileges, pattern the context builder to check for a job-specific header or trust flag:
147
+
148
+ ```ts
149
+ const buildContext = defineContext(async (req) => ({
150
+ requestId: crypto.randomUUID(),
151
+ user: req.headers['x-service-account'] === process.env.QUEUE_SECRET
152
+ ? SERVICE_ACCOUNT
153
+ : await verifyJwt(req.headers.authorization),
154
+ }));
155
+ ```
156
+
157
+ ## License
158
+
159
+ MIT
@@ -0,0 +1,21 @@
1
+ import type { QueueAdapter, QueueMessage, QueueResult } from '../types.js';
2
+ export type BullMQAdapterOptions = {
3
+ connection: {
4
+ host: string;
5
+ port: number;
6
+ } | {
7
+ url: string;
8
+ };
9
+ concurrency?: number;
10
+ removeOnComplete?: number;
11
+ removeOnFail?: number;
12
+ };
13
+ export declare class BullMQAdapter implements QueueAdapter {
14
+ private options;
15
+ private workers;
16
+ constructor(options: BullMQAdapterOptions);
17
+ start(queueName: string, onMessage: (msg: QueueMessage) => Promise<QueueResult>): Promise<void>;
18
+ enqueue(queueName: string, msg: QueueMessage): Promise<void>;
19
+ stop(): Promise<void>;
20
+ }
21
+ //# sourceMappingURL=bullmq.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bullmq.d.ts","sourceRoot":"","sources":["../../src/adapters/bullmq.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAa3E,MAAM,MAAM,oBAAoB,GAAG;IACjC,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,qBAAa,aAAc,YAAW,YAAY;IAChD,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,OAAO,CAAiD;gBAEpD,OAAO,EAAE,oBAAoB;IAInC,KAAK,CACT,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,OAAO,CAAC,WAAW,CAAC,GACrD,OAAO,CAAC,IAAI,CAAC;IAwBV,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAO5D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAM5B"}
@@ -0,0 +1,46 @@
1
+ async function loadBullMQ() {
2
+ try {
3
+ return await import('bullmq');
4
+ }
5
+ catch {
6
+ throw new Error('[capix] capix-transport-queue BullMQ adapter requires bullmq and ioredis.\n' +
7
+ 'Install them: pnpm add bullmq ioredis');
8
+ }
9
+ }
10
+ export class BullMQAdapter {
11
+ options;
12
+ workers = new Map();
13
+ constructor(options) {
14
+ this.options = options;
15
+ }
16
+ async start(queueName, onMessage) {
17
+ const { Worker } = await loadBullMQ();
18
+ const worker = new Worker(queueName, async (job) => {
19
+ const result = await onMessage(job.data);
20
+ if (!result.ok) {
21
+ throw new Error(JSON.stringify(result.error));
22
+ }
23
+ return result.data;
24
+ }, {
25
+ connection: this.options.connection,
26
+ concurrency: this.options.concurrency ?? 10,
27
+ removeOnComplete: { count: this.options.removeOnComplete ?? 100 },
28
+ removeOnFail: { count: this.options.removeOnFail ?? 1000 },
29
+ });
30
+ this.workers.set(queueName, worker);
31
+ console.log(`[capix] Queue transport processing: ${queueName}`);
32
+ }
33
+ async enqueue(queueName, msg) {
34
+ const { Queue } = await loadBullMQ();
35
+ const queue = new Queue(queueName, { connection: this.options.connection });
36
+ await queue.add(msg.capability, msg, { jobId: msg.id });
37
+ await queue.close();
38
+ }
39
+ async stop() {
40
+ for (const worker of this.workers.values()) {
41
+ await worker.close();
42
+ }
43
+ this.workers.clear();
44
+ }
45
+ }
46
+ //# sourceMappingURL=bullmq.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bullmq.js","sourceRoot":"","sources":["../../src/adapters/bullmq.ts"],"names":[],"mappings":"AAEA,KAAK,UAAU,UAAU;IACvB,IAAI,CAAC;QACH,OAAO,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,6EAA6E;YAC7E,uCAAuC,CACxC,CAAC;IACJ,CAAC;AACH,CAAC;AASD,MAAM,OAAO,aAAa;IAChB,OAAO,CAAuB;IAC9B,OAAO,GAAG,IAAI,GAAG,EAAsC,CAAC;IAEhE,YAAY,OAA6B;QACvC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,KAAK,CACT,SAAiB,EACjB,SAAsD;QAEtD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,UAAU,EAAE,CAAC;QAEtC,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,SAAS,EACT,KAAK,EAAE,GAA2B,EAAE,EAAE;YACpC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;gBACf,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAChD,CAAC;YACD,OAAO,MAAM,CAAC,IAAI,CAAC;QACrB,CAAC,EACD;YACE,UAAU,EAAQ,IAAI,CAAC,OAAO,CAAC,UAAU;YACzC,WAAW,EAAO,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,EAAE;YAChD,gBAAgB,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,gBAAgB,IAAI,GAAG,EAAE;YACjE,YAAY,EAAM,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,IAAI,EAAE;SAC/D,CACF,CAAC;QAEF,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,MAAoC,CAAC,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,uCAAuC,SAAS,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,SAAiB,EAAE,GAAiB;QAChD,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,UAAU,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;QAC5E,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QACxD,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,IAAI;QACR,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAC3C,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;CACF"}
@@ -0,0 +1,11 @@
1
+ import type { QueueAdapter, QueueMessage, QueueResult } from '../types.js';
2
+ export declare class MemoryQueueAdapter implements QueueAdapter {
3
+ private queues;
4
+ private handlers;
5
+ private running;
6
+ start(queueName: string, onMessage: (msg: QueueMessage) => Promise<QueueResult>): Promise<void>;
7
+ enqueue(queueName: string, msg: QueueMessage): Promise<void>;
8
+ private processQueue;
9
+ stop(): Promise<void>;
10
+ }
11
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/adapters/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM3E,qBAAa,kBAAmB,YAAW,YAAY;IACrD,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,QAAQ,CAAkE;IAClF,OAAO,CAAC,OAAO,CAAU;IAEnB,KAAK,CACT,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,OAAO,CAAC,WAAW,CAAC,GACrD,OAAO,CAAC,IAAI,CAAC;IAMV,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAelE,OAAO,CAAC,YAAY;IAcd,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAI5B"}
@@ -0,0 +1,44 @@
1
+ export class MemoryQueueAdapter {
2
+ queues = new Map();
3
+ handlers = new Map();
4
+ running = false;
5
+ async start(queueName, onMessage) {
6
+ this.handlers.set(queueName, onMessage);
7
+ this.running = true;
8
+ this.processQueue(queueName);
9
+ }
10
+ async enqueue(queueName, msg) {
11
+ const handler = this.handlers.get(queueName);
12
+ if (handler && this.running) {
13
+ setImmediate(() => {
14
+ handler(msg).catch(() => {
15
+ // Silently drop failed jobs — caller should handle errors in onMessage
16
+ });
17
+ });
18
+ }
19
+ else {
20
+ if (!this.queues.has(queueName))
21
+ this.queues.set(queueName, []);
22
+ this.queues.get(queueName).push({ msg });
23
+ }
24
+ }
25
+ processQueue(queueName) {
26
+ const pending = this.queues.get(queueName);
27
+ if (!pending || pending.length === 0)
28
+ return;
29
+ const handler = this.handlers.get(queueName);
30
+ if (!handler)
31
+ return;
32
+ this.queues.set(queueName, []);
33
+ for (const job of pending) {
34
+ setImmediate(() => {
35
+ handler(job.msg).catch(() => { });
36
+ });
37
+ }
38
+ }
39
+ async stop() {
40
+ this.running = false;
41
+ this.handlers.clear();
42
+ }
43
+ }
44
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/adapters/memory.ts"],"names":[],"mappings":"AAMA,MAAM,OAAO,kBAAkB;IACrB,MAAM,GAAK,IAAI,GAAG,EAAwB,CAAC;IAC3C,QAAQ,GAAG,IAAI,GAAG,EAAuD,CAAC;IAC1E,OAAO,GAAI,KAAK,CAAC;IAEzB,KAAK,CAAC,KAAK,CACT,SAAiB,EACjB,SAAsD;QAEtD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,SAAiB,EAAE,GAAiB;QAChD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAE7C,IAAI,OAAO,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC5B,YAAY,CAAC,GAAG,EAAE;gBAChB,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;oBACtB,uEAAuE;gBACzE,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC;gBAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;YAChE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAE,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,SAAiB;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAC/B,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,YAAY,CAAC,GAAG,EAAE;gBAChB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACnC,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ export { queueTransport, createQueueClient } from './transport.js';
2
+ export { MemoryQueueAdapter } from './adapters/memory.js';
3
+ export { BullMQAdapter } from './adapters/bullmq.js';
4
+ export type { QueueAdapter, QueueMessage, QueueResult } from './types.js';
5
+ export type { QueueTransportOptions } from './transport.js';
6
+ export type { BullMQAdapterOptions } from './adapters/bullmq.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAqB,sBAAsB,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAA0B,sBAAsB,CAAC;AACzE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC1E,YAAY,EAAE,qBAAqB,EAAE,MAAa,gBAAgB,CAAC;AACnE,YAAY,EAAE,oBAAoB,EAAE,MAAc,sBAAsB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { queueTransport, createQueueClient } from './transport.js';
2
+ export { MemoryQueueAdapter } from './adapters/memory.js';
3
+ export { BullMQAdapter } from './adapters/bullmq.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAqB,sBAAsB,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAA0B,sBAAsB,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { GroupTree, TransportWithCapabilities } from '@capixjs/core';
2
+ import type { QueueAdapter } from './types.js';
3
+ export type QueueTransportOptions = {
4
+ queues: string[];
5
+ adapter: QueueAdapter;
6
+ /** Capability registry for this transport only. Overrides the server-level default. */
7
+ capabilities?: GroupTree;
8
+ };
9
+ export declare function queueTransport(options: QueueTransportOptions): TransportWithCapabilities;
10
+ export declare function createQueueClient(adapter: QueueAdapter, queueName: string): {
11
+ enqueue(capability: string, input: unknown, headers?: Record<string, string>): Promise<string>;
12
+ };
13
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqC,SAAS,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAC7G,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAoD,YAAY,CAAC;AAG3G,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAI,MAAM,EAAE,CAAC;IACnB,OAAO,EAAG,YAAY,CAAC;IACvB,uFAAuF;IACvF,YAAY,CAAC,EAAE,SAAS,CAAC;CAC1B,CAAC;AAEF,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,yBAAyB,CAqBxF;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM;wBAGxD,MAAM,SACN,OAAO,YACP,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACjC,OAAO,CAAC,MAAM,CAAC;EAMrB"}
@@ -0,0 +1,31 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ export function queueTransport(options) {
3
+ return {
4
+ ...(options.capabilities !== undefined ? { _capabilities: options.capabilities } : {}),
5
+ async mount(invoke, _mountOptions) {
6
+ for (const queueName of options.queues) {
7
+ await options.adapter.start(queueName, async (msg) => {
8
+ return invoke({
9
+ capability: msg.capability,
10
+ input: msg.input,
11
+ headers: msg.headers,
12
+ signal: AbortSignal.timeout(300_000),
13
+ });
14
+ });
15
+ }
16
+ },
17
+ async unmount() {
18
+ await options.adapter.stop();
19
+ },
20
+ };
21
+ }
22
+ export function createQueueClient(adapter, queueName) {
23
+ return {
24
+ async enqueue(capability, input, headers = {}) {
25
+ const id = randomUUID();
26
+ await adapter.enqueue(queueName, { id, capability, input, headers });
27
+ return id;
28
+ },
29
+ };
30
+ }
31
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAyE,aAAa,CAAC;AAS5G,MAAM,UAAU,cAAc,CAAC,OAA8B;IAC3D,OAAO;QACL,GAAG,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAEtF,KAAK,CAAC,KAAK,CAAC,MAAgB,EAAE,aAA2B;YACvD,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACvC,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,EAAE,GAAiB,EAAE,EAAE;oBACjE,OAAO,MAAM,CAAC;wBACZ,UAAU,EAAE,GAAG,CAAC,UAAU;wBAC1B,KAAK,EAAO,GAAG,CAAC,KAAK;wBACrB,OAAO,EAAK,GAAG,CAAC,OAAO;wBACvB,MAAM,EAAM,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC;qBACzC,CAAC,CAAC;gBACL,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,KAAK,CAAC,OAAO;YACX,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAC/B,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAAqB,EAAE,SAAiB;IACxE,OAAO;QACL,KAAK,CAAC,OAAO,CACX,UAAkB,EAClB,KAAmB,EACnB,UAAqC,EAAE;YAEvC,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC;YACxB,MAAM,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;YACrE,OAAO,EAAE,CAAC;QACZ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,24 @@
1
+ export type QueueMessage = {
2
+ id: string;
3
+ capability: string;
4
+ input: unknown;
5
+ headers: Record<string, string>;
6
+ };
7
+ export type QueueResult = {
8
+ ok: true;
9
+ data: unknown;
10
+ } | {
11
+ ok: false;
12
+ error: {
13
+ status: number;
14
+ error: string;
15
+ message: string;
16
+ meta?: Record<string, unknown>;
17
+ };
18
+ };
19
+ export interface QueueAdapter {
20
+ start(queueName: string, onMessage: (msg: QueueMessage) => Promise<QueueResult>): Promise<void>;
21
+ enqueue(queueName: string, msg: QueueMessage): Promise<void>;
22
+ stop(): Promise<void>;
23
+ }
24
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAU,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAO,OAAO,CAAC;IACpB,OAAO,EAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,WAAW,GACnB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GAC5B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAA;CAAE,CAAC;AAE7G,MAAM,WAAW,YAAY;IAC3B,KAAK,CACH,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,OAAO,CAAC,WAAW,CAAC,GACrD,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@capixjs/transport-queue",
3
+ "version": "0.1.0-alpha.1",
4
+ "description": "Message queue transport for Capix (BullMQ + in-memory)",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ },
14
+ "./memory": {
15
+ "import": "./dist/adapters/memory.js",
16
+ "types": "./dist/adapters/memory.d.ts"
17
+ },
18
+ "./bullmq": {
19
+ "import": "./dist/adapters/bullmq.js",
20
+ "types": "./dist/adapters/bullmq.d.ts"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "!dist/**/*.test.*",
26
+ "LICENSE"
27
+ ],
28
+ "keywords": [
29
+ "capix",
30
+ "queue",
31
+ "bullmq",
32
+ "redis",
33
+ "transport",
34
+ "background-jobs",
35
+ "typescript"
36
+ ],
37
+ "engines": {
38
+ "node": ">=20"
39
+ },
40
+ "scripts": {
41
+ "build": "tsc",
42
+ "test": "vitest run",
43
+ "typecheck": "tsc --noEmit"
44
+ },
45
+ "peerDependencies": {
46
+ "@capixjs/core": ">=0.1.0-0"
47
+ },
48
+ "peerDependenciesMeta": {
49
+ "bullmq": {
50
+ "optional": true
51
+ },
52
+ "ioredis": {
53
+ "optional": true
54
+ }
55
+ },
56
+ "devDependencies": {
57
+ "@types/node": "^20.0.0",
58
+ "bullmq": "^5.0.0",
59
+ "ioredis": "^5.0.0",
60
+ "typescript": "^5.5.0",
61
+ "vitest": "^1.6.0",
62
+ "zod": "^3.23.0",
63
+ "@capixjs/core": "workspace:*"
64
+ }
65
+ }