@cloudnux/local-cloud-provider 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,15 +1,6 @@
1
- // src/dev-console-plugin/plugin.ts
2
- import path3 from "path";
3
- import fastifyStatic from "@fastify/static";
4
- import fsPlugin3 from "fastify-plugin";
5
- import { createRequire } from "module";
6
-
7
- // src/queue-plugin/plugin.ts
8
- import fsPlugin from "fastify-plugin";
9
-
10
- // src/queue-plugin/core.ts
11
- import chalk2 from "chalk";
12
- import logSymbols from "log-symbols";
1
+ // src/logging/pretty-writer.ts
2
+ import chalk from "chalk";
3
+ import { EOL as EOL2 } from "os";
13
4
 
14
5
  // ../../../node_modules/lodash-es/_freeGlobal.js
15
6
  var freeGlobal = typeof global == "object" && global && global.Object === Object && global;
@@ -457,8 +448,8 @@ ListCache.prototype.set = listCacheSet_default;
457
448
  var ListCache_default = ListCache;
458
449
 
459
450
  // ../../../node_modules/lodash-es/_Map.js
460
- var Map = getNative_default(root_default, "Map");
461
- var Map_default = Map;
451
+ var Map2 = getNative_default(root_default, "Map");
452
+ var Map_default = Map2;
462
453
 
463
454
  // ../../../node_modules/lodash-es/_mapCacheClear.js
464
455
  function mapCacheClear() {
@@ -833,20 +824,32 @@ var utils = {
833
824
  };
834
825
  var env = Object.assign(_env, utils);
835
826
 
836
- // ../../utils/src/logging/index.ts
837
- import chalk from "chalk";
838
- import { EOL } from "os";
839
-
840
827
  // ../../utils/src/logging/types.ts
841
828
  var logLevels = {
842
829
  fatal: -1,
843
830
  error: 0,
844
831
  warn: 1,
845
832
  info: 2,
846
- debug: 3
833
+ debug: 3,
834
+ trace: 4
847
835
  };
848
836
 
849
837
  // ../../utils/src/logging/error-to-string.ts
838
+ var safeJsonStringify = (value) => {
839
+ const seen = /* @__PURE__ */ new WeakSet();
840
+ return JSON.stringify(value, (key, currentValue) => {
841
+ if (key === "constructor") return void 0;
842
+ if (typeof currentValue === "object" && currentValue !== null) {
843
+ if (seen.has(currentValue)) return "[Circular]";
844
+ seen.add(currentValue);
845
+ }
846
+ return currentValue;
847
+ });
848
+ };
849
+ var hasOwnConstructorProp = (value) => {
850
+ if (typeof value !== "object" || value === null) return false;
851
+ return Object.prototype.hasOwnProperty.call(value, "constructor");
852
+ };
850
853
  var errorToString = (error) => {
851
854
  if (error === null) return "Null error";
852
855
  if (error === void 0) return "Undefined error";
@@ -856,13 +859,22 @@ var errorToString = (error) => {
856
859
  `Message: ${error.message}`,
857
860
  `Stack: ${error.stack || "No stack trace available"}`,
858
861
  // Handle additional properties that might exist on custom errors
859
- ...Object.entries(error).filter(([key]) => !["name", "message", "stack"].includes(key)).map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
862
+ ...Object.entries(error).filter(
863
+ ([key, value]) => !["name", "message", "stack"].includes(key) && !hasOwnConstructorProp(value)
864
+ ).map(([key, value]) => `${key}: ${safeJsonStringify(value)}`)
860
865
  ].join("\n");
861
866
  }
862
867
  if (typeof error === "string") return error;
863
868
  if (typeof error === "object") {
864
869
  try {
865
- return JSON.stringify(error, null, 2);
870
+ return JSON.stringify(
871
+ error,
872
+ (key, value) => {
873
+ if (key === "constructor") return void 0;
874
+ return value;
875
+ },
876
+ 2
877
+ );
866
878
  } catch {
867
879
  return `[Object that cannot be stringified: ${Object.prototype.toString.call(error)}]`;
868
880
  }
@@ -870,62 +882,136 @@ var errorToString = (error) => {
870
882
  return String(error);
871
883
  };
872
884
 
873
- // ../../utils/src/logging/index.ts
874
- var currentLogLevel = logLevels[env("LOG_LEVEL")?.toLowerCase()] ?? logLevels.info;
875
- var module = "default";
876
- var requestId = "";
877
- var logger = {
878
- fatal: (message, meta) => {
879
- if (currentLogLevel >= logLevels.fatal) {
880
- console.error(
881
- `[${(/* @__PURE__ */ new Date()).toTimeString()}]`,
882
- `${chalk.bgRed.white(" fatal ")} - ${module || "unknown module"} - ${requestId || "no request ID"} - ${EOL}`,
883
- errorToString(message),
884
- meta ? `${EOL}${JSON.stringify(meta, null, 2)}` : ""
885
- );
886
- }
887
- },
888
- error: (message, meta) => {
889
- if (currentLogLevel >= logLevels.error) {
890
- console.error(
891
- `[${(/* @__PURE__ */ new Date()).toTimeString()}]`,
892
- `${chalk.bgRed.white(" error ")} - ${module || "unknown module"} - ${requestId || "no request ID"} - ${EOL}`,
893
- errorToString(message),
894
- meta ? `${EOL}${JSON.stringify(meta, null, 2)}` : ""
895
- );
896
- }
897
- },
898
- warn: (message, meta) => {
899
- if (currentLogLevel >= logLevels.warn) {
900
- console.warn(
901
- `[${(/* @__PURE__ */ new Date()).toTimeString()}]`,
902
- `${chalk.bgYellow.black(" warn ")} - ${module || "unknown module"} - ${requestId || "no request ID"} - ${EOL}`,
903
- errorToString(message),
904
- meta ? `${EOL}${JSON.stringify(meta, null, 2)}` : ""
905
- );
906
- }
907
- },
908
- info: (message, meta) => {
909
- if (currentLogLevel >= logLevels.info) {
910
- console.info(
911
- `[${(/* @__PURE__ */ new Date()).toTimeString()}]`,
912
- `${chalk.bgBlue.white(" info ")} - ${module || "unknown module"} - ${requestId || "no request ID"} - ${EOL}`,
913
- message,
914
- meta ? `${EOL}${JSON.stringify(meta, null, 2)}` : ""
915
- );
916
- }
917
- },
918
- debug: (message, meta) => {
919
- if (currentLogLevel >= logLevels.debug) {
920
- console.debug(
921
- `[${(/* @__PURE__ */ new Date()).toTimeString()}]`,
922
- `${chalk.bgWhite.black(" debug ")} - ${module || "unknown module"} - ${requestId || "no request ID"} - ${EOL}`,
923
- message,
924
- meta ? `${EOL}${JSON.stringify(meta, null, 2)}` : ""
925
- );
926
- }
927
- }
885
+ // ../../utils/src/logging/writer.ts
886
+ import { EOL } from "os";
887
+ var jsonWriter = (entry) => {
888
+ process.stdout.write(JSON.stringify(entry) + EOL);
928
889
  };
890
+ var _writer = jsonWriter;
891
+ function setWriter(writer) {
892
+ _writer = writer;
893
+ }
894
+ function getWriter() {
895
+ return _writer;
896
+ }
897
+
898
+ // ../../utils/src/logging/index.ts
899
+ var levelValues = {
900
+ fatal: 70,
901
+ error: 60,
902
+ warn: 50,
903
+ info: 40,
904
+ debug: 30,
905
+ trace: 20
906
+ };
907
+ var currentLogLevel = 2;
908
+ var _module = "default";
909
+ var _requestId = "";
910
+ function writeLine(level, mergeObject, msg, bindings) {
911
+ getWriter()({
912
+ level: levelValues[level],
913
+ levelName: level,
914
+ time: Date.now(),
915
+ module: bindings.module || _module,
916
+ reqId: bindings.reqId || _requestId,
917
+ msg: level === "error" || level === "fatal" ? errorToString(msg) : msg,
918
+ ...mergeObject ? { meta: mergeObject } : {}
919
+ });
920
+ }
921
+ function createLogger(bindings = {}) {
922
+ const currentLogLevelName = env("LOG_LEVEL")?.toLowerCase() ?? "info";
923
+ currentLogLevel = logLevels[currentLogLevelName] ?? logLevels.info;
924
+ return {
925
+ level: currentLogLevelName,
926
+ fatal: (mergeObject, msg) => {
927
+ if (currentLogLevel >= logLevels.fatal) {
928
+ typeof mergeObject === "string" || mergeObject instanceof Error ? writeLine("fatal", null, mergeObject, bindings) : writeLine("fatal", mergeObject, msg ?? "", bindings);
929
+ }
930
+ },
931
+ error: (mergeObject, msg) => {
932
+ if (currentLogLevel >= logLevels.error) {
933
+ typeof mergeObject === "string" || mergeObject instanceof Error ? writeLine("error", null, mergeObject, bindings) : writeLine("error", mergeObject, msg ?? "", bindings);
934
+ }
935
+ },
936
+ warn: (mergeObject, msg) => {
937
+ if (currentLogLevel >= logLevels.warn) {
938
+ typeof mergeObject === "string" ? writeLine("warn", null, mergeObject, bindings) : writeLine("warn", mergeObject, msg ?? "", bindings);
939
+ }
940
+ },
941
+ info: (mergeObject, msg) => {
942
+ if (currentLogLevel >= logLevels.info) {
943
+ typeof mergeObject === "string" ? writeLine("info", null, mergeObject, bindings) : writeLine("info", mergeObject, msg ?? "", bindings);
944
+ }
945
+ },
946
+ debug: (mergeObject, msg) => {
947
+ if (currentLogLevel >= logLevels.debug) {
948
+ typeof mergeObject === "string" ? writeLine("debug", null, mergeObject, bindings) : writeLine("debug", mergeObject, msg ?? "", bindings);
949
+ }
950
+ },
951
+ trace: (mergeObject, msg) => {
952
+ if (currentLogLevel >= logLevels.trace) {
953
+ typeof mergeObject === "string" ? writeLine("trace", null, mergeObject, bindings) : writeLine("trace", mergeObject, msg ?? "", bindings);
954
+ }
955
+ },
956
+ silent: () => {
957
+ },
958
+ child: (childBindings) => createLogger({ ...bindings, ...childBindings })
959
+ };
960
+ }
961
+ var logger = createLogger();
962
+
963
+ // src/logging/pretty-writer.ts
964
+ var levelColor = {
965
+ fatal: chalk.bgRed.white,
966
+ error: chalk.red,
967
+ warn: chalk.yellow,
968
+ info: chalk.cyan,
969
+ debug: chalk.gray,
970
+ trace: chalk.white
971
+ };
972
+ function formatTime(ms) {
973
+ return new Date(ms).toTimeString().slice(0, 8);
974
+ }
975
+ function formatMeta(meta) {
976
+ const { req, res, ...rest } = meta;
977
+ const lines = [];
978
+ if (req) {
979
+ const reqParts = [`${req.method} ${req.url}`];
980
+ if (req.remoteAddress) reqParts.push(`from ${req.remoteAddress}:${req.remotePort ?? ""}`);
981
+ if (req.headers) reqParts.push(`headers=${JSON.stringify(req.headers, null, 2)}`);
982
+ if (req.body !== void 0) reqParts.push(`body=${typeof req.body === "string" ? req.body : JSON.stringify(req.body, null, 2)}`);
983
+ lines.push(chalk.dim(" req: " + reqParts.join(" ")));
984
+ }
985
+ if (res) {
986
+ const resParts = [`${res.statusCode}`];
987
+ if (res.headers) resParts.push(`headers=${JSON.stringify(res.headers, null, 2)}`);
988
+ if (res.body !== void 0) resParts.push(`body=${typeof res.body === "string" ? res.body : JSON.stringify(res.body, null, 2)}`);
989
+ lines.push(chalk.dim(" res: " + resParts.join(" ")));
990
+ }
991
+ if (Object.keys(rest).length) {
992
+ lines.push(chalk.dim(" " + JSON.stringify(rest, null, 2)));
993
+ }
994
+ return lines.length ? EOL2 + lines.join(EOL2) : "";
995
+ }
996
+ var prettyWriter = (entry) => {
997
+ const color = levelColor[entry.levelName] ?? chalk.white;
998
+ const time = chalk.dim(formatTime(entry.time));
999
+ const level = color(entry.levelName.toUpperCase().padEnd(5));
1000
+ const module = chalk.magenta(entry.module);
1001
+ const reqId = entry.reqId ? chalk.dim(`[${entry.reqId}]`) + " " : "";
1002
+ const meta = entry.meta ? formatMeta(entry.meta) : "";
1003
+ process.stdout.write(`${time} ${level} ${module} ${reqId}- ${entry.msg}${meta}${EOL2}`);
1004
+ };
1005
+ setWriter(prettyWriter);
1006
+
1007
+ // src/dev-console-plugin/plugin.ts
1008
+ import path3 from "path";
1009
+ import fastifyStatic from "@fastify/static";
1010
+ import fsPlugin4 from "fastify-plugin";
1011
+ import { createRequire } from "module";
1012
+
1013
+ // src/queue-plugin/plugin.ts
1014
+ import fsPlugin from "fastify-plugin";
929
1015
 
930
1016
  // src/queue-plugin/core.ts
931
1017
  var DEFAULT_CONFIG = {
@@ -951,14 +1037,14 @@ var mergeConfig = (defaultConfig, userConfig) => ({
951
1037
  ...userConfig?.persistence || {}
952
1038
  }
953
1039
  });
954
- var createQueueService = (handler, module2) => ({
1040
+ var createQueueService = (handler, module) => ({
955
1041
  handler,
956
1042
  incoming: [],
957
1043
  processing: [],
958
1044
  dlq: [],
959
1045
  timeoutId: null,
960
1046
  processingBatch: false,
961
- module: module2
1047
+ module
962
1048
  });
963
1049
  var createQueueMessage = (body, headers) => {
964
1050
  const id = Date.now().toString() + Math.random().toString(36).substring(2, 7);
@@ -1039,32 +1125,36 @@ var purgeDLQ = (queueService) => {
1039
1125
  return dlqCount;
1040
1126
  };
1041
1127
  var logSuccess = (message, messageId, queueName) => {
1042
- logger.debug(`${logSymbols.success} ${chalk2.green(message)} ${chalk2.yellow(messageId)} in queue ${chalk2.magenta(queueName)}`);
1128
+ logger.debug(`Success: ${message} ${messageId} in queue ${queueName}`);
1043
1129
  };
1044
1130
  var logError = (message, messageId, queueName, error) => {
1045
- logger.error(`${logSymbols.error} ${chalk2.red(message)} ${chalk2.yellow(messageId)} in queue ${chalk2.magenta(queueName)}: ${error}`);
1131
+ logger.error(`Error: ${message} ${messageId} in queue ${queueName}: ${error}`);
1046
1132
  };
1047
1133
  var logRetryScheduled = (messageId, delayMs) => {
1048
- logger.debug(`${chalk2.blue("\u23F1\uFE0F Scheduling retry")} for message ${chalk2.yellow(messageId)} in ${chalk2.cyan(delayMs)}ms`);
1134
+ logger.debug(`Scheduling retry for message ${messageId} in ${delayMs}ms`);
1049
1135
  };
1050
1136
  var logDLQOperation = (operation, count, queueName) => {
1051
- logger.warn(`${logSymbols.warning} ${chalk2.yellow(operation)} ${chalk2.red(count)} messages from DLQ for ${chalk2.green(queueName)}`);
1137
+ logger.warn(`${operation} ${count} messages from DLQ for ${queueName}`);
1052
1138
  };
1053
1139
 
1054
1140
  // src/queue-plugin/processing.ts
1055
1141
  var createProcessMessageHandler = (config) => async (queueName, message, queueService) => {
1056
1142
  try {
1057
- await queueService.handler(message);
1058
- removeFromProcessing(queueService, message.id);
1059
- logSuccess("Successfully processed message", message.id, queueName);
1060
- } catch (error) {
1061
- await handleProcessingError(queueName, message, queueService, error, config);
1143
+ const result = await queueService.handler(message);
1144
+ if (result?.failureId) {
1145
+ await handleProcessingError(queueName, message, queueService, config);
1146
+ } else {
1147
+ removeFromProcessing(queueService, message.id);
1148
+ logSuccess("Successfully processed message", message.id, queueName);
1149
+ }
1150
+ } catch {
1151
+ await handleProcessingError(queueName, message, queueService, config);
1062
1152
  }
1063
1153
  };
1064
- var handleProcessingError = async (queueName, message, queueService, error, config) => {
1065
- logError("Error processing message", message.id, queueName, error.message);
1154
+ var handleProcessingError = async (queueName, message, queueService, config) => {
1155
+ logError("Error processing message", message.id, queueName, "handler returned failure");
1066
1156
  if (message.attempts >= config.maxRetries) {
1067
- moveToDLQ(queueService, message, error.message);
1157
+ moveToDLQ(queueService, message, "max retries exceeded");
1068
1158
  return;
1069
1159
  }
1070
1160
  const updatedMessage = incrementAttempts(queueService, message.id);
@@ -1124,8 +1214,6 @@ var handleImmediateProcessing = (queueService, config, processBatch, queueName)
1124
1214
  // src/queue-plugin/persistence.ts
1125
1215
  import * as fs from "fs/promises";
1126
1216
  import * as path from "path";
1127
- import chalk3 from "chalk";
1128
- import logSymbols2 from "log-symbols";
1129
1217
  var createQueueData = (queueService) => ({
1130
1218
  incoming: queueService.incoming,
1131
1219
  processing: queueService.processing,
@@ -1160,10 +1248,9 @@ var createPersistenceInitializer = (config, loadAllQueueStates, saveDirtyQueueSt
1160
1248
  process.on("SIGINT", shutdownHandler);
1161
1249
  process.on("SIGTERM", shutdownHandler);
1162
1250
  }
1163
- logger.debug(`${logSymbols2.success} ${chalk3.green("Queue persistence initialized:")} ${chalk3.yellow(config.persistence.directory)}`);
1251
+ logger.debug(`Queue persistence initialized: ${config.persistence.directory}`);
1164
1252
  } catch (error) {
1165
- console.log("[logger]", logger);
1166
- logger.error(`${logSymbols2.error} ${chalk3.red("Failed to initialize queue persistence:")} ${chalk3.yellow(error?.message)}`);
1253
+ logger.error(`Failed to initialize queue persistence: ${error?.message}`);
1167
1254
  }
1168
1255
  };
1169
1256
  var createQueueStateSaver = (config) => async (queueName, queueService) => {
@@ -1175,7 +1262,7 @@ var createQueueStateSaver = (config) => async (queueName, queueService) => {
1175
1262
  const tempFilePath = path.join(config.persistence.directory, `${queueName}.${now}temp.json`);
1176
1263
  await fs.writeFile(tempFilePath, JSON.stringify(queueData, null, 2), "utf8");
1177
1264
  await fs.rename(tempFilePath, queueFilePath);
1178
- logger.debug(`${logSymbols2.info} ${chalk3.blue("Queue state saved:")} ${chalk3.green(queueName)}`);
1265
+ logger.debug(`Queue state saved: ${queueName}`);
1179
1266
  } catch (error) {
1180
1267
  logger.error(`Failed to save queue state for ${queueName}:`, error?.message);
1181
1268
  }
@@ -1185,9 +1272,9 @@ var createAllQueuesStateSaver = (config, saveQueueState) => (queues) => async ()
1185
1272
  for (const [queueName, queueService] of Object.entries(queues)) {
1186
1273
  await saveQueueState(queueName, queueService);
1187
1274
  }
1188
- logger.debug(`${logSymbols2.success} ${chalk3.green("All queue states saved to")} ${chalk3.yellow(config.persistence.directory)}`);
1275
+ logger.debug(`All queue states saved to ${config.persistence.directory}`);
1189
1276
  } catch (error) {
1190
- logger.error(`${logSymbols2.error} ${chalk3.red("Failed to save all queue states:")} ${chalk3.yellow(error?.message)}`);
1277
+ logger.error(`Failed to save all queue states: ${error?.message}`);
1191
1278
  }
1192
1279
  };
1193
1280
  var createDirtyQueuesStateSaver = (saveQueueState, dirtyQueues) => (queues) => async () => {
@@ -1201,7 +1288,7 @@ var createDirtyQueuesStateSaver = (saveQueueState, dirtyQueues) => (queues) => a
1201
1288
  }
1202
1289
  }
1203
1290
  } catch (error) {
1204
- logger.error(`${logSymbols2.error} ${chalk3.red("Failed to save dirty queue states:")} ${chalk3.yellow(error?.message)}`);
1291
+ logger.error(`Failed to save dirty queue states: ${error?.message}`);
1205
1292
  }
1206
1293
  };
1207
1294
  var createQueueStateLoader = (config, scheduleProcessing, processMessage) => (queues) => async (queueName) => {
@@ -1313,8 +1400,6 @@ var registerQueueRoutes = (app, prefix = "") => {
1313
1400
  };
1314
1401
 
1315
1402
  // src/queue-plugin/decorator.ts
1316
- import chalk4 from "chalk";
1317
- import logSymbols3 from "log-symbols";
1318
1403
  var isValidQueueName = (queueName) => {
1319
1404
  return typeof queueName === "string" && queueName.length > 0 && /^[a-zA-Z0-9_-]+$/.test(queueName);
1320
1405
  };
@@ -1340,21 +1425,21 @@ var createQueueManager = ({
1340
1425
  throw new Error("Handler must be a function");
1341
1426
  }
1342
1427
  };
1343
- const addQueue = async (queueName, handler, module2) => {
1428
+ const addQueue = async (queueName, handler, module) => {
1344
1429
  try {
1345
1430
  validateQueueName(queueName);
1346
1431
  validateHandler(handler);
1347
1432
  if (queues[queueName]) {
1348
- logger.warn(`${logSymbols3.warning} ${chalk4.yellow("Queue already exists:")} ${chalk4.magenta(queueName)}.`);
1433
+ logger.warn(`Queue already exists: ${queueName}.`);
1349
1434
  return;
1350
1435
  }
1351
- queues[queueName] = createQueueService(handler, module2);
1436
+ queues[queueName] = createQueueService(handler, module);
1352
1437
  if (config.persistence.enabled && loadQueueState) {
1353
1438
  await loadQueueState(queueName);
1354
1439
  }
1355
- logger.info(`${logSymbols3.success} ${chalk4.green("Queue added:")} ${chalk4.magenta(queueName)}`);
1440
+ logger.info(`Queue added: ${queueName}`);
1356
1441
  } catch (error) {
1357
- logger.error(`${logSymbols3.error} ${chalk4.red("Failed to add queue")} ${chalk4.magenta(queueName)}: ${error.message}`);
1442
+ logger.error(`Failed to add queue ${queueName}: ${error.message}`);
1358
1443
  throw error;
1359
1444
  }
1360
1445
  };
@@ -1367,7 +1452,7 @@ var createQueueManager = ({
1367
1452
  const queueService = queues[queueName];
1368
1453
  const totalMessages = queueService.incoming.length + queueService.processing.length;
1369
1454
  if (totalMessages > 0) {
1370
- logger.warn(`${logSymbols3.warning} ${chalk4.yellow("Removing queue with")} ${chalk4.red(totalMessages)} ${chalk4.yellow("pending messages:")} ${chalk4.magenta(queueName)}`);
1455
+ logger.warn(`Removing queue with ${totalMessages} pending messages: ${queueName}`);
1371
1456
  }
1372
1457
  if (queueService.timeoutId) {
1373
1458
  clearTimeout(queueService.timeoutId);
@@ -1376,9 +1461,9 @@ var createQueueManager = ({
1376
1461
  await saveQueueState(queueName, queueService);
1377
1462
  }
1378
1463
  delete queues[queueName];
1379
- logger.info(`${logSymbols3.success} ${chalk4.green("Queue removed:")} ${chalk4.magenta(queueName)}`);
1464
+ logger.info(`Queue removed: ${queueName}`);
1380
1465
  } catch (error) {
1381
- logger.error(`${logSymbols3.error} ${chalk4.red("Failed to remove queue")} ${chalk4.magenta(queueName)}: ${error.message}`);
1466
+ logger.error(`Failed to remove queue ${queueName}: ${error.message}`);
1382
1467
  throw error;
1383
1468
  }
1384
1469
  };
@@ -1390,10 +1475,10 @@ var createQueueManager = ({
1390
1475
  return false;
1391
1476
  }
1392
1477
  };
1393
- const listQueues = (module2) => {
1478
+ const listQueues = (module) => {
1394
1479
  return Object.keys(queues).filter((queueName) => {
1395
1480
  const queueService = queues[queueName];
1396
- return !module2 || queueService.module === module2;
1481
+ return !module || queueService.module === module;
1397
1482
  }).sort();
1398
1483
  };
1399
1484
  const getQueueStats = (queueName) => {
@@ -1555,15 +1640,8 @@ import fsPlugin2 from "fastify-plugin";
1555
1640
 
1556
1641
  // src/schedule-plugin/core.ts
1557
1642
  import * as fs3 from "fs/promises";
1558
- import chalk9 from "chalk";
1559
- import logSymbols7 from "log-symbols";
1560
-
1561
- // src/schedule-plugin/execution.ts
1562
- import chalk6 from "chalk";
1563
- import logSymbols4 from "log-symbols";
1564
1643
 
1565
1644
  // src/schedule-plugin/cron-utils.ts
1566
- import chalk5 from "chalk";
1567
1645
  import { parseExpression } from "cron-parser";
1568
1646
  function parseCronExpression(cronExpression, lastRun, options = {}) {
1569
1647
  const {
@@ -1595,7 +1673,7 @@ function parseCronExpression(cronExpression, lastRun, options = {}) {
1595
1673
  description: describeCronExpression(normalizedCron)
1596
1674
  };
1597
1675
  } catch (error) {
1598
- logger.error(`${chalk5.red("Invalid cron expression:")} ${cronExpression} - ${error.message}`);
1676
+ logger.error(`Invalid cron expression: ${cronExpression} - ${error.message}`);
1599
1677
  const fallbackTime = /* @__PURE__ */ new Date();
1600
1678
  fallbackTime.setHours(fallbackTime.getHours() + 1);
1601
1679
  fallbackTime.setMinutes(0);
@@ -1624,7 +1702,7 @@ function getNextExecutions(cronExpression, count = 5, options = {}) {
1624
1702
  }
1625
1703
  return executions;
1626
1704
  } catch (error) {
1627
- logger.error(`${chalk5.red("Error getting next executions:")} ${error.message}`);
1705
+ logger.error(`Error getting next executions: ${error.message}`);
1628
1706
  return [];
1629
1707
  }
1630
1708
  }
@@ -1939,7 +2017,7 @@ var scheduleJob = (scheduler, state, executeJobFn) => {
1939
2017
  updatedScheduler.timerId = setTimeout(() => {
1940
2018
  executeJobFn(updatedScheduler);
1941
2019
  }, timeUntilNextRun);
1942
- logger.debug(`${chalk6.blue("\u{1F4C5} Scheduled job")} ${chalk6.green(scheduler.job.name)} to run in ${chalk6.cyan(Math.round(timeUntilNextRun / 1e3))}s`);
2020
+ logger.debug(`Scheduled job ${scheduler.job.name} to run in ${Math.round(timeUntilNextRun / 1e3)}s`);
1943
2021
  }
1944
2022
  return updatedScheduler;
1945
2023
  };
@@ -1968,20 +2046,18 @@ var updateJobAfterExecution = (job, execution, config) => {
1968
2046
  return updatedJob;
1969
2047
  };
1970
2048
  var handleExecutionError = (execution, error) => {
1971
- logger.error(`${logSymbols4.error} ${chalk6.red("Job failed")} ${execution.jobId}: ${error.message}`);
2049
+ logger.error(`Job failed ${execution.jobId}: ${error.message}`);
1972
2050
  return completeExecution(execution, void 0, error.message);
1973
2051
  };
1974
2052
  var handleExecutionSuccess = (execution, result) => {
1975
2053
  const duration = execution.endTime ? execution.endTime.getTime() - execution.startTime.getTime() : 0;
1976
- logger.debug(`${logSymbols4.success} ${chalk6.green("Job completed")} in ${duration}ms`);
2054
+ logger.debug(`Job completed in ${duration}ms`);
1977
2055
  return completeExecution(execution, result);
1978
2056
  };
1979
2057
 
1980
2058
  // src/schedule-plugin/persistence.ts
1981
2059
  import * as fs2 from "fs/promises";
1982
2060
  import * as path2 from "path";
1983
- import chalk7 from "chalk";
1984
- import logSymbols5 from "log-symbols";
1985
2061
  var createStateFilePath = (directory) => path2.join(directory, "scheduler-state.json");
1986
2062
  var createTempFilePath = (directory) => path2.join(directory, `scheduler-state.${Date.now()}.temp.json`);
1987
2063
  var serializeSchedulerState = (schedulers, executionHistory) => ({
@@ -1997,7 +2073,7 @@ var saveSchedulerState = async (state) => {
1997
2073
  const tempFile = createTempFilePath(state.config.persistence.directory);
1998
2074
  await fs2.writeFile(tempFile, JSON.stringify(serializedState, null, 2), "utf8");
1999
2075
  await fs2.rename(tempFile, stateFile);
2000
- logger.debug(`${logSymbols5.info} ${chalk7.blue("Enhanced scheduler state saved")}`);
2076
+ logger.debug("Enhanced scheduler state saved");
2001
2077
  } catch (error) {
2002
2078
  logger.error("Failed to save scheduler state:", error);
2003
2079
  }
@@ -2009,7 +2085,7 @@ var loadSchedulerStateData = async (directory) => {
2009
2085
  return JSON.parse(data);
2010
2086
  } catch (error) {
2011
2087
  if (error.code === "ENOENT") {
2012
- logger.debug(`${chalk7.blue("No previous scheduler state found - starting fresh")}`);
2088
+ logger.debug("No previous scheduler state found - starting fresh");
2013
2089
  } else {
2014
2090
  logger.error("Failed to load scheduler state:", error);
2015
2091
  }
@@ -2022,20 +2098,20 @@ var validateAndAdjustNextRun = (job, savedNextRun, lastRestartTime, config) => {
2022
2098
  return calculateNextRunFromLastRun(job, job.lastRun, config);
2023
2099
  }
2024
2100
  if (savedNextRun <= now) {
2025
- logger.debug(`${chalk7.yellow("\u23F0 Saved next run is in the past for")} ${chalk7.green(job.name)} - recalculating`);
2101
+ logger.debug(`Saved next run is in the past for ${job.name} - recalculating`);
2026
2102
  return calculateNextRunFromLastRun(job, job.lastRun, config);
2027
2103
  }
2028
2104
  const timeSinceRestart = now.getTime() - lastRestartTime.getTime();
2029
2105
  const isRapidRestart = timeSinceRestart < config.restartBehavior.rapidRestartThreshold;
2030
2106
  if (isRapidRestart) {
2031
- logger.debug(`${chalk7.blue("\u26A1 Rapid restart detected for")} ${chalk7.green(job.name)} - preserving saved timing`);
2107
+ logger.debug(`Rapid restart detected for ${job.name} - preserving saved timing`);
2032
2108
  return savedNextRun;
2033
2109
  }
2034
2110
  if (job.cronExpression || job.intervalMs) {
2035
2111
  const expectedNextRun = calculateNextRunFromLastRun(job, job.lastRun, config);
2036
2112
  const timeDiff = Math.abs(savedNextRun.getTime() - expectedNextRun.getTime());
2037
2113
  if (timeDiff > config.restartBehavior.maxTimingDrift) {
2038
- logger.debug(`${chalk7.yellow("\u{1F527} Adjusting timing for")} ${chalk7.green(job.name)} - drift of ${Math.round(timeDiff / 1e3)}s detected`);
2114
+ logger.debug(`Adjusting timing for ${job.name} - drift of ${Math.round(timeDiff / 1e3)}s detected`);
2039
2115
  return expectedNextRun;
2040
2116
  }
2041
2117
  }
@@ -2049,7 +2125,7 @@ var restoreJobFromSavedData = (scheduler, savedJob, config, lastRestartTime) =>
2049
2125
  lastRun: savedJob.lastRun ? new Date(savedJob.lastRun) : void 0
2050
2126
  };
2051
2127
  if (definitionChanged) {
2052
- logger.debug(`${chalk7.yellow("\u{1F504} Job definition changed:")} ${chalk7.green(savedJob.name)} - recalculating schedule`);
2128
+ logger.debug(`Job definition changed: ${savedJob.name} - recalculating schedule`);
2053
2129
  updatedJob.nextRun = calculateNextRunFromLastRun(updatedJob, updatedJob.lastRun, config);
2054
2130
  } else {
2055
2131
  const savedNextRun = savedJob.nextRun ? new Date(savedJob.nextRun) : void 0;
@@ -2059,7 +2135,7 @@ var restoreJobFromSavedData = (scheduler, savedJob, config, lastRestartTime) =>
2059
2135
  const result = parseCronExpression(updatedJob.cronExpression, updatedJob.lastRun, {
2060
2136
  timezone: updatedJob.timezone
2061
2137
  });
2062
- logger.debug(`${chalk7.blue("\u{1F4C5} Job restored:")} ${chalk7.green(savedJob.name)} - ${result.description} - next: ${chalk7.cyan(updatedJob.nextRun.toLocaleString())}`);
2138
+ logger.debug(`Job restored: ${savedJob.name} - ${result.description} - next: ${updatedJob.nextRun.toLocaleString()}`);
2063
2139
  }
2064
2140
  return { ...scheduler, job: updatedJob };
2065
2141
  };
@@ -2089,20 +2165,18 @@ var loadSchedulerState = async (schedulers, config, lastRestartTime) => {
2089
2165
  }
2090
2166
  }
2091
2167
  const executionHistory = stateData.executions ? restoreExecutionHistory(stateData.executions) : [];
2092
- logger.debug(`${logSymbols5.success} ${chalk7.green("Enhanced scheduler state loaded")} (saved at ${stateData.savedAt})`);
2168
+ logger.debug(`Enhanced scheduler state loaded (saved at ${stateData.savedAt})`);
2093
2169
  return { schedulers: restoredSchedulers, executionHistory };
2094
2170
  };
2095
2171
 
2096
2172
  // src/schedule-plugin/cleanup.ts
2097
- import chalk8 from "chalk";
2098
- import logSymbols6 from "log-symbols";
2099
2173
  var cleanupExecutionHistory = (state) => {
2100
2174
  if (state.executionHistory.length > state.config.cleanup.maxExecutionHistory) {
2101
2175
  const removed = state.executionHistory.splice(
2102
2176
  0,
2103
2177
  state.executionHistory.length - state.config.cleanup.maxExecutionHistory
2104
2178
  );
2105
- logger.debug(`${chalk8.blue("\u{1F9F9} Cleaned up")} ${removed.length} old execution records`);
2179
+ logger.debug(`Cleaned up ${removed.length} old execution records`);
2106
2180
  return removed;
2107
2181
  }
2108
2182
  return [];
@@ -2169,11 +2243,11 @@ var createSchedulerFunctions = (state) => {
2169
2243
  const { canExecute, reason } = canExecuteJob(scheduler, state);
2170
2244
  if (!canExecute) {
2171
2245
  if (reason === "Maximum concurrent executions reached") {
2172
- logger.warn(`${chalk9.yellow("\u26A0\uFE0F Delaying job")} ${chalk9.green(scheduler.job.name)} - ${reason}`);
2246
+ logger.warn(`Delaying job ${scheduler.job.name} - ${reason}`);
2173
2247
  scheduler.job.nextRun = new Date(Date.now() + 3e4);
2174
2248
  scheduleJobFn(scheduler);
2175
2249
  } else if (reason === "Job reached maximum runs") {
2176
- logger.info(`${chalk9.yellow("\u23F9\uFE0F Job")} ${chalk9.green(scheduler.job.name)} reached max runs (${scheduler.job.maxRuns})`);
2250
+ logger.info(`Job ${scheduler.job.name} reached max runs (${scheduler.job.maxRuns})`);
2177
2251
  }
2178
2252
  return;
2179
2253
  }
@@ -2182,7 +2256,7 @@ var createSchedulerFunctions = (state) => {
2182
2256
  state.executionHistory.push(execution);
2183
2257
  scheduler.isRunning = true;
2184
2258
  state.runningExecutions++;
2185
- logger.info(`${chalk9.blue("\u{1F680} Executing job")} ${chalk9.green(scheduler.job.name)} (${execution.id})`);
2259
+ logger.info(`Executing job ${scheduler.job.name} (${execution.id})`);
2186
2260
  try {
2187
2261
  const result = await executeJobWithTimeout(
2188
2262
  scheduler.handler,
@@ -2242,20 +2316,18 @@ var initializeScheduler = async (state, scheduleJobFn) => {
2242
2316
  scheduleJobFn(scheduler);
2243
2317
  }
2244
2318
  }
2245
- logger.debug(`${logSymbols7.success} ${chalk9.green("Scheduler initialized:")} ${Object.keys(state.schedulers).length} jobs loaded`);
2319
+ logger.debug(`Scheduler initialized: ${Object.keys(state.schedulers).length} jobs loaded`);
2246
2320
  } catch (error) {
2247
- logger.error(`${logSymbols7.error} ${chalk9.red("Failed to initialize scheduler:")} ${error.message}`);
2321
+ logger.error(`Failed to initialize scheduler: ${error.message}`);
2248
2322
  throw error;
2249
2323
  }
2250
2324
  };
2251
2325
 
2252
2326
  // src/schedule-plugin/jobs.ts
2253
- import chalk10 from "chalk";
2254
- import logSymbols8 from "log-symbols";
2255
2327
  var validateJobDefinition = (jobDef) => {
2256
2328
  const expressionType = detectExpressionType(jobDef.cronExpression);
2257
2329
  if (expressionType === "unknown") {
2258
- logger.error(`${logSymbols8.error} ${chalk10.red("Invalid cron expression for job:")} ${jobDef.name}`);
2330
+ logger.error(`Invalid cron expression for job: ${jobDef.name}`);
2259
2331
  throw new Error(`Invalid cron expression for job: ${jobDef.name}`);
2260
2332
  }
2261
2333
  };
@@ -2267,11 +2339,11 @@ var createJobFromDefinition = (jobDef, config) => {
2267
2339
  const result = parseCronExpression(cronExpression, void 0, {
2268
2340
  timezone: jobDef.timezone ?? config.cron.defaultTimezone
2269
2341
  });
2270
- logger.debug(`${chalk10.blue("\u{1F4C5} Job")} ${chalk10.green(jobDef.name)}: ${result.description} - Next: ${chalk10.cyan(result.nextRun.toLocaleString())}`);
2342
+ logger.debug(`Job ${jobDef.name}: ${result.description} - Next: ${result.nextRun.toLocaleString()}`);
2271
2343
  const upcoming = getNextExecutions(cronExpression, 3, {
2272
2344
  timezone: jobDef.timezone ?? config.cron.defaultTimezone
2273
2345
  });
2274
- logger.debug(`${chalk10.blue(" Upcoming:")} ${upcoming.map((d) => d.toLocaleTimeString()).join(", ")}`);
2346
+ logger.debug(`Upcoming: ${upcoming.map((d) => d.toLocaleTimeString()).join(", ")}`);
2275
2347
  }
2276
2348
  const job = {
2277
2349
  id: generateJobId(),
@@ -2391,8 +2463,6 @@ var registerAllRoutes = (app, state, executeJobFn, scheduleJobFn) => {
2391
2463
  };
2392
2464
 
2393
2465
  // src/schedule-plugin/decorator.ts
2394
- import chalk11 from "chalk";
2395
- import logSymbols9 from "log-symbols";
2396
2466
  var isValidJobName = (jobName) => {
2397
2467
  return typeof jobName === "string" && jobName.length > 0 && /^[a-zA-Z0-9_-]+$/.test(jobName);
2398
2468
  };
@@ -2422,7 +2492,7 @@ var createSchedulerManager = ({
2422
2492
  validateJobDefinition(jobDefinition);
2423
2493
  const existingJob = Object.values(state.schedulers).find((s) => s.job.name === jobDefinition.name);
2424
2494
  if (existingJob) {
2425
- logger.warn(`${logSymbols9.warning} ${chalk11.yellow("Job already exists:")} ${chalk11.magenta(jobDefinition.name)}.`);
2495
+ logger.warn(`Job already exists: ${jobDefinition.name}.`);
2426
2496
  return existingJob.job.id;
2427
2497
  }
2428
2498
  const job = createJobFromDefinition(jobDefinition, config);
@@ -2431,10 +2501,10 @@ var createSchedulerManager = ({
2431
2501
  if (job.enabled) {
2432
2502
  scheduleJobFn(scheduler);
2433
2503
  }
2434
- logger.info(`${logSymbols9.success} ${chalk11.green("Job added:")} ${chalk11.magenta(jobDefinition.name)} (${job.id})`);
2504
+ logger.info(`Job added: ${jobDefinition.name} (${job.id})`);
2435
2505
  return job.id;
2436
2506
  } catch (error) {
2437
- logger.error(`${logSymbols9.error} ${chalk11.red("Failed to add job")} ${chalk11.magenta(jobDefinition.name)}: ${error.message}`);
2507
+ logger.error(`Failed to add job ${jobDefinition.name}: ${error.message}`);
2438
2508
  throw error;
2439
2509
  }
2440
2510
  };
@@ -2446,15 +2516,15 @@ var createSchedulerManager = ({
2446
2516
  throw new Error(`Job '${jobName}' does not exist`);
2447
2517
  }
2448
2518
  if (scheduler.isRunning) {
2449
- logger.warn(`${logSymbols9.warning} ${chalk11.yellow("Removing job that is currently running:")} ${chalk11.magenta(jobName)}`);
2519
+ logger.warn(`Removing job that is currently running: ${jobName}`);
2450
2520
  }
2451
2521
  if (scheduler.timerId) {
2452
2522
  clearTimeout(scheduler.timerId);
2453
2523
  }
2454
2524
  delete state.schedulers[scheduler.job.id];
2455
- logger.info(`${logSymbols9.success} ${chalk11.green("Job removed:")} ${chalk11.magenta(jobName)}`);
2525
+ logger.info(`Job removed: ${jobName}`);
2456
2526
  } catch (error) {
2457
- logger.error(`${logSymbols9.error} ${chalk11.red("Failed to remove job")} ${chalk11.magenta(jobName)}: ${error.message}`);
2527
+ logger.error(`Failed to remove job ${jobName}: ${error.message}`);
2458
2528
  throw error;
2459
2529
  }
2460
2530
  };
@@ -2466,8 +2536,8 @@ var createSchedulerManager = ({
2466
2536
  return false;
2467
2537
  }
2468
2538
  };
2469
- const listJobs = (module2) => {
2470
- return Object.values(state.schedulers).filter((s) => !module2 || s.job.module === module2).map((s) => s.job.name).sort();
2539
+ const listJobs = (module) => {
2540
+ return Object.values(state.schedulers).filter((s) => !module || s.job.module === module).map((s) => s.job.name).sort();
2471
2541
  };
2472
2542
  const getJobStats = (jobName) => {
2473
2543
  try {
@@ -2486,14 +2556,14 @@ var createSchedulerManager = ({
2486
2556
  throw new Error(`Job '${jobName}' does not exist`);
2487
2557
  }
2488
2558
  if (scheduler.job.enabled) {
2489
- logger.debug(`${logSymbols9.info} ${chalk11.blue("Job is already enabled:")} ${chalk11.magenta(jobName)}`);
2559
+ logger.debug(`Job is already enabled: ${jobName}`);
2490
2560
  return;
2491
2561
  }
2492
2562
  scheduler.job.enabled = true;
2493
2563
  scheduleJobFn(scheduler);
2494
- logger.info(`${logSymbols9.success} ${chalk11.green("Job enabled:")} ${chalk11.magenta(jobName)}`);
2564
+ logger.info(`Job enabled: ${jobName}`);
2495
2565
  } catch (error) {
2496
- logger.error(`${logSymbols9.error} ${chalk11.red("Failed to enable job")} ${chalk11.magenta(jobName)}: ${error.message}`);
2566
+ logger.error(`Failed to enable job ${jobName}: ${error.message}`);
2497
2567
  throw error;
2498
2568
  }
2499
2569
  };
@@ -2505,7 +2575,7 @@ var createSchedulerManager = ({
2505
2575
  throw new Error(`Job '${jobName}' does not exist`);
2506
2576
  }
2507
2577
  if (!scheduler.job.enabled) {
2508
- logger.debug(`${logSymbols9.info} ${chalk11.blue("Job is already disabled:")} ${chalk11.magenta(jobName)}`);
2578
+ logger.debug(`Job is already disabled: ${jobName}`);
2509
2579
  return;
2510
2580
  }
2511
2581
  scheduler.job.enabled = false;
@@ -2513,9 +2583,9 @@ var createSchedulerManager = ({
2513
2583
  clearTimeout(scheduler.timerId);
2514
2584
  scheduler.timerId = void 0;
2515
2585
  }
2516
- logger.info(`${logSymbols9.success} ${chalk11.green("Job disabled:")} ${chalk11.magenta(jobName)}`);
2586
+ logger.info(`Job disabled: ${jobName}`);
2517
2587
  } catch (error) {
2518
- logger.error(`${logSymbols9.error} ${chalk11.red("Failed to disable job")} ${chalk11.magenta(jobName)}: ${error.message}`);
2588
+ logger.error(`Failed to disable job ${jobName}: ${error.message}`);
2519
2589
  throw error;
2520
2590
  }
2521
2591
  };
@@ -2530,9 +2600,9 @@ var createSchedulerManager = ({
2530
2600
  throw new Error(`Job '${jobName}' is already running`);
2531
2601
  }
2532
2602
  setImmediate(() => executeJob(scheduler));
2533
- logger.info(`${logSymbols9.success} ${chalk11.green("Job triggered:")} ${chalk11.magenta(jobName)}`);
2603
+ logger.info(`Job triggered: ${jobName}`);
2534
2604
  } catch (error) {
2535
- logger.error(`${logSymbols9.error} ${chalk11.red("Failed to trigger job")} ${chalk11.magenta(jobName)}: ${error.message}`);
2605
+ logger.error(`Failed to trigger job ${jobName}: ${error.message}`);
2536
2606
  throw error;
2537
2607
  }
2538
2608
  };
@@ -2572,10 +2642,141 @@ var schedulerPlugin = fsPlugin2(async (app, options) => {
2572
2642
  registerAllRoutes(app, state, executeJob, scheduleJobFn);
2573
2643
  });
2574
2644
 
2645
+ // src/websocket-plugin/plugin.ts
2646
+ import crypto from "crypto";
2647
+ import fsPlugin3 from "fastify-plugin";
2648
+ import websocketPlugin from "@fastify/websocket";
2649
+ var DEFAULT_CONFIG3 = {
2650
+ routeKeyField: "action"
2651
+ };
2652
+ function mergeConfig3(defaults, overrides) {
2653
+ return { ...defaults, ...overrides };
2654
+ }
2655
+ var websocketsPlugin = fsPlugin3(async (app, options) => {
2656
+ const config = mergeConfig3(DEFAULT_CONFIG3, options.config);
2657
+ const connections = /* @__PURE__ */ new Map();
2658
+ const handlers = [];
2659
+ const registeredPaths = /* @__PURE__ */ new Set();
2660
+ const pathModuleMap = /* @__PURE__ */ new Map();
2661
+ await app.register(websocketPlugin);
2662
+ function ensureRouteForPath(path4) {
2663
+ if (registeredPaths.has(path4)) return;
2664
+ registeredPaths.add(path4);
2665
+ app.get(path4, {
2666
+ websocket: true,
2667
+ preHandler: async (request, reply) => {
2668
+ const connectionId = crypto.randomUUID();
2669
+ request._wsConnectionId = connectionId;
2670
+ const connectHandlers = handlers.filter((h) => h.path === path4 && h.event === "connect");
2671
+ for (const h of connectHandlers) {
2672
+ await h.handler(connectionId, "connect", null, request, reply);
2673
+ }
2674
+ if (reply.statusCode !== 200)
2675
+ return reply;
2676
+ }
2677
+ }, (socket, request) => {
2678
+ const connectionId = request._wsConnectionId ?? crypto.randomUUID();
2679
+ const connection = {
2680
+ connectionId,
2681
+ socket,
2682
+ path: path4,
2683
+ connectedAt: /* @__PURE__ */ new Date()
2684
+ };
2685
+ connections.set(connectionId, connection);
2686
+ const pathHandlers = () => handlers.filter((h) => h.path === path4);
2687
+ socket.on("message", (raw) => {
2688
+ const data = raw.toString();
2689
+ const currentHandlers = pathHandlers();
2690
+ let routeKey;
2691
+ try {
2692
+ const parsed = JSON.parse(data);
2693
+ routeKey = parsed?.[config.routeKeyField];
2694
+ } catch {
2695
+ }
2696
+ let matched = false;
2697
+ if (routeKey) {
2698
+ const routeHandlers = currentHandlers.filter(
2699
+ (h) => h.event === "message" && h.route === routeKey
2700
+ );
2701
+ for (const h of routeHandlers) {
2702
+ matched = true;
2703
+ h.handler(connectionId, "message", data, request).catch((e) => {
2704
+ logger.error(e);
2705
+ });
2706
+ }
2707
+ }
2708
+ if (!matched) {
2709
+ const defaultHandlers = currentHandlers.filter(
2710
+ (h) => h.event === "message" && !h.route
2711
+ );
2712
+ for (const h of defaultHandlers) {
2713
+ h.handler(connectionId, "message", data, request).catch((e) => {
2714
+ logger.error(e);
2715
+ });
2716
+ }
2717
+ }
2718
+ });
2719
+ socket.on("close", () => {
2720
+ const disconnectHandlers = pathHandlers().filter((h) => h.event === "disconnect");
2721
+ for (const h of disconnectHandlers) {
2722
+ h.handler(connectionId, "disconnect", null, request).catch((e) => {
2723
+ logger.error(e);
2724
+ });
2725
+ }
2726
+ connections.delete(connectionId);
2727
+ });
2728
+ });
2729
+ }
2730
+ const manager = {
2731
+ registerHandler(handler) {
2732
+ handlers.push(handler);
2733
+ if (!pathModuleMap.has(handler.path)) {
2734
+ pathModuleMap.set(handler.path, handler.module);
2735
+ }
2736
+ ensureRouteForPath(handler.path);
2737
+ },
2738
+ getConnections(path4) {
2739
+ const allConnections = Array.from(connections.values());
2740
+ if (path4) {
2741
+ return allConnections.filter((c) => c.path === path4);
2742
+ }
2743
+ return allConnections;
2744
+ },
2745
+ getRegisteredPaths(module) {
2746
+ const all = Array.from(pathModuleMap.entries()).map(([path4, mod]) => ({ path: path4, module: mod }));
2747
+ if (module) {
2748
+ return all.filter((p) => p.module === module);
2749
+ }
2750
+ return all;
2751
+ },
2752
+ async sendToClient(connectionId, data) {
2753
+ const connection = connections.get(connectionId);
2754
+ if (!connection) {
2755
+ throw new Error(`WebSocket connection ${connectionId} not found`);
2756
+ }
2757
+ const payload = typeof data === "string" ? data : JSON.stringify(data);
2758
+ connection.socket.send(payload);
2759
+ },
2760
+ async disconnect(connectionId) {
2761
+ const connection = connections.get(connectionId);
2762
+ if (!connection) {
2763
+ throw new Error(`WebSocket connection ${connectionId} not found`);
2764
+ }
2765
+ connection.socket.close();
2766
+ }
2767
+ };
2768
+ app.decorate("websockets", manager);
2769
+ });
2770
+
2575
2771
  // src/dev-console-plugin/route-registry.ts
2576
- var RouteRegistry = class {
2772
+ var RouteRegistry = class _RouteRegistry {
2577
2773
  routes = [];
2774
+ static IGNORED_METHODS = /* @__PURE__ */ new Set(["OPTIONS", "HEAD"]);
2578
2775
  register(routeOptions) {
2776
+ const methods = Array.isArray(routeOptions.method) ? routeOptions.method : [routeOptions.method];
2777
+ if (methods.every((m) => _RouteRegistry.IGNORED_METHODS.has(m.toUpperCase()))) {
2778
+ return;
2779
+ }
2579
2780
  const routeInfo = {
2580
2781
  method: routeOptions.method,
2581
2782
  url: routeOptions.url,
@@ -2621,17 +2822,6 @@ var LogStore = class {
2621
2822
  getLogs(limit = 100) {
2622
2823
  return this.logs.slice(0, limit);
2623
2824
  }
2624
- getLogsByLevel(level, limit = 100) {
2625
- return this.logs.filter((log) => log.level === level).slice(0, limit);
2626
- }
2627
- getLogsByModule(module2, limit = 100) {
2628
- return this.logs.filter((log) => log.module === module2).slice(0, limit);
2629
- }
2630
- getLogsByTrigger(triggerType, triggerName, limit = 100) {
2631
- return this.logs.filter(
2632
- (log) => log.triggerType === triggerType && log.trigger === triggerName
2633
- ).slice(0, limit);
2634
- }
2635
2825
  clear() {
2636
2826
  this.logs = [];
2637
2827
  }
@@ -2643,59 +2833,26 @@ var LogStore = class {
2643
2833
  }
2644
2834
  };
2645
2835
  var logStore = new LogStore();
2646
- var originalConsole = {
2647
- log: console.log,
2648
- error: console.error,
2649
- warn: console.warn,
2650
- info: console.info,
2651
- debug: console.debug
2652
- };
2653
- var captureConsoleLog = (level, originalMethod) => {
2654
- return (...args) => {
2655
- originalMethod.apply(console, args);
2656
- const message = args.join(" ");
2657
- let source = "unknown";
2658
- let module2;
2659
- let trigger;
2660
- let triggerType;
2661
- if (message.includes("Queue") || message.includes("queue")) {
2662
- source = "queue";
2663
- triggerType = "queue";
2664
- const queueMatch = message.match(/queue[:\s]+([a-zA-Z0-9_-]+)/i);
2665
- if (queueMatch) trigger = queueMatch[1];
2666
- } else if (message.includes("Schedule") || message.includes("job")) {
2667
- source = "schedule";
2668
- triggerType = "schedule";
2669
- const jobMatch = message.match(/(?:job|schedule)[:\s]+([a-zA-Z0-9_-]+)/i);
2670
- if (jobMatch) trigger = jobMatch[1];
2671
- } else if (message.includes("HTTP") || message.includes("api") || message.includes("/api/")) {
2672
- source = "http";
2673
- triggerType = "http";
2674
- const routeMatch = message.match(/\/api\/[^\s]+/);
2675
- if (routeMatch) trigger = routeMatch[0];
2676
- }
2677
- 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);
2678
- if (moduleMatch) module2 = moduleMatch[1];
2679
- logStore.addLog({
2680
- id: Date.now().toString() + Math.random().toString(36).substr(2, 9),
2681
- timestamp: /* @__PURE__ */ new Date(),
2682
- level,
2683
- message: message.replace(/\x1b\[[0-9;]*m/g, ""),
2684
- // Remove ANSI colors
2685
- source,
2686
- module: module2,
2687
- trigger,
2688
- triggerType
2689
- });
2690
- };
2691
- };
2692
- console.error = captureConsoleLog("error", originalConsole.error);
2693
- console.warn = captureConsoleLog("warn", originalConsole.warn);
2694
- console.info = captureConsoleLog("info", originalConsole.info);
2695
- console.log = captureConsoleLog("info", originalConsole.log);
2696
- console.debug = captureConsoleLog("debug", originalConsole.debug);
2697
2836
  async function devConsolePluginFunction(fastify, options = {}) {
2698
2837
  const { prefix = "console", enableUI = true } = options;
2838
+ const upstream = getWriter();
2839
+ setWriter((entry) => {
2840
+ logStore.addLog({
2841
+ id: Date.now().toString() + Math.random().toString(36).slice(2, 9),
2842
+ timestamp: new Date(entry.time),
2843
+ levelName: entry.levelName,
2844
+ message: entry.msg,
2845
+ meta: entry.meta,
2846
+ module: entry.module,
2847
+ reqId: entry.reqId
2848
+ });
2849
+ upstream(entry);
2850
+ });
2851
+ fastify.addHook("onClose", (_instance, done) => {
2852
+ setWriter(upstream);
2853
+ logStore.clear();
2854
+ done();
2855
+ });
2699
2856
  fastify.addHook("onRoute", (routeOptions) => {
2700
2857
  if (routeOptions.prefix === "/api") {
2701
2858
  routeRegistry.register(routeOptions);
@@ -2717,7 +2874,8 @@ async function devConsolePluginFunction(fastify, options = {}) {
2717
2874
  fastify.get(`/${prefix}/modules`, async (_, reply) => {
2718
2875
  const queueManager = fastify.queues;
2719
2876
  const schedulerManager = fastify.scheduler;
2720
- if (!queueManager || !schedulerManager) {
2877
+ const wsManager = fastify.websockets;
2878
+ if (!queueManager || !schedulerManager || !wsManager) {
2721
2879
  return reply.status(503).send({ error: "Services not available" });
2722
2880
  }
2723
2881
  const allRoutes = routeRegistry.getAll();
@@ -2736,6 +2894,9 @@ async function devConsolePluginFunction(fastify, options = {}) {
2736
2894
  const jobStats = schedulerManager.getJobStats(jobName);
2737
2895
  if (jobStats?.job.module) moduleSet.add(jobStats.job.module);
2738
2896
  });
2897
+ wsManager.getRegisteredPaths().forEach((p) => {
2898
+ if (p.module) moduleSet.add(p.module);
2899
+ });
2739
2900
  const modules = Array.from(moduleSet).map((moduleName) => {
2740
2901
  const moduleRoutes = httpRoutes.filter((route) => route.module === moduleName);
2741
2902
  const moduleQueueNames = queueManager.listQueues(moduleName);
@@ -2761,11 +2922,16 @@ async function devConsolePluginFunction(fastify, options = {}) {
2761
2922
  timezone: jobStats?.job.timezone
2762
2923
  };
2763
2924
  });
2925
+ const moduleWebSockets = wsManager ? wsManager.getRegisteredPaths(moduleName).map((p) => ({
2926
+ path: p.path,
2927
+ connectionCount: wsManager.getConnections(p.path).length
2928
+ })) : [];
2764
2929
  return {
2765
2930
  name: moduleName,
2766
2931
  routes: moduleRoutes,
2767
2932
  queues: moduleQueues,
2768
- schedules: moduleSchedules
2933
+ schedules: moduleSchedules,
2934
+ websockets: moduleWebSockets
2769
2935
  };
2770
2936
  });
2771
2937
  return { modules };
@@ -2883,7 +3049,7 @@ async function devConsolePluginFunction(fastify, options = {}) {
2883
3049
  }
2884
3050
  });
2885
3051
  fastify.post(`/${prefix}/queues`, async (request, reply) => {
2886
- const { queueName, module: module2 } = request.body;
3052
+ const { queueName, module } = request.body;
2887
3053
  const queueManager = fastify.queues;
2888
3054
  if (!queueManager) {
2889
3055
  return reply.status(503).send({ error: "Queue service not available" });
@@ -2894,8 +3060,9 @@ async function devConsolePluginFunction(fastify, options = {}) {
2894
3060
  try {
2895
3061
  const handler = async (message) => {
2896
3062
  console.log(`Processing message in ${queueName}:`, message);
3063
+ return void 0;
2897
3064
  };
2898
- await queueManager.addQueue(queueName, handler, module2);
3065
+ await queueManager.addQueue(queueName, handler, module);
2899
3066
  return reply.status(201).send({
2900
3067
  status: "success",
2901
3068
  message: `Queue ${queueName} created successfully`,
@@ -2995,27 +3162,18 @@ async function devConsolePluginFunction(fastify, options = {}) {
2995
3162
  const {
2996
3163
  limit = 100,
2997
3164
  level,
2998
- source,
2999
- module: module2,
3000
- trigger,
3001
- triggerType
3165
+ module,
3166
+ reqId
3002
3167
  } = request.query;
3003
3168
  let logs = logStore.getLogs(Number(limit));
3004
3169
  if (level) {
3005
- logs = logs.filter((log) => log.level === level);
3170
+ logs = logs.filter((log) => log.levelName === level);
3006
3171
  }
3007
- if (source) {
3008
- logs = logs.filter((log) => log.source === source);
3172
+ if (module) {
3173
+ logs = logs.filter((log) => log.module === module);
3009
3174
  }
3010
- if (module2) {
3011
- logs = logs.filter(
3012
- (log) => log.module === module2 || log.message.toLowerCase().includes(module2.toLowerCase())
3013
- );
3014
- }
3015
- if (trigger && triggerType) {
3016
- logs = logs.filter(
3017
- (log) => log.trigger === trigger && log.triggerType === triggerType || log.message.toLowerCase().includes(trigger.toLowerCase())
3018
- );
3175
+ if (reqId) {
3176
+ logs = logs.filter((log) => log.reqId === reqId);
3019
3177
  }
3020
3178
  return { logs };
3021
3179
  });
@@ -3023,6 +3181,50 @@ async function devConsolePluginFunction(fastify, options = {}) {
3023
3181
  logStore.clear();
3024
3182
  return { status: "success", message: "Logs cleared" };
3025
3183
  });
3184
+ fastify.get(`/${prefix}/websockets`, async (_, reply) => {
3185
+ const wsManager = fastify.websockets;
3186
+ if (!wsManager) {
3187
+ return reply.status(503).send({ error: "WebSocket service not available" });
3188
+ }
3189
+ const connections = wsManager.getConnections();
3190
+ const pathSet = new Set(connections.map((c) => c.path));
3191
+ const paths = Array.from(pathSet).map((p) => ({
3192
+ path: p,
3193
+ connections: wsManager.getConnections(p).map((c) => ({
3194
+ connectionId: c.connectionId,
3195
+ path: c.path,
3196
+ connectedAt: c.connectedAt
3197
+ }))
3198
+ }));
3199
+ return { paths };
3200
+ });
3201
+ fastify.get(`/${prefix}/websockets/:path`, async (request, reply) => {
3202
+ const wsManager = fastify.websockets;
3203
+ if (!wsManager) {
3204
+ return reply.status(503).send({ error: "WebSocket service not available" });
3205
+ }
3206
+ const { path: wsPath } = request.params;
3207
+ const decodedPath = "/" + wsPath;
3208
+ const connections = wsManager.getConnections(decodedPath).map((c) => ({
3209
+ connectionId: c.connectionId,
3210
+ path: c.path,
3211
+ connectedAt: c.connectedAt
3212
+ }));
3213
+ return { path: decodedPath, connections };
3214
+ });
3215
+ fastify.post(`/${prefix}/websockets/:connectionId/send`, async (request, reply) => {
3216
+ const wsManager = fastify.websockets;
3217
+ if (!wsManager) {
3218
+ return reply.status(503).send({ error: "WebSocket service not available" });
3219
+ }
3220
+ const { connectionId } = request.params;
3221
+ try {
3222
+ await wsManager.sendToClient(connectionId, request.body);
3223
+ return reply.status(200).send({ status: "success", message: `Message sent to ${connectionId}` });
3224
+ } catch (error) {
3225
+ return reply.status(404).send({ error: error.message });
3226
+ }
3227
+ });
3026
3228
  fastify.get(`/${prefix}/logs/stream`, async (request, reply) => {
3027
3229
  reply.type("text/event-stream");
3028
3230
  reply.header("Cache-Control", "no-cache");
@@ -3047,14 +3249,15 @@ async function devConsolePluginFunction(fastify, options = {}) {
3047
3249
  );
3048
3250
  await fastify.register(fastifyStatic, {
3049
3251
  root: devConsolePath,
3050
- decorateReply: true
3252
+ decorateReply: true,
3253
+ prefix: `/${prefix}/`
3051
3254
  });
3052
3255
  fastify.get(`/${prefix}`, async (_, reply) => {
3053
3256
  return reply.sendFile("index.html");
3054
3257
  });
3055
3258
  }
3056
3259
  }
3057
- var devConsolePlugin = fsPlugin3(devConsolePluginFunction, {
3260
+ var devConsolePlugin = fsPlugin4(devConsolePluginFunction, {
3058
3261
  name: "dev-console-plugin"
3059
3262
  });
3060
3263
  export {