@treatwell/moleculer-essentials 1.0.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.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -0
  3. package/dist/context-factory-BWO3xPWE.d.cts +520 -0
  4. package/dist/context-factory-BWO3xPWE.d.mts +520 -0
  5. package/dist/index-82e1CXJX.cjs +11 -0
  6. package/dist/index-BV1ZqQrU.mjs +351 -0
  7. package/dist/index-DNJWwcZu.mjs +8 -0
  8. package/dist/index-rZl77S1z.cjs +375 -0
  9. package/dist/index.cjs +1570 -0
  10. package/dist/index.d.cts +373 -0
  11. package/dist/index.d.mts +373 -0
  12. package/dist/index.mjs +1535 -0
  13. package/dist/mixins/database.mixin.cjs +1673 -0
  14. package/dist/mixins/database.mixin.d.cts +958 -0
  15. package/dist/mixins/database.mixin.d.mts +958 -0
  16. package/dist/mixins/database.mixin.mjs +1645 -0
  17. package/dist/mixins/encryptor.mixin.cjs +84 -0
  18. package/dist/mixins/encryptor.mixin.d.cts +31 -0
  19. package/dist/mixins/encryptor.mixin.d.mts +31 -0
  20. package/dist/mixins/encryptor.mixin.mjs +81 -0
  21. package/dist/mixins/global-store.mixin.cjs +56 -0
  22. package/dist/mixins/global-store.mixin.d.cts +39 -0
  23. package/dist/mixins/global-store.mixin.d.mts +39 -0
  24. package/dist/mixins/global-store.mixin.mjs +54 -0
  25. package/dist/mixins/jwt.mixin.cjs +118 -0
  26. package/dist/mixins/jwt.mixin.d.cts +43 -0
  27. package/dist/mixins/jwt.mixin.d.mts +43 -0
  28. package/dist/mixins/jwt.mixin.mjs +115 -0
  29. package/dist/mixins/queue.mixin.cjs +420 -0
  30. package/dist/mixins/queue.mixin.d.cts +150 -0
  31. package/dist/mixins/queue.mixin.d.mts +150 -0
  32. package/dist/mixins/queue.mixin.mjs +414 -0
  33. package/dist/mixins/redis.mixin.cjs +50 -0
  34. package/dist/mixins/redis.mixin.d.cts +27 -0
  35. package/dist/mixins/redis.mixin.d.mts +27 -0
  36. package/dist/mixins/redis.mixin.mjs +48 -0
  37. package/dist/mixins/redlock.mixin.cjs +76 -0
  38. package/dist/mixins/redlock.mixin.d.cts +30 -0
  39. package/dist/mixins/redlock.mixin.d.mts +30 -0
  40. package/dist/mixins/redlock.mixin.mjs +74 -0
  41. package/package.json +181 -0
@@ -0,0 +1,115 @@
1
+ import { sign, verify } from 'jsonwebtoken';
2
+ import { JwksClient } from 'jwks-rsa';
3
+ import { Errors } from 'moleculer';
4
+ import { w as wrapMixin } from '../index-DNJWwcZu.mjs';
5
+
6
+ function JwtSignerMixin(opts) {
7
+ const { privateKey, signOptions, renewBefore, disableAction } = opts;
8
+ let jwt = null;
9
+ let expiryDate = null;
10
+ return wrapMixin({
11
+ methods: {
12
+ generateJwt(payload = {}) {
13
+ const options = {
14
+ algorithm: "ES512",
15
+ notBefore: "-2s",
16
+ ...signOptions
17
+ };
18
+ return new Promise(
19
+ (resolve, reject) => sign(
20
+ payload,
21
+ privateKey,
22
+ options,
23
+ (err, token) => err || !token ? reject(err) : resolve(token)
24
+ )
25
+ );
26
+ }
27
+ },
28
+ actions: {
29
+ getToken: disableAction ? false : {
30
+ visibility: "public",
31
+ params: {
32
+ type: "object",
33
+ additionalProperties: false,
34
+ required: [],
35
+ properties: {}
36
+ },
37
+ async handler() {
38
+ if (renewBefore && jwt && expiryDate && expiryDate - Date.now() > renewBefore) {
39
+ return jwt;
40
+ }
41
+ jwt = await this.generateJwt();
42
+ if (typeof signOptions.expiresIn === "number") {
43
+ expiryDate = Date.now() + signOptions.expiresIn * 1e3;
44
+ }
45
+ return jwt;
46
+ }
47
+ }
48
+ }
49
+ });
50
+ }
51
+ function JwtVerifierMixin(opts) {
52
+ const { jwksOptions, validClaim } = opts;
53
+ const jwksClient = new JwksClient(jwksOptions);
54
+ return wrapMixin({
55
+ methods: {
56
+ getJwksClient() {
57
+ return jwksClient;
58
+ },
59
+ /**
60
+ * Used with jsonwebtoken verify function. Retrieves the signing public key
61
+ * from the kid defined in the JWT header.
62
+ */
63
+ async getVerifyPublicKey(header, callback) {
64
+ try {
65
+ const key = await this.getJwksClient().getSigningKey(header.kid);
66
+ callback(null, key.getPublicKey());
67
+ } catch (err) {
68
+ callback(err);
69
+ }
70
+ },
71
+ /**
72
+ * Will validate the JWT token signature but also some claims like the issuer.
73
+ */
74
+ verifyJwt(token) {
75
+ return new Promise((resolve, reject) => {
76
+ verify(
77
+ token,
78
+ (header, callback) => this.getVerifyPublicKey(header, callback),
79
+ validClaim,
80
+ (err) => err ? reject(err) : resolve()
81
+ );
82
+ });
83
+ },
84
+ async verifyAuthorizationHeader(ctx, value) {
85
+ if (!value || typeof value !== "string" || !value.startsWith("Bearer ")) {
86
+ throw new Errors.MoleculerError(
87
+ "Incorrect bearer format authorization",
88
+ 401,
89
+ "Unauthorized"
90
+ );
91
+ }
92
+ const token = value.slice(7);
93
+ if (!token) {
94
+ throw new Errors.MoleculerError(
95
+ "Incorrect token",
96
+ 401,
97
+ "Unauthorized"
98
+ );
99
+ }
100
+ try {
101
+ await this.verifyJwt(token);
102
+ } catch (err) {
103
+ ctx.logger.warn("Unable to verify JWT", { err });
104
+ throw new Errors.MoleculerError(
105
+ "Unable to verify JWT",
106
+ 401,
107
+ "Unauthorized"
108
+ );
109
+ }
110
+ }
111
+ }
112
+ });
113
+ }
114
+
115
+ export { JwtSignerMixin, JwtVerifierMixin };
@@ -0,0 +1,420 @@
1
+ 'use strict';
2
+
3
+ var moleculer = require('moleculer');
4
+ var bullmq = require('bullmq');
5
+ var lodash = require('lodash');
6
+ var index = require('../index-82e1CXJX.cjs');
7
+ var mixins_globalStore_mixin = require('./global-store.mixin.cjs');
8
+ var ioredis = require('ioredis');
9
+ var utils = require('ioredis/built/utils');
10
+
11
+ function createRedisConnection(url) {
12
+ let tls;
13
+ if (url.startsWith("rediss://")) {
14
+ tls = {};
15
+ }
16
+ const connection = new ioredis.Redis({
17
+ ...utils.parseURL(url),
18
+ tls,
19
+ maxRetriesPerRequest: null,
20
+ connectTimeout: 1e3 * 60
21
+ });
22
+ connection.setMaxListeners(0);
23
+ return connection;
24
+ }
25
+
26
+ function QueueClient(queueName, opts) {
27
+ const kKey = Symbol("Queue Client Key");
28
+ return index.wrapMixin({
29
+ mixins: [mixins_globalStore_mixin.GlobalStoreMixin()],
30
+ methods: {
31
+ _getQueues() {
32
+ return this.$queues;
33
+ },
34
+ /**
35
+ * Add a job to a specific queue. The queue name needs to be passed as parameters
36
+ * to enable multiple queue clients in the same service.
37
+ */
38
+ addJob(qName, name, data, jOpts) {
39
+ const q = this._getQueues().get(qName);
40
+ if (!q) {
41
+ throw new moleculer.Errors.MoleculerServerError(
42
+ `Queue '${qName}' does not exists on '${this.name}'`
43
+ );
44
+ }
45
+ return q.add(name, data, jOpts);
46
+ },
47
+ /**
48
+ * Add jobs to a specific queue. The queue name needs to be passed as parameters
49
+ * to enable multiple queue clients in the same service.
50
+ */
51
+ addBulkJob(qName, name, data, jOpts) {
52
+ const q = this._getQueues().get(qName);
53
+ if (!q) {
54
+ throw new moleculer.Errors.MoleculerServerError(
55
+ `Queue '${qName}' does not exists on '${this.name}'`
56
+ );
57
+ }
58
+ return q.addBulk(data.map((d) => ({ name, data: d, opts: jOpts })));
59
+ },
60
+ /**
61
+ * Get a queue bundle if you need specific features
62
+ */
63
+ getQueue(qName) {
64
+ const q = this._getQueues().get(qName);
65
+ if (!q) {
66
+ throw new moleculer.Errors.MoleculerServerError(
67
+ `Queue '${qName}' does not exists on '${this.name}'`
68
+ );
69
+ }
70
+ return q;
71
+ }
72
+ },
73
+ created() {
74
+ if (!this.$queues) {
75
+ this.$queues = /* @__PURE__ */ new Map();
76
+ }
77
+ },
78
+ async started() {
79
+ if (this._getQueues().has(queueName)) {
80
+ throw new Error(
81
+ `Queue client '${queueName}' already exists on service '${this.name}'`
82
+ );
83
+ }
84
+ const key = lodash.isFunction(opts.brokerURL) ? await opts.brokerURL(this) : opts.brokerURL;
85
+ this[kKey] = key;
86
+ let connection = this.getFromStore("redis", key);
87
+ if (!connection) {
88
+ connection = createRedisConnection(key);
89
+ this.setClientToStore(
90
+ "redis",
91
+ key,
92
+ connection,
93
+ () => connection?.disconnect()
94
+ );
95
+ }
96
+ const queue = new bullmq.Queue(queueName, { connection, ...opts });
97
+ queue.setMaxListeners(0);
98
+ queue.on(
99
+ "error",
100
+ (err) => this.logger.error(`Queue ${queueName} got error`, { err })
101
+ );
102
+ this._getQueues().set(queueName, queue);
103
+ },
104
+ async stopped() {
105
+ const q = this._getQueues().get(queueName);
106
+ if (q) {
107
+ await q.close();
108
+ }
109
+ await this.removeServiceFromStore("redis", this[kKey]);
110
+ }
111
+ });
112
+ }
113
+
114
+ function QueueEventsClient(queueName, opts) {
115
+ const kKey = Symbol("Queue Events Client Key");
116
+ return index.wrapMixin({
117
+ mixins: [mixins_globalStore_mixin.GlobalStoreMixin()],
118
+ methods: {
119
+ _getQueueEvents() {
120
+ return this.$queuesEvents;
121
+ },
122
+ /**
123
+ * Return the QueueEvents instance for the given queue name.
124
+ * Will run the QueueEvents if it's not already running (lazy connect).
125
+ * Will throw an error if the QueueEvents is not found.
126
+ */
127
+ getQueueEvents(qName) {
128
+ const queueEvents = this._getQueueEvents().get(qName);
129
+ if (!queueEvents) {
130
+ throw new Error(`QueueEvents '${qName}' not found`);
131
+ }
132
+ const qEvents = queueEvents.events;
133
+ if (!queueEvents.running) {
134
+ qEvents.run().catch((error) => qEvents.emit("error", error));
135
+ queueEvents.running = true;
136
+ }
137
+ return qEvents;
138
+ },
139
+ /**
140
+ * Same as addJob but will also wait for the job to finish before returning.
141
+ */
142
+ async addAndWait(qName, name, data, jOpts, ttl) {
143
+ const job = await this.addJob(qName, name, data, jOpts);
144
+ return job.waitUntilFinished(this.getQueueEvents(qName), ttl);
145
+ },
146
+ /**
147
+ * Same as addBulkJob but will also wait for the jobs to finish before returning.
148
+ */
149
+ async addBulkAndWait(qName, name, data, jOpts, ttl) {
150
+ const jobs = await this.addBulkJob(qName, name, data, jOpts);
151
+ const q = this.getQueueEvents(qName);
152
+ return Promise.all(jobs.map((j) => j.waitUntilFinished(q, ttl)));
153
+ }
154
+ },
155
+ created() {
156
+ if (!this.$queuesEvents) {
157
+ this.$queuesEvents = /* @__PURE__ */ new Map();
158
+ }
159
+ },
160
+ async started() {
161
+ if (this._getQueueEvents().get(queueName)) {
162
+ throw new Error(
163
+ `Queue client '${queueName}' already exists on service '${this.name}'`
164
+ );
165
+ }
166
+ const key = lodash.isFunction(opts.brokerURL) ? await opts.brokerURL(this) : opts.brokerURL;
167
+ this[kKey] = key;
168
+ let connection = this.getFromStore("redis", key);
169
+ if (!connection) {
170
+ connection = createRedisConnection(key);
171
+ this.setClientToStore(
172
+ "redis",
173
+ key,
174
+ connection,
175
+ () => connection?.disconnect()
176
+ );
177
+ }
178
+ const qEvents = new bullmq.QueueEvents(queueName, {
179
+ connection,
180
+ ...opts,
181
+ autorun: false
182
+ });
183
+ qEvents.setMaxListeners(0);
184
+ qEvents.on(
185
+ "error",
186
+ (err) => this.logger.error(`QueueEvents on ${queueName} got error`, { err })
187
+ );
188
+ this._getQueueEvents().set(queueName, {
189
+ events: qEvents,
190
+ running: false
191
+ });
192
+ },
193
+ async stopped() {
194
+ const q = this._getQueueEvents().get(queueName);
195
+ if (q) {
196
+ await q.events.close();
197
+ }
198
+ await this.removeServiceFromStore("redis", this[kKey]);
199
+ }
200
+ });
201
+ }
202
+
203
+ const kConnection$1 = Symbol("Queue FlowProducer Connection");
204
+ function QueueFlowProducerMixin(opts) {
205
+ return index.wrapMixin({
206
+ methods: {
207
+ getFlowProducer() {
208
+ return this.$flowProducer;
209
+ }
210
+ },
211
+ async started() {
212
+ if (this.$flowProducer) {
213
+ throw new Error(
214
+ `Queue Flow producer already exists on service '${this.name}'`
215
+ );
216
+ }
217
+ const url = lodash.isFunction(opts.brokerURL) ? await opts.brokerURL(this) : opts.brokerURL;
218
+ const connection = createRedisConnection(url);
219
+ this.$flowProducer = new bullmq.FlowProducer({ connection, ...opts });
220
+ this[kConnection$1] = connection;
221
+ },
222
+ async stopped() {
223
+ await this.$flowProducer?.close();
224
+ this[kConnection$1]?.disconnect();
225
+ }
226
+ });
227
+ }
228
+
229
+ function isPropertyEqual(a, b) {
230
+ if (a && b && a === b) {
231
+ return true;
232
+ }
233
+ return !a && !b;
234
+ }
235
+ function isSameRepeatableJob(repeatableJob, job) {
236
+ return isPropertyEqual(repeatableJob.name, job.name) && isPropertyEqual(repeatableJob.pattern, job.pattern) && isPropertyEqual(repeatableJob.every, job.every?.toString()) && isPropertyEqual(repeatableJob.tz, job.tz);
237
+ }
238
+ function getFilteredJobs(qName, jobs) {
239
+ const allowList = new Set(
240
+ process.env.SCHEDULER_JOBS_ALLOWLIST?.split(",") || []
241
+ );
242
+ const denyList = new Set(
243
+ process.env.SCHEDULER_JOBS_DENYLIST?.split(",") || []
244
+ );
245
+ return jobs.filter((j) => {
246
+ if (allowList.size > 0) {
247
+ return allowList.has(`${qName}:${j.name}`);
248
+ }
249
+ if (denyList.size > 0) {
250
+ return !denyList.has(`${qName}:${j.name}`);
251
+ }
252
+ return true;
253
+ });
254
+ }
255
+ const mixinStore = Symbol("QueueStaticRepeatableJobsMixinStore");
256
+ function QueueStaticRepeatableJobs(queueName, jobs, opts) {
257
+ const kKey = Symbol("Queue Static Repeatable Jobs Key");
258
+ return index.wrapMixin({
259
+ mixins: [mixins_globalStore_mixin.GlobalStoreMixin()],
260
+ methods: {
261
+ async registerRepeatableJobs() {
262
+ const key = lodash.isFunction(opts.brokerURL) ? await opts.brokerURL(this) : opts.brokerURL;
263
+ this[kKey] = key;
264
+ let connection = this.getFromStore("redis", key);
265
+ if (!connection) {
266
+ connection = createRedisConnection(key);
267
+ this.setClientToStore(
268
+ "redis",
269
+ key,
270
+ connection,
271
+ () => connection?.disconnect()
272
+ );
273
+ }
274
+ const queue = new bullmq.Queue(queueName, { connection });
275
+ const filteredJobs = getFilteredJobs(queueName, jobs);
276
+ await Promise.all(
277
+ filteredJobs.map(
278
+ ({ name, data, ...repeat }) => queue.add(name, data, { repeat, removeOnComplete: true })
279
+ )
280
+ );
281
+ if (opts.autoRemove !== false) {
282
+ const repeatableJobs = await queue.getRepeatableJobs();
283
+ const rjToRemove = repeatableJobs.filter(
284
+ (rj) => !filteredJobs.some((j) => isSameRepeatableJob(rj, j))
285
+ );
286
+ if (rjToRemove.length) {
287
+ await Promise.all(
288
+ rjToRemove.map((rj) => queue.removeRepeatableByKey(rj.key))
289
+ );
290
+ }
291
+ }
292
+ await queue.close();
293
+ await this.removeServiceFromStore("redis", key);
294
+ }
295
+ },
296
+ created() {
297
+ if (!this[mixinStore]) {
298
+ this[mixinStore] = /* @__PURE__ */ new Set();
299
+ }
300
+ if (this[mixinStore].has(this[kKey])) {
301
+ throw new Error(
302
+ `Queue ${queueName} has already registered static repeatable jobs`
303
+ );
304
+ }
305
+ this[mixinStore].add(queueName);
306
+ },
307
+ events: {
308
+ // TODO Improve this to only be run once in a while globally on the cluster
309
+ "$broker.started": {
310
+ async handler() {
311
+ await this.registerRepeatableJobs();
312
+ }
313
+ }
314
+ }
315
+ });
316
+ }
317
+
318
+ const kConnection = Symbol("Queue Worker Connection");
319
+ function QueueWorker(queueName, opts, processorOptions = {}) {
320
+ return index.wrapMixin({
321
+ metadata: {
322
+ worker: true,
323
+ [`worker-${queueName}`]: true
324
+ },
325
+ methods: {
326
+ getWorker() {
327
+ return this.$worker;
328
+ },
329
+ async processJob(job, token) {
330
+ if (processorOptions.wrapper) {
331
+ return processorOptions.wrapper(
332
+ job,
333
+ token,
334
+ this._processJob.bind(this)
335
+ );
336
+ }
337
+ return this._processJob(job, token);
338
+ },
339
+ async _processJob(job, token) {
340
+ const methodName = processorOptions.useNamedFunctions ? job.name : "processor";
341
+ if (!this.actions[methodName]) {
342
+ throw new Error(`action '${methodName}' does not exist.`);
343
+ }
344
+ const logBase = {
345
+ msg: `Job ${job.name} on ${queueName} (${job.id})`,
346
+ name: job.name,
347
+ id: job.id
348
+ };
349
+ if (processorOptions.logDataFields) {
350
+ processorOptions.logDataFields.forEach((field) => {
351
+ logBase[field] = job.data?.[field];
352
+ });
353
+ }
354
+ if (processorOptions.skipNormalLogs !== true) {
355
+ this.logger.info(logBase);
356
+ }
357
+ const start = Date.now();
358
+ try {
359
+ const res = await this.actions[methodName](job.data, {
360
+ meta: { job, jobWorkerToken: token }
361
+ });
362
+ if (processorOptions.skipNormalLogs !== true) {
363
+ this.logger.info({
364
+ ...logBase,
365
+ msg: `${logBase.msg} succeeded`,
366
+ duration: Date.now() - start
367
+ });
368
+ }
369
+ return res;
370
+ } catch (err) {
371
+ this.logger.info({
372
+ ...logBase,
373
+ msg: `${logBase.msg} failed`,
374
+ duration: Date.now() - start,
375
+ err
376
+ });
377
+ throw err;
378
+ }
379
+ }
380
+ },
381
+ async started() {
382
+ if (this.$worker) {
383
+ throw new Error(
384
+ `A QueueWorker mixin was already on service '${this.name}'`
385
+ );
386
+ }
387
+ const url = lodash.isFunction(opts.brokerURL) ? await opts.brokerURL(this) : opts.brokerURL;
388
+ const connection = createRedisConnection(url);
389
+ const worker = new bullmq.Worker(queueName, this.processJob.bind(this), {
390
+ connection,
391
+ ...opts,
392
+ autorun: false
393
+ });
394
+ worker.on(
395
+ "error",
396
+ (err) => this.logger.error(`Worker on ${queueName} got error`, { err })
397
+ );
398
+ this.$worker = worker;
399
+ this[kConnection] = connection;
400
+ },
401
+ events: {
402
+ "$broker.started": {
403
+ handler() {
404
+ const worker = this.getWorker();
405
+ worker.run().catch((error) => worker.emit("error", error));
406
+ }
407
+ }
408
+ },
409
+ async stopped() {
410
+ await this.$worker?.close();
411
+ this[kConnection]?.disconnect();
412
+ }
413
+ });
414
+ }
415
+
416
+ exports.QueueClient = QueueClient;
417
+ exports.QueueEventsClient = QueueEventsClient;
418
+ exports.QueueFlowProducerMixin = QueueFlowProducerMixin;
419
+ exports.QueueStaticRepeatableJobs = QueueStaticRepeatableJobs;
420
+ exports.QueueWorker = QueueWorker;
@@ -0,0 +1,150 @@
1
+ import { a as CustomServiceSchema } from '../context-factory-BWO3xPWE.cjs';
2
+ import { Redis } from 'ioredis';
3
+ import { QueueOptions, Queue, JobsOptions, Job, QueueEventsOptions, QueueEvents, QueueBaseOptions, FlowProducer, RepeatOptions, WorkerOptions, Worker } from 'bullmq';
4
+ import { Service } from 'moleculer';
5
+ import 'bson';
6
+ import 'zod/v4';
7
+ import 'ajv/dist/2019.js';
8
+
9
+ type QueueMixinOptions = {
10
+ brokerURL: string | (<TService extends Service = Service>(svc: TService) => Promise<string>);
11
+ };
12
+ /**
13
+ * connection is mandatory for BullMQ but is managed by each mixins.
14
+ */
15
+ type WithoutConnection<T> = Omit<T, 'connection'>;
16
+
17
+ /**
18
+ * This Mixin add the capability to launch a job.
19
+ */
20
+ declare function QueueClient<N extends string>(queueName: N, opts: WithoutConnection<QueueOptions> & QueueMixinOptions): Partial<CustomServiceSchema<unknown, {
21
+ _getQueues(): Map<string, Queue>;
22
+ /**
23
+ * Add a job to a specific queue. The queue name needs to be passed as parameters
24
+ * to enable multiple queue clients in the same service.
25
+ */
26
+ addJob<D = unknown>(qName: N, name: string, data: D, jOpts?: JobsOptions): Promise<Job>;
27
+ /**
28
+ * Add jobs to a specific queue. The queue name needs to be passed as parameters
29
+ * to enable multiple queue clients in the same service.
30
+ */
31
+ addBulkJob<D = unknown>(qName: N, name: string, data: D[], jOpts?: JobsOptions): Promise<Job[]>;
32
+ /**
33
+ * Get a queue bundle if you need specific features
34
+ */
35
+ getQueue(qName: N): Queue;
36
+ }, Partial<CustomServiceSchema<unknown, {
37
+ getStore(storeName: string): Map<string, {
38
+ services: Set<unknown>;
39
+ client: Redis;
40
+ onClose: () => Promise<void> | void;
41
+ }>;
42
+ getFromStore(storeName: string, key: string): Redis | null;
43
+ removeServiceFromStore(storeName: string, key: string): Promise<boolean>;
44
+ setClientToStore(storeName: string, key: string, client: Redis, onClose: () => Promise<void> | void): void;
45
+ }, unknown, unknown>>[], unknown>>;
46
+
47
+ /**
48
+ * This Mixin add the capability to wait on a job.
49
+ * WARNING: Needs to be used with QueueClient mixin.
50
+ */
51
+ declare function QueueEventsClient<N extends string>(queueName: N, opts: WithoutConnection<QueueEventsOptions> & QueueMixinOptions): Partial<CustomServiceSchema<unknown, {
52
+ _getQueueEvents(): Map<string, {
53
+ events: QueueEvents;
54
+ running: boolean;
55
+ }>;
56
+ /**
57
+ * Return the QueueEvents instance for the given queue name.
58
+ * Will run the QueueEvents if it's not already running (lazy connect).
59
+ * Will throw an error if the QueueEvents is not found.
60
+ */
61
+ getQueueEvents(qName: N): QueueEvents;
62
+ /**
63
+ * Same as addJob but will also wait for the job to finish before returning.
64
+ */
65
+ addAndWait<T = unknown, D = unknown>(qName: N, name: string, data: D, jOpts?: JobsOptions, ttl?: number): Promise<T>;
66
+ /**
67
+ * Same as addBulkJob but will also wait for the jobs to finish before returning.
68
+ */
69
+ addBulkAndWait<T = unknown, D = unknown>(qName: N, name: string, data: D[], jOpts?: JobsOptions, ttl?: number): Promise<T[]>;
70
+ }, Partial<CustomServiceSchema<unknown, {
71
+ getStore(storeName: string): Map<string, {
72
+ services: Set<unknown>;
73
+ client: Redis;
74
+ onClose: () => Promise<void> | void;
75
+ }>;
76
+ getFromStore(storeName: string, key: string): Redis | null;
77
+ removeServiceFromStore(storeName: string, key: string): Promise<boolean>;
78
+ setClientToStore(storeName: string, key: string, client: Redis, onClose: () => Promise<void> | void): void;
79
+ }, unknown, unknown>>[], unknown>>;
80
+
81
+ /**
82
+ * This Mixin add the capability to launch a BullMQ flows.
83
+ */
84
+ declare function QueueFlowProducerMixin(opts: WithoutConnection<QueueBaseOptions> & QueueMixinOptions): Partial<CustomServiceSchema<unknown, {
85
+ getFlowProducer(): FlowProducer;
86
+ }, unknown, unknown>>;
87
+
88
+ type RepeatableJob = {
89
+ name: string;
90
+ data?: unknown;
91
+ } & RepeatOptions;
92
+ type QueueStaticRepeatableJobsOptions = {
93
+ /**
94
+ * Set to `false` to prevent deleting repeatable jobs not registered.
95
+ */
96
+ autoRemove?: boolean;
97
+ };
98
+ /**
99
+ * This Mixin allow to register repeatable jobs and remove other ones.
100
+ * It should mainly be setup on the same service as the related QueueWorker.
101
+ */
102
+ declare function QueueStaticRepeatableJobs(queueName: string, jobs: RepeatableJob[], opts: QueueStaticRepeatableJobsOptions & QueueMixinOptions): Partial<CustomServiceSchema<unknown, {
103
+ registerRepeatableJobs(): Promise<void>;
104
+ }, Partial<CustomServiceSchema<unknown, {
105
+ getStore(storeName: string): Map<string, {
106
+ services: Set<unknown>;
107
+ client: Redis;
108
+ onClose: () => Promise<void> | void;
109
+ }>;
110
+ getFromStore(storeName: string, key: string): Redis | null;
111
+ removeServiceFromStore(storeName: string, key: string): Promise<boolean>;
112
+ setClientToStore(storeName: string, key: string, client: Redis, onClose: () => Promise<void> | void): void;
113
+ }, unknown, unknown>>[], unknown>>;
114
+
115
+ type JobMeta = {
116
+ job?: Job;
117
+ jobWorkerToken?: string;
118
+ };
119
+ type JobProcessorOptions = {
120
+ /**
121
+ * Use the job name as the action name.
122
+ * When false (default), the action name is 'processor'.
123
+ */
124
+ useNamedFunctions?: boolean;
125
+ /**
126
+ * Skip normal info logs at the start and end of the job.
127
+ * Will never disable logs on errors.
128
+ */
129
+ skipNormalLogs?: boolean;
130
+ /**
131
+ * Allow to log additional fields from the job data.
132
+ * Currently, doesn't support nested fields.
133
+ */
134
+ logDataFields?: string[];
135
+ /**
136
+ * Optional wrapper that MUST call the passed function.
137
+ */
138
+ wrapper?: (job: Job, token: string | undefined, fn: (job: Job, token?: string) => Promise<unknown>) => Promise<unknown>;
139
+ };
140
+ /**
141
+ * This Mixin create the worker system.
142
+ */
143
+ declare function QueueWorker(queueName: string, opts: WithoutConnection<WorkerOptions> & QueueMixinOptions, processorOptions?: JobProcessorOptions): Partial<CustomServiceSchema<unknown, {
144
+ getWorker(): Worker;
145
+ processJob(job: Job, token?: string): Promise<any>;
146
+ _processJob(job: Job, token?: string): Promise<any>;
147
+ }, unknown, unknown>>;
148
+
149
+ export { QueueClient, QueueEventsClient, QueueFlowProducerMixin, QueueStaticRepeatableJobs, QueueWorker };
150
+ export type { JobMeta, JobProcessorOptions, QueueMixinOptions, QueueStaticRepeatableJobsOptions, RepeatableJob };