@cequrebackends/cequre-ts 0.11.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.
Files changed (60) hide show
  1. package/dist/adapters/bun/bun-cron.d.ts +20 -0
  2. package/dist/adapters/bun/bun-media.d.ts +9 -0
  3. package/dist/adapters/bun/bun-redis-cache.d.ts +33 -0
  4. package/dist/adapters/bun/bun-response.d.ts +13 -0
  5. package/dist/adapters/bun/bun-server.d.ts +6 -0
  6. package/dist/adapters/bun/bun-storage.d.ts +10 -0
  7. package/dist/adapters/bun/bun-websocket.d.ts +104 -0
  8. package/dist/adapters/bun/index.d.ts +9 -0
  9. package/dist/adapters/bun/index.js +547 -0
  10. package/dist/adapters/node/index.d.ts +9 -0
  11. package/dist/adapters/node/index.js +902 -0
  12. package/dist/adapters/node/node-cron.d.ts +20 -0
  13. package/dist/adapters/node/node-media.d.ts +9 -0
  14. package/dist/adapters/node/node-redis-cache.d.ts +32 -0
  15. package/dist/adapters/node/node-response.d.ts +13 -0
  16. package/dist/adapters/node/node-server.d.ts +6 -0
  17. package/dist/adapters/node/node-storage.d.ts +10 -0
  18. package/dist/adapters/node/node-websocket.d.ts +102 -0
  19. package/dist/index-17yswtmg.js +175 -0
  20. package/dist/index-kyvy0s1x.js +2662 -0
  21. package/dist/index-mfqj7cwr.js +165 -0
  22. package/dist/index-rf1kdn5b.js +732 -0
  23. package/dist/index.d.ts +18 -0
  24. package/dist/index.js +3152 -0
  25. package/dist/interface-map.d.ts +175 -0
  26. package/dist/shared/core/adapter.d.ts +84 -0
  27. package/dist/shared/core/base-sql-adapter.d.ts +34 -0
  28. package/dist/shared/core/cache.d.ts +8 -0
  29. package/dist/shared/core/email.d.ts +53 -0
  30. package/dist/shared/core/index.d.ts +12 -0
  31. package/dist/shared/core/index.js +47 -0
  32. package/dist/shared/core/openapi.d.ts +24 -0
  33. package/dist/shared/core/plugins.d.ts +2 -0
  34. package/dist/shared/core/request.d.ts +32 -0
  35. package/dist/shared/core/sdk.d.ts +3 -0
  36. package/dist/shared/core/stream.d.ts +24 -0
  37. package/dist/shared/core/types-generator.d.ts +0 -0
  38. package/dist/shared/core/types.d.ts +304 -0
  39. package/dist/shared/core/ulid.d.ts +5 -0
  40. package/dist/shared/core/validator.d.ts +32 -0
  41. package/dist/shared/main/access-evaluator.d.ts +13 -0
  42. package/dist/shared/main/access.d.ts +34 -0
  43. package/dist/shared/main/aot.d.ts +3 -0
  44. package/dist/shared/main/hooks.d.ts +76 -0
  45. package/dist/shared/main/population.d.ts +13 -0
  46. package/dist/shared/main/router.d.ts +112 -0
  47. package/dist/shared/main/runtime.d.ts +195 -0
  48. package/dist/shared/main/sse.d.ts +87 -0
  49. package/dist/shared/utils/crypto.d.ts +23 -0
  50. package/dist/shared/utils/durable-queue.d.ts +20 -0
  51. package/dist/shared/utils/duration.d.ts +15 -0
  52. package/dist/shared/utils/error.d.ts +52 -0
  53. package/dist/shared/utils/kv/adapters/memory.d.ts +20 -0
  54. package/dist/shared/utils/kv/adapters/sqlite.d.ts +32 -0
  55. package/dist/shared/utils/kv/index.d.ts +37 -0
  56. package/dist/shared/utils/kv/types.d.ts +38 -0
  57. package/dist/shared/utils/logger.d.ts +42 -0
  58. package/dist/shared/utils/queue-manager.d.ts +64 -0
  59. package/dist/shared/utils/url.d.ts +13 -0
  60. package/package.json +63 -0
@@ -0,0 +1,732 @@
1
+ // @bun
2
+ import {
3
+ CequreError,
4
+ __esm,
5
+ __export,
6
+ __require,
7
+ __toCommonJS
8
+ } from "./index-17yswtmg.js";
9
+
10
+ // shared/utils/kv/adapters/memory.ts
11
+ function getLog() {
12
+ if (!log) {
13
+ const { createLogger } = (init_logger(), __toCommonJS(exports_logger));
14
+ log = createLogger("kv-memory");
15
+ }
16
+ return log;
17
+ }
18
+
19
+ class MemoryAdapter {
20
+ store = new Map;
21
+ get(key) {
22
+ const entry = this.store.get(key);
23
+ if (!entry)
24
+ return null;
25
+ if (entry.expiresAt !== null && entry.expiresAt <= Date.now()) {
26
+ this.store.delete(key);
27
+ return null;
28
+ }
29
+ return entry.value;
30
+ }
31
+ getMany(keys) {
32
+ const result = new Map;
33
+ const now = Date.now();
34
+ for (const key of keys) {
35
+ const entry = this.store.get(key);
36
+ if (entry) {
37
+ if (entry.expiresAt !== null && entry.expiresAt <= now) {
38
+ this.store.delete(key);
39
+ } else {
40
+ result.set(key, entry.value);
41
+ }
42
+ }
43
+ }
44
+ return result;
45
+ }
46
+ set(key, value, ttl) {
47
+ const expiresAt = ttl != null ? Date.now() + ttl * 1000 : null;
48
+ this.store.set(key, { value, expiresAt });
49
+ }
50
+ setMany(entries) {
51
+ const now = Date.now();
52
+ for (const { key, value, ttl } of entries) {
53
+ const expiresAt = ttl != null ? now + ttl * 1000 : null;
54
+ this.store.set(key, { value, expiresAt });
55
+ }
56
+ }
57
+ delete(key) {
58
+ return this.store.delete(key);
59
+ }
60
+ deleteMany(keys) {
61
+ let deleted = 0;
62
+ for (const key of keys) {
63
+ if (this.store.delete(key))
64
+ deleted++;
65
+ }
66
+ return deleted;
67
+ }
68
+ has(key) {
69
+ const entry = this.store.get(key);
70
+ if (!entry)
71
+ return false;
72
+ if (entry.expiresAt !== null && entry.expiresAt <= Date.now()) {
73
+ this.store.delete(key);
74
+ return false;
75
+ }
76
+ return true;
77
+ }
78
+ keys(prefix) {
79
+ const now = Date.now();
80
+ const result = [];
81
+ for (const [key, entry] of this.store.entries()) {
82
+ if (entry.expiresAt === null || entry.expiresAt > now) {
83
+ if (!prefix || key.startsWith(prefix)) {
84
+ result.push(key);
85
+ }
86
+ }
87
+ }
88
+ return result;
89
+ }
90
+ count() {
91
+ const now = Date.now();
92
+ let count = 0;
93
+ for (const entry of this.store.values()) {
94
+ if (entry.expiresAt === null || entry.expiresAt > now) {
95
+ count++;
96
+ }
97
+ }
98
+ return count;
99
+ }
100
+ clear() {
101
+ this.store.clear();
102
+ }
103
+ cleanup() {
104
+ const now = Date.now();
105
+ let removed = 0;
106
+ for (const [key, entry] of this.store.entries()) {
107
+ if (entry.expiresAt !== null && entry.expiresAt <= now) {
108
+ this.store.delete(key);
109
+ removed++;
110
+ }
111
+ }
112
+ if (removed > 0) {
113
+ getLog().debug({ removed }, "KV expired entries cleaned up (Memory)");
114
+ }
115
+ return removed;
116
+ }
117
+ close() {
118
+ this.store.clear();
119
+ getLog().debug("Memory KV store closed");
120
+ }
121
+ }
122
+ var log = null;
123
+ var init_memory = () => {};
124
+
125
+ // shared/utils/kv/adapters/sqlite.ts
126
+ import { Database } from "bun:sqlite";
127
+ function getLog2() {
128
+ if (!log2) {
129
+ const { createLogger } = (init_logger(), __toCommonJS(exports_logger));
130
+ log2 = createLogger("kv-sqlite");
131
+ }
132
+ return log2;
133
+ }
134
+
135
+ class SQLiteAdapter {
136
+ db;
137
+ stmtGet;
138
+ stmtSet;
139
+ stmtDel;
140
+ stmtHas;
141
+ stmtKeys;
142
+ stmtKeysPrefix;
143
+ stmtClear;
144
+ stmtCleanup;
145
+ stmtCount;
146
+ constructor(options) {
147
+ const dbPath = options?.path ?? "./data/cequre-kv.sqlite";
148
+ if (dbPath !== ":memory:") {
149
+ const dir = dbPath.substring(0, dbPath.lastIndexOf("/"));
150
+ if (dir) {
151
+ try {
152
+ const { mkdirSync } = __require("fs");
153
+ mkdirSync(dir, { recursive: true });
154
+ } catch {}
155
+ }
156
+ }
157
+ this.db = new Database(dbPath);
158
+ this.db.run("PRAGMA journal_mode = WAL");
159
+ this.db.run("PRAGMA synchronous = NORMAL");
160
+ this.db.run(`
161
+ CREATE TABLE IF NOT EXISTS kv (
162
+ key TEXT PRIMARY KEY,
163
+ value TEXT NOT NULL,
164
+ expires_at INTEGER
165
+ )
166
+ `);
167
+ this.db.run(`CREATE INDEX IF NOT EXISTS idx_kv_expires ON kv(expires_at) WHERE expires_at IS NOT NULL`);
168
+ this.stmtGet = this.db.prepare("SELECT value FROM kv WHERE key = ? AND (expires_at IS NULL OR expires_at > ?)");
169
+ this.stmtSet = this.db.prepare("INSERT OR REPLACE INTO kv (key, value, expires_at) VALUES (?, ?, ?)");
170
+ this.stmtDel = this.db.prepare("DELETE FROM kv WHERE key = ?");
171
+ this.stmtHas = this.db.prepare("SELECT 1 FROM kv WHERE key = ? AND (expires_at IS NULL OR expires_at > ?) LIMIT 1");
172
+ this.stmtKeys = this.db.prepare("SELECT key FROM kv WHERE expires_at IS NULL OR expires_at > ?");
173
+ this.stmtKeysPrefix = this.db.prepare("SELECT key FROM kv WHERE key LIKE ? AND (expires_at IS NULL OR expires_at > ?)");
174
+ this.stmtClear = this.db.prepare("DELETE FROM kv");
175
+ this.stmtCleanup = this.db.prepare("DELETE FROM kv WHERE expires_at IS NOT NULL AND expires_at <= ?");
176
+ this.stmtCount = this.db.prepare("SELECT COUNT(*) as count FROM kv WHERE expires_at IS NULL OR expires_at > ?");
177
+ getLog2().debug({ path: dbPath }, "SQLite KV adapter initialized");
178
+ }
179
+ async get(key) {
180
+ const now = Date.now();
181
+ const row = this.stmtGet.get(key, now);
182
+ if (!row)
183
+ return null;
184
+ try {
185
+ return JSON.parse(row.value);
186
+ } catch {
187
+ return row.value;
188
+ }
189
+ }
190
+ async getMany(keys) {
191
+ const result = new Map;
192
+ for (const key of keys) {
193
+ const val = await this.get(key);
194
+ if (val !== null)
195
+ result.set(key, val);
196
+ }
197
+ return result;
198
+ }
199
+ async set(key, value, ttl) {
200
+ const serialized = JSON.stringify(value);
201
+ const expiresAt = ttl != null ? Date.now() + ttl * 1000 : null;
202
+ this.stmtSet.run(key, serialized, expiresAt);
203
+ }
204
+ async setMany(entries) {
205
+ const tx = this.db.transaction(() => {
206
+ for (const { key, value, ttl } of entries) {
207
+ const serialized = JSON.stringify(value);
208
+ const expiresAt = ttl != null ? Date.now() + ttl * 1000 : null;
209
+ this.stmtSet.run(key, serialized, expiresAt);
210
+ }
211
+ });
212
+ tx();
213
+ }
214
+ async delete(key) {
215
+ const result = this.stmtDel.run(key);
216
+ return result.changes > 0;
217
+ }
218
+ async deleteMany(keys) {
219
+ let deleted = 0;
220
+ const tx = this.db.transaction(() => {
221
+ for (const key of keys) {
222
+ const result = this.stmtDel.run(key);
223
+ deleted += result.changes;
224
+ }
225
+ });
226
+ tx();
227
+ return deleted;
228
+ }
229
+ async has(key) {
230
+ const now = Date.now();
231
+ return this.stmtHas.get(key, now) !== null;
232
+ }
233
+ async keys(prefix) {
234
+ const now = Date.now();
235
+ const rows = prefix ? this.stmtKeysPrefix.all(`${prefix}%`, now) : this.stmtKeys.all(now);
236
+ return rows.map((r) => r.key);
237
+ }
238
+ async count() {
239
+ const now = Date.now();
240
+ const row = this.stmtCount.get(now);
241
+ return row.count;
242
+ }
243
+ async clear() {
244
+ this.stmtClear.run();
245
+ }
246
+ cleanup() {
247
+ const now = Date.now();
248
+ const result = this.stmtCleanup.run(now);
249
+ if (result.changes > 0) {
250
+ getLog2().debug({ removed: result.changes }, "KV expired entries cleaned up (SQLite)");
251
+ }
252
+ return result.changes;
253
+ }
254
+ close() {
255
+ this.db.close();
256
+ getLog2().debug("SQLite KV adapter closed");
257
+ }
258
+ }
259
+ var log2 = null;
260
+ var init_sqlite = () => {};
261
+
262
+ // adapters/bun/bun-redis-cache.ts
263
+ function getLog3() {
264
+ if (!_log)
265
+ _log = (init_logger(), __toCommonJS(exports_logger)).createLogger("kv-redis");
266
+ return _log;
267
+ }
268
+
269
+ class RedisAdapter {
270
+ redis;
271
+ constructor(options) {
272
+ this.redis = Bun.redis;
273
+ if (options?.url) {
274
+ const parsed = new URL(options.url);
275
+ const hostname = parsed.hostname;
276
+ const port = parseInt(parsed.port || "6379", 10);
277
+ if (hostname !== "localhost" || port !== 6379) {
278
+ getLog3().warn({ url: options.url }, "Custom Redis URL detected. Set REDIS_URL env var for Bun.redis to connect to non-default host.");
279
+ }
280
+ }
281
+ getLog3().debug("Redis KV adapter initialized (Bun.redis)");
282
+ }
283
+ async get(key) {
284
+ const value = await this.redis.get(key);
285
+ if (value === null)
286
+ return null;
287
+ try {
288
+ return JSON.parse(value);
289
+ } catch {
290
+ return value;
291
+ }
292
+ }
293
+ async getMany(keys) {
294
+ const result = new Map;
295
+ if (keys.length === 0)
296
+ return result;
297
+ const values = await this.redis.mget(...keys);
298
+ for (let i = 0;i < keys.length; i++) {
299
+ const key = keys[i];
300
+ if (key === undefined)
301
+ continue;
302
+ const value = values[i];
303
+ if (value !== null && value !== undefined) {
304
+ try {
305
+ result.set(key, JSON.parse(value));
306
+ } catch {
307
+ result.set(key, value);
308
+ }
309
+ }
310
+ }
311
+ return result;
312
+ }
313
+ async set(key, value, ttl) {
314
+ const serialized = JSON.stringify(value);
315
+ if (ttl != null && ttl > 0) {
316
+ await this.redis.setex(key, ttl, serialized);
317
+ } else {
318
+ await this.redis.set(key, serialized);
319
+ }
320
+ }
321
+ async setMany(entries) {
322
+ await Promise.all(entries.map(({ key, value, ttl }) => this.set(key, value, ttl)));
323
+ }
324
+ async delete(key) {
325
+ const deleted = await this.redis.del(key);
326
+ return deleted > 0;
327
+ }
328
+ async deleteMany(keys) {
329
+ if (keys.length === 0)
330
+ return 0;
331
+ return await this.redis.del(...keys);
332
+ }
333
+ async has(key) {
334
+ const exists = await this.redis.exists(key);
335
+ return exists > 0;
336
+ }
337
+ async keys(prefix) {
338
+ if (!prefix) {
339
+ return await this.redis.keys("*");
340
+ }
341
+ return await this.redis.keys(`${prefix}*`);
342
+ }
343
+ async count() {
344
+ return await this.redis.dbsize();
345
+ }
346
+ async clear() {
347
+ await this.redis.flushdb();
348
+ }
349
+ cleanup() {
350
+ return 0;
351
+ }
352
+ close() {
353
+ getLog3().debug("Redis KV adapter closed (Bun.redis singleton \u2014 connection managed by runtime)");
354
+ }
355
+ }
356
+ var _log = null;
357
+ var init_bun_redis_cache = () => {};
358
+
359
+ // shared/utils/kv/types.ts
360
+ var init_types = () => {};
361
+
362
+ // shared/utils/kv/index.ts
363
+ class CequreKV {
364
+ adapter;
365
+ cleanupTimer = null;
366
+ isCleanupNative = false;
367
+ constructor(options = {}) {
368
+ const driver = options.driver ?? "sqlite";
369
+ if (driver === "memory") {
370
+ this.adapter = new MemoryAdapter;
371
+ this.isCleanupNative = false;
372
+ } else if (driver === "redis") {
373
+ this.adapter = new RedisAdapter(options.redis);
374
+ this.isCleanupNative = true;
375
+ } else {
376
+ this.adapter = new SQLiteAdapter(options.sqlite);
377
+ this.isCleanupNative = false;
378
+ }
379
+ if (!this.isCleanupNative) {
380
+ const interval = options.cleanupInterval ?? 60000;
381
+ if (interval > 0) {
382
+ this.cleanupTimer = setInterval(() => this.cleanup(), interval);
383
+ if (this.cleanupTimer && typeof this.cleanupTimer === "object" && "unref" in this.cleanupTimer) {
384
+ this.cleanupTimer.unref();
385
+ }
386
+ }
387
+ }
388
+ }
389
+ async get(key) {
390
+ return this.adapter.get(key);
391
+ }
392
+ async getMany(keys) {
393
+ return this.adapter.getMany(keys);
394
+ }
395
+ async set(key, value, ttl) {
396
+ return this.adapter.set(key, value, ttl);
397
+ }
398
+ async setMany(entries) {
399
+ return this.adapter.setMany(entries);
400
+ }
401
+ async delete(key) {
402
+ return this.adapter.delete(key);
403
+ }
404
+ async deleteMany(keys) {
405
+ return this.adapter.deleteMany(keys);
406
+ }
407
+ async has(key) {
408
+ return this.adapter.has(key);
409
+ }
410
+ async keys(prefix) {
411
+ return this.adapter.keys(prefix);
412
+ }
413
+ async count() {
414
+ return this.adapter.count();
415
+ }
416
+ async clear() {
417
+ return this.adapter.clear();
418
+ }
419
+ async cleanup() {
420
+ return this.adapter.cleanup();
421
+ }
422
+ async close() {
423
+ if (this.cleanupTimer) {
424
+ clearInterval(this.cleanupTimer);
425
+ this.cleanupTimer = null;
426
+ }
427
+ return this.adapter.close();
428
+ }
429
+ }
430
+ var init_kv = __esm(() => {
431
+ init_memory();
432
+ init_sqlite();
433
+ init_bun_redis_cache();
434
+ init_types();
435
+ });
436
+
437
+ // shared/utils/logger.ts
438
+ var exports_logger = {};
439
+ __export(exports_logger, {
440
+ logger: () => logger,
441
+ createLogger: () => createLogger,
442
+ CequreErrorLogs: () => CequreErrorLogs
443
+ });
444
+ import pino from "pino";
445
+ import pretty from "pino-pretty";
446
+ function getErrorKV() {
447
+ if (!kvStore) {
448
+ kvStore = new CequreKV({ sqlite: { path: "./data/cequre-error-kv.sqlite" } });
449
+ }
450
+ return kvStore;
451
+ }
452
+ function createStream() {
453
+ if (Bun.env.NODE_ENV !== "production" && Bun.env.NODE_ENV !== "test") {
454
+ return pretty({
455
+ colorize: true,
456
+ translateTime: "yyyy-mm-dd HH:MM:ss.l",
457
+ ignore: "pid,hostname,component,count,output,url",
458
+ customColors: "info:bgBlue,error:bgRed,warn:bgYellow",
459
+ messageFormat: (log3, messageKey) => {
460
+ const msg = log3[messageKey];
461
+ if (log3.level === 40)
462
+ return `\x1B[33m${msg}\x1B[0m`;
463
+ if (log3.level >= 50)
464
+ return `\x1B[31m${msg}\x1B[0m`;
465
+ return msg;
466
+ }
467
+ });
468
+ }
469
+ return;
470
+ }
471
+ function storeErrorToKV(obj, msg) {
472
+ if (ERROR_LOG_KV) {
473
+ const err = obj && typeof obj === "object" && "err" in obj ? obj.err : obj;
474
+ const logData = {
475
+ level: 50,
476
+ time: Date.now(),
477
+ msg,
478
+ err
479
+ };
480
+ const key = `error:${Date.now()}:${Math.random().toString(36).slice(2)}`;
481
+ getErrorKV().set(key, JSON.stringify(logData)).catch(() => {});
482
+ }
483
+ }
484
+
485
+ class CequreErrorLogs {
486
+ static async get(options = {}) {
487
+ const { limit = 100, since } = options;
488
+ const kv = getErrorKV();
489
+ const allKeys = await kv.keys("error:");
490
+ const errors = [];
491
+ for (const key of allKeys.slice(-limit)) {
492
+ const timestamp = parseInt(key.split(":")[1] || "0", 10);
493
+ if (since && timestamp < since)
494
+ continue;
495
+ const log3 = await kv.get(key);
496
+ if (log3) {
497
+ try {
498
+ const parsed = JSON.parse(log3);
499
+ errors.push({
500
+ key,
501
+ timestamp,
502
+ level: parsed.level === 50 ? "error" : parsed.level === 60 ? "fatal" : "error",
503
+ message: parsed.msg || parsed.message || "",
504
+ error: parsed.err?.message,
505
+ stack: parsed.err?.stack
506
+ });
507
+ } catch {
508
+ errors.push({ key, timestamp, level: "error", message: log3 });
509
+ }
510
+ }
511
+ }
512
+ return errors.sort((a, b) => b.timestamp - a.timestamp);
513
+ }
514
+ static async count() {
515
+ const kv = getErrorKV();
516
+ const keys = await kv.keys("error:");
517
+ return keys.length;
518
+ }
519
+ static async clear() {
520
+ const kv = getErrorKV();
521
+ const keys = await kv.keys("error:");
522
+ await kv.deleteMany(keys);
523
+ }
524
+ }
525
+ function createLogger(component) {
526
+ if (!logger) {
527
+ return new Proxy({}, {
528
+ get(target, prop) {
529
+ if (!logger)
530
+ return () => {};
531
+ const child = logger.child({ component });
532
+ const val = child[prop];
533
+ return typeof val === "function" ? val.bind(child) : val;
534
+ }
535
+ });
536
+ }
537
+ return logger.child({ component });
538
+ }
539
+ var LOG_LEVEL, ERROR_LOG_KV, kvStore = null, consoleStream, logger;
540
+ var init_logger = __esm(() => {
541
+ init_kv();
542
+ LOG_LEVEL = Bun.env.CEQURE_LOG_LEVEL || Bun.env.LOG_LEVEL || (Bun.env.NODE_ENV === "test" ? "silent" : "info");
543
+ ERROR_LOG_KV = Bun.env.CEQURE_ERROR_LOG_KV === "true";
544
+ consoleStream = createStream();
545
+ logger = consoleStream ? pino({ name: "cequre", level: LOG_LEVEL }, consoleStream) : pino({ name: "cequre", level: LOG_LEVEL });
546
+ if (ERROR_LOG_KV) {
547
+ const loggerWithErrorStorage = logger;
548
+ const originalError = loggerWithErrorStorage.error.bind(logger);
549
+ loggerWithErrorStorage.error = (objOrMsg, msgOrFn, ...args) => {
550
+ const msg = typeof msgOrFn === "string" ? msgOrFn : typeof objOrMsg === "string" ? objOrMsg : String(objOrMsg);
551
+ storeErrorToKV(objOrMsg, msg);
552
+ return originalError(objOrMsg, msgOrFn, ...args);
553
+ };
554
+ }
555
+ });
556
+
557
+ // shared/utils/queue-manager.ts
558
+ import { Queue as BullQueue, Worker as BullWorker, QueueEvents as BullQueueEvents } from "bullmq";
559
+ init_logger();
560
+
561
+ class BullMQQueueAdapter {
562
+ queue;
563
+ constructor(queue) {
564
+ this.queue = queue;
565
+ }
566
+ async add(name, data, opts) {
567
+ return this.queue.add(name, data, opts);
568
+ }
569
+ async addBulk(jobs) {
570
+ const bulkJobs = jobs.map((job) => ({
571
+ name: job.name,
572
+ data: job.data,
573
+ opts: job.opts
574
+ }));
575
+ return this.queue.addBulk(bulkJobs);
576
+ }
577
+ async getRepeatableJobs() {
578
+ return this.queue.getRepeatableJobs();
579
+ }
580
+ async removeRepeatableByKey(key) {
581
+ return this.queue.removeRepeatableByKey(key);
582
+ }
583
+ async disconnect() {
584
+ await this.queue.close();
585
+ }
586
+ }
587
+
588
+ class CequreQueueManager {
589
+ static instance;
590
+ queues = new Map;
591
+ workers = new Map;
592
+ queueEvents = new Map;
593
+ config;
594
+ closing = false;
595
+ constructor(config) {
596
+ this.config = config;
597
+ if (!this.config.bullmq?.connection) {
598
+ throw CequreError.NotConfigured('CequreQueueManager: bullmq provider requires "bullmq.connection"');
599
+ }
600
+ }
601
+ getBullMQBaseOptions() {
602
+ return {
603
+ ...this.config.bullmq.prefix ? { prefix: this.config.bullmq.prefix } : {},
604
+ connection: {
605
+ ...this.config.bullmq.connection,
606
+ maxRetriesPerRequest: null
607
+ }
608
+ };
609
+ }
610
+ static initialize(config) {
611
+ if (!CequreQueueManager.instance) {
612
+ CequreQueueManager.instance = new CequreQueueManager(config);
613
+ }
614
+ return CequreQueueManager.instance;
615
+ }
616
+ static getInstance() {
617
+ if (!CequreQueueManager.instance) {
618
+ throw CequreError.NotConfigured("CequreQueueManager not initialized. Call initialize() first.");
619
+ }
620
+ return CequreQueueManager.instance;
621
+ }
622
+ getQueue(name) {
623
+ const existing = this.queues.get(name);
624
+ if (existing)
625
+ return existing;
626
+ const queue = new BullQueue(name, {
627
+ ...this.config.defaultQueueOptions ?? {},
628
+ ...this.getBullMQBaseOptions()
629
+ });
630
+ const wrapped = new BullMQQueueAdapter(queue);
631
+ this.queues.set(name, wrapped);
632
+ return wrapped;
633
+ }
634
+ async addJob(queueName, jobName, data, opts) {
635
+ const queue = this.getQueue(queueName);
636
+ return queue.add(jobName, data, opts);
637
+ }
638
+ async addBulk(queueName, jobs) {
639
+ const queue = this.getQueue(queueName);
640
+ return queue.addBulk(jobs);
641
+ }
642
+ async registerWorker(queueName, handler, options) {
643
+ const existing = this.workers.get(queueName);
644
+ const queueNameForLogs = `[ ${queueName?.toUpperCase()} WORKER ]`;
645
+ if (existing) {
646
+ logger.warn(`${queueNameForLogs} Replacing existing worker for queue "${queueName}"`);
647
+ try {
648
+ await existing.close();
649
+ } catch (err) {
650
+ logger.error(err, `${queueNameForLogs} Error closing old worker for "${queueName}"`);
651
+ }
652
+ this.workers.delete(queueName);
653
+ }
654
+ const worker = new BullWorker(queueName, async (job) => await handler(job), {
655
+ ...this.config.defaultWorkerOptions ?? {},
656
+ ...options ?? {},
657
+ ...this.getBullMQBaseOptions()
658
+ });
659
+ worker.on("completed", (job) => {
660
+ logger.info(`${queueNameForLogs} Job ${job.id} completed`);
661
+ });
662
+ worker.on("failed", (job, err) => {
663
+ logger.error(err, `${queueNameForLogs} Job ${job?.id ?? "unknown"} failed`);
664
+ });
665
+ worker.on("error", (err) => {
666
+ logger.error(err, `${queueNameForLogs} Worker error`);
667
+ });
668
+ await worker.waitUntilReady();
669
+ logger.info(`${queueNameForLogs} Worker is ready and listening . . .`);
670
+ const wrapped = {
671
+ close: async () => {
672
+ await worker.close();
673
+ },
674
+ waitUntilReady: async () => {
675
+ await worker.waitUntilReady();
676
+ }
677
+ };
678
+ this.workers.set(queueName, wrapped);
679
+ return wrapped;
680
+ }
681
+ getQueueEvents(name) {
682
+ const existing = this.queueEvents.get(name);
683
+ if (existing)
684
+ return existing;
685
+ const events = new BullQueueEvents(name, {
686
+ ...this.getBullMQBaseOptions()
687
+ });
688
+ const wrapped = {
689
+ disconnect: async () => {
690
+ await events.close();
691
+ }
692
+ };
693
+ this.queueEvents.set(name, wrapped);
694
+ return wrapped;
695
+ }
696
+ static _reset() {
697
+ CequreQueueManager.instance = undefined;
698
+ }
699
+ static async _resetAndClose() {
700
+ const existing = CequreQueueManager.instance;
701
+ CequreQueueManager.instance = undefined;
702
+ if (existing) {
703
+ await existing.close();
704
+ }
705
+ }
706
+ async close() {
707
+ if (this.closing)
708
+ return;
709
+ this.closing = true;
710
+ const closeAll = async (items, label) => {
711
+ await Promise.all(items.map(async (item) => {
712
+ try {
713
+ if (item.close)
714
+ await item.close();
715
+ else if (item.disconnect)
716
+ await item.disconnect();
717
+ } catch (err) {
718
+ logger.error(err, `[QueueManager] Error closing ${label}`);
719
+ }
720
+ }));
721
+ };
722
+ await closeAll(Array.from(this.workers.values()), "worker");
723
+ await closeAll(Array.from(this.queueEvents.values()), "queue events");
724
+ await closeAll(Array.from(this.queues.values()), "queue");
725
+ this.workers.clear();
726
+ this.queueEvents.clear();
727
+ this.queues.clear();
728
+ this.closing = false;
729
+ }
730
+ }
731
+
732
+ export { logger, CequreErrorLogs, createLogger, exports_logger, init_logger, RedisAdapter, init_bun_redis_cache, CequreKV, init_kv, CequreQueueManager };