bullpane 0.5.1 → 0.5.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.
Files changed (2) hide show
  1. package/dist/server.mjs +84 -78
  2. package/package.json +2 -2
package/dist/server.mjs CHANGED
@@ -4,11 +4,11 @@ var __export = (target, all) => {
4
4
  __defProp(target, name, { get: all[name], enumerable: true });
5
5
  };
6
6
 
7
- // ../redis-inspector/src/inspector.ts
7
+ // packages/redis-inspector/src/inspector.ts
8
8
  import { Cluster as Cluster2 } from "ioredis";
9
9
  import { Job, Queue, UnrecoverableError } from "bullmq";
10
10
 
11
- // ../shared/src/index.ts
11
+ // packages/shared/src/index.ts
12
12
  import { z } from "zod";
13
13
  var PRO_FEATURES = ["alerts", "users", "folders", "flows", "audit", "sso", "mcp"];
14
14
  var PRO_PRICING = { monthlyUsd: 39, yearlyUsd: 390 };
@@ -456,7 +456,7 @@ var mcpConsentDecisionSchema = z.object({
456
456
  access: z.enum(["read", "write"]).default("read")
457
457
  });
458
458
 
459
- // ../redis-inspector/src/connection.ts
459
+ // packages/redis-inspector/src/connection.ts
460
460
  import Redis, { Cluster } from "ioredis";
461
461
  function parseRedisUrl(url) {
462
462
  const u = new URL(url);
@@ -530,7 +530,7 @@ function createBullmqConnection(config, connectTimeoutMs) {
530
530
  };
531
531
  }
532
532
 
533
- // ../redis-inspector/src/keys.ts
533
+ // packages/redis-inspector/src/keys.ts
534
534
  function queueKey(prefix, queue) {
535
535
  return `${prefix}:${queue}`;
536
536
  }
@@ -663,7 +663,7 @@ function queueNameFromQueueKey(prefix, qualified) {
663
663
  return qualified.startsWith(head) ? qualified.slice(head.length) : qualified;
664
664
  }
665
665
 
666
- // ../redis-inspector/src/util.ts
666
+ // packages/redis-inspector/src/util.ts
667
667
  function globToRegExp(glob) {
668
668
  const escaped = glob.split("").map((ch) => {
669
669
  if (ch === "*") return ".*";
@@ -726,7 +726,7 @@ function errorMessage(err) {
726
726
  return String(err);
727
727
  }
728
728
 
729
- // ../redis-inspector/src/parse.ts
729
+ // packages/redis-inspector/src/parse.ts
730
730
  function rowToHash(row) {
731
731
  const id3 = String(row[0] ?? "");
732
732
  const hash = {};
@@ -931,7 +931,7 @@ function optsParent(raw) {
931
931
  return null;
932
932
  }
933
933
 
934
- // ../redis-inspector/src/scripts.ts
934
+ // packages/redis-inspector/src/scripts.ts
935
935
  import { readFileSync } from "node:fs";
936
936
  var SCRIPTS = {
937
937
  /** 8 state keys + meta + groups + metrics (4) + repeat + stalled */
@@ -981,7 +981,7 @@ function pipelineScript(pipeline, name, args) {
981
981
  fn.call(pipeline, ...args);
982
982
  }
983
983
 
984
- // ../redis-inspector/src/inspector.ts
984
+ // packages/redis-inspector/src/inspector.ts
985
985
  var DEFAULTS = {
986
986
  discoveryTtlMs: 3e4,
987
987
  previewBytes: 2048,
@@ -2170,7 +2170,7 @@ function optsPrunesCompleted(optsJson) {
2170
2170
  }
2171
2171
  }
2172
2172
 
2173
- // ../redis-inspector/src/pool.ts
2173
+ // packages/redis-inspector/src/pool.ts
2174
2174
  var RedisInspectorPool = class {
2175
2175
  constructor(options = {}) {
2176
2176
  this.options = options;
@@ -2209,14 +2209,14 @@ function createInspectorPool(options = {}) {
2209
2209
  return new RedisInspectorPool(options);
2210
2210
  }
2211
2211
 
2212
- // ../../apps/server/src/app.ts
2212
+ // apps/server/src/app.ts
2213
2213
  import { existsSync, readFileSync as readFileSync2 } from "node:fs";
2214
2214
  import path2 from "node:path";
2215
2215
  import fastifyCookie from "@fastify/cookie";
2216
2216
  import fastifyStatic from "@fastify/static";
2217
2217
  import Fastify, { LogController } from "fastify";
2218
2218
 
2219
- // ../../apps/server/src/ee/alerts/deliver.ts
2219
+ // apps/server/src/ee/alerts/deliver.ts
2220
2220
  var DELIVERY_TIMEOUT_MS = 5e3;
2221
2221
  function channelLabel(channel) {
2222
2222
  const raw = channel.type === "slack" ? channel.webhookUrl : channel.url;
@@ -2305,7 +2305,7 @@ async function deliverToAll(channels, notification, fetchImpl) {
2305
2305
  return Promise.all(channels.map((c) => deliverToChannel(c, notification, fetchImpl)));
2306
2306
  }
2307
2307
 
2308
- // ../../apps/server/src/ee/alerts/evaluate.ts
2308
+ // apps/server/src/ee/alerts/evaluate.ts
2309
2309
  function measure(condition, m) {
2310
2310
  if (condition.kind !== m.kind) {
2311
2311
  throw new Error(`measurement kind ${m.kind} does not match condition ${condition.kind}`);
@@ -2394,11 +2394,11 @@ function formatMessage(input) {
2394
2394
  return input.status === "fired" ? `${scope}: ${describeCondition(input.condition)} \u2014 current ${value}${threshold}.` : `${scope}: back below threshold \u2014 current ${value}${threshold}.`;
2395
2395
  }
2396
2396
 
2397
- // ../../apps/server/src/ee/services/alerts.ts
2397
+ // apps/server/src/ee/services/alerts.ts
2398
2398
  import { and, desc, eq, lt } from "drizzle-orm";
2399
2399
  import { nanoid } from "nanoid";
2400
2400
 
2401
- // ../../apps/server/src/db/schema.mysql.ts
2401
+ // apps/server/src/db/schema.mysql.ts
2402
2402
  var schema_mysql_exports = {};
2403
2403
  __export(schema_mysql_exports, {
2404
2404
  alertEvents: () => alertEvents,
@@ -2647,7 +2647,7 @@ var settings = mysqlTable("settings", {
2647
2647
  value: text("value").notNull()
2648
2648
  });
2649
2649
 
2650
- // ../../apps/server/src/db/schema.sqlite.ts
2650
+ // apps/server/src/db/schema.sqlite.ts
2651
2651
  var schema_sqlite_exports = {};
2652
2652
  __export(schema_sqlite_exports, {
2653
2653
  alertEvents: () => alertEvents2,
@@ -2870,7 +2870,7 @@ var settings2 = sqliteTable("settings", {
2870
2870
  value: text2("value").notNull()
2871
2871
  });
2872
2872
 
2873
- // ../../apps/server/src/db/schema.ts
2873
+ // apps/server/src/db/schema.ts
2874
2874
  var users3 = users;
2875
2875
  var sessions3 = sessions;
2876
2876
  var ssoProviders3 = ssoProviders;
@@ -2910,7 +2910,7 @@ function useSchema(dialect) {
2910
2910
  current = dialect;
2911
2911
  }
2912
2912
 
2913
- // ../../apps/server/src/plugins/errors.ts
2913
+ // apps/server/src/plugins/errors.ts
2914
2914
  import { ZodError } from "zod";
2915
2915
  var HttpError = class extends Error {
2916
2916
  status;
@@ -2992,7 +2992,7 @@ function registerErrorHandling(app) {
2992
2992
  });
2993
2993
  }
2994
2994
 
2995
- // ../../apps/server/src/ee/services/alerts.ts
2995
+ // apps/server/src/ee/services/alerts.ts
2996
2996
  function scopeOf(row) {
2997
2997
  switch (row.scopeType) {
2998
2998
  case "folder":
@@ -3132,7 +3132,7 @@ var AlertsService = class {
3132
3132
  }
3133
3133
  };
3134
3134
 
3135
- // ../../apps/server/src/ee/alerts/engine.ts
3135
+ // apps/server/src/ee/alerts/engine.ts
3136
3136
  var EVENT_RETENTION_DAYS = 30;
3137
3137
  var NOTICE_MAX_NAMES = 10;
3138
3138
  var AlertsEngine = class {
@@ -3685,11 +3685,11 @@ function errorText(err) {
3685
3685
  return err instanceof Error ? err.message : String(err);
3686
3686
  }
3687
3687
 
3688
- // ../../apps/server/src/auth/sessions.ts
3688
+ // apps/server/src/auth/sessions.ts
3689
3689
  import { randomBytes as randomBytes2 } from "node:crypto";
3690
3690
  import { and as and2, eq as eq2, gt, isNull, lt as lt2 } from "drizzle-orm";
3691
3691
 
3692
- // ../../apps/server/src/config.ts
3692
+ // apps/server/src/config.ts
3693
3693
  import { randomBytes } from "node:crypto";
3694
3694
  import path from "node:path";
3695
3695
  import { fileURLToPath } from "node:url";
@@ -3814,7 +3814,7 @@ function isHttps(publicUrl) {
3814
3814
  return /^https:\/\//i.test(publicUrl);
3815
3815
  }
3816
3816
 
3817
- // ../../apps/server/src/auth/sessions.ts
3817
+ // apps/server/src/auth/sessions.ts
3818
3818
  var SESSION_COOKIE = "bullpane_session";
3819
3819
  var SESSION_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
3820
3820
  function toUserDto(row) {
@@ -3874,7 +3874,7 @@ var SessionService = class {
3874
3874
  }
3875
3875
  };
3876
3876
 
3877
- // ../../apps/server/src/ee/mcp/internal.ts
3877
+ // apps/server/src/ee/mcp/internal.ts
3878
3878
  import { randomBytes as randomBytes3, timingSafeEqual } from "node:crypto";
3879
3879
  var MCP_CALL_HEADER = "x-bullpane-mcp-call";
3880
3880
  function cappedRole(role, access) {
@@ -3903,7 +3903,7 @@ var McpCallBridge = class {
3903
3903
  }
3904
3904
  };
3905
3905
 
3906
- // ../../apps/server/src/auth/plugin.ts
3906
+ // apps/server/src/auth/plugin.ts
3907
3907
  async function authPlugin(app) {
3908
3908
  app.decorateRequest("user", null);
3909
3909
  app.decorateRequest("sessionId", null);
@@ -3932,7 +3932,7 @@ async function authPlugin(app) {
3932
3932
  }
3933
3933
  authPlugin[Symbol.for("skip-override")] = true;
3934
3934
 
3935
- // ../../apps/server/src/ee/plugins/audit.ts
3935
+ // apps/server/src/ee/plugins/audit.ts
3936
3936
  var ROUTE_ACTIONS = {
3937
3937
  // jobs
3938
3938
  "POST /api/connections/:id/queues/:queue/jobs": "job.add",
@@ -4058,7 +4058,7 @@ function registerAuditHook(app) {
4058
4058
  });
4059
4059
  }
4060
4060
 
4061
- // ../../apps/server/src/plugins/gates.ts
4061
+ // apps/server/src/plugins/gates.ts
4062
4062
  function assertFeature(edition, feature) {
4063
4063
  if (!edition.features[feature]) throw proRequired(feature);
4064
4064
  }
@@ -4086,10 +4086,10 @@ async function blockWrites(request, _reply) {
4086
4086
  throw readOnlyLocked();
4087
4087
  }
4088
4088
 
4089
- // ../../apps/server/src/ee/routes/alerts.ts
4089
+ // apps/server/src/ee/routes/alerts.ts
4090
4090
  import { z as z2 } from "zod";
4091
4091
 
4092
- // ../../apps/server/src/auth/guards.ts
4092
+ // apps/server/src/auth/guards.ts
4093
4093
  async function requireAuth(request, _reply) {
4094
4094
  if (!request.user) throw unauthenticated();
4095
4095
  }
@@ -4100,7 +4100,7 @@ function requireRole(role) {
4100
4100
  };
4101
4101
  }
4102
4102
 
4103
- // ../../apps/server/src/ee/routes/alerts.ts
4103
+ // apps/server/src/ee/routes/alerts.ts
4104
4104
  var eventsQuerySchema = z2.object({
4105
4105
  limit: z2.coerce.number().int().min(1).max(1e3).default(100),
4106
4106
  alertId: z2.string().optional()
@@ -4152,7 +4152,7 @@ async function alertRoutes(app) {
4152
4152
  );
4153
4153
  }
4154
4154
 
4155
- // ../../apps/server/src/ee/routes/audit.ts
4155
+ // apps/server/src/ee/routes/audit.ts
4156
4156
  var EXPORT_MAX_ROWS = 5e4;
4157
4157
  var EXPORT_PAGE = 500;
4158
4158
  async function auditRoutes(app) {
@@ -4221,7 +4221,7 @@ function csvRow(e) {
4221
4221
  ].map(csvCell).join(",") + "\n";
4222
4222
  }
4223
4223
 
4224
- // ../../apps/server/src/auth/password.ts
4224
+ // apps/server/src/auth/password.ts
4225
4225
  import bcrypt from "bcryptjs";
4226
4226
  var BCRYPT_ROUNDS = 10;
4227
4227
  function hashPassword(password) {
@@ -4232,7 +4232,7 @@ function verifyPassword(password, hash) {
4232
4232
  return bcrypt.compare(password, hash);
4233
4233
  }
4234
4234
 
4235
- // ../../apps/server/src/routes/auth.ts
4235
+ // apps/server/src/routes/auth.ts
4236
4236
  async function authRoutes(app) {
4237
4237
  app.post("/auth/login", async (request, reply) => {
4238
4238
  const input = loginSchema.parse(request.body);
@@ -4275,7 +4275,7 @@ async function authRoutes(app) {
4275
4275
  });
4276
4276
  }
4277
4277
 
4278
- // ../../apps/server/src/ee/sso/crypto.ts
4278
+ // apps/server/src/ee/sso/crypto.ts
4279
4279
  import { createCipheriv, createDecipheriv, hkdfSync, randomBytes as randomBytes4, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
4280
4280
  var VERSION = "v1";
4281
4281
  var ALGO = "aes-256-gcm";
@@ -4326,7 +4326,7 @@ function safeEqual(a, b) {
4326
4326
  return timingSafeEqual2(ba, bb);
4327
4327
  }
4328
4328
 
4329
- // ../../apps/server/src/ee/sso/oidc.ts
4329
+ // apps/server/src/ee/sso/oidc.ts
4330
4330
  import { createHash, createPublicKey, createVerify, randomBytes as randomBytes5 } from "node:crypto";
4331
4331
  var CLOCK_SKEW_SECONDS = 120;
4332
4332
  var FETCH_TIMEOUT_MS = 8e3;
@@ -4517,7 +4517,7 @@ async function fetchJwks(jwksUri) {
4517
4517
  return { keys: doc.keys };
4518
4518
  }
4519
4519
 
4520
- // ../../apps/server/src/ee/sso/saml.ts
4520
+ // apps/server/src/ee/sso/saml.ts
4521
4521
  import { SAML, ValidateInResponseTo } from "@node-saml/node-saml";
4522
4522
  var SamlError = class extends Error {
4523
4523
  constructor(message, publicMessage = message) {
@@ -4624,7 +4624,7 @@ function nameFromProfile(profile) {
4624
4624
  return null;
4625
4625
  }
4626
4626
 
4627
- // ../../apps/server/src/ee/routes/auth-sso.ts
4627
+ // apps/server/src/ee/routes/auth-sso.ts
4628
4628
  var FLOW_COOKIE_PREFIX = "bullpane_sso_";
4629
4629
  var FLOW_TTL_MS = 10 * 60 * 1e3;
4630
4630
  function flowCookieName(providerId) {
@@ -4867,10 +4867,10 @@ async function testProvider(row, callbackUrl, entityId) {
4867
4867
  };
4868
4868
  }
4869
4869
 
4870
- // ../../apps/server/src/routes/connections.ts
4870
+ // apps/server/src/routes/connections.ts
4871
4871
  import { z as z3 } from "zod";
4872
4872
 
4873
- // ../../apps/server/src/services/inspector-errors.ts
4873
+ // apps/server/src/services/inspector-errors.ts
4874
4874
  var CONNECTION_ERROR_PATTERNS = [
4875
4875
  /ECONNREFUSED/i,
4876
4876
  /ECONNRESET/i,
@@ -4918,7 +4918,7 @@ async function withRedis(fn) {
4918
4918
  }
4919
4919
  }
4920
4920
 
4921
- // ../../apps/server/src/routes/connections.ts
4921
+ // apps/server/src/routes/connections.ts
4922
4922
  var queuesQuerySchema = z3.object({ refresh: z3.string().optional(), includeHidden: z3.string().optional() });
4923
4923
  var isTrue = (v) => v === "1" || v === "true";
4924
4924
  async function connectionRoutes(app) {
@@ -5022,7 +5022,7 @@ async function connectionRoutes(app) {
5022
5022
  });
5023
5023
  }
5024
5024
 
5025
- // ../../apps/server/src/ee/routes/flows.ts
5025
+ // apps/server/src/ee/routes/flows.ts
5026
5026
  import { z as z4 } from "zod";
5027
5027
  var flowsQuerySchema = z4.object({ sample: z4.coerce.number().int().min(10).max(2e3).default(200) });
5028
5028
  async function flowRoutes(app) {
@@ -5045,7 +5045,7 @@ async function flowRoutes(app) {
5045
5045
  });
5046
5046
  }
5047
5047
 
5048
- // ../../apps/server/src/ee/routes/folders.ts
5048
+ // apps/server/src/ee/routes/folders.ts
5049
5049
  async function folderRoutes(app) {
5050
5050
  const gate = requireFeature("folders");
5051
5051
  const viewer = [requireAuth, gate, requireRole("viewer")];
@@ -5071,10 +5071,10 @@ async function folderRoutes(app) {
5071
5071
  });
5072
5072
  }
5073
5073
 
5074
- // ../../apps/server/src/routes/groups.ts
5074
+ // apps/server/src/routes/groups.ts
5075
5075
  import { z as z6 } from "zod";
5076
5076
 
5077
- // ../../apps/server/src/routes/jobs.ts
5077
+ // apps/server/src/routes/jobs.ts
5078
5078
  import { z as z5 } from "zod";
5079
5079
  var logsQuerySchema = z5.object({
5080
5080
  start: z5.coerce.number().int().min(0).default(0),
@@ -5193,7 +5193,7 @@ async function jobRoutes(app) {
5193
5193
  }
5194
5194
  }
5195
5195
 
5196
- // ../../apps/server/src/routes/groups.ts
5196
+ // apps/server/src/routes/groups.ts
5197
5197
  var pagingSchema = z6.object({
5198
5198
  page: z6.coerce.number().int().min(1).default(1),
5199
5199
  pageSize: z6.coerce.number().int().min(1).max(200).default(25)
@@ -5215,7 +5215,7 @@ async function groupRoutes(app) {
5215
5215
  });
5216
5216
  }
5217
5217
 
5218
- // ../../apps/server/src/routes/health.ts
5218
+ // apps/server/src/routes/health.ts
5219
5219
  async function healthRoutes(app) {
5220
5220
  app.get("/health", async () => ({
5221
5221
  ok: true,
@@ -5232,7 +5232,7 @@ async function healthRoutes(app) {
5232
5232
  );
5233
5233
  }
5234
5234
 
5235
- // ../../apps/server/src/routes/license.ts
5235
+ // apps/server/src/routes/license.ts
5236
5236
  import { z as z7 } from "zod";
5237
5237
  var putLicenseSchema = z7.object({ key: z7.string().min(1).max(8192) });
5238
5238
  async function licenseRoutes(app) {
@@ -5255,7 +5255,7 @@ async function licenseRoutes(app) {
5255
5255
  });
5256
5256
  }
5257
5257
 
5258
- // ../../apps/server/src/routes/queues.ts
5258
+ // apps/server/src/routes/queues.ts
5259
5259
  import { z as z8 } from "zod";
5260
5260
  var retryAllSchema = z8.object({ state: z8.enum(["failed", "completed"]) });
5261
5261
  var drainSchema = z8.object({ includeDelayed: z8.boolean().optional() }).default({});
@@ -5355,7 +5355,7 @@ async function queueRoutes(app) {
5355
5355
  });
5356
5356
  }
5357
5357
 
5358
- // ../../apps/server/src/routes/settings.ts
5358
+ // apps/server/src/routes/settings.ts
5359
5359
  async function settingsRoutes(app) {
5360
5360
  app.get("/settings/attention", { preHandler: [requireAuth] }, async () => app.ctx.attention.get());
5361
5361
  app.put(
@@ -5375,7 +5375,7 @@ async function settingsRoutes(app) {
5375
5375
  );
5376
5376
  }
5377
5377
 
5378
- // ../../apps/server/src/routes/setup.ts
5378
+ // apps/server/src/routes/setup.ts
5379
5379
  async function setupRoutes(app) {
5380
5380
  app.get("/setup/status", async () => {
5381
5381
  const authRequired = app.ctx.edition.getEdition().features.users;
@@ -5401,7 +5401,7 @@ async function setupRoutes(app) {
5401
5401
  });
5402
5402
  }
5403
5403
 
5404
- // ../../apps/server/src/ee/routes/sso.ts
5404
+ // apps/server/src/ee/routes/sso.ts
5405
5405
  async function ssoRoutes(app) {
5406
5406
  const admin = [requireAuth, requireFeature("sso"), requireRole("admin")];
5407
5407
  const adminMutating = [...admin, blockInDemo];
@@ -5471,7 +5471,7 @@ async function ssoRoutes(app) {
5471
5471
  });
5472
5472
  }
5473
5473
 
5474
- // ../../apps/server/src/ee/mcp/service.ts
5474
+ // apps/server/src/ee/mcp/service.ts
5475
5475
  import { createHash as createHash2, createHmac, hkdfSync as hkdfSync2, randomBytes as randomBytes6, timingSafeEqual as timingSafeEqual3 } from "node:crypto";
5476
5476
  import { nanoid as nanoid2 } from "nanoid";
5477
5477
  var MCP_SETTINGS_KEY = "mcp.max_access";
@@ -5877,7 +5877,7 @@ function toGrantDto(r) {
5877
5877
  };
5878
5878
  }
5879
5879
 
5880
- // ../../apps/server/src/ee/routes/mcp.ts
5880
+ // apps/server/src/ee/routes/mcp.ts
5881
5881
  async function asApiError(fn) {
5882
5882
  try {
5883
5883
  return await fn();
@@ -5920,7 +5920,7 @@ async function mcpRoutes(app) {
5920
5920
  });
5921
5921
  }
5922
5922
 
5923
- // ../../apps/server/src/ee/routes/users.ts
5923
+ // apps/server/src/ee/routes/users.ts
5924
5924
  async function userRoutes(app) {
5925
5925
  const gate = requireFeature("users");
5926
5926
  const admin = [requireAuth, gate, requireRole("admin")];
@@ -5960,7 +5960,7 @@ async function userRoutes(app) {
5960
5960
  });
5961
5961
  }
5962
5962
 
5963
- // ../../apps/server/src/routes/index.ts
5963
+ // apps/server/src/routes/index.ts
5964
5964
  async function apiPlugin(app) {
5965
5965
  await app.register(authPlugin);
5966
5966
  app.addHook("onRequest", blockWrites);
@@ -5987,7 +5987,7 @@ async function apiPlugin(app) {
5987
5987
  await app.register(mcpRoutes);
5988
5988
  }
5989
5989
 
5990
- // ../../apps/server/src/ee/services/audit.ts
5990
+ // apps/server/src/ee/services/audit.ts
5991
5991
  import { and as and3, asc, desc as desc2, eq as eq3, gte, lt as lt3, lte, or, sql } from "drizzle-orm";
5992
5992
  import { nanoid as nanoid3 } from "nanoid";
5993
5993
  var MAX_ERROR = 500;
@@ -6184,7 +6184,7 @@ var AuditService = class {
6184
6184
  }
6185
6185
  };
6186
6186
 
6187
- // ../../apps/server/src/services/connections.ts
6187
+ // apps/server/src/services/connections.ts
6188
6188
  import { and as and4, eq as eq4, inArray } from "drizzle-orm";
6189
6189
  import { nanoid as nanoid4 } from "nanoid";
6190
6190
  var STATUS_TTL_MS = 1e4;
@@ -6533,10 +6533,10 @@ function emptyCounts() {
6533
6533
  };
6534
6534
  }
6535
6535
 
6536
- // ../../apps/server/src/services/edition.ts
6536
+ // apps/server/src/services/edition.ts
6537
6537
  import os from "node:os";
6538
6538
 
6539
- // ../../apps/server/src/license.ts
6539
+ // apps/server/src/license.ts
6540
6540
  import { createPrivateKey, sign as cryptoSign, verify as cryptoVerify } from "node:crypto";
6541
6541
  import { z as z9 } from "zod";
6542
6542
  var LICENSE_PUBLIC_KEY_B64 = "MCowBQYDK2VwAyEAiOdWgp41hqTFeVlG0WO0qH3T4bPZpoUeUHUlxk5Lwis=";
@@ -6590,7 +6590,7 @@ function verifyLicenseKey(key, opts = {}) {
6590
6590
  return { valid: true, payload, reason: null };
6591
6591
  }
6592
6592
 
6593
- // ../../apps/server/src/services/license-client.ts
6593
+ // apps/server/src/services/license-client.ts
6594
6594
  var LicenseApiFailure = class extends Error {
6595
6595
  constructor(code, message, status = null) {
6596
6596
  super(message);
@@ -6663,7 +6663,7 @@ function errorText2(err) {
6663
6663
  return String(err);
6664
6664
  }
6665
6665
 
6666
- // ../../apps/server/src/services/edition.ts
6666
+ // apps/server/src/services/edition.ts
6667
6667
  var LICENSE_SETTING_KEY = "license_key";
6668
6668
  var LICENSE_ONLINE_SETTING_KEY = "license_online";
6669
6669
  function features(enabled) {
@@ -7023,7 +7023,7 @@ function toHttpError(err) {
7023
7023
  return licenseServerUnavailable(errorMessage2(err));
7024
7024
  }
7025
7025
 
7026
- // ../../apps/server/src/services/attention.ts
7026
+ // apps/server/src/services/attention.ts
7027
7027
  var KEY = "attention.thresholds";
7028
7028
  var AttentionService = class {
7029
7029
  constructor(settings4) {
@@ -7050,7 +7050,7 @@ var AttentionService = class {
7050
7050
  }
7051
7051
  };
7052
7052
 
7053
- // ../../apps/server/src/services/settings-store.ts
7053
+ // apps/server/src/services/settings-store.ts
7054
7054
  import { eq as eq5 } from "drizzle-orm";
7055
7055
  var DrizzleSettingsStore = class {
7056
7056
  constructor(db) {
@@ -7079,7 +7079,7 @@ var DrizzleSettingsStore = class {
7079
7079
  }
7080
7080
  };
7081
7081
 
7082
- // ../../apps/server/src/ee/services/flows.ts
7082
+ // apps/server/src/ee/services/flows.ts
7083
7083
  import { and as and5, eq as eq6 } from "drizzle-orm";
7084
7084
  import { nanoid as nanoid5 } from "nanoid";
7085
7085
  var FLOW_CACHE_TTL_MS = 3e4;
@@ -7214,7 +7214,7 @@ var FlowsService = class {
7214
7214
  }
7215
7215
  };
7216
7216
 
7217
- // ../../apps/server/src/ee/services/folders.ts
7217
+ // apps/server/src/ee/services/folders.ts
7218
7218
  import { eq as eq7, inArray as inArray2 } from "drizzle-orm";
7219
7219
  import { nanoid as nanoid6 } from "nanoid";
7220
7220
  var FoldersService = class {
@@ -7308,7 +7308,7 @@ function toFolderDto(row, queues) {
7308
7308
  };
7309
7309
  }
7310
7310
 
7311
- // ../../apps/server/src/services/health.ts
7311
+ // apps/server/src/services/health.ts
7312
7312
  var MIN_SAMPLE_INTERVAL_MS = 2e3;
7313
7313
  var HISTORY_POINTS = 200;
7314
7314
  var HealthService = class {
@@ -7464,7 +7464,7 @@ function buildWarnings(info, error, memoryUsedPct) {
7464
7464
  return out;
7465
7465
  }
7466
7466
 
7467
- // ../../apps/server/src/ee/services/sso.ts
7467
+ // apps/server/src/ee/services/sso.ts
7468
7468
  import { asc as asc2, eq as eq8 } from "drizzle-orm";
7469
7469
  import { nanoid as nanoid7 } from "nanoid";
7470
7470
  var REQUIRE_SSO_KEY = "sso.require_sso";
@@ -7685,7 +7685,7 @@ var SsoService = class {
7685
7685
  }
7686
7686
  };
7687
7687
 
7688
- // ../../apps/server/src/ee/mcp/tools.ts
7688
+ // apps/server/src/ee/mcp/tools.ts
7689
7689
  import { z as z10 } from "zod";
7690
7690
  var MAX_TEXT = 1e5;
7691
7691
  var seg = encodeURIComponent;
@@ -7979,7 +7979,7 @@ function toolsFor(access) {
7979
7979
  return access === "write" ? MCP_TOOLS : MCP_TOOLS.filter((t) => t.access === "read");
7980
7980
  }
7981
7981
 
7982
- // ../../apps/server/src/ee/mcp/routes.ts
7982
+ // apps/server/src/ee/mcp/routes.ts
7983
7983
  var MCP_PROTOCOL_VERSIONS = ["2025-11-25", "2025-06-18", "2025-03-26"];
7984
7984
  var SERVER_INSTRUCTIONS = "Bullpane is a dashboard for BullMQ queues stored in Redis. Start with list_connections, then list_queues. Every action runs as the Bullpane user who connected this client and is recorded in Bullpane's audit log. Draining, cleaning or obliterating a queue is never done from here: request_destructive_action returns a dashboard link for the user to confirm.";
7985
7985
  function sendOAuthError(reply, err) {
@@ -8163,7 +8163,7 @@ This connection has ${caller.access} access as ${caller.user.email}.`
8163
8163
  app.delete("/mcp", notAllowed);
8164
8164
  }
8165
8165
 
8166
- // ../../apps/server/src/ee/mcp/store.ts
8166
+ // apps/server/src/ee/mcp/store.ts
8167
8167
  import { and as and6, desc as desc3, eq as eq9, lt as lt4, notInArray } from "drizzle-orm";
8168
8168
  function affectedRows(result) {
8169
8169
  const header = Array.isArray(result) ? result[0] : result;
@@ -8238,7 +8238,7 @@ var DrizzleMcpStore = class {
8238
8238
  }
8239
8239
  };
8240
8240
 
8241
- // ../../apps/server/src/services/users.ts
8241
+ // apps/server/src/services/users.ts
8242
8242
  import { and as and7, eq as eq10, isNull as isNull2 } from "drizzle-orm";
8243
8243
  import { nanoid as nanoid8 } from "nanoid";
8244
8244
  var UsersService = class {
@@ -8313,7 +8313,7 @@ var UsersService = class {
8313
8313
  }
8314
8314
  };
8315
8315
 
8316
- // ../../apps/server/src/app.ts
8316
+ // apps/server/src/app.ts
8317
8317
  function readVersion() {
8318
8318
  try {
8319
8319
  const pkg = JSON.parse(readFileSync2(path2.join(SERVER_ROOT, "package.json"), "utf8"));
@@ -8400,7 +8400,13 @@ async function buildApp(opts) {
8400
8400
  index: ["index.html"],
8401
8401
  cacheControl: true,
8402
8402
  maxAge: "1h",
8403
- immutable: false
8403
+ immutable: false,
8404
+ // index.html names the hashed bundles of the running version. Cached for
8405
+ // an hour, it survives an upgrade and asks for bundles that are gone: a
8406
+ // blank page until the cache expires. Everything else keeps the 1 h.
8407
+ setHeaders(reply, filePath) {
8408
+ if (path2.basename(filePath) === "index.html") reply.header("cache-control", "no-cache");
8409
+ }
8404
8410
  });
8405
8411
  }
8406
8412
  app.setNotFoundHandler(async (request, reply) => {
@@ -8408,14 +8414,14 @@ async function buildApp(opts) {
8408
8414
  return reply.status(404).send({ error: "not_found", message: `Route ${request.method} ${request.url} not found` });
8409
8415
  }
8410
8416
  if (serveWeb && (request.method === "GET" || request.method === "HEAD")) {
8411
- return reply.header("cache-control", "no-cache").sendFile("index.html");
8417
+ return reply.header("cache-control", "no-cache").sendFile("index.html", { cacheControl: false });
8412
8418
  }
8413
8419
  return reply.status(404).send({ error: "not_found", message: "Not found" });
8414
8420
  });
8415
8421
  return app;
8416
8422
  }
8417
8423
 
8418
- // ../../apps/server/src/db/index.ts
8424
+ // apps/server/src/db/index.ts
8419
8425
  import { mkdirSync } from "node:fs";
8420
8426
  import path3 from "node:path";
8421
8427
  import { createClient } from "@libsql/client";
@@ -8497,7 +8503,7 @@ function errorMessage3(err) {
8497
8503
  return err instanceof Error ? err.message : String(err);
8498
8504
  }
8499
8505
 
8500
- // ../../apps/server/src/db/migrate.ts
8506
+ // apps/server/src/db/migrate.ts
8501
8507
  import { readdir, readFile } from "node:fs/promises";
8502
8508
  import path4 from "node:path";
8503
8509
  var MIGRATIONS_DIR = path4.resolve(SERVER_ROOT, "migrations");
@@ -8533,7 +8539,7 @@ async function runMigrations(database2, log, dir = path4.join(MIGRATIONS_DIR, da
8533
8539
  return { applied };
8534
8540
  }
8535
8541
 
8536
- // ../../apps/server/src/demo/seed.ts
8542
+ // apps/server/src/demo/seed.ts
8537
8543
  var DEMO_CONNECTION_NAME = "Demo Redis";
8538
8544
  var DEMO_QUEUES = [
8539
8545
  "payments.charge",
@@ -8615,7 +8621,7 @@ async function seedDemo(ctx, log) {
8615
8621
  }
8616
8622
  }
8617
8623
 
8618
- // ../../apps/server/src/seedConnections.ts
8624
+ // apps/server/src/seedConnections.ts
8619
8625
  async function seedConnections(connections5, wanted, log) {
8620
8626
  let created = 0;
8621
8627
  for (const input of wanted) {
@@ -8627,7 +8633,7 @@ async function seedConnections(connections5, wanted, log) {
8627
8633
  return created;
8628
8634
  }
8629
8635
 
8630
- // ../../apps/server/src/index.ts
8636
+ // apps/server/src/index.ts
8631
8637
  async function main() {
8632
8638
  const config = loadConfig(process.env, { warn: (m) => console.warn(`[config] ${m}`) });
8633
8639
  const database2 = createDatabase(config.database);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bullpane",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Self-hosted dashboard for BullMQ and BullMQ Pro: queues, jobs, failures, metrics, Redis health, flows and Pro groups. A bull-board alternative you can run with npx.",
5
5
  "keywords": [
6
6
  "bullmq",
@@ -41,7 +41,7 @@
41
41
  },
42
42
  "dependencies": {
43
43
  "@fastify/cookie": "^11.0.1",
44
- "@fastify/static": "^8.0.3",
44
+ "@fastify/static": "^10.1.5",
45
45
  "@libsql/client": "^0.18.0",
46
46
  "@node-saml/node-saml": "^5.1.0",
47
47
  "bcryptjs": "^2.4.3",