@queuedash/sdk 0.1.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 ADDED
@@ -0,0 +1,163 @@
1
+ # @queuedash/sdk
2
+
3
+ Official SDK for QueueDash - Real-time monitoring for Bull, BullMQ, and Bee-Queue.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @queuedash/sdk
9
+ # or
10
+ pnpm add @queuedash/sdk
11
+ # or
12
+ yarn add @queuedash/sdk
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ### BullMQ
18
+
19
+ ```typescript
20
+ import { Queue } from "bullmq";
21
+ import { QueueDashClient, attachToBullMQ } from "@queuedash/sdk";
22
+
23
+ // Create your queue
24
+ const myQueue = new Queue("my-queue", {
25
+ connection: { host: "localhost", port: 6379 },
26
+ });
27
+
28
+ // Initialize QueueDash client
29
+ const queueDash = new QueueDashClient({
30
+ apiKey: process.env.QUEUEDASH_API_KEY,
31
+ });
32
+
33
+ // Attach to your queue - that's it!
34
+ attachToBullMQ(myQueue, queueDash);
35
+
36
+ // Jobs are now automatically synced to QueueDash
37
+ ```
38
+
39
+ ### Bull
40
+
41
+ ```typescript
42
+ import Queue from "bull";
43
+ import { QueueDashClient, attachToBull } from "@queuedash/sdk";
44
+
45
+ const myQueue = new Queue("my-queue", {
46
+ redis: { host: "localhost", port: 6379 },
47
+ });
48
+
49
+ const queueDash = new QueueDashClient({
50
+ apiKey: process.env.QUEUEDASH_API_KEY,
51
+ });
52
+
53
+ attachToBull(myQueue, queueDash);
54
+ ```
55
+
56
+ ### Bee-Queue
57
+
58
+ ```typescript
59
+ import Queue from "bee-queue";
60
+ import { QueueDashClient, attachToBeeQueue } from "@queuedash/sdk";
61
+
62
+ const myQueue = new Queue("my-queue", {
63
+ redis: { host: "localhost", port: 6379 },
64
+ });
65
+
66
+ const queueDash = new QueueDashClient({
67
+ apiKey: process.env.QUEUEDASH_API_KEY,
68
+ });
69
+
70
+ attachToBeeQueue(myQueue, queueDash);
71
+ ```
72
+
73
+ ## Configuration
74
+
75
+ ### API Key
76
+
77
+ Get your API key from [QueueDash](https://queuedash.com):
78
+
79
+ 1. Navigate to your environment settings
80
+ 2. Click "API Keys"
81
+ 3. Generate a new API key
82
+
83
+ ```bash
84
+ # Set in your environment
85
+ QUEUEDASH_API_KEY=sk_live_...
86
+ ```
87
+
88
+ ### Advanced Options
89
+
90
+ ```typescript
91
+ interface QueueDashClientOptions {
92
+ // Required: Your API key from QueueDash
93
+ apiKey: string;
94
+
95
+ // Optional: Batch size for syncing jobs (defaults to 50)
96
+ batchSize?: number;
97
+
98
+ // Optional: Flush interval in milliseconds (defaults to 100)
99
+ flushInterval?: number;
100
+
101
+ // Optional: Max retry attempts with exponential backoff (defaults to 5)
102
+ maxRetries?: number;
103
+
104
+ // Optional: Request timeout in milliseconds (defaults to 30000)
105
+ requestTimeout?: number;
106
+
107
+ // Optional: Max jobs to queue in memory (defaults to 10000)
108
+ maxQueueSize?: number;
109
+
110
+ // Optional: Error handler called on critical failures
111
+ onError?: (error: Error) => void;
112
+ }
113
+ ```
114
+
115
+ ### Reliability & Robustness
116
+
117
+ The SDK is production-ready with multiple layers of protection:
118
+
119
+ **Retry Logic**
120
+
121
+ - Automatic retries up to 5 times (configurable)
122
+ - Exponential backoff: 1s → 2s → 4s → 8s → 16s → 30s (capped)
123
+ - Jobs preserved in local queue until successfully synced
124
+
125
+ **Circuit Breaker**
126
+
127
+ - Opens after 10 consecutive failures to prevent overwhelming the API
128
+ - Auto-resets after 60 seconds
129
+ - Prevents cascading failures
130
+
131
+ **Memory Protection**
132
+
133
+ - Queue size limit (10,000 jobs default) prevents memory leaks
134
+ - Oldest jobs dropped first if limit reached
135
+ - Warning logged when queue limit hit
136
+
137
+ **Graceful Shutdown**
138
+
139
+ - SIGTERM/SIGINT handlers flush pending jobs before exit
140
+ - Warns if jobs remain unsynced on crash
141
+ - No jobs lost during normal shutdown
142
+
143
+ **Request Safety**
144
+
145
+ - 30-second timeout on all HTTP requests
146
+ - Duplicate detection prevents same job syncing twice
147
+ - Network errors handled gracefully
148
+
149
+ ## Features
150
+
151
+ - **Real-time sync**: Jobs are synced as events happen
152
+ - **Smart batching**: Events are automatically batched for performance
153
+ - **Auto-retry**: Failed syncs are automatically retried
154
+ - **Zero config**: Works out of the box with sensible defaults
155
+ - **TypeScript**: Full TypeScript support
156
+
157
+ ## How It Works
158
+
159
+ The SDK automatically syncs your queue jobs to QueueDash's SaaS platform at `api.queuedash.com`. Just provide your API key and you're done - no additional configuration needed!
160
+
161
+ ## License
162
+
163
+ MIT
@@ -0,0 +1,37 @@
1
+ import { JobData, QueueDashClientOptions } from "./types";
2
+ export declare class QueueDashClient {
3
+ private apiKey;
4
+ private apiUrl;
5
+ private batchSize;
6
+ private flushInterval;
7
+ private maxRetries;
8
+ private requestTimeout;
9
+ private maxQueueSize;
10
+ private onError?;
11
+ private jobQueue;
12
+ private flushTimer?;
13
+ private isFlushing;
14
+ private retryCount;
15
+ private circuitBreakerFailures;
16
+ private circuitBreakerOpen;
17
+ private circuitBreakerResetTimer?;
18
+ private syncingJobIds;
19
+ constructor(options: QueueDashClientOptions);
20
+ /**
21
+ * Queue a job for syncing
22
+ */
23
+ syncJob(job: JobData): void;
24
+ /**
25
+ * Manually flush all pending jobs
26
+ */
27
+ flush(): Promise<void>;
28
+ private openCircuitBreaker;
29
+ private logger;
30
+ /**
31
+ * Stop the client and flush remaining jobs
32
+ */
33
+ stop(): Promise<void>;
34
+ private startFlushTimer;
35
+ private setupShutdownHandlers;
36
+ }
37
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,sBAAsB,EAAgB,MAAM,SAAS,CAAC;AAExE,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,OAAO,CAAC,CAAyB;IAEzC,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,UAAU,CAAC,CAAiB;IACpC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,sBAAsB,CAAK;IACnC,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,wBAAwB,CAAC,CAAiB;IAClD,OAAO,CAAC,aAAa,CAAqB;gBAE9B,OAAO,EAAE,sBAAsB;IA0B3C;;OAEG;IACI,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI;IA8BlC;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyGnC,OAAO,CAAC,kBAAkB;IAoB1B,OAAO,CAAC,MAAM;IASd;;OAEG;IACU,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAUlC,OAAO,CAAC,eAAe;IAavB,OAAO,CAAC,qBAAqB;CAkB9B"}
package/dist/client.js ADDED
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QueueDashClient = void 0;
4
+ class QueueDashClient {
5
+ constructor(options) {
6
+ this.jobQueue = [];
7
+ this.isFlushing = false;
8
+ this.retryCount = 0;
9
+ this.circuitBreakerFailures = 0;
10
+ this.circuitBreakerOpen = false;
11
+ this.syncingJobIds = new Set();
12
+ if (!options.apiKey) {
13
+ throw new Error("QueueDash: apiKey is required");
14
+ }
15
+ this.apiKey = options.apiKey;
16
+ // Hardcoded SaaS API URL - can be overridden for staging only
17
+ this.apiUrl =
18
+ options.__dangerouslyOverrideApiUrl ||
19
+ (process.env.NODE_ENV === "production"
20
+ ? "https://api.queuedash.com"
21
+ : "http://localhost:4001");
22
+ this.batchSize = options.batchSize || 50;
23
+ this.flushInterval = options.flushInterval || 100; // ms
24
+ this.maxRetries = options.maxRetries || 5;
25
+ this.requestTimeout = options.requestTimeout || 30000; // 30s default
26
+ this.maxQueueSize = options.maxQueueSize || 10000; // Prevent memory issues
27
+ this.onError = options.onError;
28
+ // Start auto-flush timer
29
+ this.startFlushTimer();
30
+ // Graceful shutdown handlers
31
+ this.setupShutdownHandlers();
32
+ }
33
+ /**
34
+ * Queue a job for syncing
35
+ */
36
+ syncJob(job) {
37
+ // Check circuit breaker
38
+ if (this.circuitBreakerOpen) {
39
+ this.logger("Circuit breaker open, dropping job");
40
+ return;
41
+ }
42
+ // Prevent duplicate syncs of same job
43
+ const jobKey = `${job.queueName}:${job.jobId}`;
44
+ if (this.syncingJobIds.has(jobKey)) {
45
+ return;
46
+ }
47
+ this.syncingJobIds.add(jobKey);
48
+ // Prevent memory leak - drop oldest jobs if queue too large
49
+ if (this.jobQueue.length >= this.maxQueueSize) {
50
+ const dropped = this.jobQueue.shift();
51
+ this.logger(`Queue size limit reached (${this.maxQueueSize}), dropping oldest job: ${dropped?.jobId}`);
52
+ }
53
+ this.jobQueue.push(job);
54
+ // Flush if batch size reached
55
+ if (this.jobQueue.length >= this.batchSize) {
56
+ this.flush();
57
+ }
58
+ }
59
+ /**
60
+ * Manually flush all pending jobs
61
+ */
62
+ async flush() {
63
+ if (this.isFlushing ||
64
+ this.jobQueue.length === 0 ||
65
+ this.circuitBreakerOpen) {
66
+ return;
67
+ }
68
+ this.isFlushing = true;
69
+ const jobsToSync = [...this.jobQueue];
70
+ this.jobQueue = [];
71
+ try {
72
+ // Add timeout to fetch
73
+ const controller = new AbortController();
74
+ const timeoutId = setTimeout(() => controller.abort(), this.requestTimeout);
75
+ const response = await fetch(`${this.apiUrl}/api/v1/jobs/sync`, {
76
+ method: "POST",
77
+ headers: {
78
+ "Content-Type": "application/json",
79
+ Authorization: `Bearer ${this.apiKey}`,
80
+ },
81
+ body: JSON.stringify({
82
+ jobs: jobsToSync,
83
+ }),
84
+ signal: controller.signal,
85
+ });
86
+ clearTimeout(timeoutId);
87
+ if (!response.ok) {
88
+ const errorText = await response.text();
89
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
90
+ }
91
+ const result = (await response.json());
92
+ if (!result.success && result.errors) {
93
+ console.warn("QueueDash: Some jobs failed to sync:", result.errors);
94
+ }
95
+ // Success - reset counters and clear syncing jobs
96
+ this.retryCount = 0;
97
+ this.circuitBreakerFailures = 0;
98
+ jobsToSync.forEach((job) => {
99
+ this.syncingJobIds.delete(`${job.queueName}:${job.jobId}`);
100
+ });
101
+ }
102
+ catch (error) {
103
+ this.retryCount++;
104
+ this.circuitBreakerFailures++;
105
+ const err = error instanceof Error ? error : new Error(String(error));
106
+ // Circuit breaker - open after 10 consecutive failures
107
+ if (this.circuitBreakerFailures >= 10) {
108
+ this.openCircuitBreaker();
109
+ }
110
+ // Check if we should retry
111
+ if (this.retryCount <= this.maxRetries) {
112
+ // Put jobs back in queue for retry with exponential backoff
113
+ this.jobQueue.unshift(...jobsToSync);
114
+ const backoffMs = Math.min(1000 * Math.pow(2, this.retryCount - 1), 30000); // Max 30s
115
+ this.logger(`Retry ${this.retryCount}/${this.maxRetries} after ${backoffMs}ms`, err);
116
+ // Schedule retry
117
+ setTimeout(() => {
118
+ if (this.jobQueue.length > 0) {
119
+ this.flush();
120
+ }
121
+ }, backoffMs);
122
+ }
123
+ else {
124
+ // Max retries reached - clear syncing jobs and alert
125
+ this.retryCount = 0;
126
+ jobsToSync.forEach((job) => {
127
+ this.syncingJobIds.delete(`${job.queueName}:${job.jobId}`);
128
+ });
129
+ const errorMsg = `Failed to sync ${jobsToSync.length} jobs after ${this.maxRetries} retries`;
130
+ if (this.onError) {
131
+ this.onError(new Error(`${errorMsg}: ${err.message}`));
132
+ }
133
+ else {
134
+ console.error(`QueueDash: ${errorMsg}`, err);
135
+ }
136
+ }
137
+ }
138
+ finally {
139
+ this.isFlushing = false;
140
+ }
141
+ }
142
+ openCircuitBreaker() {
143
+ if (this.circuitBreakerOpen)
144
+ return;
145
+ this.circuitBreakerOpen = true;
146
+ console.error("QueueDash: Circuit breaker opened after 10 consecutive failures. Will retry in 60s.");
147
+ // Auto-reset after 60 seconds
148
+ this.circuitBreakerResetTimer = setTimeout(() => {
149
+ this.circuitBreakerOpen = false;
150
+ this.circuitBreakerFailures = 0;
151
+ console.log("QueueDash: Circuit breaker reset, resuming sync attempts");
152
+ }, 60000);
153
+ if (this.circuitBreakerResetTimer.unref) {
154
+ this.circuitBreakerResetTimer.unref();
155
+ }
156
+ }
157
+ logger(message, error) {
158
+ if (this.onError && error) {
159
+ // If onError is provided, use it for warnings too
160
+ console.warn(`QueueDash: ${message}`, error);
161
+ }
162
+ else {
163
+ console.warn(`QueueDash: ${message}`);
164
+ }
165
+ }
166
+ /**
167
+ * Stop the client and flush remaining jobs
168
+ */
169
+ async stop() {
170
+ if (this.flushTimer) {
171
+ clearInterval(this.flushTimer);
172
+ }
173
+ if (this.circuitBreakerResetTimer) {
174
+ clearTimeout(this.circuitBreakerResetTimer);
175
+ }
176
+ await this.flush();
177
+ }
178
+ startFlushTimer() {
179
+ this.flushTimer = setInterval(() => {
180
+ if (this.jobQueue.length > 0) {
181
+ this.flush();
182
+ }
183
+ }, this.flushInterval);
184
+ // Don't keep process alive
185
+ if (this.flushTimer.unref) {
186
+ this.flushTimer.unref();
187
+ }
188
+ }
189
+ setupShutdownHandlers() {
190
+ const shutdown = async () => {
191
+ console.log("QueueDash: Graceful shutdown - flushing remaining jobs...");
192
+ await this.stop();
193
+ process.exit(0);
194
+ };
195
+ // Handle graceful shutdown
196
+ process.once("SIGTERM", shutdown);
197
+ process.once("SIGINT", shutdown);
198
+ process.once("beforeExit", () => {
199
+ if (this.jobQueue.length > 0) {
200
+ console.warn(`QueueDash: Process exiting with ${this.jobQueue.length} unsync'd jobs`);
201
+ }
202
+ });
203
+ }
204
+ }
205
+ exports.QueueDashClient = QueueDashClient;
@@ -0,0 +1,6 @@
1
+ export { QueueDashClient } from "./client";
2
+ export { attachToBullMQ } from "./integrations/bullmq";
3
+ export { attachToBull } from "./integrations/bull";
4
+ export { attachToBeeQueue } from "./integrations/bee";
5
+ export type { QueueDashClientOptions, JobData, SyncResponse } from "./types";
6
+ //# 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,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,sBAAsB,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.attachToBeeQueue = exports.attachToBull = exports.attachToBullMQ = exports.QueueDashClient = void 0;
4
+ var client_1 = require("./client");
5
+ Object.defineProperty(exports, "QueueDashClient", { enumerable: true, get: function () { return client_1.QueueDashClient; } });
6
+ var bullmq_1 = require("./integrations/bullmq");
7
+ Object.defineProperty(exports, "attachToBullMQ", { enumerable: true, get: function () { return bullmq_1.attachToBullMQ; } });
8
+ var bull_1 = require("./integrations/bull");
9
+ Object.defineProperty(exports, "attachToBull", { enumerable: true, get: function () { return bull_1.attachToBull; } });
10
+ var bee_1 = require("./integrations/bee");
11
+ Object.defineProperty(exports, "attachToBeeQueue", { enumerable: true, get: function () { return bee_1.attachToBeeQueue; } });
@@ -0,0 +1,8 @@
1
+ import { QueueDashClient } from "../client";
2
+ type BeeQueue = any;
3
+ /**
4
+ * Attach QueueDash monitoring to a Bee-Queue
5
+ */
6
+ export declare function attachToBeeQueue(queue: BeeQueue, client: QueueDashClient): void;
7
+ export {};
8
+ //# sourceMappingURL=bee.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bee.d.ts","sourceRoot":"","sources":["../../src/integrations/bee.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAG5C,KAAK,QAAQ,GAAG,GAAG,CAAC;AAGpB;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE,eAAe,GACtB,IAAI,CAwCN"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.attachToBeeQueue = attachToBeeQueue;
4
+ /**
5
+ * Attach QueueDash monitoring to a Bee-Queue
6
+ */
7
+ function attachToBeeQueue(queue, client) {
8
+ const queueName = queue.name;
9
+ const extractJobData = (job) => {
10
+ return {
11
+ jobId: String(job.id),
12
+ name: "default", // Bee-Queue doesn't have job names
13
+ queueName,
14
+ data: job.data,
15
+ opts: job.options || {},
16
+ addedAt: job.options?.timestamp
17
+ ? new Date(job.options.timestamp)
18
+ : new Date(),
19
+ processedAt: null,
20
+ finishedAt: null,
21
+ priority: null,
22
+ delay: job.options?.delay,
23
+ };
24
+ };
25
+ // Listen to queue events
26
+ queue.on("succeeded", (job) => {
27
+ const jobData = extractJobData(job);
28
+ jobData.finishedAt = new Date();
29
+ client.syncJob(jobData);
30
+ });
31
+ queue.on("failed", (job, err) => {
32
+ const jobData = extractJobData(job);
33
+ jobData.failedReason = err.message;
34
+ jobData.stacktrace = err.stack ? [err.stack] : undefined;
35
+ jobData.finishedAt = new Date();
36
+ client.syncJob(jobData);
37
+ });
38
+ queue.on("retrying", (job) => {
39
+ const jobData = extractJobData(job);
40
+ jobData.retriedAt = new Date();
41
+ client.syncJob(jobData);
42
+ });
43
+ }
@@ -0,0 +1,8 @@
1
+ import { QueueDashClient } from "../client";
2
+ type BullQueue = any;
3
+ /**
4
+ * Attach QueueDash monitoring to a Bull queue
5
+ */
6
+ export declare function attachToBull(queue: BullQueue, client: QueueDashClient): void;
7
+ export {};
8
+ //# sourceMappingURL=bull.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bull.d.ts","sourceRoot":"","sources":["../../src/integrations/bull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAG5C,KAAK,SAAS,GAAG,GAAG,CAAC;AAGrB;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA4C5E"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.attachToBull = attachToBull;
4
+ /**
5
+ * Attach QueueDash monitoring to a Bull queue
6
+ */
7
+ function attachToBull(queue, client) {
8
+ const queueName = queue.name;
9
+ const extractJobData = (job) => {
10
+ return {
11
+ jobId: job.id,
12
+ name: job.name || "default",
13
+ queueName,
14
+ data: job.data,
15
+ opts: job.opts,
16
+ addedAt: new Date(job.timestamp),
17
+ processedAt: job.processedOn ? new Date(job.processedOn) : null,
18
+ finishedAt: job.finishedOn ? new Date(job.finishedOn) : null,
19
+ failedReason: job.failedReason,
20
+ stacktrace: job.stacktrace,
21
+ priority: job.opts?.priority,
22
+ delay: job.opts?.delay,
23
+ timestamp: job.timestamp,
24
+ progress: job._progress || null,
25
+ };
26
+ };
27
+ // Listen to queue events
28
+ queue.on("completed", (job) => {
29
+ client.syncJob(extractJobData(job));
30
+ });
31
+ queue.on("failed", (job) => {
32
+ if (job) {
33
+ client.syncJob(extractJobData(job));
34
+ }
35
+ });
36
+ queue.on("active", (job) => {
37
+ client.syncJob(extractJobData(job));
38
+ });
39
+ queue.on("progress", (job) => {
40
+ client.syncJob(extractJobData(job));
41
+ });
42
+ queue.on("removed", (job) => {
43
+ client.syncJob(extractJobData(job));
44
+ });
45
+ }
@@ -0,0 +1,8 @@
1
+ import { QueueDashClient } from "../client";
2
+ type BullMQQueue = any;
3
+ /**
4
+ * Attach QueueDash monitoring to a BullMQ queue
5
+ */
6
+ export declare function attachToBullMQ(queue: BullMQQueue, client: QueueDashClient): void;
7
+ export {};
8
+ //# sourceMappingURL=bullmq.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bullmq.d.ts","sourceRoot":"","sources":["../../src/integrations/bullmq.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAG5C,KAAK,WAAW,GAAG,GAAG,CAAC;AAGvB;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,eAAe,GACtB,IAAI,CA6CN"}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.attachToBullMQ = attachToBullMQ;
4
+ /**
5
+ * Attach QueueDash monitoring to a BullMQ queue
6
+ */
7
+ function attachToBullMQ(queue, client) {
8
+ const queueName = queue.name;
9
+ const extractJobData = (job) => {
10
+ return {
11
+ jobId: job.id,
12
+ name: job.name,
13
+ queueName,
14
+ data: job.data,
15
+ opts: job.opts,
16
+ addedAt: new Date(job.timestamp),
17
+ processedAt: job.processedOn ? new Date(job.processedOn) : null,
18
+ finishedAt: job.finishedOn ? new Date(job.finishedOn) : null,
19
+ failedReason: job.failedReason,
20
+ stacktrace: job.stacktrace,
21
+ retriedAt: job.retriedAt ? new Date(job.retriedAt) : null,
22
+ priority: job.opts?.priority,
23
+ delay: job.opts?.delay,
24
+ timestamp: job.timestamp,
25
+ progress: job.progress || null,
26
+ };
27
+ };
28
+ // Listen to queue events
29
+ queue.on("completed", (job) => {
30
+ client.syncJob(extractJobData(job));
31
+ });
32
+ queue.on("failed", (job) => {
33
+ if (job) {
34
+ client.syncJob(extractJobData(job));
35
+ }
36
+ });
37
+ queue.on("active", (job) => {
38
+ client.syncJob(extractJobData(job));
39
+ });
40
+ queue.on("progress", (job) => {
41
+ client.syncJob(extractJobData(job));
42
+ });
43
+ queue.on("removed", (job) => {
44
+ client.syncJob(extractJobData(job));
45
+ });
46
+ }
@@ -0,0 +1,35 @@
1
+ export interface QueueDashClientOptions {
2
+ apiKey: string;
3
+ batchSize?: number;
4
+ flushInterval?: number;
5
+ maxRetries?: number;
6
+ requestTimeout?: number;
7
+ maxQueueSize?: number;
8
+ onError?: (error: Error) => void;
9
+ /** @internal - Not for public use. Override API URL for staging environments only. */
10
+ __dangerouslyOverrideApiUrl?: string;
11
+ }
12
+ export interface JobData {
13
+ jobId: string;
14
+ name: string;
15
+ queueName: string;
16
+ data?: Record<string, unknown>;
17
+ opts?: Record<string, unknown>;
18
+ addedAt: Date;
19
+ processedAt?: Date | null;
20
+ finishedAt?: Date | null;
21
+ failedReason?: string;
22
+ stacktrace?: string[];
23
+ logs?: string[];
24
+ retriedAt?: Date | null;
25
+ priority?: number | null;
26
+ delay?: number | null;
27
+ timestamp?: number | null;
28
+ progress?: number | null;
29
+ }
30
+ export interface SyncResponse {
31
+ success: boolean;
32
+ synced: number;
33
+ errors?: string[];
34
+ }
35
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,sFAAsF;IACtF,2BAA2B,CAAC,EAAE,MAAM,CAAC;CACtC;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,EAAE,IAAI,CAAC;IACd,WAAW,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@queuedash/sdk",
3
+ "version": "0.1.0",
4
+ "description": "QueueDash SDK for real-time queue monitoring",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "README.md"
10
+ ],
11
+ "keywords": [
12
+ "queue",
13
+ "bullmq",
14
+ "bull",
15
+ "bee-queue",
16
+ "monitoring",
17
+ "dashboard"
18
+ ],
19
+ "author": "QueueDash",
20
+ "license": "MIT",
21
+ "peerDependencies": {
22
+ "bullmq": ">=3.0.0",
23
+ "bull": ">=4.0.0",
24
+ "bee-queue": ">=1.0.0"
25
+ },
26
+ "peerDependenciesMeta": {
27
+ "bullmq": {
28
+ "optional": true
29
+ },
30
+ "bull": {
31
+ "optional": true
32
+ },
33
+ "bee-queue": {
34
+ "optional": true
35
+ }
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^20.0.0",
39
+ "typescript": "^5.9.3"
40
+ },
41
+ "scripts": {
42
+ "build": "tsc"
43
+ }
44
+ }