@cloudnux/local-cloud-provider 0.2.0 → 0.2.2

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.
@@ -0,0 +1,3047 @@
1
+ // ../../../node_modules/tsup/assets/esm_shims.js
2
+ import { fileURLToPath } from "url";
3
+ import path from "path";
4
+ var getFilename = () => fileURLToPath(import.meta.url);
5
+ var getDirname = () => path.dirname(getFilename());
6
+ var __dirname = /* @__PURE__ */ getDirname();
7
+
8
+ // src/dev-console-plugin/plugin.ts
9
+ import path4 from "path";
10
+ import fastifyStatic from "@fastify/static";
11
+ import fsPlugin3 from "fastify-plugin";
12
+
13
+ // src/queue-plugin/plugin.ts
14
+ import fsPlugin from "fastify-plugin";
15
+
16
+ // src/queue-plugin/core.ts
17
+ import chalk2 from "chalk";
18
+ import logSymbols from "log-symbols";
19
+
20
+ // ../../../node_modules/lodash-es/_freeGlobal.js
21
+ var freeGlobal = typeof global == "object" && global && global.Object === Object && global;
22
+ var freeGlobal_default = freeGlobal;
23
+
24
+ // ../../../node_modules/lodash-es/_root.js
25
+ var freeSelf = typeof self == "object" && self && self.Object === Object && self;
26
+ var root = freeGlobal_default || freeSelf || Function("return this")();
27
+ var root_default = root;
28
+
29
+ // ../../../node_modules/lodash-es/_Symbol.js
30
+ var Symbol = root_default.Symbol;
31
+ var Symbol_default = Symbol;
32
+
33
+ // ../../../node_modules/lodash-es/_getRawTag.js
34
+ var objectProto = Object.prototype;
35
+ var hasOwnProperty = objectProto.hasOwnProperty;
36
+ var nativeObjectToString = objectProto.toString;
37
+ var symToStringTag = Symbol_default ? Symbol_default.toStringTag : void 0;
38
+ function getRawTag(value) {
39
+ var isOwn = hasOwnProperty.call(value, symToStringTag), tag = value[symToStringTag];
40
+ try {
41
+ value[symToStringTag] = void 0;
42
+ var unmasked = true;
43
+ } catch (e) {
44
+ }
45
+ var result = nativeObjectToString.call(value);
46
+ if (unmasked) {
47
+ if (isOwn) {
48
+ value[symToStringTag] = tag;
49
+ } else {
50
+ delete value[symToStringTag];
51
+ }
52
+ }
53
+ return result;
54
+ }
55
+ var getRawTag_default = getRawTag;
56
+
57
+ // ../../../node_modules/lodash-es/_objectToString.js
58
+ var objectProto2 = Object.prototype;
59
+ var nativeObjectToString2 = objectProto2.toString;
60
+ function objectToString(value) {
61
+ return nativeObjectToString2.call(value);
62
+ }
63
+ var objectToString_default = objectToString;
64
+
65
+ // ../../../node_modules/lodash-es/_baseGetTag.js
66
+ var nullTag = "[object Null]";
67
+ var undefinedTag = "[object Undefined]";
68
+ var symToStringTag2 = Symbol_default ? Symbol_default.toStringTag : void 0;
69
+ function baseGetTag(value) {
70
+ if (value == null) {
71
+ return value === void 0 ? undefinedTag : nullTag;
72
+ }
73
+ return symToStringTag2 && symToStringTag2 in Object(value) ? getRawTag_default(value) : objectToString_default(value);
74
+ }
75
+ var baseGetTag_default = baseGetTag;
76
+
77
+ // ../../../node_modules/lodash-es/isObjectLike.js
78
+ function isObjectLike(value) {
79
+ return value != null && typeof value == "object";
80
+ }
81
+ var isObjectLike_default = isObjectLike;
82
+
83
+ // ../../../node_modules/lodash-es/isSymbol.js
84
+ var symbolTag = "[object Symbol]";
85
+ function isSymbol(value) {
86
+ return typeof value == "symbol" || isObjectLike_default(value) && baseGetTag_default(value) == symbolTag;
87
+ }
88
+ var isSymbol_default = isSymbol;
89
+
90
+ // ../../../node_modules/lodash-es/_arrayMap.js
91
+ function arrayMap(array2, iteratee) {
92
+ var index = -1, length = array2 == null ? 0 : array2.length, result = Array(length);
93
+ while (++index < length) {
94
+ result[index] = iteratee(array2[index], index, array2);
95
+ }
96
+ return result;
97
+ }
98
+ var arrayMap_default = arrayMap;
99
+
100
+ // ../../../node_modules/lodash-es/isArray.js
101
+ var isArray = Array.isArray;
102
+ var isArray_default = isArray;
103
+
104
+ // ../../../node_modules/lodash-es/_baseToString.js
105
+ var INFINITY = 1 / 0;
106
+ var symbolProto = Symbol_default ? Symbol_default.prototype : void 0;
107
+ var symbolToString = symbolProto ? symbolProto.toString : void 0;
108
+ function baseToString(value) {
109
+ if (typeof value == "string") {
110
+ return value;
111
+ }
112
+ if (isArray_default(value)) {
113
+ return arrayMap_default(value, baseToString) + "";
114
+ }
115
+ if (isSymbol_default(value)) {
116
+ return symbolToString ? symbolToString.call(value) : "";
117
+ }
118
+ var result = value + "";
119
+ return result == "0" && 1 / value == -INFINITY ? "-0" : result;
120
+ }
121
+ var baseToString_default = baseToString;
122
+
123
+ // ../../../node_modules/lodash-es/_trimmedEndIndex.js
124
+ var reWhitespace = /\s/;
125
+ function trimmedEndIndex(string) {
126
+ var index = string.length;
127
+ while (index-- && reWhitespace.test(string.charAt(index))) {
128
+ }
129
+ return index;
130
+ }
131
+ var trimmedEndIndex_default = trimmedEndIndex;
132
+
133
+ // ../../../node_modules/lodash-es/_baseTrim.js
134
+ var reTrimStart = /^\s+/;
135
+ function baseTrim(string) {
136
+ return string ? string.slice(0, trimmedEndIndex_default(string) + 1).replace(reTrimStart, "") : string;
137
+ }
138
+ var baseTrim_default = baseTrim;
139
+
140
+ // ../../../node_modules/lodash-es/isObject.js
141
+ function isObject(value) {
142
+ var type = typeof value;
143
+ return value != null && (type == "object" || type == "function");
144
+ }
145
+ var isObject_default = isObject;
146
+
147
+ // ../../../node_modules/lodash-es/isFunction.js
148
+ var asyncTag = "[object AsyncFunction]";
149
+ var funcTag = "[object Function]";
150
+ var genTag = "[object GeneratorFunction]";
151
+ var proxyTag = "[object Proxy]";
152
+ function isFunction(value) {
153
+ if (!isObject_default(value)) {
154
+ return false;
155
+ }
156
+ var tag = baseGetTag_default(value);
157
+ return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
158
+ }
159
+ var isFunction_default = isFunction;
160
+
161
+ // ../../../node_modules/lodash-es/_coreJsData.js
162
+ var coreJsData = root_default["__core-js_shared__"];
163
+ var coreJsData_default = coreJsData;
164
+
165
+ // ../../../node_modules/lodash-es/_isMasked.js
166
+ var maskSrcKey = function() {
167
+ var uid = /[^.]+$/.exec(coreJsData_default && coreJsData_default.keys && coreJsData_default.keys.IE_PROTO || "");
168
+ return uid ? "Symbol(src)_1." + uid : "";
169
+ }();
170
+ function isMasked(func) {
171
+ return !!maskSrcKey && maskSrcKey in func;
172
+ }
173
+ var isMasked_default = isMasked;
174
+
175
+ // ../../../node_modules/lodash-es/_toSource.js
176
+ var funcProto = Function.prototype;
177
+ var funcToString = funcProto.toString;
178
+ function toSource(func) {
179
+ if (func != null) {
180
+ try {
181
+ return funcToString.call(func);
182
+ } catch (e) {
183
+ }
184
+ try {
185
+ return func + "";
186
+ } catch (e) {
187
+ }
188
+ }
189
+ return "";
190
+ }
191
+ var toSource_default = toSource;
192
+
193
+ // ../../../node_modules/lodash-es/_baseIsNative.js
194
+ var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
195
+ var reIsHostCtor = /^\[object .+?Constructor\]$/;
196
+ var funcProto2 = Function.prototype;
197
+ var objectProto3 = Object.prototype;
198
+ var funcToString2 = funcProto2.toString;
199
+ var hasOwnProperty2 = objectProto3.hasOwnProperty;
200
+ var reIsNative = RegExp(
201
+ "^" + funcToString2.call(hasOwnProperty2).replace(reRegExpChar, "\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, "$1.*?") + "$"
202
+ );
203
+ function baseIsNative(value) {
204
+ if (!isObject_default(value) || isMasked_default(value)) {
205
+ return false;
206
+ }
207
+ var pattern = isFunction_default(value) ? reIsNative : reIsHostCtor;
208
+ return pattern.test(toSource_default(value));
209
+ }
210
+ var baseIsNative_default = baseIsNative;
211
+
212
+ // ../../../node_modules/lodash-es/_getValue.js
213
+ function getValue(object, key) {
214
+ return object == null ? void 0 : object[key];
215
+ }
216
+ var getValue_default = getValue;
217
+
218
+ // ../../../node_modules/lodash-es/_getNative.js
219
+ function getNative(object, key) {
220
+ var value = getValue_default(object, key);
221
+ return baseIsNative_default(value) ? value : void 0;
222
+ }
223
+ var getNative_default = getNative;
224
+
225
+ // ../../../node_modules/lodash-es/_baseFindIndex.js
226
+ function baseFindIndex(array2, predicate, fromIndex, fromRight) {
227
+ var length = array2.length, index = fromIndex + (fromRight ? 1 : -1);
228
+ while (fromRight ? index-- : ++index < length) {
229
+ if (predicate(array2[index], index, array2)) {
230
+ return index;
231
+ }
232
+ }
233
+ return -1;
234
+ }
235
+ var baseFindIndex_default = baseFindIndex;
236
+
237
+ // ../../../node_modules/lodash-es/_baseIsNaN.js
238
+ function baseIsNaN(value) {
239
+ return value !== value;
240
+ }
241
+ var baseIsNaN_default = baseIsNaN;
242
+
243
+ // ../../../node_modules/lodash-es/_strictIndexOf.js
244
+ function strictIndexOf(array2, value, fromIndex) {
245
+ var index = fromIndex - 1, length = array2.length;
246
+ while (++index < length) {
247
+ if (array2[index] === value) {
248
+ return index;
249
+ }
250
+ }
251
+ return -1;
252
+ }
253
+ var strictIndexOf_default = strictIndexOf;
254
+
255
+ // ../../../node_modules/lodash-es/_baseIndexOf.js
256
+ function baseIndexOf(array2, value, fromIndex) {
257
+ return value === value ? strictIndexOf_default(array2, value, fromIndex) : baseFindIndex_default(array2, baseIsNaN_default, fromIndex);
258
+ }
259
+ var baseIndexOf_default = baseIndexOf;
260
+
261
+ // ../../../node_modules/lodash-es/_isIndex.js
262
+ var MAX_SAFE_INTEGER = 9007199254740991;
263
+ var reIsUint = /^(?:0|[1-9]\d*)$/;
264
+ function isIndex(value, length) {
265
+ var type = typeof value;
266
+ length = length == null ? MAX_SAFE_INTEGER : length;
267
+ return !!length && (type == "number" || type != "symbol" && reIsUint.test(value)) && (value > -1 && value % 1 == 0 && value < length);
268
+ }
269
+ var isIndex_default = isIndex;
270
+
271
+ // ../../../node_modules/lodash-es/eq.js
272
+ function eq(value, other) {
273
+ return value === other || value !== value && other !== other;
274
+ }
275
+ var eq_default = eq;
276
+
277
+ // ../../../node_modules/lodash-es/isLength.js
278
+ var MAX_SAFE_INTEGER2 = 9007199254740991;
279
+ function isLength(value) {
280
+ return typeof value == "number" && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER2;
281
+ }
282
+ var isLength_default = isLength;
283
+
284
+ // ../../../node_modules/lodash-es/_baseIsArguments.js
285
+ var argsTag = "[object Arguments]";
286
+ function baseIsArguments(value) {
287
+ return isObjectLike_default(value) && baseGetTag_default(value) == argsTag;
288
+ }
289
+ var baseIsArguments_default = baseIsArguments;
290
+
291
+ // ../../../node_modules/lodash-es/isArguments.js
292
+ var objectProto4 = Object.prototype;
293
+ var hasOwnProperty3 = objectProto4.hasOwnProperty;
294
+ var propertyIsEnumerable = objectProto4.propertyIsEnumerable;
295
+ var isArguments = baseIsArguments_default(/* @__PURE__ */ function() {
296
+ return arguments;
297
+ }()) ? baseIsArguments_default : function(value) {
298
+ return isObjectLike_default(value) && hasOwnProperty3.call(value, "callee") && !propertyIsEnumerable.call(value, "callee");
299
+ };
300
+ var isArguments_default = isArguments;
301
+
302
+ // ../../../node_modules/lodash-es/_isKey.js
303
+ var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/;
304
+ var reIsPlainProp = /^\w*$/;
305
+ function isKey(value, object) {
306
+ if (isArray_default(value)) {
307
+ return false;
308
+ }
309
+ var type = typeof value;
310
+ if (type == "number" || type == "symbol" || type == "boolean" || value == null || isSymbol_default(value)) {
311
+ return true;
312
+ }
313
+ return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || object != null && value in Object(object);
314
+ }
315
+ var isKey_default = isKey;
316
+
317
+ // ../../../node_modules/lodash-es/_nativeCreate.js
318
+ var nativeCreate = getNative_default(Object, "create");
319
+ var nativeCreate_default = nativeCreate;
320
+
321
+ // ../../../node_modules/lodash-es/_hashClear.js
322
+ function hashClear() {
323
+ this.__data__ = nativeCreate_default ? nativeCreate_default(null) : {};
324
+ this.size = 0;
325
+ }
326
+ var hashClear_default = hashClear;
327
+
328
+ // ../../../node_modules/lodash-es/_hashDelete.js
329
+ function hashDelete(key) {
330
+ var result = this.has(key) && delete this.__data__[key];
331
+ this.size -= result ? 1 : 0;
332
+ return result;
333
+ }
334
+ var hashDelete_default = hashDelete;
335
+
336
+ // ../../../node_modules/lodash-es/_hashGet.js
337
+ var HASH_UNDEFINED = "__lodash_hash_undefined__";
338
+ var objectProto5 = Object.prototype;
339
+ var hasOwnProperty4 = objectProto5.hasOwnProperty;
340
+ function hashGet(key) {
341
+ var data = this.__data__;
342
+ if (nativeCreate_default) {
343
+ var result = data[key];
344
+ return result === HASH_UNDEFINED ? void 0 : result;
345
+ }
346
+ return hasOwnProperty4.call(data, key) ? data[key] : void 0;
347
+ }
348
+ var hashGet_default = hashGet;
349
+
350
+ // ../../../node_modules/lodash-es/_hashHas.js
351
+ var objectProto6 = Object.prototype;
352
+ var hasOwnProperty5 = objectProto6.hasOwnProperty;
353
+ function hashHas(key) {
354
+ var data = this.__data__;
355
+ return nativeCreate_default ? data[key] !== void 0 : hasOwnProperty5.call(data, key);
356
+ }
357
+ var hashHas_default = hashHas;
358
+
359
+ // ../../../node_modules/lodash-es/_hashSet.js
360
+ var HASH_UNDEFINED2 = "__lodash_hash_undefined__";
361
+ function hashSet(key, value) {
362
+ var data = this.__data__;
363
+ this.size += this.has(key) ? 0 : 1;
364
+ data[key] = nativeCreate_default && value === void 0 ? HASH_UNDEFINED2 : value;
365
+ return this;
366
+ }
367
+ var hashSet_default = hashSet;
368
+
369
+ // ../../../node_modules/lodash-es/_Hash.js
370
+ function Hash(entries) {
371
+ var index = -1, length = entries == null ? 0 : entries.length;
372
+ this.clear();
373
+ while (++index < length) {
374
+ var entry = entries[index];
375
+ this.set(entry[0], entry[1]);
376
+ }
377
+ }
378
+ Hash.prototype.clear = hashClear_default;
379
+ Hash.prototype["delete"] = hashDelete_default;
380
+ Hash.prototype.get = hashGet_default;
381
+ Hash.prototype.has = hashHas_default;
382
+ Hash.prototype.set = hashSet_default;
383
+ var Hash_default = Hash;
384
+
385
+ // ../../../node_modules/lodash-es/_listCacheClear.js
386
+ function listCacheClear() {
387
+ this.__data__ = [];
388
+ this.size = 0;
389
+ }
390
+ var listCacheClear_default = listCacheClear;
391
+
392
+ // ../../../node_modules/lodash-es/_assocIndexOf.js
393
+ function assocIndexOf(array2, key) {
394
+ var length = array2.length;
395
+ while (length--) {
396
+ if (eq_default(array2[length][0], key)) {
397
+ return length;
398
+ }
399
+ }
400
+ return -1;
401
+ }
402
+ var assocIndexOf_default = assocIndexOf;
403
+
404
+ // ../../../node_modules/lodash-es/_listCacheDelete.js
405
+ var arrayProto = Array.prototype;
406
+ var splice = arrayProto.splice;
407
+ function listCacheDelete(key) {
408
+ var data = this.__data__, index = assocIndexOf_default(data, key);
409
+ if (index < 0) {
410
+ return false;
411
+ }
412
+ var lastIndex = data.length - 1;
413
+ if (index == lastIndex) {
414
+ data.pop();
415
+ } else {
416
+ splice.call(data, index, 1);
417
+ }
418
+ --this.size;
419
+ return true;
420
+ }
421
+ var listCacheDelete_default = listCacheDelete;
422
+
423
+ // ../../../node_modules/lodash-es/_listCacheGet.js
424
+ function listCacheGet(key) {
425
+ var data = this.__data__, index = assocIndexOf_default(data, key);
426
+ return index < 0 ? void 0 : data[index][1];
427
+ }
428
+ var listCacheGet_default = listCacheGet;
429
+
430
+ // ../../../node_modules/lodash-es/_listCacheHas.js
431
+ function listCacheHas(key) {
432
+ return assocIndexOf_default(this.__data__, key) > -1;
433
+ }
434
+ var listCacheHas_default = listCacheHas;
435
+
436
+ // ../../../node_modules/lodash-es/_listCacheSet.js
437
+ function listCacheSet(key, value) {
438
+ var data = this.__data__, index = assocIndexOf_default(data, key);
439
+ if (index < 0) {
440
+ ++this.size;
441
+ data.push([key, value]);
442
+ } else {
443
+ data[index][1] = value;
444
+ }
445
+ return this;
446
+ }
447
+ var listCacheSet_default = listCacheSet;
448
+
449
+ // ../../../node_modules/lodash-es/_ListCache.js
450
+ function ListCache(entries) {
451
+ var index = -1, length = entries == null ? 0 : entries.length;
452
+ this.clear();
453
+ while (++index < length) {
454
+ var entry = entries[index];
455
+ this.set(entry[0], entry[1]);
456
+ }
457
+ }
458
+ ListCache.prototype.clear = listCacheClear_default;
459
+ ListCache.prototype["delete"] = listCacheDelete_default;
460
+ ListCache.prototype.get = listCacheGet_default;
461
+ ListCache.prototype.has = listCacheHas_default;
462
+ ListCache.prototype.set = listCacheSet_default;
463
+ var ListCache_default = ListCache;
464
+
465
+ // ../../../node_modules/lodash-es/_Map.js
466
+ var Map = getNative_default(root_default, "Map");
467
+ var Map_default = Map;
468
+
469
+ // ../../../node_modules/lodash-es/_mapCacheClear.js
470
+ function mapCacheClear() {
471
+ this.size = 0;
472
+ this.__data__ = {
473
+ "hash": new Hash_default(),
474
+ "map": new (Map_default || ListCache_default)(),
475
+ "string": new Hash_default()
476
+ };
477
+ }
478
+ var mapCacheClear_default = mapCacheClear;
479
+
480
+ // ../../../node_modules/lodash-es/_isKeyable.js
481
+ function isKeyable(value) {
482
+ var type = typeof value;
483
+ return type == "string" || type == "number" || type == "symbol" || type == "boolean" ? value !== "__proto__" : value === null;
484
+ }
485
+ var isKeyable_default = isKeyable;
486
+
487
+ // ../../../node_modules/lodash-es/_getMapData.js
488
+ function getMapData(map, key) {
489
+ var data = map.__data__;
490
+ return isKeyable_default(key) ? data[typeof key == "string" ? "string" : "hash"] : data.map;
491
+ }
492
+ var getMapData_default = getMapData;
493
+
494
+ // ../../../node_modules/lodash-es/_mapCacheDelete.js
495
+ function mapCacheDelete(key) {
496
+ var result = getMapData_default(this, key)["delete"](key);
497
+ this.size -= result ? 1 : 0;
498
+ return result;
499
+ }
500
+ var mapCacheDelete_default = mapCacheDelete;
501
+
502
+ // ../../../node_modules/lodash-es/_mapCacheGet.js
503
+ function mapCacheGet(key) {
504
+ return getMapData_default(this, key).get(key);
505
+ }
506
+ var mapCacheGet_default = mapCacheGet;
507
+
508
+ // ../../../node_modules/lodash-es/_mapCacheHas.js
509
+ function mapCacheHas(key) {
510
+ return getMapData_default(this, key).has(key);
511
+ }
512
+ var mapCacheHas_default = mapCacheHas;
513
+
514
+ // ../../../node_modules/lodash-es/_mapCacheSet.js
515
+ function mapCacheSet(key, value) {
516
+ var data = getMapData_default(this, key), size = data.size;
517
+ data.set(key, value);
518
+ this.size += data.size == size ? 0 : 1;
519
+ return this;
520
+ }
521
+ var mapCacheSet_default = mapCacheSet;
522
+
523
+ // ../../../node_modules/lodash-es/_MapCache.js
524
+ function MapCache(entries) {
525
+ var index = -1, length = entries == null ? 0 : entries.length;
526
+ this.clear();
527
+ while (++index < length) {
528
+ var entry = entries[index];
529
+ this.set(entry[0], entry[1]);
530
+ }
531
+ }
532
+ MapCache.prototype.clear = mapCacheClear_default;
533
+ MapCache.prototype["delete"] = mapCacheDelete_default;
534
+ MapCache.prototype.get = mapCacheGet_default;
535
+ MapCache.prototype.has = mapCacheHas_default;
536
+ MapCache.prototype.set = mapCacheSet_default;
537
+ var MapCache_default = MapCache;
538
+
539
+ // ../../../node_modules/lodash-es/memoize.js
540
+ var FUNC_ERROR_TEXT = "Expected a function";
541
+ function memoize(func, resolver) {
542
+ if (typeof func != "function" || resolver != null && typeof resolver != "function") {
543
+ throw new TypeError(FUNC_ERROR_TEXT);
544
+ }
545
+ var memoized = function() {
546
+ var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache = memoized.cache;
547
+ if (cache.has(key)) {
548
+ return cache.get(key);
549
+ }
550
+ var result = func.apply(this, args);
551
+ memoized.cache = cache.set(key, result) || cache;
552
+ return result;
553
+ };
554
+ memoized.cache = new (memoize.Cache || MapCache_default)();
555
+ return memoized;
556
+ }
557
+ memoize.Cache = MapCache_default;
558
+ var memoize_default = memoize;
559
+
560
+ // ../../../node_modules/lodash-es/_memoizeCapped.js
561
+ var MAX_MEMOIZE_SIZE = 500;
562
+ function memoizeCapped(func) {
563
+ var result = memoize_default(func, function(key) {
564
+ if (cache.size === MAX_MEMOIZE_SIZE) {
565
+ cache.clear();
566
+ }
567
+ return key;
568
+ });
569
+ var cache = result.cache;
570
+ return result;
571
+ }
572
+ var memoizeCapped_default = memoizeCapped;
573
+
574
+ // ../../../node_modules/lodash-es/_stringToPath.js
575
+ var rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
576
+ var reEscapeChar = /\\(\\)?/g;
577
+ var stringToPath = memoizeCapped_default(function(string) {
578
+ var result = [];
579
+ if (string.charCodeAt(0) === 46) {
580
+ result.push("");
581
+ }
582
+ string.replace(rePropName, function(match, number, quote, subString) {
583
+ result.push(quote ? subString.replace(reEscapeChar, "$1") : number || match);
584
+ });
585
+ return result;
586
+ });
587
+ var stringToPath_default = stringToPath;
588
+
589
+ // ../../../node_modules/lodash-es/toString.js
590
+ function toString(value) {
591
+ return value == null ? "" : baseToString_default(value);
592
+ }
593
+ var toString_default = toString;
594
+
595
+ // ../../../node_modules/lodash-es/_castPath.js
596
+ function castPath(value, object) {
597
+ if (isArray_default(value)) {
598
+ return value;
599
+ }
600
+ return isKey_default(value, object) ? [value] : stringToPath_default(toString_default(value));
601
+ }
602
+ var castPath_default = castPath;
603
+
604
+ // ../../../node_modules/lodash-es/_toKey.js
605
+ var INFINITY2 = 1 / 0;
606
+ function toKey(value) {
607
+ if (typeof value == "string" || isSymbol_default(value)) {
608
+ return value;
609
+ }
610
+ var result = value + "";
611
+ return result == "0" && 1 / value == -INFINITY2 ? "-0" : result;
612
+ }
613
+ var toKey_default = toKey;
614
+
615
+ // ../../../node_modules/lodash-es/_baseSlice.js
616
+ function baseSlice(array2, start, end) {
617
+ var index = -1, length = array2.length;
618
+ if (start < 0) {
619
+ start = -start > length ? 0 : length + start;
620
+ }
621
+ end = end > length ? length : end;
622
+ if (end < 0) {
623
+ end += length;
624
+ }
625
+ length = start > end ? 0 : end - start >>> 0;
626
+ start >>>= 0;
627
+ var result = Array(length);
628
+ while (++index < length) {
629
+ result[index] = array2[index + start];
630
+ }
631
+ return result;
632
+ }
633
+ var baseSlice_default = baseSlice;
634
+
635
+ // ../../../node_modules/lodash-es/_castSlice.js
636
+ function castSlice(array2, start, end) {
637
+ var length = array2.length;
638
+ end = end === void 0 ? length : end;
639
+ return !start && end >= length ? array2 : baseSlice_default(array2, start, end);
640
+ }
641
+ var castSlice_default = castSlice;
642
+
643
+ // ../../../node_modules/lodash-es/_hasUnicode.js
644
+ var rsAstralRange = "\\ud800-\\udfff";
645
+ var rsComboMarksRange = "\\u0300-\\u036f";
646
+ var reComboHalfMarksRange = "\\ufe20-\\ufe2f";
647
+ var rsComboSymbolsRange = "\\u20d0-\\u20ff";
648
+ var rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange;
649
+ var rsVarRange = "\\ufe0e\\ufe0f";
650
+ var rsZWJ = "\\u200d";
651
+ var reHasUnicode = RegExp("[" + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + "]");
652
+ function hasUnicode(string) {
653
+ return reHasUnicode.test(string);
654
+ }
655
+ var hasUnicode_default = hasUnicode;
656
+
657
+ // ../../../node_modules/lodash-es/_asciiToArray.js
658
+ function asciiToArray(string) {
659
+ return string.split("");
660
+ }
661
+ var asciiToArray_default = asciiToArray;
662
+
663
+ // ../../../node_modules/lodash-es/_unicodeToArray.js
664
+ var rsAstralRange2 = "\\ud800-\\udfff";
665
+ var rsComboMarksRange2 = "\\u0300-\\u036f";
666
+ var reComboHalfMarksRange2 = "\\ufe20-\\ufe2f";
667
+ var rsComboSymbolsRange2 = "\\u20d0-\\u20ff";
668
+ var rsComboRange2 = rsComboMarksRange2 + reComboHalfMarksRange2 + rsComboSymbolsRange2;
669
+ var rsVarRange2 = "\\ufe0e\\ufe0f";
670
+ var rsAstral = "[" + rsAstralRange2 + "]";
671
+ var rsCombo = "[" + rsComboRange2 + "]";
672
+ var rsFitz = "\\ud83c[\\udffb-\\udfff]";
673
+ var rsModifier = "(?:" + rsCombo + "|" + rsFitz + ")";
674
+ var rsNonAstral = "[^" + rsAstralRange2 + "]";
675
+ var rsRegional = "(?:\\ud83c[\\udde6-\\uddff]){2}";
676
+ var rsSurrPair = "[\\ud800-\\udbff][\\udc00-\\udfff]";
677
+ var rsZWJ2 = "\\u200d";
678
+ var reOptMod = rsModifier + "?";
679
+ var rsOptVar = "[" + rsVarRange2 + "]?";
680
+ var rsOptJoin = "(?:" + rsZWJ2 + "(?:" + [rsNonAstral, rsRegional, rsSurrPair].join("|") + ")" + rsOptVar + reOptMod + ")*";
681
+ var rsSeq = rsOptVar + reOptMod + rsOptJoin;
682
+ var rsSymbol = "(?:" + [rsNonAstral + rsCombo + "?", rsCombo, rsRegional, rsSurrPair, rsAstral].join("|") + ")";
683
+ var reUnicode = RegExp(rsFitz + "(?=" + rsFitz + ")|" + rsSymbol + rsSeq, "g");
684
+ function unicodeToArray(string) {
685
+ return string.match(reUnicode) || [];
686
+ }
687
+ var unicodeToArray_default = unicodeToArray;
688
+
689
+ // ../../../node_modules/lodash-es/_stringToArray.js
690
+ function stringToArray(string) {
691
+ return hasUnicode_default(string) ? unicodeToArray_default(string) : asciiToArray_default(string);
692
+ }
693
+ var stringToArray_default = stringToArray;
694
+
695
+ // ../../../node_modules/lodash-es/_hasPath.js
696
+ function hasPath(object, path5, hasFunc) {
697
+ path5 = castPath_default(path5, object);
698
+ var index = -1, length = path5.length, result = false;
699
+ while (++index < length) {
700
+ var key = toKey_default(path5[index]);
701
+ if (!(result = object != null && hasFunc(object, key))) {
702
+ break;
703
+ }
704
+ object = object[key];
705
+ }
706
+ if (result || ++index != length) {
707
+ return result;
708
+ }
709
+ length = object == null ? 0 : object.length;
710
+ return !!length && isLength_default(length) && isIndex_default(key, length) && (isArray_default(object) || isArguments_default(object));
711
+ }
712
+ var hasPath_default = hasPath;
713
+
714
+ // ../../../node_modules/lodash-es/_baseHas.js
715
+ var objectProto7 = Object.prototype;
716
+ var hasOwnProperty6 = objectProto7.hasOwnProperty;
717
+ function baseHas(object, key) {
718
+ return object != null && hasOwnProperty6.call(object, key);
719
+ }
720
+ var baseHas_default = baseHas;
721
+
722
+ // ../../../node_modules/lodash-es/has.js
723
+ function has(object, path5) {
724
+ return object != null && hasPath_default(object, path5, baseHas_default);
725
+ }
726
+ var has_default = has;
727
+
728
+ // ../../../node_modules/lodash-es/_charsEndIndex.js
729
+ function charsEndIndex(strSymbols, chrSymbols) {
730
+ var index = strSymbols.length;
731
+ while (index-- && baseIndexOf_default(chrSymbols, strSymbols[index], 0) > -1) {
732
+ }
733
+ return index;
734
+ }
735
+ var charsEndIndex_default = charsEndIndex;
736
+
737
+ // ../../../node_modules/lodash-es/_charsStartIndex.js
738
+ function charsStartIndex(strSymbols, chrSymbols) {
739
+ var index = -1, length = strSymbols.length;
740
+ while (++index < length && baseIndexOf_default(chrSymbols, strSymbols[index], 0) > -1) {
741
+ }
742
+ return index;
743
+ }
744
+ var charsStartIndex_default = charsStartIndex;
745
+
746
+ // ../../../node_modules/lodash-es/trim.js
747
+ function trim(string, chars, guard) {
748
+ string = toString_default(string);
749
+ if (string && (guard || chars === void 0)) {
750
+ return baseTrim_default(string);
751
+ }
752
+ if (!string || !(chars = baseToString_default(chars))) {
753
+ return string;
754
+ }
755
+ var strSymbols = stringToArray_default(string), chrSymbols = stringToArray_default(chars), start = charsStartIndex_default(strSymbols, chrSymbols), end = charsEndIndex_default(strSymbols, chrSymbols) + 1;
756
+ return castSlice_default(strSymbols, start, end).join("");
757
+ }
758
+ var trim_default = trim;
759
+
760
+ // ../../utils/src/config/env.ts
761
+ function _env(key, defaultValue) {
762
+ return has_default(process.env, key) ? process.env[key] ?? "" : defaultValue ?? "";
763
+ }
764
+ function int(key, defaultValue) {
765
+ if (!has_default(process.env, key)) {
766
+ return defaultValue ?? 0;
767
+ }
768
+ const value = process.env[key] ?? "0";
769
+ return parseInt(value, 10);
770
+ }
771
+ function float(key, defaultValue) {
772
+ if (!has_default(process.env, key)) {
773
+ return defaultValue ?? 0;
774
+ }
775
+ const value = process.env[key] ?? "0";
776
+ return parseFloat(value);
777
+ }
778
+ function bool(key, defaultValue) {
779
+ if (!has_default(process.env, key)) {
780
+ return defaultValue ?? false;
781
+ }
782
+ const value = process.env[key];
783
+ return value === "true";
784
+ }
785
+ function json(key, defaultValue) {
786
+ if (!has_default(process.env, key)) {
787
+ return defaultValue ?? {};
788
+ }
789
+ const value = process.env[key] ?? "{}";
790
+ try {
791
+ return JSON.parse(value);
792
+ } catch (error) {
793
+ throw new Error(`Invalid json environment variable ${key}: ${error.message}`);
794
+ }
795
+ }
796
+ function array(key, defaultValue) {
797
+ if (!has_default(process.env, key)) {
798
+ return defaultValue ?? [];
799
+ }
800
+ let value = process.env[key] ?? "";
801
+ if (value.startsWith("[") && value.endsWith("]")) {
802
+ value = value.substring(1, value.length - 1);
803
+ }
804
+ return value.split(",").map((v) => {
805
+ return trim_default(trim_default(v, " "), '"');
806
+ });
807
+ }
808
+ function date(key, defaultValue) {
809
+ if (!has_default(process.env, key)) {
810
+ return defaultValue ?? /* @__PURE__ */ new Date();
811
+ }
812
+ const value = process.env[key] ?? Date();
813
+ return new Date(value);
814
+ }
815
+ var utils = {
816
+ int,
817
+ float,
818
+ bool,
819
+ json,
820
+ array,
821
+ date,
822
+ /**
823
+ * Gets a value from env that matches oneOf provided values
824
+ * @param {string} key
825
+ * @param {string[]} expectedValues
826
+ * @param {string|undefined} defaultValue
827
+ * @returns {string|undefined}
828
+ */
829
+ oneOf(key, expectedValues, defaultValue) {
830
+ if (!expectedValues) {
831
+ throw new Error(`env.oneOf requires expectedValues`);
832
+ }
833
+ if (defaultValue && !expectedValues.includes(defaultValue)) {
834
+ throw new Error(`env.oneOf requires defaultValue to be included in expectedValues`);
835
+ }
836
+ const rawValue = env(key, defaultValue);
837
+ return expectedValues.includes(rawValue) ? rawValue : defaultValue ?? "";
838
+ }
839
+ };
840
+ var env = Object.assign(_env, utils);
841
+
842
+ // ../../utils/src/logging/index.ts
843
+ import chalk from "chalk";
844
+ import { EOL } from "os";
845
+
846
+ // ../../utils/src/logging/types.ts
847
+ var logLevels = {
848
+ fatal: -1,
849
+ error: 0,
850
+ warn: 1,
851
+ info: 2,
852
+ debug: 3
853
+ };
854
+
855
+ // ../../utils/src/logging/error-to-string.ts
856
+ var errorToString = (error) => {
857
+ if (error === null) return "Null error";
858
+ if (error === void 0) return "Undefined error";
859
+ if (error instanceof Error) {
860
+ return [
861
+ `Name: ${error.name}`,
862
+ `Message: ${error.message}`,
863
+ `Stack: ${error.stack || "No stack trace available"}`,
864
+ // Handle additional properties that might exist on custom errors
865
+ ...Object.entries(error).filter(([key]) => !["name", "message", "stack"].includes(key)).map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
866
+ ].join("\n");
867
+ }
868
+ if (typeof error === "string") return error;
869
+ if (typeof error === "object") {
870
+ try {
871
+ return JSON.stringify(error, null, 2);
872
+ } catch {
873
+ return `[Object that cannot be stringified: ${Object.prototype.toString.call(error)}]`;
874
+ }
875
+ }
876
+ return String(error);
877
+ };
878
+
879
+ // ../../utils/src/logging/index.ts
880
+ var currentLogLevel = logLevels[env("LOG_LEVEL")?.toLowerCase()] ?? logLevels.info;
881
+ var logger = {
882
+ fatal: (message, meta) => {
883
+ if (currentLogLevel >= logLevels.fatal) {
884
+ console.error(
885
+ `[${(/* @__PURE__ */ new Date()).toTimeString()}]`,
886
+ `${chalk.bgRed.white(" fatal ")}${EOL}`,
887
+ errorToString(message),
888
+ meta ? `${EOL}${JSON.stringify(meta, null, 2)}` : ""
889
+ );
890
+ }
891
+ },
892
+ error: (message, meta) => {
893
+ if (currentLogLevel >= logLevels.error) {
894
+ console.error(
895
+ `[${(/* @__PURE__ */ new Date()).toTimeString()}]`,
896
+ `${chalk.bgRed.white(" error ")}${EOL}`,
897
+ errorToString(message),
898
+ meta ? `${EOL}${JSON.stringify(meta, null, 2)}` : ""
899
+ );
900
+ }
901
+ },
902
+ warn: (message, meta) => {
903
+ if (currentLogLevel >= logLevels.warn) {
904
+ console.warn(
905
+ `[${(/* @__PURE__ */ new Date()).toTimeString()}]`,
906
+ `${chalk.bgYellow.black(" warn ")}${EOL}`,
907
+ errorToString(message),
908
+ meta ? `${EOL}${JSON.stringify(meta, null, 2)}` : ""
909
+ );
910
+ }
911
+ },
912
+ info: (message, meta) => {
913
+ if (currentLogLevel >= logLevels.info) {
914
+ console.info(
915
+ `[${(/* @__PURE__ */ new Date()).toTimeString()}]`,
916
+ `${chalk.bgBlue.white(" info ")}${EOL}`,
917
+ message,
918
+ meta ? `${EOL}${JSON.stringify(meta, null, 2)}` : ""
919
+ );
920
+ }
921
+ },
922
+ debug: (message, meta) => {
923
+ if (currentLogLevel >= logLevels.debug) {
924
+ console.debug(
925
+ `[${(/* @__PURE__ */ new Date()).toTimeString()}]`,
926
+ `${chalk.bgWhite.black(" debug ")}${EOL}`,
927
+ message,
928
+ meta ? `${EOL}${JSON.stringify(meta, null, 2)}` : ""
929
+ );
930
+ }
931
+ }
932
+ };
933
+
934
+ // src/queue-plugin/core.ts
935
+ var DEFAULT_CONFIG = {
936
+ batchSize: 10,
937
+ batchWindowMs: 500,
938
+ maxRetries: 3,
939
+ parallel: true,
940
+ maxConcurrent: 5,
941
+ retryBackoff: true,
942
+ persistence: {
943
+ enabled: true,
944
+ directory: "./.develop/queue-data",
945
+ saveInterval: 6e4,
946
+ saveOnShutdown: false,
947
+ loadOnStartup: true
948
+ }
949
+ };
950
+ var mergeConfig = (defaultConfig, userConfig) => ({
951
+ ...defaultConfig,
952
+ ...userConfig,
953
+ persistence: {
954
+ ...defaultConfig.persistence,
955
+ ...userConfig?.persistence || {}
956
+ }
957
+ });
958
+ var createQueueService = (handler, module) => ({
959
+ handler,
960
+ incoming: [],
961
+ processing: [],
962
+ dlq: [],
963
+ timeoutId: null,
964
+ processingBatch: false,
965
+ activeProcessing: 0,
966
+ module
967
+ });
968
+ var createQueueMessage = (body, headers) => {
969
+ const id = Date.now().toString() + Math.random().toString(36).substring(2, 7);
970
+ return {
971
+ id,
972
+ timestamp: /* @__PURE__ */ new Date(),
973
+ attempts: 0,
974
+ payload: body,
975
+ attributes: headers
976
+ };
977
+ };
978
+ var moveToProcessing = (queueService, batchSize) => {
979
+ return queueService.incoming.splice(0, batchSize);
980
+ };
981
+ var removeFromProcessing = (queueService, messageId) => {
982
+ queueService.processing = queueService.processing.filter((msg) => msg.id !== messageId);
983
+ };
984
+ var moveToDLQ = (queueService, message, error) => {
985
+ queueService.dlq.push({
986
+ ...message,
987
+ error,
988
+ failedAt: /* @__PURE__ */ new Date()
989
+ });
990
+ removeFromProcessing(queueService, message.id);
991
+ };
992
+ var incrementAttempts = (queueService, messageId) => {
993
+ const index = queueService.processing.findIndex((m) => m.id === messageId);
994
+ if (index >= 0) {
995
+ queueService.processing[index].attempts += 1;
996
+ return queueService.processing[index];
997
+ }
998
+ return null;
999
+ };
1000
+ var calculateBackoffDelay = (attempts) => {
1001
+ return Math.pow(2, attempts) * 100;
1002
+ };
1003
+ var setNextAttemptTime = (message, delayMs) => ({
1004
+ ...message,
1005
+ nextAttempt: new Date(Date.now() + delayMs)
1006
+ });
1007
+ var createQueueSummary = (queueService, config) => ({
1008
+ incoming: queueService.incoming.length,
1009
+ processing: queueService.processing.length,
1010
+ dlq: queueService.dlq.length,
1011
+ isProcessing: queueService.processingBatch,
1012
+ activeProcessing: queueService.activeProcessing,
1013
+ configuration: {
1014
+ batchSize: config.batchSize,
1015
+ batchWindowMs: config.batchWindowMs,
1016
+ parallel: config.parallel,
1017
+ maxConcurrent: config.maxConcurrent
1018
+ }
1019
+ });
1020
+ var createDashboardSummary = (queues, config) => {
1021
+ return Object.entries(queues).reduce((summary, [queueName, queue]) => {
1022
+ summary[queueName] = createQueueSummary(queue, config);
1023
+ return summary;
1024
+ }, {});
1025
+ };
1026
+ var moveDLQToIncoming = (queueService) => {
1027
+ const dlqCount = queueService.dlq.length;
1028
+ if (dlqCount === 0) return 0;
1029
+ const movedMessages = queueService.dlq.map((message) => ({
1030
+ ...message,
1031
+ attempts: 0,
1032
+ error: void 0,
1033
+ failedAt: void 0,
1034
+ reprocessed: true,
1035
+ originalId: message.id,
1036
+ id: Date.now().toString() + Math.random().toString(36).substring(2, 7)
1037
+ }));
1038
+ queueService.incoming.push(...movedMessages);
1039
+ queueService.dlq = [];
1040
+ return dlqCount;
1041
+ };
1042
+ var purgeDLQ = (queueService) => {
1043
+ const dlqCount = queueService.dlq.length;
1044
+ queueService.dlq = [];
1045
+ return dlqCount;
1046
+ };
1047
+ var logSuccess = (message, messageId, queueName) => {
1048
+ logger.debug(`${logSymbols.success} ${chalk2.green(message)} ${chalk2.yellow(messageId)} in queue ${chalk2.magenta(queueName)}`);
1049
+ };
1050
+ var logError = (message, messageId, queueName, error) => {
1051
+ logger.error(`${logSymbols.error} ${chalk2.red(message)} ${chalk2.yellow(messageId)} in queue ${chalk2.magenta(queueName)}: ${error}`);
1052
+ };
1053
+ var logRetryScheduled = (messageId, delayMs) => {
1054
+ logger.info(`${chalk2.blue("\u23F1\uFE0F Scheduling retry")} for message ${chalk2.yellow(messageId)} in ${chalk2.cyan(delayMs)}ms`);
1055
+ };
1056
+ var logDLQOperation = (operation, count, queueName) => {
1057
+ logger.warn(`${logSymbols.warning} ${chalk2.yellow(operation)} ${chalk2.red(count)} messages from DLQ for ${chalk2.green(queueName)}`);
1058
+ };
1059
+
1060
+ // src/queue-plugin/processing.ts
1061
+ var createProcessMessageHandler = (config) => async (queueName, message, queueService) => {
1062
+ try {
1063
+ await queueService.handler(message);
1064
+ removeFromProcessing(queueService, message.id);
1065
+ logSuccess("Successfully processed message", message.id, queueName);
1066
+ } catch (error) {
1067
+ await handleProcessingError(queueName, message, queueService, error, config);
1068
+ }
1069
+ };
1070
+ var handleProcessingError = async (queueName, message, queueService, error, config) => {
1071
+ logError("Error processing message", message.id, queueName, error.message);
1072
+ if (message.attempts >= config.maxRetries) {
1073
+ moveToDLQ(queueService, message, error.message);
1074
+ return;
1075
+ }
1076
+ const updatedMessage = incrementAttempts(queueService, message.id);
1077
+ if (!updatedMessage) return;
1078
+ if (config.retryBackoff) {
1079
+ const delayMs = calculateBackoffDelay(updatedMessage.attempts);
1080
+ const messageWithNextAttempt = setNextAttemptTime(updatedMessage, delayMs);
1081
+ logRetryScheduled(message.id, delayMs);
1082
+ setTimeout(() => {
1083
+ createProcessMessageHandler(config)(queueName, messageWithNextAttempt, queueService);
1084
+ }, delayMs);
1085
+ }
1086
+ };
1087
+ var createBatchProcessor = (processMessage, config, saveQueueState) => async (queueName, queueService) => {
1088
+ if (queueService.timeoutId) {
1089
+ clearTimeout(queueService.timeoutId);
1090
+ queueService.timeoutId = null;
1091
+ }
1092
+ if (queueService.processingBatch) {
1093
+ return;
1094
+ }
1095
+ try {
1096
+ queueService.processingBatch = true;
1097
+ const messagesToProcess = moveToProcessing(queueService, config.batchSize);
1098
+ if (messagesToProcess.length === 0) {
1099
+ return;
1100
+ }
1101
+ queueService.processing.push(...messagesToProcess);
1102
+ await Promise.all(messagesToProcess.map((message) => {
1103
+ return processMessage(queueName, message, queueService);
1104
+ }));
1105
+ if (config.persistence.enabled && saveQueueState) {
1106
+ await saveQueueState(queueName);
1107
+ }
1108
+ } finally {
1109
+ queueService.processingBatch = false;
1110
+ }
1111
+ };
1112
+ var createProcessingScheduler = (processBatch, config) => (queueName, queueService, overrideDelay = null) => {
1113
+ if (!queueService.timeoutId) {
1114
+ const delay = overrideDelay ?? config.batchWindowMs;
1115
+ queueService.timeoutId = setTimeout(() => {
1116
+ processBatch(queueName, queueService);
1117
+ }, delay);
1118
+ }
1119
+ };
1120
+ var handleImmediateProcessing = (queueService, config, processBatch, queueName) => {
1121
+ if (queueService.incoming.length >= config.batchSize) {
1122
+ if (queueService.timeoutId) {
1123
+ clearTimeout(queueService.timeoutId);
1124
+ queueService.timeoutId = null;
1125
+ }
1126
+ setImmediate(() => processBatch(queueName, queueService));
1127
+ }
1128
+ };
1129
+
1130
+ // src/queue-plugin/persistence.ts
1131
+ import * as fs from "fs/promises";
1132
+ import * as path2 from "path";
1133
+ import chalk3 from "chalk";
1134
+ import logSymbols2 from "log-symbols";
1135
+ var createQueueData = (queueService) => ({
1136
+ incoming: queueService.incoming,
1137
+ processing: queueService.processing,
1138
+ dlq: queueService.dlq,
1139
+ savedAt: /* @__PURE__ */ new Date()
1140
+ });
1141
+ var restoreDates = (messages) => {
1142
+ messages.forEach((msg) => {
1143
+ msg.timestamp = new Date(msg.timestamp);
1144
+ if (msg.nextAttempt) msg.nextAttempt = new Date(msg.nextAttempt);
1145
+ if (msg.failedAt) msg.failedAt = new Date(msg.failedAt);
1146
+ });
1147
+ };
1148
+ var createPersistenceInitializer = (config, loadAllQueueStates, saveAllQueueStates) => async () => {
1149
+ try {
1150
+ await fs.mkdir(config.persistence.directory, { recursive: true });
1151
+ if (config.persistence.loadOnStartup) {
1152
+ await loadAllQueueStates();
1153
+ }
1154
+ if (config.persistence.saveInterval > 0) {
1155
+ setInterval(saveAllQueueStates, config.persistence.saveInterval);
1156
+ }
1157
+ if (config.persistence.saveOnShutdown) {
1158
+ const shutdownHandler = async () => {
1159
+ logger.debug("Saving queue state before shutdown...");
1160
+ await saveAllQueueStates();
1161
+ process.exit(0);
1162
+ };
1163
+ process.on("SIGINT", shutdownHandler);
1164
+ process.on("SIGTERM", shutdownHandler);
1165
+ }
1166
+ logger.debug(`${logSymbols2.success} ${chalk3.green("Queue persistence initialized:")} ${chalk3.yellow(config.persistence.directory)}`);
1167
+ } catch (error) {
1168
+ logger.error(`${logSymbols2.error} ${chalk3.red("Failed to initialize queue persistence:")} ${chalk3.yellow(error.message)}`);
1169
+ }
1170
+ };
1171
+ var createQueueStateSaver = (config) => async (queueName, queueService) => {
1172
+ try {
1173
+ if (!queueService) return;
1174
+ const queueData = createQueueData(queueService);
1175
+ const now = Date.now();
1176
+ const queueFilePath = path2.join(config.persistence.directory, `${queueName}.json`);
1177
+ const tempFilePath = path2.join(config.persistence.directory, `${queueName}.${now}temp.json`);
1178
+ await fs.writeFile(tempFilePath, JSON.stringify(queueData, null, 2), "utf8");
1179
+ await fs.rename(tempFilePath, queueFilePath);
1180
+ logger.info(`${logSymbols2.info} ${chalk3.blue("Queue state saved:")} ${chalk3.green(queueName)}`);
1181
+ } catch (error) {
1182
+ logger.error(`Failed to save queue state for ${queueName}:`, error);
1183
+ }
1184
+ };
1185
+ var createAllQueuesStateSaver = (config, saveQueueState) => (queues) => async () => {
1186
+ try {
1187
+ for (const [queueName, queueService] of Object.entries(queues)) {
1188
+ await saveQueueState(queueName, queueService);
1189
+ }
1190
+ logger.debug(`${logSymbols2.success} ${chalk3.green("All queue states saved to")} ${chalk3.yellow(config.persistence.directory)}`);
1191
+ } catch (error) {
1192
+ logger.error(`${logSymbols2.error} ${chalk3.red("Failed to save all queue states:")} ${chalk3.yellow(error.message)}`);
1193
+ }
1194
+ };
1195
+ var createQueueStateLoader = (config, scheduleProcessing, processMessage) => (queues) => async (queueName) => {
1196
+ try {
1197
+ if (!queues[queueName]) {
1198
+ logger.warn(`Skipping load for non-existent queue: ${queueName}`);
1199
+ return;
1200
+ }
1201
+ const queueFilePath = path2.join(config.persistence.directory, `${queueName}.json`);
1202
+ try {
1203
+ const data = await fs.readFile(queueFilePath, "utf8");
1204
+ const queueData = JSON.parse(data);
1205
+ restoreDates(queueData.incoming);
1206
+ restoreDates(queueData.processing);
1207
+ restoreDates(queueData.dlq);
1208
+ queues[queueName].incoming = queueData.incoming;
1209
+ queues[queueName].processing = queueData.processing;
1210
+ queues[queueName].dlq = queueData.dlq;
1211
+ logger.debug(`Queue state loaded: ${queueName} (saved at ${queueData.savedAt})`);
1212
+ if (queues[queueName].incoming.length > 0) {
1213
+ scheduleProcessing(queueName, queues[queueName]);
1214
+ }
1215
+ if (queues[queueName].processing.length > 0) {
1216
+ for (const message of [...queues[queueName].processing]) {
1217
+ if (message.attempts >= config.maxRetries) continue;
1218
+ setTimeout(() => {
1219
+ processMessage(queueName, message, queues[queueName]);
1220
+ }, 100 * (Math.random() * 10));
1221
+ }
1222
+ }
1223
+ } catch (error) {
1224
+ if (error.code === "ENOENT") {
1225
+ logger.debug(`No saved state found for queue: ${queueName}`);
1226
+ } else {
1227
+ throw error;
1228
+ }
1229
+ }
1230
+ } catch (error) {
1231
+ logger.error(`Failed to load queue state for ${queueName}:`, error);
1232
+ }
1233
+ };
1234
+ var createAllQueuesStateLoader = (config, loadQueueState) => async () => {
1235
+ try {
1236
+ const files = await fs.readdir(config.persistence.directory);
1237
+ const queueFiles = files.filter((file) => file.endsWith(".json") && !file.includes(".temp."));
1238
+ for (const file of queueFiles) {
1239
+ const queueName = path2.basename(file, ".json");
1240
+ await loadQueueState(queueName);
1241
+ }
1242
+ logger.debug("All queue states loaded");
1243
+ } catch (error) {
1244
+ logger.error("Failed to load queue states:", error);
1245
+ }
1246
+ };
1247
+
1248
+ // src/queue-plugin/routes.ts
1249
+ var registerQueueRoutes = (app, prefix = "") => {
1250
+ app.get(
1251
+ `/${prefix}/dashboard`,
1252
+ async (_, reply) => {
1253
+ const summary = app.queues.getDashboardSummary();
1254
+ return reply.status(200).send(summary);
1255
+ }
1256
+ );
1257
+ app.get(
1258
+ `/${prefix}/:queue`,
1259
+ async (request, reply) => {
1260
+ const queueName = request.params.queue;
1261
+ const summary = app.queues.getQueueSummary(queueName);
1262
+ if (summary === null) {
1263
+ return reply.status(404).send({ error: "Queue not found" });
1264
+ }
1265
+ return reply.status(200).send(summary);
1266
+ }
1267
+ );
1268
+ app.post(
1269
+ `/${prefix}/:queue`,
1270
+ async (request, reply) => {
1271
+ const queueName = request.params.queue;
1272
+ const result = await app.queues.enqueueMessage(queueName, request.body, request.headers);
1273
+ if (result === null) {
1274
+ return reply.status(404).send({ error: "Queue not found" });
1275
+ }
1276
+ return reply.status(200).send(result);
1277
+ }
1278
+ );
1279
+ app.get(
1280
+ `/${prefix}/:queue/process-dlq`,
1281
+ async (request, reply) => {
1282
+ const queueName = request.params.queue;
1283
+ const result = await app.queues.processDlq(queueName);
1284
+ if (result === null) {
1285
+ return reply.status(404).send(result);
1286
+ }
1287
+ return reply.status(200).send(result);
1288
+ }
1289
+ );
1290
+ app.post(
1291
+ `/${prefix}/:queue/purge-dlq`,
1292
+ async (request, reply) => {
1293
+ const queueName = request.params.queue;
1294
+ const result = await app.queues.purgeDlq(queueName);
1295
+ if (result === null) {
1296
+ return reply.status(404).send({ error: "Queue not found" });
1297
+ }
1298
+ return reply.status(200).send(result);
1299
+ }
1300
+ );
1301
+ };
1302
+
1303
+ // src/queue-plugin/decorator.ts
1304
+ import chalk4 from "chalk";
1305
+ import logSymbols3 from "log-symbols";
1306
+ var isValidQueueName = (queueName) => {
1307
+ return typeof queueName === "string" && queueName.length > 0 && /^[a-zA-Z0-9_-]+$/.test(queueName);
1308
+ };
1309
+ var createQueueManager = ({
1310
+ config,
1311
+ queues,
1312
+ saveQueueState,
1313
+ loadQueueState,
1314
+ scheduleProcessing,
1315
+ processBatch
1316
+ }) => {
1317
+ const validateQueueName = (queueName) => {
1318
+ if (!queueName || typeof queueName !== "string") {
1319
+ throw new Error("Queue name must be a non-empty string");
1320
+ }
1321
+ if (!isValidQueueName(queueName)) {
1322
+ throw new Error("Queue name must contain only alphanumeric characters, hyphens, and underscores");
1323
+ }
1324
+ };
1325
+ const validateHandler = (handler) => {
1326
+ if (typeof handler !== "function") {
1327
+ throw new Error("Handler must be a function");
1328
+ }
1329
+ };
1330
+ const addQueue = async (queueName, handler, module) => {
1331
+ try {
1332
+ validateQueueName(queueName);
1333
+ validateHandler(handler);
1334
+ if (queues[queueName]) {
1335
+ logger.warn(`${logSymbols3.warning} ${chalk4.yellow("Queue already exists:")} ${chalk4.magenta(queueName)}.`);
1336
+ return;
1337
+ }
1338
+ queues[queueName] = createQueueService(handler, module);
1339
+ if (config.persistence.enabled && loadQueueState) {
1340
+ await loadQueueState(queueName);
1341
+ }
1342
+ logger.info(`${logSymbols3.success} ${chalk4.green("Queue added:")} ${chalk4.magenta(queueName)}`);
1343
+ } catch (error) {
1344
+ logger.error(`${logSymbols3.error} ${chalk4.red("Failed to add queue")} ${chalk4.magenta(queueName)}: ${error.message}`);
1345
+ throw error;
1346
+ }
1347
+ };
1348
+ const removeQueue = async (queueName) => {
1349
+ try {
1350
+ validateQueueName(queueName);
1351
+ if (!queues[queueName]) {
1352
+ throw new Error(`Queue '${queueName}' does not exist`);
1353
+ }
1354
+ const queueService = queues[queueName];
1355
+ const totalMessages = queueService.incoming.length + queueService.processing.length;
1356
+ if (totalMessages > 0) {
1357
+ logger.warn(`${logSymbols3.warning} ${chalk4.yellow("Removing queue with")} ${chalk4.red(totalMessages)} ${chalk4.yellow("pending messages:")} ${chalk4.magenta(queueName)}`);
1358
+ }
1359
+ if (queueService.timeoutId) {
1360
+ clearTimeout(queueService.timeoutId);
1361
+ }
1362
+ if (config.persistence.enabled && saveQueueState) {
1363
+ await saveQueueState(queueName, queueService);
1364
+ }
1365
+ delete queues[queueName];
1366
+ logger.info(`${logSymbols3.success} ${chalk4.green("Queue removed:")} ${chalk4.magenta(queueName)}`);
1367
+ } catch (error) {
1368
+ logger.error(`${logSymbols3.error} ${chalk4.red("Failed to remove queue")} ${chalk4.magenta(queueName)}: ${error.message}`);
1369
+ throw error;
1370
+ }
1371
+ };
1372
+ const hasQueue = (queueName) => {
1373
+ try {
1374
+ validateQueueName(queueName);
1375
+ return queueName in queues;
1376
+ } catch {
1377
+ return false;
1378
+ }
1379
+ };
1380
+ const listQueues = (module) => {
1381
+ return Object.keys(queues).filter((queueName) => {
1382
+ const queueService = queues[queueName];
1383
+ return !module || queueService.module === module;
1384
+ }).sort();
1385
+ };
1386
+ const getQueueStats = (queueName) => {
1387
+ try {
1388
+ validateQueueName(queueName);
1389
+ return queues[queueName] || null;
1390
+ } catch {
1391
+ return null;
1392
+ }
1393
+ };
1394
+ const getQueuesMap = () => {
1395
+ return { ...queues };
1396
+ };
1397
+ const getConfig = () => config;
1398
+ const getDashboardSummary = () => createDashboardSummary(queues, config);
1399
+ const getQueueSummary = (queueName) => {
1400
+ if (!queues[queueName]) {
1401
+ return null;
1402
+ }
1403
+ const queue = queues[queueName];
1404
+ const stats = createQueueSummary(queue, config);
1405
+ return {
1406
+ stats,
1407
+ messages: {
1408
+ incoming: queue.incoming,
1409
+ processing: queue.processing,
1410
+ dlq: queue.dlq
1411
+ }
1412
+ };
1413
+ };
1414
+ const enqueueMessage = async (queueName, body, attributes) => {
1415
+ if (!queues[queueName]) {
1416
+ return null;
1417
+ }
1418
+ const message = createQueueMessage(body, attributes);
1419
+ queues[queueName].incoming.push(message);
1420
+ scheduleProcessing(queueName, queues[queueName]);
1421
+ handleImmediateProcessing(queues[queueName], config, processBatch, queueName);
1422
+ if (config.persistence.enabled && saveQueueState) {
1423
+ await saveQueueState(queueName, queues[queueName]);
1424
+ }
1425
+ return {
1426
+ id: message.id,
1427
+ queueName
1428
+ };
1429
+ };
1430
+ const processDlq = async (queueName) => {
1431
+ if (!queues[queueName]) {
1432
+ return null;
1433
+ }
1434
+ const processedCount = moveDLQToIncoming(queues[queueName]);
1435
+ if (processedCount === 0) {
1436
+ return {
1437
+ status: "success",
1438
+ message: "No messages in DLQ to process",
1439
+ processed: 0
1440
+ };
1441
+ }
1442
+ logDLQOperation("Moving", processedCount, queueName);
1443
+ scheduleProcessing(queueName, queues[queueName]);
1444
+ if (saveQueueState) {
1445
+ await saveQueueState(queueName, queues[queueName]);
1446
+ }
1447
+ return {
1448
+ status: "success",
1449
+ message: `Moved ${processedCount} messages from DLQ to processing queue`,
1450
+ processed: processedCount
1451
+ };
1452
+ };
1453
+ const purgeDlq = async (queueName) => {
1454
+ if (!queues[queueName]) {
1455
+ return null;
1456
+ }
1457
+ const purgedCount = purgeDLQ(queues[queueName]);
1458
+ if (purgedCount === 0) {
1459
+ return {
1460
+ status: "success",
1461
+ message: "No messages in DLQ to purge",
1462
+ purged: 0
1463
+ };
1464
+ }
1465
+ logDLQOperation("Purging", purgedCount, queueName);
1466
+ if (saveQueueState) {
1467
+ await saveQueueState(queueName, queues[queueName]);
1468
+ }
1469
+ return {
1470
+ status: "success",
1471
+ message: `Purged ${purgedCount} messages from DLQ`,
1472
+ purged: purgedCount
1473
+ };
1474
+ };
1475
+ return {
1476
+ addQueue,
1477
+ removeQueue,
1478
+ hasQueue,
1479
+ listQueues,
1480
+ getQueueStats,
1481
+ getQueuesMap,
1482
+ getConfig,
1483
+ getDashboardSummary,
1484
+ getQueueSummary,
1485
+ enqueueMessage,
1486
+ processDlq,
1487
+ purgeDlq
1488
+ };
1489
+ };
1490
+ var createQueueDecorator = (queueManager) => (app) => {
1491
+ app.decorate("queues", queueManager);
1492
+ };
1493
+
1494
+ // src/queue-plugin/plugin.ts
1495
+ var queuesPlugin = fsPlugin(async (app, options) => {
1496
+ const config = mergeConfig(DEFAULT_CONFIG, options.config);
1497
+ const queues = {};
1498
+ const processMessage = createProcessMessageHandler(config);
1499
+ const saveQueueState = config.persistence.enabled ? createQueueStateSaver(config) : void 0;
1500
+ const saveAllQueueStates = config.persistence.enabled && saveQueueState ? createAllQueuesStateSaver(config, saveQueueState)(queues) : async () => {
1501
+ };
1502
+ const processBatch = createBatchProcessor(
1503
+ processMessage,
1504
+ config,
1505
+ saveQueueState ? (queueName) => saveQueueState(queueName, queues[queueName]) : void 0
1506
+ );
1507
+ const scheduleProcessing = createProcessingScheduler(processBatch, config);
1508
+ const loadQueueState = config.persistence.enabled ? createQueueStateLoader(
1509
+ config,
1510
+ scheduleProcessing,
1511
+ processMessage
1512
+ )(queues) : async () => {
1513
+ };
1514
+ const loadAllQueueStates = config.persistence.enabled ? createAllQueuesStateLoader(config, loadQueueState) : async () => {
1515
+ };
1516
+ const initializePersistence = config.persistence.enabled ? createPersistenceInitializer(config, loadAllQueueStates, saveAllQueueStates) : async () => {
1517
+ };
1518
+ const queueManager = createQueueManager({
1519
+ config,
1520
+ queues,
1521
+ saveQueueState: saveQueueState ? (queueName) => saveQueueState(queueName, queues[queueName]) : void 0,
1522
+ loadQueueState,
1523
+ scheduleProcessing,
1524
+ processBatch
1525
+ });
1526
+ const decorateQueues = createQueueDecorator(queueManager);
1527
+ decorateQueues(app);
1528
+ registerQueueRoutes(
1529
+ app,
1530
+ options.prefix
1531
+ );
1532
+ await initializePersistence();
1533
+ });
1534
+
1535
+ // src/schedule-plugin/plugin.ts
1536
+ import fsPlugin2 from "fastify-plugin";
1537
+
1538
+ // src/schedule-plugin/core.ts
1539
+ import * as fs3 from "fs/promises";
1540
+ import chalk9 from "chalk";
1541
+ import logSymbols7 from "log-symbols";
1542
+
1543
+ // src/schedule-plugin/execution.ts
1544
+ import chalk6 from "chalk";
1545
+ import logSymbols4 from "log-symbols";
1546
+
1547
+ // src/schedule-plugin/cron-utils.ts
1548
+ import chalk5 from "chalk";
1549
+ import { parseExpression } from "cron-parser";
1550
+ function parseCronExpression(cronExpression, lastRun, options = {}) {
1551
+ const {
1552
+ preserveNaturalTiming = true,
1553
+ timezone,
1554
+ utc = false,
1555
+ currentDate
1556
+ } = options;
1557
+ try {
1558
+ const normalizedCron = normalizeCronExpression(cronExpression);
1559
+ const parseOptions = {
1560
+ tz: timezone,
1561
+ utc,
1562
+ currentDate: currentDate ?? /* @__PURE__ */ new Date()
1563
+ };
1564
+ if (preserveNaturalTiming && lastRun) {
1565
+ parseOptions.currentDate = lastRun;
1566
+ }
1567
+ const interval = parseExpression(normalizedCron, parseOptions);
1568
+ let nextRun = interval.next().toDate();
1569
+ const now = /* @__PURE__ */ new Date();
1570
+ while (nextRun <= now) {
1571
+ nextRun = interval.next().toDate();
1572
+ }
1573
+ return {
1574
+ nextRun,
1575
+ isValid: true,
1576
+ pattern: normalizedCron,
1577
+ description: describeCronExpression(normalizedCron)
1578
+ };
1579
+ } catch (error) {
1580
+ logger.error(`${chalk5.red("Invalid cron expression:")} ${cronExpression} - ${error.message}`);
1581
+ const fallbackTime = /* @__PURE__ */ new Date();
1582
+ fallbackTime.setHours(fallbackTime.getHours() + 1);
1583
+ fallbackTime.setMinutes(0);
1584
+ fallbackTime.setSeconds(0);
1585
+ fallbackTime.setMilliseconds(0);
1586
+ return {
1587
+ nextRun: fallbackTime,
1588
+ isValid: false,
1589
+ error: error.message,
1590
+ pattern: cronExpression
1591
+ };
1592
+ }
1593
+ }
1594
+ function getNextExecutions(cronExpression, count = 5, options = {}) {
1595
+ try {
1596
+ const normalizedCron = normalizeCronExpression(cronExpression);
1597
+ const parseOptions = {
1598
+ tz: options.timezone,
1599
+ utc: options.utc ?? false,
1600
+ currentDate: options.currentDate ?? /* @__PURE__ */ new Date()
1601
+ };
1602
+ const interval = parseExpression(normalizedCron, parseOptions);
1603
+ const executions = [];
1604
+ for (let i = 0; i < count; i++) {
1605
+ executions.push(interval.next().toDate());
1606
+ }
1607
+ return executions;
1608
+ } catch (error) {
1609
+ logger.error(`${chalk5.red("Error getting next executions:")} ${error.message}`);
1610
+ return [];
1611
+ }
1612
+ }
1613
+ function validateCronExpression(cronExpression) {
1614
+ try {
1615
+ const normalized = normalizeCronExpression(cronExpression);
1616
+ parseExpression(normalized);
1617
+ return true;
1618
+ } catch {
1619
+ return false;
1620
+ }
1621
+ }
1622
+ function normalizeCronExpression(cronExpression) {
1623
+ const parts = cronExpression.trim().split(/\s+/);
1624
+ if (parts.length === 5) {
1625
+ return cronExpression;
1626
+ } else if (parts.length === 6) {
1627
+ return cronExpression;
1628
+ } else if (parts.length === 7) {
1629
+ return cronExpression;
1630
+ } else {
1631
+ throw new Error(`Invalid cron format: expected 5, 6, or 7 fields, got ${parts.length}`);
1632
+ }
1633
+ }
1634
+ function describeCronExpression(cronExpression) {
1635
+ const parts = cronExpression.split(" ");
1636
+ const patterns = {
1637
+ "*/5 * * * *": "Every 5 minutes",
1638
+ "0 * * * *": "Every hour at minute 0",
1639
+ "0 */2 * * *": "Every 2 hours",
1640
+ "0 0 * * *": "Daily at midnight",
1641
+ "0 6 * * *": "Daily at 6:00 AM",
1642
+ "0 0 * * 0": "Weekly on Sunday at midnight",
1643
+ "0 0 1 * *": "Monthly on the 1st at midnight",
1644
+ "0 0 1 1 *": "Yearly on January 1st at midnight"
1645
+ };
1646
+ if (patterns[cronExpression]) {
1647
+ return patterns[cronExpression];
1648
+ }
1649
+ if (parts.length >= 5) {
1650
+ const [minute, hour, day, month, dayOfWeek] = parts;
1651
+ let description = "Runs ";
1652
+ if (minute.includes("*/")) {
1653
+ const interval = minute.split("*/")[1];
1654
+ description += `every ${interval} minutes`;
1655
+ } else if (minute === "*") {
1656
+ description += "every minute";
1657
+ } else {
1658
+ description += `at minute ${minute}`;
1659
+ }
1660
+ if (hour.includes("*/")) {
1661
+ const interval = hour.split("*/")[1];
1662
+ description += `, every ${interval} hours`;
1663
+ } else if (hour !== "*") {
1664
+ description += `, at hour ${hour}`;
1665
+ }
1666
+ if (day !== "*") {
1667
+ description += `, on day ${day}`;
1668
+ }
1669
+ if (month !== "*") {
1670
+ description += `, in month ${month}`;
1671
+ }
1672
+ if (dayOfWeek !== "*") {
1673
+ const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
1674
+ const dayNames = dayOfWeek.split(",").map((d) => days[parseInt(d)] || d).join(", ");
1675
+ description += `, on ${dayNames}`;
1676
+ }
1677
+ return description;
1678
+ }
1679
+ return "Custom schedule";
1680
+ }
1681
+ function detectExpressionType(expression) {
1682
+ if (!expression || typeof expression !== "string") {
1683
+ return "unknown";
1684
+ }
1685
+ const trimmedExpression = expression.trim();
1686
+ const ratePattern = /^rate\(\s*(\d+)\s+(minute|minutes|hour|hours|day|days)\s*\)$/i;
1687
+ if (ratePattern.test(trimmedExpression)) {
1688
+ return "rate";
1689
+ }
1690
+ const cronParts = trimmedExpression.split(/\s+/);
1691
+ if (cronParts.length >= 5 && cronParts.length <= 7) {
1692
+ const cronCharPattern = /^[\d\*\-\,\/\?\#LW]+$/;
1693
+ const validCronParts = cronParts.every((part) => cronCharPattern.test(part) || part === "*");
1694
+ if (validCronParts) {
1695
+ return "cron";
1696
+ }
1697
+ }
1698
+ return "unknown";
1699
+ }
1700
+ function convertRateToCron(rateExpression) {
1701
+ const trimmedExpression = rateExpression.trim();
1702
+ const ratePattern = /^rate\(\s*(\d+)\s+(minute|minutes|hour|hours|day|days)\s*\)$/i;
1703
+ const match = trimmedExpression.match(ratePattern);
1704
+ if (!match) {
1705
+ return {
1706
+ cronExpression: "",
1707
+ isValid: false,
1708
+ error: "Invalid rate expression format. Expected: rate(value unit)",
1709
+ originalRate: rateExpression,
1710
+ description: ""
1711
+ };
1712
+ }
1713
+ const value = parseInt(match[1]);
1714
+ const unit = match[2].toLowerCase();
1715
+ if (value <= 0) {
1716
+ return {
1717
+ cronExpression: "",
1718
+ isValid: false,
1719
+ error: "Rate value must be greater than 0",
1720
+ originalRate: rateExpression,
1721
+ description: ""
1722
+ };
1723
+ }
1724
+ let cronExpression = "";
1725
+ let description = "";
1726
+ try {
1727
+ switch (unit) {
1728
+ case "minute":
1729
+ case "minutes":
1730
+ if (value > 59) {
1731
+ return {
1732
+ cronExpression: "",
1733
+ isValid: false,
1734
+ error: "Minutes value cannot exceed 59. Use hours for longer intervals.",
1735
+ originalRate: rateExpression,
1736
+ description: ""
1737
+ };
1738
+ }
1739
+ if (value === 1) {
1740
+ cronExpression = "* * * * *";
1741
+ description = "Every minute";
1742
+ } else {
1743
+ cronExpression = `*/${value} * * * *`;
1744
+ description = `Every ${value} minutes`;
1745
+ }
1746
+ break;
1747
+ case "hour":
1748
+ case "hours":
1749
+ if (value > 23) {
1750
+ if (value % 24 === 0) {
1751
+ const days = value / 24;
1752
+ cronExpression = `0 0 */${days} * *`;
1753
+ description = `Every ${days} day${days > 1 ? "s" : ""}`;
1754
+ } else {
1755
+ return {
1756
+ cronExpression: "",
1757
+ isValid: false,
1758
+ error: "Hours value greater than 23 must be divisible by 24, or use days unit.",
1759
+ originalRate: rateExpression,
1760
+ description: ""
1761
+ };
1762
+ }
1763
+ } else if (value === 1) {
1764
+ cronExpression = "0 * * * *";
1765
+ description = "Every hour";
1766
+ } else {
1767
+ cronExpression = `0 */${value} * * *`;
1768
+ description = `Every ${value} hours`;
1769
+ }
1770
+ break;
1771
+ case "day":
1772
+ case "days":
1773
+ if (value > 365) {
1774
+ return {
1775
+ cronExpression: "",
1776
+ isValid: false,
1777
+ error: "Days value cannot exceed 365",
1778
+ originalRate: rateExpression,
1779
+ description: ""
1780
+ };
1781
+ }
1782
+ if (value === 1) {
1783
+ cronExpression = "0 0 * * *";
1784
+ description = "Every day (daily)";
1785
+ } else if (value === 7) {
1786
+ cronExpression = "0 0 * * 0";
1787
+ description = "Every 7 days (weekly)";
1788
+ } else if (value <= 31) {
1789
+ cronExpression = `0 0 */${value} * *`;
1790
+ description = `Every ${value} days`;
1791
+ } else {
1792
+ cronExpression = `0 0 */${value} * *`;
1793
+ description = `Every ${value} days (approximate)`;
1794
+ }
1795
+ break;
1796
+ default:
1797
+ return {
1798
+ cronExpression: "",
1799
+ isValid: false,
1800
+ error: `Unsupported time unit: ${unit}. Use minute(s), hour(s), or day(s).`,
1801
+ originalRate: rateExpression,
1802
+ description: ""
1803
+ };
1804
+ }
1805
+ if (!validateCronExpression(cronExpression)) {
1806
+ return {
1807
+ cronExpression: "",
1808
+ isValid: false,
1809
+ error: "Generated cron expression is invalid",
1810
+ originalRate: rateExpression,
1811
+ description: ""
1812
+ };
1813
+ }
1814
+ return {
1815
+ cronExpression,
1816
+ isValid: true,
1817
+ originalRate: rateExpression,
1818
+ description
1819
+ };
1820
+ } catch (error) {
1821
+ return {
1822
+ cronExpression: "",
1823
+ isValid: false,
1824
+ error: `Conversion error: ${error.message}`,
1825
+ originalRate: rateExpression,
1826
+ description: ""
1827
+ };
1828
+ }
1829
+ }
1830
+
1831
+ // src/schedule-plugin/utils.ts
1832
+ var generateJobId = () => `job_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
1833
+ var generateExecutionId = () => `exec_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
1834
+ var calculateNextRun = (job, preserveNaturalTiming = true) => {
1835
+ const now = /* @__PURE__ */ new Date();
1836
+ if (job.cronExpression) {
1837
+ const result = parseCronExpression(job.cronExpression, job.lastRun, {
1838
+ preserveNaturalTiming,
1839
+ timezone: job.timezone,
1840
+ currentDate: preserveNaturalTiming && job.lastRun ? job.lastRun : now
1841
+ });
1842
+ return result.nextRun;
1843
+ }
1844
+ if (job.intervalMs) {
1845
+ return new Date(now.getTime() + job.intervalMs);
1846
+ }
1847
+ if (job.delayMs) {
1848
+ return new Date(now.getTime() + job.delayMs);
1849
+ }
1850
+ return new Date(now.getTime() + 36e5);
1851
+ };
1852
+ var calculateNextRunFromLastRun = (job, lastRun, config) => {
1853
+ const now = /* @__PURE__ */ new Date();
1854
+ if (job.cronExpression) {
1855
+ const result = parseCronExpression(job.cronExpression, lastRun, {
1856
+ preserveNaturalTiming: config.restartBehavior.preserveNaturalTiming,
1857
+ timezone: job.timezone ?? config.cron.defaultTimezone
1858
+ });
1859
+ return result.nextRun;
1860
+ }
1861
+ if (job.intervalMs && lastRun) {
1862
+ let nextRun = new Date(lastRun.getTime() + job.intervalMs);
1863
+ if (config.restartBehavior.skipMissedRuns) {
1864
+ while (nextRun <= now) {
1865
+ nextRun = new Date(nextRun.getTime() + job.intervalMs);
1866
+ }
1867
+ } else {
1868
+ if (nextRun <= now) {
1869
+ nextRun = new Date(now.getTime() + job.intervalMs);
1870
+ }
1871
+ }
1872
+ return nextRun;
1873
+ }
1874
+ return calculateNextRun(job, config.restartBehavior.preserveNaturalTiming);
1875
+ };
1876
+ var hasJobDefinitionChanged = (currentJob, savedJob) => currentJob.cronExpression !== savedJob.cronExpression || currentJob.intervalMs !== savedJob.intervalMs || currentJob.delayMs !== savedJob.delayMs || currentJob.maxRuns !== savedJob.maxRuns || currentJob.timezone !== savedJob.timezone;
1877
+ var shouldSkipJob = (job) => {
1878
+ if (!job.enabled) return true;
1879
+ if (job.maxRuns && job.runCount >= job.maxRuns) return true;
1880
+ return false;
1881
+ };
1882
+ var getTimeUntilNextRun = (job) => Math.max(0, job.nextRun.getTime() - Date.now());
1883
+
1884
+ // src/schedule-plugin/execution.ts
1885
+ var createJobExecution = (jobId) => ({
1886
+ id: generateExecutionId(),
1887
+ jobId,
1888
+ startTime: /* @__PURE__ */ new Date(),
1889
+ status: "running"
1890
+ });
1891
+ var completeExecution = (execution, result, error) => ({
1892
+ ...execution,
1893
+ endTime: /* @__PURE__ */ new Date(),
1894
+ status: error ? "failed" : "completed",
1895
+ result,
1896
+ error
1897
+ });
1898
+ var canExecuteJob = (scheduler, state) => {
1899
+ if (state.isShuttingDown) {
1900
+ return { canExecute: false, reason: "System is shutting down" };
1901
+ }
1902
+ if (scheduler.isRunning) {
1903
+ return { canExecute: false, reason: "Job is already running" };
1904
+ }
1905
+ if (shouldSkipJob(scheduler.job)) {
1906
+ const reason = !scheduler.job.enabled ? "Job is disabled" : "Job reached maximum runs";
1907
+ return { canExecute: false, reason };
1908
+ }
1909
+ if (state.runningExecutions >= state.config.execution.maxConcurrent) {
1910
+ return { canExecute: false, reason: "Maximum concurrent executions reached" };
1911
+ }
1912
+ return { canExecute: true };
1913
+ };
1914
+ var scheduleJob = (scheduler, state, executeJobFn) => {
1915
+ if (state.isShuttingDown) return scheduler;
1916
+ const timeUntilNextRun = getTimeUntilNextRun(scheduler.job);
1917
+ const updatedScheduler = { ...scheduler };
1918
+ if (timeUntilNextRun <= 0) {
1919
+ setImmediate(() => executeJobFn(updatedScheduler));
1920
+ } else {
1921
+ updatedScheduler.timerId = setTimeout(() => {
1922
+ executeJobFn(updatedScheduler);
1923
+ }, timeUntilNextRun);
1924
+ logger.info(`${chalk6.blue("\u{1F4C5} Scheduled job")} ${chalk6.green(scheduler.job.name)} to run in ${chalk6.cyan(Math.round(timeUntilNextRun / 1e3))}s`);
1925
+ }
1926
+ return updatedScheduler;
1927
+ };
1928
+ var executeJobWithTimeout = async (handler, job, execution, timeoutMs) => {
1929
+ return Promise.race([
1930
+ handler(job, execution),
1931
+ new Promise(
1932
+ (_, reject) => setTimeout(() => reject(new Error("Job execution timeout")), timeoutMs)
1933
+ )
1934
+ ]);
1935
+ };
1936
+ var updateJobAfterExecution = (job, execution, config) => {
1937
+ const updatedJob = {
1938
+ ...job,
1939
+ lastRun: execution.startTime,
1940
+ runCount: job.runCount + 1
1941
+ };
1942
+ if (job.enabled) {
1943
+ updatedJob.nextRun = calculateNextRunFromLastRun(updatedJob, updatedJob.lastRun, config);
1944
+ }
1945
+ return updatedJob;
1946
+ };
1947
+ var handleExecutionError = (execution, error) => {
1948
+ logger.error(`${logSymbols4.error} ${chalk6.red("Job failed")} ${execution.jobId}: ${error.message}`);
1949
+ return completeExecution(execution, void 0, error.message);
1950
+ };
1951
+ var handleExecutionSuccess = (execution, result) => {
1952
+ const duration = execution.endTime ? execution.endTime.getTime() - execution.startTime.getTime() : 0;
1953
+ logger.debug(`${logSymbols4.success} ${chalk6.green("Job completed")} in ${duration}ms`);
1954
+ return completeExecution(execution, result);
1955
+ };
1956
+
1957
+ // src/schedule-plugin/persistence.ts
1958
+ import * as fs2 from "fs/promises";
1959
+ import * as path3 from "path";
1960
+ import chalk7 from "chalk";
1961
+ import logSymbols5 from "log-symbols";
1962
+ var createStateFilePath = (directory) => path3.join(directory, "scheduler-state.json");
1963
+ var createTempFilePath = (directory) => path3.join(directory, `scheduler-state.${Date.now()}.temp.json`);
1964
+ var serializeSchedulerState = (schedulers, executionHistory) => ({
1965
+ jobs: Object.values(schedulers).map((s) => s.job),
1966
+ executions: executionHistory.slice(-100),
1967
+ savedAt: /* @__PURE__ */ new Date(),
1968
+ version: "1.0"
1969
+ });
1970
+ var saveSchedulerState = async (state) => {
1971
+ try {
1972
+ const serializedState = serializeSchedulerState(state.schedulers, state.executionHistory);
1973
+ const stateFile = createStateFilePath(state.config.persistence.directory);
1974
+ const tempFile = createTempFilePath(state.config.persistence.directory);
1975
+ await fs2.writeFile(tempFile, JSON.stringify(serializedState, null, 2), "utf8");
1976
+ await fs2.rename(tempFile, stateFile);
1977
+ logger.info(`${logSymbols5.info} ${chalk7.blue("Enhanced scheduler state saved")}`);
1978
+ } catch (error) {
1979
+ logger.error("Failed to save scheduler state:", error);
1980
+ }
1981
+ };
1982
+ var loadSchedulerStateData = async (directory) => {
1983
+ try {
1984
+ const stateFile = createStateFilePath(directory);
1985
+ const data = await fs2.readFile(stateFile, "utf8");
1986
+ return JSON.parse(data);
1987
+ } catch (error) {
1988
+ if (error.code === "ENOENT") {
1989
+ logger.info(`${chalk7.blue("No previous scheduler state found - starting fresh")}`);
1990
+ } else {
1991
+ logger.error("Failed to load scheduler state:", error);
1992
+ }
1993
+ return null;
1994
+ }
1995
+ };
1996
+ var validateAndAdjustNextRun = (job, savedNextRun, lastRestartTime, config) => {
1997
+ const now = /* @__PURE__ */ new Date();
1998
+ if (!savedNextRun) {
1999
+ return calculateNextRunFromLastRun(job, job.lastRun, config);
2000
+ }
2001
+ if (savedNextRun <= now) {
2002
+ logger.info(`${chalk7.yellow("\u23F0 Saved next run is in the past for")} ${chalk7.green(job.name)} - recalculating`);
2003
+ return calculateNextRunFromLastRun(job, job.lastRun, config);
2004
+ }
2005
+ const timeSinceRestart = now.getTime() - lastRestartTime.getTime();
2006
+ const isRapidRestart = timeSinceRestart < config.restartBehavior.rapidRestartThreshold;
2007
+ if (isRapidRestart) {
2008
+ logger.info(`${chalk7.blue("\u26A1 Rapid restart detected for")} ${chalk7.green(job.name)} - preserving saved timing`);
2009
+ return savedNextRun;
2010
+ }
2011
+ if (job.cronExpression || job.intervalMs) {
2012
+ const expectedNextRun = calculateNextRunFromLastRun(job, job.lastRun, config);
2013
+ const timeDiff = Math.abs(savedNextRun.getTime() - expectedNextRun.getTime());
2014
+ if (timeDiff > config.restartBehavior.maxTimingDrift) {
2015
+ logger.info(`${chalk7.yellow("\u{1F527} Adjusting timing for")} ${chalk7.green(job.name)} - drift of ${Math.round(timeDiff / 1e3)}s detected`);
2016
+ return expectedNextRun;
2017
+ }
2018
+ }
2019
+ return savedNextRun;
2020
+ };
2021
+ var restoreJobFromSavedData = (scheduler, savedJob, config, lastRestartTime) => {
2022
+ const definitionChanged = hasJobDefinitionChanged(scheduler.job, savedJob);
2023
+ const updatedJob = {
2024
+ ...scheduler.job,
2025
+ runCount: savedJob.runCount,
2026
+ lastRun: savedJob.lastRun ? new Date(savedJob.lastRun) : void 0
2027
+ };
2028
+ if (definitionChanged) {
2029
+ logger.info(`${chalk7.yellow("\u{1F504} Job definition changed:")} ${chalk7.green(savedJob.name)} - recalculating schedule`);
2030
+ updatedJob.nextRun = calculateNextRunFromLastRun(updatedJob, updatedJob.lastRun, config);
2031
+ } else {
2032
+ const savedNextRun = savedJob.nextRun ? new Date(savedJob.nextRun) : void 0;
2033
+ updatedJob.nextRun = validateAndAdjustNextRun(updatedJob, savedNextRun, lastRestartTime, config);
2034
+ }
2035
+ if (config.cron.logCronDetails && updatedJob.cronExpression) {
2036
+ const result = parseCronExpression(updatedJob.cronExpression, updatedJob.lastRun, {
2037
+ timezone: updatedJob.timezone
2038
+ });
2039
+ logger.info(`${chalk7.blue("\u{1F4C5} Job restored:")} ${chalk7.green(savedJob.name)} - ${result.description} - next: ${chalk7.cyan(updatedJob.nextRun.toLocaleString())}`);
2040
+ }
2041
+ return { ...scheduler, job: updatedJob };
2042
+ };
2043
+ var restoreExecutionHistory = (savedExecutions) => {
2044
+ return savedExecutions.map((exec) => ({
2045
+ ...exec,
2046
+ startTime: new Date(exec.startTime),
2047
+ endTime: exec.endTime ? new Date(exec.endTime) : void 0
2048
+ }));
2049
+ };
2050
+ var loadSchedulerState = async (schedulers, config, lastRestartTime) => {
2051
+ const stateData = await loadSchedulerStateData(config.persistence.directory);
2052
+ if (!stateData) {
2053
+ return { schedulers, executionHistory: [] };
2054
+ }
2055
+ const restoredSchedulers = { ...schedulers };
2056
+ for (const savedJob of stateData.jobs) {
2057
+ const existingScheduler = Object.values(schedulers).find((s) => s.job.name === savedJob.name);
2058
+ if (existingScheduler) {
2059
+ const restoredScheduler = restoreJobFromSavedData(
2060
+ existingScheduler,
2061
+ savedJob,
2062
+ config,
2063
+ lastRestartTime
2064
+ );
2065
+ restoredSchedulers[restoredScheduler.job.id] = restoredScheduler;
2066
+ }
2067
+ }
2068
+ const executionHistory = stateData.executions ? restoreExecutionHistory(stateData.executions) : [];
2069
+ logger.debug(`${logSymbols5.success} ${chalk7.green("Enhanced scheduler state loaded")} (saved at ${stateData.savedAt})`);
2070
+ return { schedulers: restoredSchedulers, executionHistory };
2071
+ };
2072
+
2073
+ // src/schedule-plugin/cleanup.ts
2074
+ import chalk8 from "chalk";
2075
+ import logSymbols6 from "log-symbols";
2076
+ var cleanupExecutionHistory = (state) => {
2077
+ if (state.executionHistory.length > state.config.cleanup.maxExecutionHistory) {
2078
+ const removed = state.executionHistory.splice(
2079
+ 0,
2080
+ state.executionHistory.length - state.config.cleanup.maxExecutionHistory
2081
+ );
2082
+ logger.info(`${chalk8.blue("\u{1F9F9} Cleaned up")} ${removed.length} old execution records`);
2083
+ return removed;
2084
+ }
2085
+ return [];
2086
+ };
2087
+ var startCleanupInterval = (state) => {
2088
+ return setInterval(() => {
2089
+ cleanupExecutionHistory(state);
2090
+ }, state.config.cleanup.cleanupInterval);
2091
+ };
2092
+
2093
+ // src/schedule-plugin/core.ts
2094
+ var DEFAULT_CONFIG2 = {
2095
+ persistence: {
2096
+ enabled: true,
2097
+ directory: "./.develop/scheduler-data",
2098
+ saveInterval: 3e4
2099
+ // 30 seconds
2100
+ },
2101
+ execution: {
2102
+ maxConcurrent: 5,
2103
+ defaultTimeout: 3e5,
2104
+ // 5 minutes
2105
+ retryOnError: false,
2106
+ maxRetries: 3
2107
+ },
2108
+ cleanup: {
2109
+ maxExecutionHistory: 1e3,
2110
+ cleanupInterval: 6e5
2111
+ // 10 minutes
2112
+ },
2113
+ restartBehavior: {
2114
+ preserveNaturalTiming: true,
2115
+ skipMissedRuns: true,
2116
+ maxTimingDrift: 6e4,
2117
+ // 1 minute
2118
+ rapidRestartThreshold: 1e4
2119
+ // 10 seconds
2120
+ },
2121
+ cron: {
2122
+ defaultTimezone: void 0,
2123
+ // Use system timezone
2124
+ logCronDetails: true
2125
+ }
2126
+ };
2127
+ var mergeConfig2 = (defaultConfig, userConfig) => ({
2128
+ ...defaultConfig,
2129
+ ...userConfig,
2130
+ persistence: { ...defaultConfig.persistence, ...userConfig?.persistence },
2131
+ execution: { ...defaultConfig.execution, ...userConfig?.execution },
2132
+ cleanup: { ...defaultConfig.cleanup, ...userConfig?.cleanup },
2133
+ restartBehavior: { ...defaultConfig.restartBehavior, ...userConfig?.restartBehavior },
2134
+ cron: { ...defaultConfig.cron, ...userConfig?.cron }
2135
+ });
2136
+ var createInitialState = (config) => {
2137
+ return {
2138
+ schedulers: {},
2139
+ executions: {},
2140
+ executionHistory: [],
2141
+ isShuttingDown: false,
2142
+ runningExecutions: 0,
2143
+ lastRestartTime: /* @__PURE__ */ new Date(),
2144
+ config
2145
+ };
2146
+ };
2147
+ var createSchedulerFunctions = (state) => {
2148
+ const executeJob = async (scheduler) => {
2149
+ const { canExecute, reason } = canExecuteJob(scheduler, state);
2150
+ if (!canExecute) {
2151
+ if (reason === "Maximum concurrent executions reached") {
2152
+ logger.warn(`${chalk9.yellow("\u26A0\uFE0F Delaying job")} ${chalk9.green(scheduler.job.name)} - ${reason}`);
2153
+ scheduler.job.nextRun = new Date(Date.now() + 3e4);
2154
+ scheduleJobFn(scheduler);
2155
+ } else if (reason === "Job reached maximum runs") {
2156
+ logger.info(`${chalk9.yellow("\u23F9\uFE0F Job")} ${chalk9.green(scheduler.job.name)} reached max runs (${scheduler.job.maxRuns})`);
2157
+ }
2158
+ return;
2159
+ }
2160
+ const execution = createJobExecution(scheduler.job.id);
2161
+ state.executions[execution.id] = execution;
2162
+ state.executionHistory.push(execution);
2163
+ scheduler.isRunning = true;
2164
+ state.runningExecutions++;
2165
+ logger.info(`${chalk9.blue("\u{1F680} Executing job")} ${chalk9.green(scheduler.job.name)} (${execution.id})`);
2166
+ try {
2167
+ const result = await executeJobWithTimeout(
2168
+ scheduler.handler,
2169
+ scheduler.job,
2170
+ execution,
2171
+ state.config.execution.defaultTimeout
2172
+ );
2173
+ const completedExecution = handleExecutionSuccess(execution, result);
2174
+ state.executions[execution.id] = completedExecution;
2175
+ scheduler.job = updateJobAfterExecution(scheduler.job, execution, state.config);
2176
+ } catch (error) {
2177
+ const failedExecution = handleExecutionError(execution, error);
2178
+ state.executions[execution.id] = failedExecution;
2179
+ } finally {
2180
+ scheduler.isRunning = false;
2181
+ state.runningExecutions--;
2182
+ if (scheduler.job.enabled && !state.isShuttingDown) {
2183
+ scheduleJobFn(scheduler);
2184
+ }
2185
+ if (state.config.persistence.enabled) {
2186
+ await saveSchedulerState(state);
2187
+ }
2188
+ }
2189
+ };
2190
+ const scheduleJobFn = (scheduler) => {
2191
+ const updatedScheduler = scheduleJob(scheduler, state, executeJob);
2192
+ state.schedulers[scheduler.job.id] = updatedScheduler;
2193
+ return updatedScheduler;
2194
+ };
2195
+ return { executeJob, scheduleJobFn };
2196
+ };
2197
+ var initializeScheduler = async (state, scheduleJobFn) => {
2198
+ try {
2199
+ if (state.config.persistence.enabled) {
2200
+ await fs3.mkdir(state.config.persistence.directory, { recursive: true });
2201
+ const { schedulers, executionHistory } = await loadSchedulerState(
2202
+ state.schedulers,
2203
+ state.config,
2204
+ state.lastRestartTime
2205
+ );
2206
+ state.schedulers = schedulers;
2207
+ state.executionHistory = executionHistory;
2208
+ if (state.config.persistence.saveInterval > 0) {
2209
+ setInterval(() => saveSchedulerState(state), state.config.persistence.saveInterval);
2210
+ }
2211
+ }
2212
+ state.cleanupInterval = startCleanupInterval(state);
2213
+ for (const scheduler of Object.values(state.schedulers)) {
2214
+ if (scheduler.job.enabled) {
2215
+ scheduleJobFn(scheduler);
2216
+ }
2217
+ }
2218
+ logger.debug(`${logSymbols7.success} ${chalk9.green("Scheduler initialized:")} ${Object.keys(state.schedulers).length} jobs loaded`);
2219
+ } catch (error) {
2220
+ logger.error(`${logSymbols7.error} ${chalk9.red("Failed to initialize scheduler:")} ${error.message}`);
2221
+ throw error;
2222
+ }
2223
+ };
2224
+
2225
+ // src/schedule-plugin/jobs.ts
2226
+ import chalk10 from "chalk";
2227
+ import logSymbols8 from "log-symbols";
2228
+ var validateJobDefinition = (jobDef) => {
2229
+ const expressionType = detectExpressionType(jobDef.cronExpression);
2230
+ if (expressionType === "unknown") {
2231
+ logger.error(`${logSymbols8.error} ${chalk10.red("Invalid cron expression for job:")} ${jobDef.name}`);
2232
+ throw new Error(`Invalid cron expression for job: ${jobDef.name}`);
2233
+ }
2234
+ };
2235
+ var createJobFromDefinition = (jobDef, config) => {
2236
+ validateJobDefinition(jobDef);
2237
+ const expressionType = detectExpressionType(jobDef.cronExpression);
2238
+ if (config.cron.logCronDetails && jobDef.cronExpression) {
2239
+ const cronExpression = expressionType === "rate" ? convertRateToCron(jobDef.cronExpression).cronExpression : jobDef.cronExpression;
2240
+ const result = parseCronExpression(cronExpression, void 0, {
2241
+ timezone: jobDef.timezone ?? config.cron.defaultTimezone
2242
+ });
2243
+ logger.info(`${chalk10.blue("\u{1F4C5} Job")} ${chalk10.green(jobDef.name)}: ${result.description} - Next: ${chalk10.cyan(result.nextRun.toLocaleString())}`);
2244
+ const upcoming = getNextExecutions(cronExpression, 3, {
2245
+ timezone: jobDef.timezone ?? config.cron.defaultTimezone
2246
+ });
2247
+ logger.info(`${chalk10.blue(" Upcoming:")} ${upcoming.map((d) => d.toLocaleTimeString()).join(", ")}`);
2248
+ }
2249
+ const job = {
2250
+ id: generateJobId(),
2251
+ name: jobDef.name,
2252
+ cronExpression: expressionType === "rate" ? convertRateToCron(jobDef.cronExpression).cronExpression : jobDef.cronExpression,
2253
+ intervalMs: jobDef.intervalMs,
2254
+ delayMs: jobDef.delayMs,
2255
+ nextRun: /* @__PURE__ */ new Date(),
2256
+ enabled: jobDef.enabled ?? true,
2257
+ runCount: 0,
2258
+ maxRuns: jobDef.maxRuns,
2259
+ metadata: jobDef.metadata,
2260
+ createdAt: /* @__PURE__ */ new Date(),
2261
+ timezone: jobDef.timezone,
2262
+ module: jobDef.module
2263
+ };
2264
+ job.nextRun = calculateNextRun(job);
2265
+ return job;
2266
+ };
2267
+ var createSchedulerService = (job, handler) => ({
2268
+ job,
2269
+ handler,
2270
+ isRunning: false
2271
+ });
2272
+ var enableJob = (scheduler) => ({
2273
+ ...scheduler,
2274
+ job: {
2275
+ ...scheduler.job,
2276
+ enabled: true,
2277
+ nextRun: calculateNextRun(scheduler.job)
2278
+ }
2279
+ });
2280
+ var disableJob = (scheduler) => {
2281
+ if (scheduler.timerId) {
2282
+ clearTimeout(scheduler.timerId);
2283
+ }
2284
+ return {
2285
+ ...scheduler,
2286
+ job: { ...scheduler.job, enabled: false },
2287
+ timerId: void 0
2288
+ };
2289
+ };
2290
+
2291
+ // src/schedule-plugin/routes.ts
2292
+ var createDashboardData = (state) => {
2293
+ const jobs = Object.values(state.schedulers).map((s) => {
2294
+ const nextExecutions = s.job.cronExpression ? getNextExecutions(s.job.cronExpression, 3, { timezone: s.job.timezone }) : [];
2295
+ return {
2296
+ ...s.job,
2297
+ isRunning: s.isRunning,
2298
+ timeUntilNextRun: getTimeUntilNextRun(s.job),
2299
+ upcomingExecutions: nextExecutions,
2300
+ cronDescription: s.job.cronExpression ? parseCronExpression(s.job.cronExpression, void 0, { timezone: s.job.timezone }).description : void 0
2301
+ };
2302
+ });
2303
+ return { jobs, runningExecutions: state.runningExecutions };
2304
+ };
2305
+ var createExecutionsData = (state) => ({
2306
+ executions: state.executionHistory.slice(-50),
2307
+ // Last 50 executions
2308
+ running: Object.values(state.executions).filter((e) => e.status === "running")
2309
+ });
2310
+ var registerDashboardRoute = (app, state) => {
2311
+ app.get("/dashboard", async function(_, reply) {
2312
+ const dashboardData = createDashboardData(state);
2313
+ return reply.status(200).send(dashboardData);
2314
+ });
2315
+ };
2316
+ var registerExecutionsRoute = (app, state) => {
2317
+ app.get("/executions", async function(_, reply) {
2318
+ const executionsData = createExecutionsData(state);
2319
+ return reply.status(200).send(executionsData);
2320
+ });
2321
+ };
2322
+ var registerTriggerJobRoute = (app, state, executeJobFn) => {
2323
+ app.post("/jobs/:jobId/trigger", async function(request, reply) {
2324
+ const scheduler = state.schedulers[request.params.jobId];
2325
+ if (!scheduler) {
2326
+ return reply.status(404).send({ error: "Job not found" });
2327
+ }
2328
+ if (scheduler.isRunning) {
2329
+ return reply.status(409).send({ error: "Job is already running" });
2330
+ }
2331
+ setImmediate(() => executeJobFn(scheduler));
2332
+ return reply.status(200).send({ message: "Job triggered successfully" });
2333
+ });
2334
+ };
2335
+ var registerEnableJobRoute = (app, state, scheduleJobFn) => {
2336
+ app.put("/jobs/:jobId/enable", async function(request, reply) {
2337
+ const scheduler = state.schedulers[request.params.jobId];
2338
+ if (!scheduler) {
2339
+ return reply.status(404).send({ error: "Job not found" });
2340
+ }
2341
+ const enabledScheduler = enableJob(scheduler);
2342
+ state.schedulers[request.params.jobId] = enabledScheduler;
2343
+ scheduleJobFn(enabledScheduler);
2344
+ return reply.status(200).send({ message: "Job enabled successfully" });
2345
+ });
2346
+ };
2347
+ var registerDisableJobRoute = (app, state) => {
2348
+ app.put("/jobs/:jobId/disable", async function(request, reply) {
2349
+ const scheduler = state.schedulers[request.params.jobId];
2350
+ if (!scheduler) {
2351
+ return reply.status(404).send({ error: "Job not found" });
2352
+ }
2353
+ const disabledScheduler = disableJob(scheduler);
2354
+ state.schedulers[request.params.jobId] = disabledScheduler;
2355
+ return reply.status(200).send({ message: "Job disabled successfully" });
2356
+ });
2357
+ };
2358
+ var registerAllRoutes = (app, state, executeJobFn, scheduleJobFn) => {
2359
+ registerDashboardRoute(app, state);
2360
+ registerExecutionsRoute(app, state);
2361
+ registerTriggerJobRoute(app, state, executeJobFn);
2362
+ registerEnableJobRoute(app, state, scheduleJobFn);
2363
+ registerDisableJobRoute(app, state);
2364
+ };
2365
+
2366
+ // src/schedule-plugin/decorator.ts
2367
+ import chalk11 from "chalk";
2368
+ import logSymbols9 from "log-symbols";
2369
+ var isValidJobName = (jobName) => {
2370
+ return typeof jobName === "string" && jobName.length > 0 && /^[a-zA-Z0-9_-]+$/.test(jobName);
2371
+ };
2372
+ var createSchedulerManager = ({
2373
+ state,
2374
+ scheduleJobFn,
2375
+ executeJob,
2376
+ config
2377
+ }) => {
2378
+ const validateJobName = (jobName) => {
2379
+ if (!jobName || typeof jobName !== "string") {
2380
+ throw new Error("Job name must be a non-empty string");
2381
+ }
2382
+ if (!isValidJobName(jobName)) {
2383
+ throw new Error("Job name must contain only alphanumeric characters, hyphens, and underscores");
2384
+ }
2385
+ };
2386
+ const validateHandler = (handler) => {
2387
+ if (typeof handler !== "function") {
2388
+ throw new Error("Handler must be a function");
2389
+ }
2390
+ };
2391
+ const addJob = async (jobDefinition) => {
2392
+ try {
2393
+ validateJobName(jobDefinition.name);
2394
+ validateHandler(jobDefinition.handler);
2395
+ validateJobDefinition(jobDefinition);
2396
+ const existingJob = Object.values(state.schedulers).find((s) => s.job.name === jobDefinition.name);
2397
+ if (existingJob) {
2398
+ logger.warn(`${logSymbols9.warning} ${chalk11.yellow("Job already exists:")} ${chalk11.magenta(jobDefinition.name)}.`);
2399
+ return existingJob.job.id;
2400
+ }
2401
+ const job = createJobFromDefinition(jobDefinition, config);
2402
+ const scheduler = createSchedulerService(job, jobDefinition.handler);
2403
+ state.schedulers[job.id] = scheduler;
2404
+ if (job.enabled) {
2405
+ scheduleJobFn(scheduler);
2406
+ }
2407
+ logger.info(`${logSymbols9.success} ${chalk11.green("Job added:")} ${chalk11.magenta(jobDefinition.name)} (${job.id})`);
2408
+ return job.id;
2409
+ } catch (error) {
2410
+ logger.error(`${logSymbols9.error} ${chalk11.red("Failed to add job")} ${chalk11.magenta(jobDefinition.name)}: ${error.message}`);
2411
+ throw error;
2412
+ }
2413
+ };
2414
+ const removeJob = async (jobName) => {
2415
+ try {
2416
+ validateJobName(jobName);
2417
+ const scheduler = Object.values(state.schedulers).find((s) => s.job.name === jobName);
2418
+ if (!scheduler) {
2419
+ throw new Error(`Job '${jobName}' does not exist`);
2420
+ }
2421
+ if (scheduler.isRunning) {
2422
+ logger.warn(`${logSymbols9.warning} ${chalk11.yellow("Removing job that is currently running:")} ${chalk11.magenta(jobName)}`);
2423
+ }
2424
+ if (scheduler.timerId) {
2425
+ clearTimeout(scheduler.timerId);
2426
+ }
2427
+ delete state.schedulers[scheduler.job.id];
2428
+ logger.info(`${logSymbols9.success} ${chalk11.green("Job removed:")} ${chalk11.magenta(jobName)}`);
2429
+ } catch (error) {
2430
+ logger.error(`${logSymbols9.error} ${chalk11.red("Failed to remove job")} ${chalk11.magenta(jobName)}: ${error.message}`);
2431
+ throw error;
2432
+ }
2433
+ };
2434
+ const hasJob = (jobName) => {
2435
+ try {
2436
+ validateJobName(jobName);
2437
+ return Object.values(state.schedulers).some((s) => s.job.name === jobName);
2438
+ } catch {
2439
+ return false;
2440
+ }
2441
+ };
2442
+ const listJobs = (module) => {
2443
+ return Object.values(state.schedulers).filter((s) => !module || s.job.module === module).map((s) => s.job.name).sort();
2444
+ };
2445
+ const getJobStats = (jobName) => {
2446
+ try {
2447
+ validateJobName(jobName);
2448
+ const scheduler = Object.values(state.schedulers).find((s) => s.job.name === jobName);
2449
+ return scheduler || null;
2450
+ } catch {
2451
+ return null;
2452
+ }
2453
+ };
2454
+ const enableJob2 = async (jobName) => {
2455
+ try {
2456
+ validateJobName(jobName);
2457
+ const scheduler = Object.values(state.schedulers).find((s) => s.job.name === jobName);
2458
+ if (!scheduler) {
2459
+ throw new Error(`Job '${jobName}' does not exist`);
2460
+ }
2461
+ if (scheduler.job.enabled) {
2462
+ logger.info(`${logSymbols9.info} ${chalk11.blue("Job is already enabled:")} ${chalk11.magenta(jobName)}`);
2463
+ return;
2464
+ }
2465
+ scheduler.job.enabled = true;
2466
+ scheduleJobFn(scheduler);
2467
+ logger.info(`${logSymbols9.success} ${chalk11.green("Job enabled:")} ${chalk11.magenta(jobName)}`);
2468
+ } catch (error) {
2469
+ logger.error(`${logSymbols9.error} ${chalk11.red("Failed to enable job")} ${chalk11.magenta(jobName)}: ${error.message}`);
2470
+ throw error;
2471
+ }
2472
+ };
2473
+ const disableJob2 = async (jobName) => {
2474
+ try {
2475
+ validateJobName(jobName);
2476
+ const scheduler = Object.values(state.schedulers).find((s) => s.job.name === jobName);
2477
+ if (!scheduler) {
2478
+ throw new Error(`Job '${jobName}' does not exist`);
2479
+ }
2480
+ if (!scheduler.job.enabled) {
2481
+ logger.info(`${logSymbols9.info} ${chalk11.blue("Job is already disabled:")} ${chalk11.magenta(jobName)}`);
2482
+ return;
2483
+ }
2484
+ scheduler.job.enabled = false;
2485
+ if (scheduler.timerId) {
2486
+ clearTimeout(scheduler.timerId);
2487
+ scheduler.timerId = void 0;
2488
+ }
2489
+ logger.info(`${logSymbols9.success} ${chalk11.green("Job disabled:")} ${chalk11.magenta(jobName)}`);
2490
+ } catch (error) {
2491
+ logger.error(`${logSymbols9.error} ${chalk11.red("Failed to disable job")} ${chalk11.magenta(jobName)}: ${error.message}`);
2492
+ throw error;
2493
+ }
2494
+ };
2495
+ const triggerJob = async (jobName) => {
2496
+ try {
2497
+ validateJobName(jobName);
2498
+ const scheduler = Object.values(state.schedulers).find((s) => s.job.name === jobName);
2499
+ if (!scheduler) {
2500
+ throw new Error(`Job '${jobName}' does not exist`);
2501
+ }
2502
+ if (scheduler.isRunning) {
2503
+ throw new Error(`Job '${jobName}' is already running`);
2504
+ }
2505
+ setImmediate(() => executeJob(scheduler));
2506
+ logger.info(`${logSymbols9.success} ${chalk11.green("Job triggered:")} ${chalk11.magenta(jobName)}`);
2507
+ } catch (error) {
2508
+ logger.error(`${logSymbols9.error} ${chalk11.red("Failed to trigger job")} ${chalk11.magenta(jobName)}: ${error.message}`);
2509
+ throw error;
2510
+ }
2511
+ };
2512
+ const getJobsMap = () => {
2513
+ return { ...state.schedulers };
2514
+ };
2515
+ return {
2516
+ addJob,
2517
+ removeJob,
2518
+ hasJob,
2519
+ listJobs,
2520
+ getJobStats,
2521
+ enableJob: enableJob2,
2522
+ disableJob: disableJob2,
2523
+ triggerJob,
2524
+ getJobsMap
2525
+ };
2526
+ };
2527
+ var createSchedulerDecorator = (schedulerManager) => (app) => {
2528
+ app.decorate("scheduler", schedulerManager);
2529
+ };
2530
+
2531
+ // src/schedule-plugin/plugin.ts
2532
+ var schedulerPlugin = fsPlugin2(async (app, options) => {
2533
+ const config = mergeConfig2(DEFAULT_CONFIG2, options.config);
2534
+ const state = createInitialState(config);
2535
+ const { executeJob, scheduleJobFn } = createSchedulerFunctions(state);
2536
+ await initializeScheduler(state, scheduleJobFn);
2537
+ const schedulerManager = createSchedulerManager({
2538
+ state,
2539
+ config,
2540
+ scheduleJobFn,
2541
+ executeJob
2542
+ });
2543
+ const decorateScheduler = createSchedulerDecorator(schedulerManager);
2544
+ decorateScheduler(app);
2545
+ registerAllRoutes(app, state, executeJob, scheduleJobFn);
2546
+ });
2547
+
2548
+ // src/dev-console-plugin/route-registry.ts
2549
+ var RouteRegistry = class {
2550
+ routes = [];
2551
+ register(routeOptions) {
2552
+ const routeInfo = {
2553
+ method: routeOptions.method,
2554
+ url: routeOptions.url,
2555
+ handler: routeOptions.handler?.name || "anonymous",
2556
+ registeredAt: /* @__PURE__ */ new Date(),
2557
+ module: routeOptions.module
2558
+ };
2559
+ this.routes.push(routeInfo);
2560
+ }
2561
+ getAll() {
2562
+ return [...this.routes];
2563
+ }
2564
+ getByMethod(method) {
2565
+ return this.routes.filter((route) => {
2566
+ if (Array.isArray(route.method)) {
2567
+ return route.method.includes(method.toUpperCase());
2568
+ }
2569
+ return route.method.toUpperCase() === method.toUpperCase();
2570
+ });
2571
+ }
2572
+ clear() {
2573
+ this.routes = [];
2574
+ }
2575
+ count() {
2576
+ return this.routes.length;
2577
+ }
2578
+ };
2579
+ var routeRegistry = new RouteRegistry();
2580
+
2581
+ // src/dev-console-plugin/plugin.ts
2582
+ var LogStore = class {
2583
+ logs = [];
2584
+ maxLogs = 1e3;
2585
+ listeners = [];
2586
+ addLog(entry) {
2587
+ this.logs.unshift(entry);
2588
+ if (this.logs.length > this.maxLogs) {
2589
+ this.logs = this.logs.slice(0, this.maxLogs);
2590
+ }
2591
+ this.listeners.forEach((listener) => listener(entry));
2592
+ }
2593
+ getLogs(limit = 100) {
2594
+ return this.logs.slice(0, limit);
2595
+ }
2596
+ getLogsByLevel(level, limit = 100) {
2597
+ return this.logs.filter((log) => log.level === level).slice(0, limit);
2598
+ }
2599
+ getLogsByModule(module, limit = 100) {
2600
+ return this.logs.filter((log) => log.module === module).slice(0, limit);
2601
+ }
2602
+ getLogsByTrigger(triggerType, triggerName, limit = 100) {
2603
+ return this.logs.filter(
2604
+ (log) => log.triggerType === triggerType && log.trigger === triggerName
2605
+ ).slice(0, limit);
2606
+ }
2607
+ clear() {
2608
+ this.logs = [];
2609
+ }
2610
+ subscribe(listener) {
2611
+ this.listeners.push(listener);
2612
+ return () => {
2613
+ this.listeners = this.listeners.filter((l) => l !== listener);
2614
+ };
2615
+ }
2616
+ };
2617
+ var logStore = new LogStore();
2618
+ var originalConsole = {
2619
+ log: console.log,
2620
+ error: console.error,
2621
+ warn: console.warn,
2622
+ info: console.info,
2623
+ debug: console.debug
2624
+ };
2625
+ var captureConsoleLog = (level, originalMethod) => {
2626
+ return (...args) => {
2627
+ originalMethod.apply(console, args);
2628
+ const message = args.join(" ");
2629
+ let source = "unknown";
2630
+ let module;
2631
+ let trigger;
2632
+ let triggerType;
2633
+ if (message.includes("Queue") || message.includes("queue")) {
2634
+ source = "queue";
2635
+ triggerType = "queue";
2636
+ const queueMatch = message.match(/queue[:\s]+([a-zA-Z0-9_-]+)/i);
2637
+ if (queueMatch) trigger = queueMatch[1];
2638
+ } else if (message.includes("Schedule") || message.includes("job")) {
2639
+ source = "schedule";
2640
+ triggerType = "schedule";
2641
+ const jobMatch = message.match(/(?:job|schedule)[:\s]+([a-zA-Z0-9_-]+)/i);
2642
+ if (jobMatch) trigger = jobMatch[1];
2643
+ } else if (message.includes("HTTP") || message.includes("api") || message.includes("/api/")) {
2644
+ source = "http";
2645
+ triggerType = "http";
2646
+ const routeMatch = message.match(/\/api\/[^\s]+/);
2647
+ if (routeMatch) trigger = routeMatch[0];
2648
+ }
2649
+ const moduleMatch = message.match(/module[:\s]+([a-zA-Z0-9_-]+)/i) || message.match(/\[([a-zA-Z0-9_-]+)\]/) || message.match(/in\s+([a-zA-Z0-9_-]+)\s+module/i);
2650
+ if (moduleMatch) module = moduleMatch[1];
2651
+ logStore.addLog({
2652
+ id: Date.now().toString() + Math.random().toString(36).substr(2, 9),
2653
+ timestamp: /* @__PURE__ */ new Date(),
2654
+ level,
2655
+ message: message.replace(/\x1b\[[0-9;]*m/g, ""),
2656
+ // Remove ANSI colors
2657
+ source,
2658
+ module,
2659
+ trigger,
2660
+ triggerType
2661
+ });
2662
+ };
2663
+ };
2664
+ console.error = captureConsoleLog("error", originalConsole.error);
2665
+ console.warn = captureConsoleLog("warn", originalConsole.warn);
2666
+ console.info = captureConsoleLog("info", originalConsole.info);
2667
+ console.log = captureConsoleLog("info", originalConsole.log);
2668
+ console.debug = captureConsoleLog("debug", originalConsole.debug);
2669
+ async function devConsolePluginFunction(fastify, options = {}) {
2670
+ const { prefix = "console", enableUI = true } = options;
2671
+ fastify.addHook("onRoute", (routeOptions) => {
2672
+ if (routeOptions.prefix === "/api") {
2673
+ routeRegistry.register(routeOptions);
2674
+ }
2675
+ });
2676
+ fastify.get(`/${prefix}/routes`, async () => {
2677
+ return { routes: routeRegistry.getAll() };
2678
+ });
2679
+ fastify.get(`/${prefix}/routes/:method`, async (request) => {
2680
+ const { method } = request.params;
2681
+ return { routes: routeRegistry.getByMethod(method) };
2682
+ });
2683
+ fastify.get(`/${prefix}/registry/stats`, async () => {
2684
+ return {
2685
+ totalRoutes: routeRegistry.count(),
2686
+ registeredAt: /* @__PURE__ */ new Date()
2687
+ };
2688
+ });
2689
+ fastify.get(`/${prefix}/modules`, async (_, reply) => {
2690
+ const queueManager = fastify.queues;
2691
+ const schedulerManager = fastify.scheduler;
2692
+ if (!queueManager || !schedulerManager) {
2693
+ return reply.status(503).send({ error: "Services not available" });
2694
+ }
2695
+ const allRoutes = routeRegistry.getAll();
2696
+ const httpRoutes = allRoutes;
2697
+ const moduleSet = /* @__PURE__ */ new Set();
2698
+ httpRoutes.forEach((route) => {
2699
+ if (route.module) moduleSet.add(route.module);
2700
+ });
2701
+ const allQueueNames = queueManager.listQueues();
2702
+ const allJobNames = schedulerManager.listJobs();
2703
+ allQueueNames.forEach((queueName) => {
2704
+ const queueStats = queueManager.getQueueStats(queueName);
2705
+ if (queueStats?.module) moduleSet.add(queueStats.module);
2706
+ });
2707
+ allJobNames.forEach((jobName) => {
2708
+ const jobStats = schedulerManager.getJobStats(jobName);
2709
+ if (jobStats?.job.module) moduleSet.add(jobStats.job.module);
2710
+ });
2711
+ const modules = Array.from(moduleSet).map((moduleName) => {
2712
+ const moduleRoutes = httpRoutes.filter((route) => route.module === moduleName);
2713
+ const moduleQueueNames = queueManager.listQueues(moduleName);
2714
+ const moduleQueues = moduleQueueNames.map((name) => {
2715
+ const stats = queueManager.getQueueStats(name);
2716
+ return {
2717
+ name,
2718
+ stats: stats ? {
2719
+ incoming: stats.incoming.length,
2720
+ processing: stats.processing.length,
2721
+ dlq: stats.dlq.length
2722
+ } : null
2723
+ };
2724
+ });
2725
+ const moduleJobNames = schedulerManager.listJobs(moduleName);
2726
+ const moduleSchedules = moduleJobNames.map((name) => {
2727
+ const jobStats = schedulerManager.getJobStats(name);
2728
+ return {
2729
+ name,
2730
+ enabled: jobStats?.job.enabled || false,
2731
+ isRunning: jobStats?.isRunning || false,
2732
+ cronExpression: jobStats?.job.cronExpression,
2733
+ timezone: jobStats?.job.timezone
2734
+ };
2735
+ });
2736
+ return {
2737
+ name: moduleName,
2738
+ routes: moduleRoutes,
2739
+ queues: moduleQueues,
2740
+ schedules: moduleSchedules
2741
+ };
2742
+ });
2743
+ return { modules };
2744
+ });
2745
+ fastify.get(`/${prefix}/queues`, async (_, reply) => {
2746
+ const queueManager = fastify.queues;
2747
+ if (!queueManager) {
2748
+ return reply.status(503).send({ error: "Queue service not available" });
2749
+ }
2750
+ const queueNames = queueManager.listQueues();
2751
+ const queues = queueNames.map((name) => {
2752
+ const stats = queueManager.getQueueStats(name);
2753
+ return {
2754
+ name,
2755
+ stats: stats ? {
2756
+ incoming: stats.incoming.length,
2757
+ processing: stats.processing.length,
2758
+ dlq: stats.dlq.length
2759
+ } : null
2760
+ };
2761
+ });
2762
+ return { queues };
2763
+ });
2764
+ fastify.get(`/${prefix}/queues/:queueName`, async (request, reply) => {
2765
+ const { queueName } = request.params;
2766
+ const queueManager = fastify.queues;
2767
+ if (!queueManager) {
2768
+ return reply.status(503).send({ error: "Queue service not available" });
2769
+ }
2770
+ const queueStats = queueManager.getQueueStats(queueName);
2771
+ if (!queueStats) {
2772
+ return reply.status(404).send({ error: "Queue not found" });
2773
+ }
2774
+ const config = queueManager.getConfig();
2775
+ return {
2776
+ name: queueName,
2777
+ stats: {
2778
+ incoming: queueStats.incoming.length,
2779
+ processing: queueStats.processing.length,
2780
+ dlq: queueStats.dlq.length,
2781
+ configuration: config
2782
+ },
2783
+ messages: {
2784
+ incoming: queueStats.incoming,
2785
+ processing: queueStats.processing,
2786
+ dlq: queueStats.dlq
2787
+ }
2788
+ };
2789
+ });
2790
+ fastify.get(`/${prefix}/queues/:queueName/process-dlq`, async (request, reply) => {
2791
+ const { queueName } = request.params;
2792
+ const queueManager = fastify.queues;
2793
+ if (!queueManager) {
2794
+ return reply.status(503).send({ error: "Queue service not available" });
2795
+ }
2796
+ try {
2797
+ const result = await queueManager.processDlq(queueName);
2798
+ return reply.status(200).send(result);
2799
+ } catch (error) {
2800
+ return reply.status(500).send({
2801
+ message: "Failed to process DLQ",
2802
+ error
2803
+ });
2804
+ }
2805
+ });
2806
+ fastify.get(`/${prefix}/queues/:queueName/purge-dlq`, async (request, reply) => {
2807
+ const { queueName } = request.params;
2808
+ const queueManager = fastify.queues;
2809
+ if (!queueManager) {
2810
+ return reply.status(503).send({ error: "Queue service not available" });
2811
+ }
2812
+ try {
2813
+ const result = await queueManager.purgeDlq(queueName);
2814
+ return reply.status(200).send(result);
2815
+ } catch (error) {
2816
+ return reply.status(500).send({
2817
+ message: "Failed to purge DLQ",
2818
+ error
2819
+ });
2820
+ }
2821
+ });
2822
+ fastify.post(`/${prefix}/queues/:queueName/enqueue`, async (request, reply) => {
2823
+ const { queueName } = request.params;
2824
+ const queueManager = fastify.queues;
2825
+ if (!queueManager) {
2826
+ return reply.status(503).send({ error: "Queue service not available" });
2827
+ }
2828
+ try {
2829
+ const result = await queueManager.enqueueMessage(queueName, request.body, request.headers);
2830
+ return reply.status(200).send(result);
2831
+ } catch (error) {
2832
+ return reply.status(500).send({
2833
+ message: "Failed to enqueue message",
2834
+ error
2835
+ });
2836
+ }
2837
+ });
2838
+ fastify.delete(`/${prefix}/queues/:queueName`, async (request, reply) => {
2839
+ const { queueName } = request.params;
2840
+ const queueManager = fastify.queues;
2841
+ if (!queueManager) {
2842
+ return reply.status(503).send({ error: "Queue service not available" });
2843
+ }
2844
+ try {
2845
+ await queueManager.removeQueue(queueName);
2846
+ return reply.status(200).send({
2847
+ status: "success",
2848
+ message: `Queue ${queueName} removed successfully`
2849
+ });
2850
+ } catch (error) {
2851
+ return reply.status(500).send({
2852
+ message: "Failed to remove queue",
2853
+ error
2854
+ });
2855
+ }
2856
+ });
2857
+ fastify.post(`/${prefix}/queues`, async (request, reply) => {
2858
+ const { queueName, module } = request.body;
2859
+ const queueManager = fastify.queues;
2860
+ if (!queueManager) {
2861
+ return reply.status(503).send({ error: "Queue service not available" });
2862
+ }
2863
+ if (!queueName) {
2864
+ return reply.status(400).send({ error: "Queue name is required" });
2865
+ }
2866
+ try {
2867
+ const handler = async (message) => {
2868
+ console.log(`Processing message in ${queueName}:`, message);
2869
+ };
2870
+ await queueManager.addQueue(queueName, handler, module);
2871
+ return reply.status(201).send({
2872
+ status: "success",
2873
+ message: `Queue ${queueName} created successfully`,
2874
+ queueName
2875
+ });
2876
+ } catch (error) {
2877
+ return reply.status(500).send({
2878
+ message: "Failed to create queue",
2879
+ error
2880
+ });
2881
+ }
2882
+ });
2883
+ fastify.get(`/${prefix}/schedules`, async (_, reply) => {
2884
+ const schedulerManager = fastify.scheduler;
2885
+ if (!schedulerManager) {
2886
+ return reply.status(503).send({ error: "Scheduler service not available" });
2887
+ }
2888
+ const jobNames = schedulerManager.listJobs();
2889
+ const jobs = jobNames.map((name) => {
2890
+ const jobStats = schedulerManager.getJobStats(name);
2891
+ return {
2892
+ name,
2893
+ enabled: jobStats?.job.enabled || false,
2894
+ isRunning: jobStats?.isRunning || false,
2895
+ cronExpression: jobStats?.job.cronExpression,
2896
+ timezone: jobStats?.job.timezone
2897
+ };
2898
+ });
2899
+ return { schedules: jobs };
2900
+ });
2901
+ fastify.get(`/${prefix}/schedules/:jobName`, async (request, reply) => {
2902
+ const { jobName } = request.params;
2903
+ const schedulerManager = fastify.scheduler;
2904
+ if (!schedulerManager) {
2905
+ return reply.status(503).send({ error: "Scheduler service not available" });
2906
+ }
2907
+ const jobStats = schedulerManager.getJobStats(jobName);
2908
+ if (!jobStats) {
2909
+ return reply.status(404).send({ error: "Job not found" });
2910
+ }
2911
+ return {
2912
+ name: jobName,
2913
+ job: jobStats.job,
2914
+ isRunning: jobStats.isRunning,
2915
+ timerId: jobStats.timerId ? "scheduled" : "not_scheduled"
2916
+ };
2917
+ });
2918
+ fastify.post(`/${prefix}/schedules/:jobName/trigger`, async (request, reply) => {
2919
+ const { jobName } = request.params;
2920
+ const schedulerManager = fastify.scheduler;
2921
+ if (!schedulerManager) {
2922
+ return reply.status(503).send({ error: "Scheduler service not available" });
2923
+ }
2924
+ try {
2925
+ await schedulerManager.triggerJob(jobName);
2926
+ return reply.status(200).send({
2927
+ status: "success",
2928
+ message: `Schedule ${jobName} triggered successfully`
2929
+ });
2930
+ } catch {
2931
+ return reply.status(500).send({ error: "Failed to trigger schedule" });
2932
+ }
2933
+ });
2934
+ fastify.put(`/${prefix}/schedules/:jobName/enable`, async (request, reply) => {
2935
+ const { jobName } = request.params;
2936
+ const schedulerManager = fastify.scheduler;
2937
+ if (!schedulerManager) {
2938
+ return reply.status(503).send({ error: "Scheduler service not available" });
2939
+ }
2940
+ try {
2941
+ await schedulerManager.enableJob(jobName);
2942
+ return reply.status(200).send({
2943
+ status: "success",
2944
+ message: `Schedule ${jobName} enabled successfully`
2945
+ });
2946
+ } catch {
2947
+ return reply.status(500).send({ error: "Failed to enable schedule" });
2948
+ }
2949
+ });
2950
+ fastify.put(`/${prefix}/schedules/:jobName/disable`, async (request, reply) => {
2951
+ const { jobName } = request.params;
2952
+ const schedulerManager = fastify.scheduler;
2953
+ if (!schedulerManager) {
2954
+ return reply.status(503).send({ error: "Scheduler service not available" });
2955
+ }
2956
+ try {
2957
+ await schedulerManager.disableJob(jobName);
2958
+ return reply.status(200).send({
2959
+ status: "success",
2960
+ message: `Schedule ${jobName} disabled successfully`
2961
+ });
2962
+ } catch {
2963
+ return reply.status(500).send({ error: "Failed to disable schedule" });
2964
+ }
2965
+ });
2966
+ fastify.get(`/${prefix}/logs`, async (request) => {
2967
+ const {
2968
+ limit = 100,
2969
+ level,
2970
+ source,
2971
+ module,
2972
+ trigger,
2973
+ triggerType
2974
+ } = request.query;
2975
+ let logs = logStore.getLogs(Number(limit));
2976
+ if (level) {
2977
+ logs = logs.filter((log) => log.level === level);
2978
+ }
2979
+ if (source) {
2980
+ logs = logs.filter((log) => log.source === source);
2981
+ }
2982
+ if (module) {
2983
+ logs = logs.filter(
2984
+ (log) => log.module === module || log.message.toLowerCase().includes(module.toLowerCase())
2985
+ );
2986
+ }
2987
+ if (trigger && triggerType) {
2988
+ logs = logs.filter(
2989
+ (log) => log.trigger === trigger && log.triggerType === triggerType || log.message.toLowerCase().includes(trigger.toLowerCase())
2990
+ );
2991
+ }
2992
+ return { logs };
2993
+ });
2994
+ fastify.delete(`/${prefix}/logs`, async () => {
2995
+ logStore.clear();
2996
+ return { status: "success", message: "Logs cleared" };
2997
+ });
2998
+ fastify.get(`/${prefix}/logs/stream`, async (request, reply) => {
2999
+ reply.type("text/event-stream");
3000
+ reply.header("Cache-Control", "no-cache");
3001
+ reply.header("Connection", "keep-alive");
3002
+ reply.header("Access-Control-Allow-Origin", "*");
3003
+ const initialLogs = logStore.getLogs(50);
3004
+ reply.raw.write(`data: ${JSON.stringify({ type: "initial", logs: initialLogs })}
3005
+
3006
+ `);
3007
+ const unsubscribe = logStore.subscribe((log) => {
3008
+ reply.raw.write(`data: ${JSON.stringify({ type: "log", log })}
3009
+
3010
+ `);
3011
+ });
3012
+ request.raw.on("close", () => {
3013
+ unsubscribe();
3014
+ });
3015
+ });
3016
+ if (enableUI) {
3017
+ const devConsolePath = path4.resolve(__dirname, "../../../packages/dev-console/dist");
3018
+ await fastify.register(fastifyStatic, {
3019
+ root: devConsolePath,
3020
+ decorateReply: true
3021
+ });
3022
+ fastify.get(`/${prefix}`, async (_, reply) => {
3023
+ return reply.sendFile("index.html");
3024
+ });
3025
+ }
3026
+ }
3027
+ var devConsolePlugin = fsPlugin3(devConsolePluginFunction, {
3028
+ name: "dev-console-plugin"
3029
+ });
3030
+ export {
3031
+ devConsolePlugin,
3032
+ routeRegistry
3033
+ };
3034
+ /*! Bundled license information:
3035
+
3036
+ lodash-es/lodash.js:
3037
+ (**
3038
+ * @license
3039
+ * Lodash (Custom Build) <https://lodash.com/>
3040
+ * Build: `lodash modularize exports="es" -o ./`
3041
+ * Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
3042
+ * Released under MIT license <https://lodash.com/license>
3043
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
3044
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
3045
+ *)
3046
+ */
3047
+ //# sourceMappingURL=index.mjs.map