@objectstack/service-queue 4.0.2 → 4.0.4
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/.turbo/turbo-build.log +6 -6
- package/CHANGELOG.md +15 -0
- package/README.md +453 -0
- package/package.json +5 -5
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @objectstack/service-queue@4.0.
|
|
2
|
+
> @objectstack/service-queue@4.0.4 build /home/runner/work/framework/framework/packages/services/service-queue
|
|
3
3
|
> tsup --config ../../../tsup.config.ts
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
[34mCLI[39m Cleaning output folder
|
|
11
11
|
[34mESM[39m Build start
|
|
12
12
|
[34mCJS[39m Build start
|
|
13
|
-
[32mESM[39m [1mdist/index.js [22m[32m2.78 KB[39m
|
|
14
|
-
[32mESM[39m [1mdist/index.js.map [22m[32m8.33 KB[39m
|
|
15
|
-
[32mESM[39m ⚡️ Build success in 62ms
|
|
16
13
|
[32mCJS[39m [1mdist/index.cjs [22m[32m3.89 KB[39m
|
|
17
14
|
[32mCJS[39m [1mdist/index.cjs.map [22m[32m8.90 KB[39m
|
|
18
|
-
[32mCJS[39m ⚡️ Build success in
|
|
15
|
+
[32mCJS[39m ⚡️ Build success in 94ms
|
|
16
|
+
[32mESM[39m [1mdist/index.js [22m[32m2.78 KB[39m
|
|
17
|
+
[32mESM[39m [1mdist/index.js.map [22m[32m8.33 KB[39m
|
|
18
|
+
[32mESM[39m ⚡️ Build success in 96ms
|
|
19
19
|
[34mDTS[39m Build start
|
|
20
|
-
[32mDTS[39m ⚡️ Build success in
|
|
20
|
+
[32mDTS[39m ⚡️ Build success in 14371ms
|
|
21
21
|
[32mDTS[39m [1mdist/index.d.ts [22m[32m3.63 KB[39m
|
|
22
22
|
[32mDTS[39m [1mdist/index.d.cts [22m[32m3.63 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @objectstack/service-queue
|
|
2
2
|
|
|
3
|
+
## 4.0.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [326b66b]
|
|
8
|
+
- @objectstack/spec@4.0.4
|
|
9
|
+
- @objectstack/core@4.0.4
|
|
10
|
+
|
|
11
|
+
## 4.0.3
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- @objectstack/spec@4.0.3
|
|
16
|
+
- @objectstack/core@4.0.3
|
|
17
|
+
|
|
3
18
|
## 4.0.2
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
package/README.md
ADDED
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
# @objectstack/service-queue
|
|
2
|
+
|
|
3
|
+
Queue Service for ObjectStack — implements `IQueueService` with in-memory and BullMQ adapters.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Multiple Adapters**: In-memory (development) and BullMQ/Redis (production)
|
|
8
|
+
- **Job Queues**: Organize work into named queues with priorities
|
|
9
|
+
- **Worker Pools**: Process jobs concurrently with configurable workers
|
|
10
|
+
- **Retry Logic**: Automatic retry with exponential backoff
|
|
11
|
+
- **Job Scheduling**: Delay job execution or schedule for future
|
|
12
|
+
- **Progress Tracking**: Track job progress and completion
|
|
13
|
+
- **Job Events**: Listen to job lifecycle events (active, completed, failed)
|
|
14
|
+
- **Rate Limiting**: Control job processing rate
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pnpm add @objectstack/service-queue
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
For BullMQ adapter (production):
|
|
23
|
+
```bash
|
|
24
|
+
pnpm add bullmq ioredis
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Basic Usage
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { defineStack } from '@objectstack/spec';
|
|
31
|
+
import { ServiceQueue } from '@objectstack/service-queue';
|
|
32
|
+
|
|
33
|
+
const stack = defineStack({
|
|
34
|
+
services: [
|
|
35
|
+
ServiceQueue.configure({
|
|
36
|
+
adapter: 'memory', // or 'bullmq'
|
|
37
|
+
defaultQueue: 'default',
|
|
38
|
+
}),
|
|
39
|
+
],
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Configuration
|
|
44
|
+
|
|
45
|
+
### In-Memory Adapter (Development)
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
ServiceQueue.configure({
|
|
49
|
+
adapter: 'memory',
|
|
50
|
+
concurrency: 5, // Max concurrent jobs
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### BullMQ Adapter (Production)
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
ServiceQueue.configure({
|
|
58
|
+
adapter: 'bullmq',
|
|
59
|
+
redis: {
|
|
60
|
+
host: 'localhost',
|
|
61
|
+
port: 6379,
|
|
62
|
+
password: process.env.REDIS_PASSWORD,
|
|
63
|
+
},
|
|
64
|
+
queues: {
|
|
65
|
+
default: { concurrency: 10 },
|
|
66
|
+
email: { concurrency: 5, rateLimit: { max: 100, duration: 60000 } },
|
|
67
|
+
reports: { concurrency: 2 },
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Service API
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
// Get queue service
|
|
76
|
+
const queue = kernel.getService<IQueueService>('queue');
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Adding Jobs
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
// Add a simple job
|
|
83
|
+
await queue.add('email', 'send_welcome', {
|
|
84
|
+
to: 'user@example.com',
|
|
85
|
+
template: 'welcome',
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Add job with options
|
|
89
|
+
await queue.add('reports', 'generate_monthly', {
|
|
90
|
+
month: '2024-01',
|
|
91
|
+
format: 'pdf',
|
|
92
|
+
}, {
|
|
93
|
+
priority: 1, // Higher number = higher priority
|
|
94
|
+
attempts: 3, // Retry up to 3 times
|
|
95
|
+
backoff: {
|
|
96
|
+
type: 'exponential',
|
|
97
|
+
delay: 1000,
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Add delayed job (runs in 1 hour)
|
|
102
|
+
await queue.add('notifications', 'reminder', {
|
|
103
|
+
userId: '123',
|
|
104
|
+
message: 'Don't forget!',
|
|
105
|
+
}, {
|
|
106
|
+
delay: 3600000, // 1 hour in milliseconds
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Schedule job for specific time
|
|
110
|
+
await queue.add('cleanup', 'old_files', {}, {
|
|
111
|
+
timestamp: new Date('2024-12-31T23:59:59Z').getTime(),
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Processing Jobs
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
// Register a job processor
|
|
119
|
+
queue.process('email', async (job) => {
|
|
120
|
+
console.log('Processing email job:', job.data);
|
|
121
|
+
|
|
122
|
+
// Access job data
|
|
123
|
+
const { to, template } = job.data;
|
|
124
|
+
|
|
125
|
+
// Update progress
|
|
126
|
+
await job.updateProgress(25);
|
|
127
|
+
|
|
128
|
+
// Send email
|
|
129
|
+
await sendEmail(to, template);
|
|
130
|
+
|
|
131
|
+
await job.updateProgress(100);
|
|
132
|
+
|
|
133
|
+
// Return result
|
|
134
|
+
return { sent: true, messageId: 'msg_123' };
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Process with concurrency
|
|
138
|
+
queue.process('reports', 5, async (job) => {
|
|
139
|
+
// Up to 5 reports generated concurrently
|
|
140
|
+
return await generateReport(job.data);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// Process with named handler
|
|
144
|
+
queue.process('default', 'calculate_metrics', async (job) => {
|
|
145
|
+
return await calculateMetrics(job.data);
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Job Management
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
// Get job by ID
|
|
153
|
+
const job = await queue.getJob('email', 'job_abc123');
|
|
154
|
+
|
|
155
|
+
// Get job status
|
|
156
|
+
const status = await job.getState();
|
|
157
|
+
// 'waiting' | 'active' | 'completed' | 'failed' | 'delayed'
|
|
158
|
+
|
|
159
|
+
// Remove job
|
|
160
|
+
await queue.removeJob('email', 'job_abc123');
|
|
161
|
+
|
|
162
|
+
// Retry failed job
|
|
163
|
+
await queue.retryJob('email', 'job_abc123');
|
|
164
|
+
|
|
165
|
+
// Get job result
|
|
166
|
+
const result = await job.returnvalue;
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Queue Operations
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
// Pause queue (stop processing new jobs)
|
|
173
|
+
await queue.pause('email');
|
|
174
|
+
|
|
175
|
+
// Resume queue
|
|
176
|
+
await queue.resume('email');
|
|
177
|
+
|
|
178
|
+
// Clear all jobs in queue
|
|
179
|
+
await queue.clear('email');
|
|
180
|
+
|
|
181
|
+
// Get queue statistics
|
|
182
|
+
const stats = await queue.getStats('email');
|
|
183
|
+
// {
|
|
184
|
+
// waiting: 45,
|
|
185
|
+
// active: 5,
|
|
186
|
+
// completed: 1250,
|
|
187
|
+
// failed: 12,
|
|
188
|
+
// delayed: 3
|
|
189
|
+
// }
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Advanced Features
|
|
193
|
+
|
|
194
|
+
### Job Events
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
// Listen to job lifecycle events
|
|
198
|
+
queue.on('email', 'completed', async (job, result) => {
|
|
199
|
+
console.log(`Email sent: ${result.messageId}`);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
queue.on('email', 'failed', async (job, error) => {
|
|
203
|
+
console.error(`Email failed: ${error.message}`);
|
|
204
|
+
// Send alert to admin
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
queue.on('email', 'progress', async (job, progress) => {
|
|
208
|
+
console.log(`Email progress: ${progress}%`);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
queue.on('email', 'active', async (job) => {
|
|
212
|
+
console.log(`Email job started: ${job.id}`);
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Bulk Operations
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
// Add multiple jobs at once
|
|
220
|
+
await queue.addBulk('email', [
|
|
221
|
+
{ name: 'send_welcome', data: { to: 'user1@example.com' } },
|
|
222
|
+
{ name: 'send_welcome', data: { to: 'user2@example.com' } },
|
|
223
|
+
{ name: 'send_welcome', data: { to: 'user3@example.com' } },
|
|
224
|
+
]);
|
|
225
|
+
|
|
226
|
+
// Get multiple jobs
|
|
227
|
+
const jobs = await queue.getJobs('email', ['waiting', 'active']);
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Job Patterns
|
|
231
|
+
|
|
232
|
+
#### Worker Pattern
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
// Dedicated worker process
|
|
236
|
+
queue.process('heavy_processing', async (job) => {
|
|
237
|
+
// CPU-intensive work
|
|
238
|
+
const result = await processLargeDataset(job.data);
|
|
239
|
+
return result;
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
#### Fan-Out Pattern
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
// Split work across multiple jobs
|
|
247
|
+
await queue.add('orchestrator', 'process_batch', { batchId: '123' });
|
|
248
|
+
|
|
249
|
+
queue.process('orchestrator', async (job) => {
|
|
250
|
+
const items = await loadBatchItems(job.data.batchId);
|
|
251
|
+
|
|
252
|
+
// Create sub-jobs for each item
|
|
253
|
+
for (const item of items) {
|
|
254
|
+
await queue.add('worker', 'process_item', { item });
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
queue.process('worker', async (job) => {
|
|
259
|
+
return await processItem(job.data.item);
|
|
260
|
+
});
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
#### Priority Queues
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
// High priority
|
|
267
|
+
await queue.add('tasks', 'urgent', data, { priority: 10 });
|
|
268
|
+
|
|
269
|
+
// Normal priority
|
|
270
|
+
await queue.add('tasks', 'normal', data, { priority: 5 });
|
|
271
|
+
|
|
272
|
+
// Low priority
|
|
273
|
+
await queue.add('tasks', 'background', data, { priority: 1 });
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Rate Limiting
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
// Limit queue to 100 jobs per minute
|
|
280
|
+
ServiceQueue.configure({
|
|
281
|
+
adapter: 'bullmq',
|
|
282
|
+
queues: {
|
|
283
|
+
api_calls: {
|
|
284
|
+
concurrency: 5,
|
|
285
|
+
rateLimit: {
|
|
286
|
+
max: 100,
|
|
287
|
+
duration: 60000, // 1 minute
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Repeatable Jobs
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
// Add cron-based repeatable job
|
|
298
|
+
await queue.addRepeatable('cleanup', 'old_sessions', {}, {
|
|
299
|
+
cron: '0 2 * * *', // Daily at 2 AM
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// Add interval-based repeatable job
|
|
303
|
+
await queue.addRepeatable('sync', 'data', {}, {
|
|
304
|
+
every: 300000, // Every 5 minutes
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// Remove repeatable job
|
|
308
|
+
await queue.removeRepeatable('cleanup', 'old_sessions');
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Common Use Cases
|
|
312
|
+
|
|
313
|
+
### Email Queue
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
queue.process('email', async (job) => {
|
|
317
|
+
const { to, subject, body, template } = job.data;
|
|
318
|
+
|
|
319
|
+
try {
|
|
320
|
+
const result = await emailProvider.send({
|
|
321
|
+
to,
|
|
322
|
+
subject,
|
|
323
|
+
html: renderTemplate(template, job.data),
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
return { messageId: result.id, sentAt: new Date() };
|
|
327
|
+
} catch (error) {
|
|
328
|
+
// Throw error to trigger retry
|
|
329
|
+
throw new Error(`Failed to send email: ${error.message}`);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// Add email job
|
|
334
|
+
await queue.add('email', 'welcome', {
|
|
335
|
+
to: 'newuser@example.com',
|
|
336
|
+
template: 'welcome',
|
|
337
|
+
name: 'John Doe',
|
|
338
|
+
}, {
|
|
339
|
+
attempts: 3,
|
|
340
|
+
backoff: { type: 'exponential', delay: 5000 },
|
|
341
|
+
});
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Report Generation
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
queue.process('reports', async (job) => {
|
|
348
|
+
const { reportType, userId, dateRange } = job.data;
|
|
349
|
+
|
|
350
|
+
await job.updateProgress(10);
|
|
351
|
+
|
|
352
|
+
// Fetch data
|
|
353
|
+
const data = await fetchReportData(reportType, dateRange);
|
|
354
|
+
|
|
355
|
+
await job.updateProgress(50);
|
|
356
|
+
|
|
357
|
+
// Generate report
|
|
358
|
+
const report = await generatePDF(data);
|
|
359
|
+
|
|
360
|
+
await job.updateProgress(90);
|
|
361
|
+
|
|
362
|
+
// Upload to storage
|
|
363
|
+
const url = await uploadReport(report);
|
|
364
|
+
|
|
365
|
+
await job.updateProgress(100);
|
|
366
|
+
|
|
367
|
+
// Notify user
|
|
368
|
+
await notifyUser(userId, { reportUrl: url });
|
|
369
|
+
|
|
370
|
+
return { url, size: report.length };
|
|
371
|
+
});
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Webhook Processing
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
queue.process('webhooks', async (job) => {
|
|
378
|
+
const { url, payload, headers } = job.data;
|
|
379
|
+
|
|
380
|
+
const response = await fetch(url, {
|
|
381
|
+
method: 'POST',
|
|
382
|
+
headers,
|
|
383
|
+
body: JSON.stringify(payload),
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
if (!response.ok) {
|
|
387
|
+
throw new Error(`Webhook failed: ${response.status}`);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return { status: response.status, responseTime: Date.now() - job.timestamp };
|
|
391
|
+
});
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## REST API Endpoints
|
|
395
|
+
|
|
396
|
+
```
|
|
397
|
+
POST /api/v1/queues/:queue/jobs # Add job
|
|
398
|
+
GET /api/v1/queues/:queue/jobs/:id # Get job
|
|
399
|
+
DELETE /api/v1/queues/:queue/jobs/:id # Remove job
|
|
400
|
+
POST /api/v1/queues/:queue/jobs/:id/retry # Retry failed job
|
|
401
|
+
GET /api/v1/queues/:queue/stats # Get queue stats
|
|
402
|
+
POST /api/v1/queues/:queue/pause # Pause queue
|
|
403
|
+
POST /api/v1/queues/:queue/resume # Resume queue
|
|
404
|
+
DELETE /api/v1/queues/:queue # Clear queue
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## Best Practices
|
|
408
|
+
|
|
409
|
+
1. **Idempotent Jobs**: Design jobs to be safely retried
|
|
410
|
+
2. **Error Handling**: Always handle errors and throw to trigger retry
|
|
411
|
+
3. **Progress Updates**: Update progress for long-running jobs
|
|
412
|
+
4. **Resource Limits**: Set appropriate concurrency limits
|
|
413
|
+
5. **Job Data**: Keep job data small (< 1MB)
|
|
414
|
+
6. **Monitoring**: Track queue metrics and job failure rates
|
|
415
|
+
7. **Cleanup**: Remove completed jobs periodically
|
|
416
|
+
|
|
417
|
+
## Performance Considerations
|
|
418
|
+
|
|
419
|
+
- **Concurrency**: Tune based on system resources and external API limits
|
|
420
|
+
- **Rate Limiting**: Prevent overwhelming external services
|
|
421
|
+
- **Job Size**: Keep job payloads small for faster serialization
|
|
422
|
+
- **Redis Connection**: Use connection pooling for BullMQ
|
|
423
|
+
- **Queue Organization**: Use separate queues for different job types
|
|
424
|
+
|
|
425
|
+
## Contract Implementation
|
|
426
|
+
|
|
427
|
+
Implements `IQueueService` from `@objectstack/spec/contracts`:
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
interface IQueueService {
|
|
431
|
+
add(queue: string, name: string, data: any, options?: JobOptions): Promise<Job>;
|
|
432
|
+
addBulk(queue: string, jobs: JobDefinition[]): Promise<Job[]>;
|
|
433
|
+
process(queue: string, handler: JobHandler): void;
|
|
434
|
+
getJob(queue: string, jobId: string): Promise<Job | null>;
|
|
435
|
+
removeJob(queue: string, jobId: string): Promise<void>;
|
|
436
|
+
retryJob(queue: string, jobId: string): Promise<void>;
|
|
437
|
+
getStats(queue: string): Promise<QueueStats>;
|
|
438
|
+
pause(queue: string): Promise<void>;
|
|
439
|
+
resume(queue: string): Promise<void>;
|
|
440
|
+
clear(queue: string): Promise<void>;
|
|
441
|
+
on(queue: string, event: JobEvent, handler: EventHandler): void;
|
|
442
|
+
}
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
## License
|
|
446
|
+
|
|
447
|
+
Apache-2.0
|
|
448
|
+
|
|
449
|
+
## See Also
|
|
450
|
+
|
|
451
|
+
- [BullMQ Documentation](https://docs.bullmq.io/)
|
|
452
|
+
- [@objectstack/spec/contracts](../../spec/src/contracts/)
|
|
453
|
+
- [Queue Patterns Guide](/content/docs/guides/queues/)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/service-queue",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.4",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Queue Service for ObjectStack — implements IQueueService with in-memory and BullMQ adapters",
|
|
6
6
|
"type": "module",
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@objectstack/core": "4.0.
|
|
18
|
-
"@objectstack/spec": "4.0.
|
|
17
|
+
"@objectstack/core": "4.0.4",
|
|
18
|
+
"@objectstack/spec": "4.0.4"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"@types/node": "^25.
|
|
21
|
+
"@types/node": "^25.6.0",
|
|
22
22
|
"typescript": "^6.0.2",
|
|
23
|
-
"vitest": "^4.1.
|
|
23
|
+
"vitest": "^4.1.4"
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
26
|
"build": "tsup --config ../../../tsup.config.ts",
|