@gravito/zenith 1.0.0-beta.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/bin.js +436 -43
  3. package/dist/client/assets/index-C332gZ-J.css +1 -0
  4. package/dist/client/assets/{index-oXEse8ih.js → index-D4HibwTK.js} +88 -88
  5. package/dist/client/index.html +2 -2
  6. package/dist/server/index.js +436 -43
  7. package/docs/LARAVEL_ZENITH_ROADMAP.md +109 -0
  8. package/{QUASAR_MASTER_PLAN.md → docs/QUASAR_MASTER_PLAN.md} +6 -3
  9. package/package.json +1 -1
  10. package/scripts/debug_redis_keys.ts +24 -0
  11. package/src/client/App.tsx +1 -1
  12. package/src/client/Layout.tsx +11 -12
  13. package/src/client/WorkerStatus.tsx +97 -56
  14. package/src/client/components/BrandIcons.tsx +119 -44
  15. package/src/client/components/ConfirmDialog.tsx +0 -1
  16. package/src/client/components/JobInspector.tsx +18 -6
  17. package/src/client/components/PageHeader.tsx +32 -28
  18. package/src/client/pages/OverviewPage.tsx +0 -1
  19. package/src/client/pages/PulsePage.tsx +422 -340
  20. package/src/client/pages/SettingsPage.tsx +69 -15
  21. package/src/client/pages/WorkersPage.tsx +70 -2
  22. package/src/server/index.ts +171 -11
  23. package/src/server/services/QueueService.ts +6 -3
  24. package/src/shared/types.ts +2 -0
  25. package/ARCHITECTURE.md +0 -88
  26. package/BATCH_OPERATIONS_IMPLEMENTATION.md +0 -159
  27. package/EVOLUTION_BLUEPRINT.md +0 -112
  28. package/JOBINSPECTOR_SCROLL_FIX.md +0 -152
  29. package/TESTING_BATCH_OPERATIONS.md +0 -252
  30. package/dist/client/assets/index-BSTyMCFd.css +0 -1
  31. /package/{ALERTING_GUIDE.md → docs/ALERTING_GUIDE.md} +0 -0
  32. /package/{DEPLOYMENT.md → docs/DEPLOYMENT.md} +0 -0
  33. /package/{DOCS_INTERNAL.md → docs/DOCS_INTERNAL.md} +0 -0
  34. /package/{QUICK_TEST_GUIDE.md → docs/QUICK_TEST_GUIDE.md} +0 -0
  35. /package/{ROADMAP.md → docs/ROADMAP.md} +0 -0
@@ -68748,19 +68748,19 @@ class Grammar {
68748
68748
  return `INSERT INTO ${this.wrapTable(query.table)} (${columnList}) VALUES ${valuesList}`;
68749
68749
  }
68750
68750
  compileUpdate(query, values) {
68751
- const columns = Object.keys(values);
68752
68751
  let bindingIndex = 0;
68753
- const setClause = columns.map((col) => {
68752
+ const setClause = Object.entries(values).map(([col, value]) => {
68753
+ if (value instanceof Expression) {
68754
+ return `${this.wrapColumn(col)} = ${value.getValue()}`;
68755
+ }
68754
68756
  const placeholder = this.getPlaceholder(bindingIndex);
68755
68757
  bindingIndex++;
68756
68758
  return `${this.wrapColumn(col)} = ${placeholder}`;
68757
68759
  }).join(", ");
68758
68760
  let sql = `UPDATE ${this.wrapTable(query.table)} SET ${setClause}`;
68759
68761
  if (query.wheres.length > 0) {
68760
- const whereBindingsOffset = columns.length;
68761
- const offsetQuery = { ...query, bindings: query.bindings.slice(whereBindingsOffset) };
68762
- const wheres = this.compileWheres(offsetQuery);
68763
- sql += ` ${this.offsetPlaceholders(wheres, whereBindingsOffset)}`;
68762
+ const wheres = this.compileWheres(query, bindingIndex);
68763
+ sql += ` ${wheres}`;
68764
68764
  }
68765
68765
  return sql;
68766
68766
  }
@@ -70366,7 +70366,14 @@ class QueryBuilder {
70366
70366
  return id;
70367
70367
  }
70368
70368
  async update(data) {
70369
- const values = Object.values(data);
70369
+ const values = [];
70370
+ for (const value of Object.values(data)) {
70371
+ if (value instanceof Expression) {
70372
+ values.push(...value.getBindings());
70373
+ } else {
70374
+ values.push(value);
70375
+ }
70376
+ }
70370
70377
  const allBindings = [...values, ...this.bindingsList];
70371
70378
  const compiled = this.getCompiledQuery();
70372
70379
  compiled.bindings = allBindings;
@@ -71472,7 +71479,7 @@ var require_dist_cjs = __commonJS((exports) => {
71472
71479
 
71473
71480
  // ../../node_modules/.bun/@smithy+protocol-http@5.3.7/node_modules/@smithy/protocol-http/dist-cjs/index.js
71474
71481
  var require_dist_cjs2 = __commonJS((exports) => {
71475
- var types3 = require_dist_cjs();
71482
+ var types4 = require_dist_cjs();
71476
71483
  var getHttpHandlerExtensionConfiguration = (runtimeConfig) => {
71477
71484
  return {
71478
71485
  setHttpHandler(handler) {
@@ -71499,7 +71506,7 @@ var require_dist_cjs2 = __commonJS((exports) => {
71499
71506
  name;
71500
71507
  kind;
71501
71508
  values;
71502
- constructor({ name, kind = types3.FieldPosition.HEADER, values = [] }) {
71509
+ constructor({ name, kind = types4.FieldPosition.HEADER, values = [] }) {
71503
71510
  this.name = name;
71504
71511
  this.kind = kind;
71505
71512
  this.values = values;
@@ -73986,8 +73993,8 @@ var require_dist_cjs16 = __commonJS((exports) => {
73986
73993
 
73987
73994
  // ../../node_modules/.bun/@smithy+util-middleware@4.2.7/node_modules/@smithy/util-middleware/dist-cjs/index.js
73988
73995
  var require_dist_cjs17 = __commonJS((exports) => {
73989
- var types3 = require_dist_cjs();
73990
- var getSmithyContext = (context) => context[types3.SMITHY_CONTEXT_KEY] || (context[types3.SMITHY_CONTEXT_KEY] = {});
73996
+ var types4 = require_dist_cjs();
73997
+ var getSmithyContext = (context) => context[types4.SMITHY_CONTEXT_KEY] || (context[types4.SMITHY_CONTEXT_KEY] = {});
73991
73998
  var normalizeProvider = (input) => {
73992
73999
  if (typeof input === "function")
73993
74000
  return input;
@@ -76932,7 +76939,7 @@ var require_protocols = __commonJS((exports) => {
76932
76939
  var require_dist_cjs19 = __commonJS((exports) => {
76933
76940
  var middlewareStack = require_dist_cjs6();
76934
76941
  var protocols = require_protocols();
76935
- var types3 = require_dist_cjs();
76942
+ var types4 = require_dist_cjs();
76936
76943
  var schema2 = require_schema();
76937
76944
  var serde = require_serde();
76938
76945
 
@@ -77031,7 +77038,7 @@ var require_dist_cjs19 = __commonJS((exports) => {
77031
77038
  commandName,
77032
77039
  inputFilterSensitiveLog,
77033
77040
  outputFilterSensitiveLog,
77034
- [types3.SMITHY_CONTEXT_KEY]: {
77041
+ [types4.SMITHY_CONTEXT_KEY]: {
77035
77042
  commandInstance: this,
77036
77043
  ...smithyContext
77037
77044
  },
@@ -77256,8 +77263,8 @@ var require_dist_cjs19 = __commonJS((exports) => {
77256
77263
  };
77257
77264
  var getChecksumConfiguration = (runtimeConfig) => {
77258
77265
  const checksumAlgorithms = [];
77259
- for (const id in types3.AlgorithmId) {
77260
- const algorithmId = types3.AlgorithmId[id];
77266
+ for (const id in types4.AlgorithmId) {
77267
+ const algorithmId = types4.AlgorithmId[id];
77261
77268
  if (runtimeConfig[algorithmId] === undefined) {
77262
77269
  continue;
77263
77270
  }
@@ -77765,12 +77772,12 @@ var require_dist_cjs20 = __commonJS((exports) => {
77765
77772
 
77766
77773
  // ../../node_modules/.bun/@smithy+core@3.20.0/node_modules/@smithy/core/dist-cjs/index.js
77767
77774
  var require_dist_cjs21 = __commonJS((exports) => {
77768
- var types3 = require_dist_cjs();
77775
+ var types4 = require_dist_cjs();
77769
77776
  var utilMiddleware = require_dist_cjs17();
77770
77777
  var middlewareSerde = require_dist_cjs20();
77771
77778
  var protocolHttp = require_dist_cjs2();
77772
77779
  var protocols = require_protocols();
77773
- var getSmithyContext = (context) => context[types3.SMITHY_CONTEXT_KEY] || (context[types3.SMITHY_CONTEXT_KEY] = {});
77780
+ var getSmithyContext = (context) => context[types4.SMITHY_CONTEXT_KEY] || (context[types4.SMITHY_CONTEXT_KEY] = {});
77774
77781
  var resolveAuthOptions = (candidateAuthOptions, authSchemePreference) => {
77775
77782
  if (!authSchemePreference || authSchemePreference.length === 0) {
77776
77783
  return candidateAuthOptions;
@@ -77985,9 +77992,9 @@ var require_dist_cjs21 = __commonJS((exports) => {
77985
77992
  throw new Error("request could not be signed with `apiKey` since the `apiKey` is not defined");
77986
77993
  }
77987
77994
  const clonedRequest = protocolHttp.HttpRequest.clone(httpRequest);
77988
- if (signingProperties.in === types3.HttpApiKeyAuthLocation.QUERY) {
77995
+ if (signingProperties.in === types4.HttpApiKeyAuthLocation.QUERY) {
77989
77996
  clonedRequest.query[signingProperties.name] = identity.apiKey;
77990
- } else if (signingProperties.in === types3.HttpApiKeyAuthLocation.HEADER) {
77997
+ } else if (signingProperties.in === types4.HttpApiKeyAuthLocation.HEADER) {
77991
77998
  clonedRequest.headers[signingProperties.name] = signingProperties.scheme ? `${signingProperties.scheme} ${identity.apiKey}` : identity.apiKey;
77992
77999
  } else {
77993
78000
  throw new Error("request can only be signed with `apiKey` locations `query` or `header`, " + "but found: `" + signingProperties.in + "`");
@@ -78097,7 +78104,7 @@ var require_dist_cjs21 = __commonJS((exports) => {
78097
78104
 
78098
78105
  // ../../node_modules/.bun/@smithy+util-endpoints@3.2.7/node_modules/@smithy/util-endpoints/dist-cjs/index.js
78099
78106
  var require_dist_cjs22 = __commonJS((exports) => {
78100
- var types3 = require_dist_cjs();
78107
+ var types4 = require_dist_cjs();
78101
78108
 
78102
78109
  class EndpointCache {
78103
78110
  capacity;
@@ -78220,8 +78227,8 @@ var require_dist_cjs22 = __commonJS((exports) => {
78220
78227
  var isSet = (value) => value != null;
78221
78228
  var not = (value) => !value;
78222
78229
  var DEFAULT_PORTS = {
78223
- [types3.EndpointURLScheme.HTTP]: 80,
78224
- [types3.EndpointURLScheme.HTTPS]: 443
78230
+ [types4.EndpointURLScheme.HTTP]: 80,
78231
+ [types4.EndpointURLScheme.HTTPS]: 443
78225
78232
  };
78226
78233
  var parseURL = (value) => {
78227
78234
  const whatwgURL = (() => {
@@ -78250,7 +78257,7 @@ var require_dist_cjs22 = __commonJS((exports) => {
78250
78257
  return null;
78251
78258
  }
78252
78259
  const scheme = protocol.slice(0, -1);
78253
- if (!Object.values(types3.EndpointURLScheme).includes(scheme)) {
78260
+ if (!Object.values(types4.EndpointURLScheme).includes(scheme)) {
78254
78261
  return null;
78255
78262
  }
78256
78263
  const isIp = isIpAddress(hostname);
@@ -84380,7 +84387,7 @@ var require_dist_cjs35 = __commonJS((exports) => {
84380
84387
  var getSSOTokenFilepath = require_getSSOTokenFilepath();
84381
84388
  var getSSOTokenFromFile = require_getSSOTokenFromFile();
84382
84389
  var path = __require("path");
84383
- var types3 = require_dist_cjs();
84390
+ var types4 = require_dist_cjs();
84384
84391
  var readFile = require_readFile();
84385
84392
  var ENV_PROFILE = "AWS_PROFILE";
84386
84393
  var DEFAULT_PROFILE = "default";
@@ -84391,10 +84398,10 @@ var require_dist_cjs35 = __commonJS((exports) => {
84391
84398
  if (indexOfSeparator === -1) {
84392
84399
  return false;
84393
84400
  }
84394
- return Object.values(types3.IniSectionType).includes(key.substring(0, indexOfSeparator));
84401
+ return Object.values(types4.IniSectionType).includes(key.substring(0, indexOfSeparator));
84395
84402
  }).reduce((acc, [key, value]) => {
84396
84403
  const indexOfSeparator = key.indexOf(CONFIG_PREFIX_SEPARATOR);
84397
- const updatedKey = key.substring(0, indexOfSeparator) === types3.IniSectionType.PROFILE ? key.substring(indexOfSeparator + 1) : key;
84404
+ const updatedKey = key.substring(0, indexOfSeparator) === types4.IniSectionType.PROFILE ? key.substring(indexOfSeparator + 1) : key;
84398
84405
  acc[updatedKey] = value;
84399
84406
  return acc;
84400
84407
  }, {
@@ -84420,7 +84427,7 @@ var require_dist_cjs35 = __commonJS((exports) => {
84420
84427
  const matches = prefixKeyRegex.exec(sectionName);
84421
84428
  if (matches) {
84422
84429
  const [, prefix, , name] = matches;
84423
- if (Object.values(types3.IniSectionType).includes(prefix)) {
84430
+ if (Object.values(types4.IniSectionType).includes(prefix)) {
84424
84431
  currentSection = [prefix, name].join(CONFIG_PREFIX_SEPARATOR);
84425
84432
  }
84426
84433
  } else {
@@ -84477,7 +84484,7 @@ var require_dist_cjs35 = __commonJS((exports) => {
84477
84484
  credentialsFile: parsedFiles[1]
84478
84485
  };
84479
84486
  };
84480
- var getSsoSessionData = (data) => Object.entries(data).filter(([key]) => key.startsWith(types3.IniSectionType.SSO_SESSION + CONFIG_PREFIX_SEPARATOR)).reduce((acc, [key, value]) => ({ ...acc, [key.substring(key.indexOf(CONFIG_PREFIX_SEPARATOR) + 1)]: value }), {});
84487
+ var getSsoSessionData = (data) => Object.entries(data).filter(([key]) => key.startsWith(types4.IniSectionType.SSO_SESSION + CONFIG_PREFIX_SEPARATOR)).reduce((acc, [key, value]) => ({ ...acc, [key.substring(key.indexOf(CONFIG_PREFIX_SEPARATOR) + 1)]: value }), {});
84481
84488
  var swallowError = () => ({});
84482
84489
  var loadSsoSessionData = async (init = {}) => readFile.readFile(init.configFilepath ?? getConfigFilepath()).then(parseIni).then(getSsoSessionData).catch(swallowError);
84483
84490
  var mergeConfigFiles = (...files) => {
@@ -113210,6 +113217,8 @@ class Migrator {
113210
113217
  return MigrationClass;
113211
113218
  }
113212
113219
  }
113220
+ // ../atlas/src/OrbitAtlas.ts
113221
+ init_DB();
113213
113222
  // ../atlas/src/orm/model/DirtyTracker.ts
113214
113223
  class DirtyTracker {
113215
113224
  original = new Map;
@@ -115484,6 +115493,155 @@ var Hono2 = class extends Hono {
115484
115493
  }
115485
115494
  };
115486
115495
 
115496
+ // ../quasar/src/bridges/BaseZenithBridge.ts
115497
+ class BaseZenithBridge {
115498
+ redis;
115499
+ prefix;
115500
+ workerId;
115501
+ listeners = [];
115502
+ constructor(redis, prefix = "flux_console:", workerId) {
115503
+ this.redis = redis;
115504
+ this.prefix = prefix;
115505
+ this.workerId = workerId;
115506
+ }
115507
+ async publishLog(payload) {
115508
+ try {
115509
+ const fullPayload = {
115510
+ ...payload,
115511
+ workerId: payload.workerId || this.workerId,
115512
+ timestamp: payload.timestamp || new Date().toISOString()
115513
+ };
115514
+ await this.redis.publish(`${this.prefix}logs`, JSON.stringify(fullPayload));
115515
+ const historyKey = `${this.prefix}logs:history`;
115516
+ if (typeof this.redis.pipeline === "function") {
115517
+ const pipe = this.redis.pipeline();
115518
+ pipe.lpush(historyKey, JSON.stringify(fullPayload));
115519
+ pipe.ltrim(historyKey, 0, 99);
115520
+ await pipe.exec();
115521
+ } else {
115522
+ await this.redis.lpush(historyKey, JSON.stringify(fullPayload));
115523
+ }
115524
+ } catch (err) {
115525
+ console.error("[BaseZenithBridge] Failed to publish log:", err);
115526
+ }
115527
+ }
115528
+ registerListener(target, event, handler) {
115529
+ this.listeners.push({ target, event, handler });
115530
+ }
115531
+ detach() {
115532
+ for (const { target, event, handler } of this.listeners) {
115533
+ if (typeof target.off === "function") {
115534
+ target.off(event, handler);
115535
+ } else if (typeof target.removeListener === "function") {
115536
+ target.removeListener(event, handler);
115537
+ }
115538
+ }
115539
+ this.listeners = [];
115540
+ }
115541
+ }
115542
+ // ../quasar/src/bridges/BeeQueueBridge.ts
115543
+ class BeeQueueBridge extends BaseZenithBridge {
115544
+ attach(queue) {
115545
+ const onSucceeded = async (job, result) => {
115546
+ await this.publishLog({
115547
+ level: "success",
115548
+ message: `Completed job: ${job.id}`,
115549
+ jobId: job.id,
115550
+ context: {
115551
+ data: job.data,
115552
+ result: typeof result === "object" ? JSON.stringify(result) : result
115553
+ }
115554
+ });
115555
+ };
115556
+ const onFailed = async (job, error) => {
115557
+ await this.publishLog({
115558
+ level: "error",
115559
+ message: `Job failed: ${job.id} - ${error.message}`,
115560
+ jobId: job.id,
115561
+ context: {
115562
+ data: job.data,
115563
+ error: error.message,
115564
+ stack: error.stack
115565
+ }
115566
+ });
115567
+ };
115568
+ const onProgress = async (job, progress) => {
115569
+ await this.publishLog({
115570
+ level: "info",
115571
+ message: `Job progress: ${job.id}`,
115572
+ jobId: job.id,
115573
+ context: {
115574
+ data: job.data,
115575
+ progress
115576
+ }
115577
+ });
115578
+ };
115579
+ queue.on("job succeeded", onSucceeded);
115580
+ queue.on("job failed", onFailed);
115581
+ queue.on("job progress", onProgress);
115582
+ this.registerListener(queue, "job succeeded", onSucceeded);
115583
+ this.registerListener(queue, "job failed", onFailed);
115584
+ this.registerListener(queue, "job progress", onProgress);
115585
+ }
115586
+ }
115587
+ // ../quasar/src/bridges/BullMQBridge.ts
115588
+ class BullMQBridge extends BaseZenithBridge {
115589
+ attach(worker) {
115590
+ const onActive = async (job) => {
115591
+ await this.publishLog({
115592
+ level: "info",
115593
+ message: `Processing job: ${job.name || job.id}`,
115594
+ jobId: job.id,
115595
+ context: {
115596
+ name: job.name,
115597
+ data: job.data
115598
+ }
115599
+ });
115600
+ };
115601
+ const onCompleted = async (job, result) => {
115602
+ await this.publishLog({
115603
+ level: "success",
115604
+ message: `Completed job: ${job.name || job.id}`,
115605
+ jobId: job.id,
115606
+ context: {
115607
+ name: job.name,
115608
+ result: typeof result === "object" ? JSON.stringify(result) : result
115609
+ }
115610
+ });
115611
+ };
115612
+ const onFailed = async (job, error) => {
115613
+ await this.publishLog({
115614
+ level: "error",
115615
+ message: `Job failed: ${job?.name || job?.id} - ${error.message}`,
115616
+ jobId: job?.id,
115617
+ context: {
115618
+ name: job?.name,
115619
+ error: error.message,
115620
+ stack: error.stack
115621
+ }
115622
+ });
115623
+ };
115624
+ const onProgress = async (job, progress) => {
115625
+ await this.publishLog({
115626
+ level: "info",
115627
+ message: `Job progress: ${job.name || job.id}`,
115628
+ jobId: job.id,
115629
+ context: {
115630
+ name: job.name,
115631
+ progress
115632
+ }
115633
+ });
115634
+ };
115635
+ worker.on("active", onActive);
115636
+ worker.on("completed", onCompleted);
115637
+ worker.on("failed", onFailed);
115638
+ worker.on("progress", onProgress);
115639
+ this.registerListener(worker, "active", onActive);
115640
+ this.registerListener(worker, "completed", onCompleted);
115641
+ this.registerListener(worker, "failed", onFailed);
115642
+ this.registerListener(worker, "progress", onProgress);
115643
+ }
115644
+ }
115487
115645
  // ../quasar/src/executors/BaseExecutor.ts
115488
115646
  class BaseExecutor {
115489
115647
  success(commandId, message) {
@@ -115723,6 +115881,76 @@ class CommandListener {
115723
115881
  }
115724
115882
  }
115725
115883
  }
115884
+ // ../quasar/src/probes/BeeQueueProbe.ts
115885
+ class BeeQueueProbe {
115886
+ redis;
115887
+ queueName;
115888
+ prefix;
115889
+ constructor(redis, queueName, prefix = "bq") {
115890
+ this.redis = redis;
115891
+ this.queueName = queueName;
115892
+ this.prefix = prefix;
115893
+ }
115894
+ async getSnapshot() {
115895
+ const key = (suffix) => `${this.prefix}:${this.queueName}:${suffix}`;
115896
+ const pipeline = this.redis.pipeline();
115897
+ pipeline.llen(key("waiting"));
115898
+ pipeline.llen(key("active"));
115899
+ pipeline.llen(key("failed"));
115900
+ const results = await pipeline.exec();
115901
+ if (!results)
115902
+ throw new Error("Redis pipeline failed");
115903
+ const [_waitingErr, waiting] = results[0];
115904
+ const [_activeErr, active] = results[1];
115905
+ const [_failedErr, failed] = results[2];
115906
+ return {
115907
+ name: this.queueName,
115908
+ driver: "redis",
115909
+ size: {
115910
+ waiting: Number(waiting || 0),
115911
+ active: Number(active || 0),
115912
+ failed: Number(failed || 0),
115913
+ delayed: 0
115914
+ }
115915
+ };
115916
+ }
115917
+ }
115918
+ // ../quasar/src/probes/BullMQProbe.ts
115919
+ class BullMQProbe {
115920
+ redis;
115921
+ queueName;
115922
+ prefix;
115923
+ constructor(redis, queueName, prefix = "bull") {
115924
+ this.redis = redis;
115925
+ this.queueName = queueName;
115926
+ this.prefix = prefix;
115927
+ }
115928
+ async getSnapshot() {
115929
+ const key = (suffix) => `${this.prefix}:${this.queueName}:${suffix}`;
115930
+ const pipeline = this.redis.pipeline();
115931
+ pipeline.llen(key("wait"));
115932
+ pipeline.llen(key("active"));
115933
+ pipeline.zcard(key("delayed"));
115934
+ pipeline.scard(key("failed"));
115935
+ const results = await pipeline.exec();
115936
+ if (!results)
115937
+ throw new Error("Redis pipeline failed");
115938
+ const [_waitErr, waiting] = results[0];
115939
+ const [_activeErr, active] = results[1];
115940
+ const [_delayedErr, delayed] = results[2];
115941
+ const [_failedErr, failed] = results[3];
115942
+ return {
115943
+ name: this.queueName,
115944
+ driver: "redis",
115945
+ size: {
115946
+ waiting: Number(waiting || 0),
115947
+ active: Number(active || 0),
115948
+ failed: Number(failed || 0),
115949
+ delayed: Number(delayed || 0)
115950
+ }
115951
+ };
115952
+ }
115953
+ }
115726
115954
  // ../quasar/src/probes/NodeProbe.ts
115727
115955
  import os from "os";
115728
115956
  import process2 from "process";
@@ -115821,10 +116049,10 @@ class BullProbe {
115821
116049
  const results = await pipeline.exec();
115822
116050
  if (!results)
115823
116051
  throw new Error("Redis pipeline failed");
115824
- const [waitingErr, waiting] = results[0];
115825
- const [activeErr, active] = results[1];
115826
- const [delayedErr, delayed] = results[2];
115827
- const [failedErr, failed] = results[3];
116052
+ const [_waitingErr, waiting] = results[0];
116053
+ const [_activeErr, active] = results[1];
116054
+ const [_delayedErr, delayed] = results[2];
116055
+ const [_failedErr, failed] = results[3];
115828
116056
  return {
115829
116057
  name: this.queueName,
115830
116058
  driver: "redis",
@@ -115907,6 +116135,7 @@ class QuasarAgent {
115907
116135
  interval;
115908
116136
  probe;
115909
116137
  queueProbes = [];
116138
+ bridges = [];
115910
116139
  timer = null;
115911
116140
  prefix = "gravito:quasar:node:";
115912
116141
  nodeId;
@@ -115983,7 +116212,30 @@ class QuasarAgent {
115983
116212
  this.queueProbes.push(new LaravelProbe(this.monitorRedis, name));
115984
116213
  } else if (type === "bull") {
115985
116214
  this.queueProbes.push(new BullProbe(this.monitorRedis, name));
116215
+ } else if (type === "bullmq") {
116216
+ this.queueProbes.push(new BullMQProbe(this.monitorRedis, name));
116217
+ } else if (type === "bee-queue") {
116218
+ this.queueProbes.push(new BeeQueueProbe(this.monitorRedis, name));
116219
+ }
116220
+ }
116221
+ attachBridge(worker, type) {
116222
+ if (!this.transportRedis) {
116223
+ console.warn("[Quasar] Cannot attach bridge: transport connection required");
116224
+ return;
115986
116225
  }
116226
+ const workerId = this.nodeId || `${this.service}-${process.pid}`;
116227
+ let bridge;
116228
+ if (type === "bullmq") {
116229
+ bridge = new BullMQBridge(this.transportRedis, "flux_console:", workerId);
116230
+ } else if (type === "bee-queue") {
116231
+ bridge = new BeeQueueBridge(this.transportRedis, "flux_console:", workerId);
116232
+ } else {
116233
+ console.warn(`[Quasar] Unknown bridge type: ${type}`);
116234
+ return;
116235
+ }
116236
+ bridge.attach(worker);
116237
+ this.bridges.push(bridge);
116238
+ console.log(`[Quasar] \uD83D\uDD17 Attached ${type} bridge to worker`);
115987
116239
  }
115988
116240
  async enableRemoteControl() {
115989
116241
  if (!this.monitorRedis) {
@@ -118485,7 +118737,7 @@ class QueueService {
118485
118737
  return jobs;
118486
118738
  }
118487
118739
  }
118488
- async recordStatusMetrics(nodes = {}) {
118740
+ async recordStatusMetrics(nodes = {}, injectedWorkers) {
118489
118741
  const stats = await this.listQueues();
118490
118742
  const totals = stats.reduce((acc, q3) => {
118491
118743
  acc.waiting += q3.waiting;
@@ -118498,7 +118750,7 @@ class QueueService {
118498
118750
  pipe.set(`flux_console:metrics:waiting:${now}`, totals.waiting, "EX", 3600);
118499
118751
  pipe.set(`flux_console:metrics:delayed:${now}`, totals.delayed, "EX", 3600);
118500
118752
  pipe.set(`flux_console:metrics:failed:${now}`, totals.failed, "EX", 3600);
118501
- const workers = await this.listWorkers();
118753
+ const workers = injectedWorkers || await this.listWorkers();
118502
118754
  pipe.set(`flux_console:metrics:workers:${now}`, workers.length, "EX", 3600);
118503
118755
  await pipe.exec();
118504
118756
  this.logEmitter.emit("stats", {
@@ -118687,8 +118939,8 @@ class QueueService {
118687
118939
  if (results.length >= limit) {
118688
118940
  break;
118689
118941
  }
118690
- const types6 = type === "all" ? ["waiting", "delayed", "failed"] : [type];
118691
- for (const jobType of types6) {
118942
+ const types7 = type === "all" ? ["waiting", "delayed", "failed"] : [type];
118943
+ for (const jobType of types7) {
118692
118944
  if (results.length >= limit) {
118693
118945
  break;
118694
118946
  }
@@ -118830,14 +119082,85 @@ queueService.connect().then(() => pulseService.connect()).then(() => commandServ
118830
119082
  });
118831
119083
  agent.start().catch((err) => console.error("[FluxConsole] Quasar Agent Error:", err));
118832
119084
  console.log(`[FluxConsole] Connected to Redis at ${REDIS_URL}`);
118833
- setInterval(async () => {
118834
- const nodes = await pulseService.getNodes();
118835
- queueService.recordStatusMetrics(nodes).catch(console.error);
118836
- }, 2000);
119085
+ const updateMetrics = async () => {
119086
+ try {
119087
+ const [pulseNodes, legacyWorkers] = await Promise.all([
119088
+ pulseService.getNodes(),
119089
+ queueService.listWorkers()
119090
+ ]);
119091
+ const pulseWorkers = Object.values(pulseNodes).flat().flatMap((node) => {
119092
+ const mainNode = {
119093
+ id: node.id,
119094
+ service: node.service,
119095
+ status: node.runtime.status || "online",
119096
+ pid: node.pid,
119097
+ uptime: node.runtime.uptime,
119098
+ metrics: {
119099
+ cpu: node.cpu.process,
119100
+ cores: node.cpu.cores,
119101
+ ram: {
119102
+ rss: node.memory.process.rss,
119103
+ heapUsed: node.memory.process.heapUsed,
119104
+ total: node.memory.system.total
119105
+ }
119106
+ },
119107
+ queues: node.queues,
119108
+ meta: node.meta
119109
+ };
119110
+ const subWorkers = [];
119111
+ if (node.meta?.laravel?.workers && Array.isArray(node.meta.laravel.workers)) {
119112
+ node.meta.laravel.workers.forEach((w3) => {
119113
+ subWorkers.push({
119114
+ id: `${node.id}-php-${w3.pid}`,
119115
+ service: `${node.service} / LARAVEL`,
119116
+ status: w3.status === "running" || w3.status === "sleep" ? "online" : "idle",
119117
+ pid: w3.pid,
119118
+ uptime: node.runtime.uptime,
119119
+ metrics: {
119120
+ cpu: w3.cpu,
119121
+ cores: 1,
119122
+ ram: {
119123
+ rss: w3.memory,
119124
+ heapUsed: w3.memory,
119125
+ total: node.memory.system.total
119126
+ }
119127
+ },
119128
+ meta: { isVirtual: true, cmdline: w3.cmdline }
119129
+ });
119130
+ });
119131
+ }
119132
+ return [mainNode, ...subWorkers];
119133
+ });
119134
+ const formattedLegacy = legacyWorkers.map((w3) => ({
119135
+ id: w3.id,
119136
+ status: "online",
119137
+ pid: w3.pid,
119138
+ uptime: w3.uptime,
119139
+ metrics: {
119140
+ cpu: (w3.loadAvg[0] || 0) * 100,
119141
+ cores: 0,
119142
+ ram: {
119143
+ rss: parseInt(w3.memory.rss || "0", 10),
119144
+ heapUsed: parseInt(w3.memory.heapUsed || "0", 10),
119145
+ total: 0
119146
+ }
119147
+ },
119148
+ queues: w3.queues.map((q3) => ({
119149
+ name: q3,
119150
+ size: { waiting: 0, active: 0, failed: 0, delayed: 0 }
119151
+ })),
119152
+ meta: {}
119153
+ }));
119154
+ await queueService.recordStatusMetrics(pulseNodes, [...pulseWorkers, ...formattedLegacy]);
119155
+ } catch (err) {
119156
+ console.error("[FluxConsole] Metrics Update Error:", err);
119157
+ }
119158
+ };
119159
+ setInterval(updateMetrics, 2000);
118837
119160
  setInterval(() => {
118838
119161
  queueService.tickScheduler().catch(console.error);
118839
119162
  }, 5000);
118840
- pulseService.getNodes().then((nodes) => queueService.recordStatusMetrics(nodes)).catch(console.error);
119163
+ updateMetrics();
118841
119164
  }).catch((err) => {
118842
119165
  console.error("[FluxConsole] Failed to connect to Redis", err);
118843
119166
  });
@@ -119031,9 +119354,79 @@ api.get("/throughput", async (c3) => {
119031
119354
  });
119032
119355
  api.get("/workers", async (c3) => {
119033
119356
  try {
119034
- const workers = await queueService.listWorkers();
119035
- return c3.json({ workers });
119357
+ const [legacyWorkers, pulseNodes] = await Promise.all([
119358
+ queueService.listWorkers(),
119359
+ pulseService.getNodes()
119360
+ ]);
119361
+ const pulseWorkers = Object.values(pulseNodes).flat().flatMap((node) => {
119362
+ const mainNode = {
119363
+ id: node.id,
119364
+ service: node.service,
119365
+ status: node.runtime.status || "online",
119366
+ pid: node.pid,
119367
+ uptime: node.runtime.uptime,
119368
+ metrics: {
119369
+ cpu: node.cpu.process,
119370
+ cores: node.cpu.cores,
119371
+ ram: {
119372
+ rss: node.memory.process.rss,
119373
+ heapUsed: node.memory.process.heapUsed,
119374
+ total: node.memory.system.total
119375
+ }
119376
+ },
119377
+ queues: node.queues,
119378
+ meta: node.meta
119379
+ };
119380
+ const subWorkers = [];
119381
+ if (node.meta?.laravel?.workers && Array.isArray(node.meta.laravel.workers)) {
119382
+ node.meta.laravel.workers.forEach((w3) => {
119383
+ subWorkers.push({
119384
+ id: `${node.id}-php-${w3.pid}`,
119385
+ service: `${node.service} / LARAVEL`,
119386
+ status: w3.status === "running" || w3.status === "sleep" ? "online" : "idle",
119387
+ pid: w3.pid,
119388
+ uptime: node.runtime.uptime,
119389
+ metrics: {
119390
+ cpu: w3.cpu,
119391
+ cores: 1,
119392
+ ram: {
119393
+ rss: w3.memory,
119394
+ heapUsed: w3.memory,
119395
+ total: node.memory.system.total
119396
+ }
119397
+ },
119398
+ meta: {
119399
+ isVirtual: true,
119400
+ cmdline: w3.cmdline
119401
+ }
119402
+ });
119403
+ });
119404
+ }
119405
+ return [mainNode, ...subWorkers];
119406
+ });
119407
+ const formattedLegacy = legacyWorkers.map((w3) => ({
119408
+ id: w3.id,
119409
+ status: "online",
119410
+ pid: w3.pid,
119411
+ uptime: w3.uptime,
119412
+ metrics: {
119413
+ cpu: (w3.loadAvg[0] || 0) * 100,
119414
+ cores: 0,
119415
+ ram: {
119416
+ rss: parseInt(w3.memory.rss || "0", 10),
119417
+ heapUsed: parseInt(w3.memory.heapUsed || "0", 10),
119418
+ total: 0
119419
+ }
119420
+ },
119421
+ queues: w3.queues.map((q3) => ({
119422
+ name: q3,
119423
+ size: { waiting: 0, active: 0, failed: 0, delayed: 0 }
119424
+ })),
119425
+ meta: {}
119426
+ }));
119427
+ return c3.json({ workers: [...pulseWorkers, ...formattedLegacy] });
119036
119428
  } catch (_err) {
119429
+ console.error(_err);
119037
119430
  return c3.json({ error: "Failed to fetch workers" }, 500);
119038
119431
  }
119039
119432
  });