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.
- package/dist/server.mjs +84 -78
- 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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
4089
|
+
// apps/server/src/ee/routes/alerts.ts
|
|
4090
4090
|
import { z as z2 } from "zod";
|
|
4091
4091
|
|
|
4092
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
4870
|
+
// apps/server/src/routes/connections.ts
|
|
4871
4871
|
import { z as z3 } from "zod";
|
|
4872
4872
|
|
|
4873
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
5074
|
+
// apps/server/src/routes/groups.ts
|
|
5075
5075
|
import { z as z6 } from "zod";
|
|
5076
5076
|
|
|
5077
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
6536
|
+
// apps/server/src/services/edition.ts
|
|
6537
6537
|
import os from "node:os";
|
|
6538
6538
|
|
|
6539
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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.
|
|
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": "^
|
|
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",
|