@frontmcp/plugin-dashboard 1.7.2 → 1.8.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.
@@ -18,15 +18,5 @@ export interface DashboardAuthResult {
18
18
  status?: 401;
19
19
  message?: string;
20
20
  }
21
- /**
22
- * Create the dashboard's HTTP auth check.
23
- *
24
- * Returns `undefined` when authentication is not enabled, so the caller can skip
25
- * the check entirely rather than branch on a permissive validator.
26
- *
27
- * A token may be presented as `Authorization: Bearer <token>` (preferred — a URL
28
- * token lands in access logs, `Referer` headers and browser history) or as
29
- * `?token=<token>`, which is what the documented dashboard link uses.
30
- */
31
21
  export declare function createDashboardAuthValidator(auth: DashboardAuth | undefined): ((req: DashboardAuthRequest) => DashboardAuthResult) | undefined;
32
22
  //# sourceMappingURL=dashboard-auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-auth.d.ts","sourceRoot":"","sources":["../../src/auth/dashboard-auth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;CACnE;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA6BD;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,aAAa,GAAG,SAAS,GAC9B,CAAC,CAAC,GAAG,EAAE,oBAAoB,KAAK,mBAAmB,CAAC,GAAG,SAAS,CAsBlE"}
1
+ {"version":3,"file":"dashboard-auth.d.ts","sourceRoot":"","sources":["../../src/auth/dashboard-auth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;CACnE;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAyDD,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,aAAa,GAAG,SAAS,GAC9B,CAAC,CAAC,GAAG,EAAE,oBAAoB,KAAK,mBAAmB,CAAC,GAAG,SAAS,CAqBlE"}
@@ -20,6 +20,13 @@ export declare function publishDashboardOptions(options: DashboardPluginOptions)
20
20
  * otherwise the defaults merged with whatever the caller supplied.
21
21
  */
22
22
  export declare function resolveDashboardOptions(fallback?: DashboardPluginOptionsInput): DashboardPluginOptions;
23
- /** Test seam — clears the published options between cases. */
23
+ /**
24
+ * Clear the published options.
25
+ *
26
+ * Dashboard options are process-wide, and a second CONFLICTING auth
27
+ * configuration now throws rather than silently replacing the first (BC-036).
28
+ * A host that builds several servers serially — a test suite, a CLI that
29
+ * reconfigures between runs — calls this between constructions.
30
+ */
24
31
  export declare function resetDashboardOptions(): void;
25
32
  //# sourceMappingURL=dashboard.config-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.config-store.d.ts","sourceRoot":"","sources":["../src/dashboard.config-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,sBAAsB,EAC3B,KAAK,2BAA2B,EACjC,MAAM,mBAAmB,CAAC;AAmB3B;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAuB7E;AAyBD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,GAAE,2BAAgC,GAAG,sBAAsB,CAG1G;AAED,8DAA8D;AAC9D,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C"}
1
+ {"version":3,"file":"dashboard.config-store.d.ts","sourceRoot":"","sources":["../src/dashboard.config-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,sBAAsB,EAC3B,KAAK,2BAA2B,EACjC,MAAM,mBAAmB,CAAC;AAmB3B;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAuB7E;AAyBD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,GAAE,2BAAgC,GAAG,sBAAsB,CAG1G;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C"}
package/esm/index.mjs CHANGED
@@ -368,6 +368,9 @@ function resolveDashboardOptions(fallback = {}) {
368
368
  if (publishedOptions) return publishedOptions;
369
369
  return dashboardPluginOptionsSchema.parse({ ...defaultDashboardPluginOptions, ...fallback });
370
370
  }
371
+ function resetDashboardOptions() {
372
+ publishedOptions = void 0;
373
+ }
371
374
 
372
375
  // plugins/plugin-dashboard/src/dashboard.symbol.ts
373
376
  var DashboardConfigToken = /* @__PURE__ */ Symbol("DashboardConfig");
@@ -3678,6 +3681,90 @@ var init_cloudflare_kv = __esm({
3678
3681
  }
3679
3682
  });
3680
3683
  init_runtime();
3684
+ var IPV4_OCTET_PATTERN = /^(0|[1-9]\d{0,2})$/;
3685
+ var IPV6_GROUP_PATTERN = /^[0-9a-f]{1,4}$/;
3686
+ var IPV4_BLOCKS = compileBlocks(
3687
+ [
3688
+ ["0.0.0.0/8", "this-network"],
3689
+ ["10.0.0.0/8", "private"],
3690
+ ["100.64.0.0/10", "carrier-grade-nat"],
3691
+ ["127.0.0.0/8", "loopback"],
3692
+ ["169.254.0.0/16", "link-local"],
3693
+ ["172.16.0.0/12", "private"],
3694
+ ["192.0.0.0/24", "ietf-protocol"],
3695
+ ["192.168.0.0/16", "private"],
3696
+ ["198.18.0.0/15", "benchmarking"],
3697
+ ["224.0.0.0/4", "multicast"],
3698
+ ["255.255.255.255/32", "reserved"],
3699
+ ["240.0.0.0/4", "reserved"]
3700
+ ],
3701
+ parseIpv4
3702
+ );
3703
+ var IPV6_BLOCKS = compileBlocks(
3704
+ [
3705
+ ["::/128", "unspecified"],
3706
+ ["::1/128", "loopback"],
3707
+ ["fd00:ec2::254/128", "cloud-metadata"],
3708
+ ["fc00::/7", "private"],
3709
+ ["fe80::/10", "link-local"],
3710
+ ["fec0::/10", "site-local"],
3711
+ // RFC 8215 local-use NAT64: where the IPv4 address sits depends on the operator's prefix length.
3712
+ ["64:ff9b:1::/48", "local-use-nat64"],
3713
+ ["ff00::/8", "multicast"]
3714
+ ],
3715
+ expandIpv6
3716
+ );
3717
+ var IPV4_EMBEDDINGS = compileBlocks(
3718
+ [
3719
+ ["::ffff:0:0/96", 6],
3720
+ ["::ffff:0:0:0/96", 6],
3721
+ ["::/96", 6],
3722
+ ["64:ff9b::/96", 6],
3723
+ ["2002::/16", 1]
3724
+ ],
3725
+ expandIpv6
3726
+ );
3727
+ function parseIpv4(address) {
3728
+ const parts = address.split(".");
3729
+ if (parts.length !== 4 || !parts.every((part) => IPV4_OCTET_PATTERN.test(part))) return void 0;
3730
+ const octets = parts.map(Number);
3731
+ return octets.every((octet) => octet <= 255) ? octets : void 0;
3732
+ }
3733
+ function expandIpv6(address) {
3734
+ const zoneIndex = address.indexOf("%");
3735
+ let text = (zoneIndex === -1 ? address : address.slice(0, zoneIndex)).toLowerCase();
3736
+ const lastColonIndex = text.lastIndexOf(":");
3737
+ const trailingSegment = text.slice(lastColonIndex + 1);
3738
+ if (lastColonIndex !== -1 && trailingSegment.includes(".")) {
3739
+ const octets = parseIpv4(trailingSegment);
3740
+ if (!octets) return void 0;
3741
+ const highGroup = (octets[0] << 8 | octets[1]).toString(16);
3742
+ const lowGroup = (octets[2] << 8 | octets[3]).toString(16);
3743
+ text = `${text.slice(0, lastColonIndex + 1)}${highGroup}:${lowGroup}`;
3744
+ }
3745
+ const halves = text.split("::");
3746
+ if (halves.length > 2) return void 0;
3747
+ const head = parseIpv6Groups(halves[0]);
3748
+ if (!head) return void 0;
3749
+ if (halves.length === 1) return head.length === 8 ? head : void 0;
3750
+ const tail = parseIpv6Groups(halves[1]);
3751
+ if (!tail || head.length + tail.length > 7) return void 0;
3752
+ return [...head, ...new Array(8 - head.length - tail.length).fill(0), ...tail];
3753
+ }
3754
+ function parseIpv6Groups(part) {
3755
+ if (part === "") return [];
3756
+ const groups = part.split(":");
3757
+ if (!groups.every((group) => IPV6_GROUP_PATTERN.test(group))) return void 0;
3758
+ return groups.map((group) => parseInt(group, 16));
3759
+ }
3760
+ function compileBlocks(entries, parseNetwork) {
3761
+ return entries.map(([cidr, value]) => {
3762
+ const [networkText, prefixText] = cidr.split("/");
3763
+ const network = parseNetwork(networkText);
3764
+ if (!network) throw new Error(`Invalid network in address block "${cidr}"`);
3765
+ return { cidr, network, prefixLength: Number(prefixText), value };
3766
+ });
3767
+ }
3681
3768
  init_fs2();
3682
3769
  init_crypto();
3683
3770
  var entryAvailabilitySchema = z3.object({
@@ -3724,6 +3811,14 @@ function tokenMatches(presented, expected) {
3724
3811
  if (presented.length === 0 || expected.length === 0) return false;
3725
3812
  return timingSafeEqual(sha256(presented), sha256(expected));
3726
3813
  }
3814
+ function readBearerToken(header) {
3815
+ if (!header) return void 0;
3816
+ const separator = header.indexOf(" ");
3817
+ if (separator === -1) return void 0;
3818
+ if (header.slice(0, separator).toLowerCase() !== "bearer") return void 0;
3819
+ const token = header.slice(separator + 1).trim();
3820
+ return token.length > 0 ? token : void 0;
3821
+ }
3727
3822
  function createDashboardAuthValidator(auth) {
3728
3823
  if (!auth?.enabled) return void 0;
3729
3824
  const expected = auth.token;
@@ -3731,8 +3826,7 @@ function createDashboardAuthValidator(auth) {
3731
3826
  if (!expected) {
3732
3827
  return { authorized: false, status: 401, message: "Dashboard authentication is misconfigured" };
3733
3828
  }
3734
- const header = readHeader(req.headers, "authorization");
3735
- const bearer = header?.startsWith("Bearer ") ? header.slice("Bearer ".length) : void 0;
3829
+ const bearer = readBearerToken(readHeader(req.headers, "authorization"));
3736
3830
  if (bearer && tokenMatches(bearer, expected)) return AUTHORIZED;
3737
3831
  const queryToken = readQuery(req.query, "token");
3738
3832
  if (queryToken && tokenMatches(queryToken, expected)) return AUTHORIZED;
@@ -4915,5 +5009,6 @@ export {
4915
5009
  dashboardPluginOptionsSchema,
4916
5010
  DashboardPlugin as default,
4917
5011
  defaultDashboardPluginOptions,
4918
- isDashboardEnabled
5012
+ isDashboardEnabled,
5013
+ resetDashboardOptions
4919
5014
  };
package/esm/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/plugin-dashboard",
3
- "version": "1.7.2",
3
+ "version": "1.8.1",
4
4
  "description": "Dashboard plugin for FrontMCP - visual monitoring and introspection of MCP servers",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "license": "Apache-2.0",
@@ -47,12 +47,12 @@
47
47
  }
48
48
  },
49
49
  "dependencies": {
50
- "@frontmcp/sdk": "1.7.2"
50
+ "@frontmcp/sdk": "1.8.1"
51
51
  },
52
52
  "devDependencies": {
53
53
  "reflect-metadata": "^0.2.2"
54
54
  },
55
55
  "peerDependencies": {
56
- "@frontmcp/lazy-zod": "1.7.2"
56
+ "@frontmcp/lazy-zod": "1.8.1"
57
57
  }
58
58
  }
package/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { default, default as DashboardPlugin } from './dashboard.plugin';
2
2
  export { DashboardApp } from './app';
3
3
  export { DashboardPluginOptions, DashboardPluginOptionsInput, dashboardPluginOptionsSchema, defaultDashboardPluginOptions, isDashboardEnabled, } from './dashboard.types';
4
+ export { resetDashboardOptions } from './dashboard.config-store';
4
5
  export { DashboardConfigToken, GraphDataProviderToken, ParentScopeToken } from './dashboard.symbol';
5
6
  export type { GraphData, GraphNode, GraphEdge, GraphMetadata } from './shared/types';
6
7
  export { GraphDataProvider } from './providers';
package/index.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGzE,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAGrC,OAAO,EACL,sBAAsB,EACtB,2BAA2B,EAC3B,4BAA4B,EAC5B,6BAA6B,EAC7B,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGpG,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGrF,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,6BAA6B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGzE,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAGrC,OAAO,EACL,sBAAsB,EACtB,2BAA2B,EAC3B,4BAA4B,EAC5B,6BAA6B,EAC7B,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAGjE,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGpG,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGrF,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,6BAA6B,CAAC"}
package/index.js CHANGED
@@ -297,7 +297,8 @@ __export(index_exports, {
297
297
  dashboardPluginOptionsSchema: () => dashboardPluginOptionsSchema,
298
298
  default: () => DashboardPlugin,
299
299
  defaultDashboardPluginOptions: () => defaultDashboardPluginOptions,
300
- isDashboardEnabled: () => isDashboardEnabled
300
+ isDashboardEnabled: () => isDashboardEnabled,
301
+ resetDashboardOptions: () => resetDashboardOptions
301
302
  });
302
303
  module.exports = __toCommonJS(index_exports);
303
304
 
@@ -387,6 +388,9 @@ function resolveDashboardOptions(fallback = {}) {
387
388
  if (publishedOptions) return publishedOptions;
388
389
  return dashboardPluginOptionsSchema.parse({ ...defaultDashboardPluginOptions, ...fallback });
389
390
  }
391
+ function resetDashboardOptions() {
392
+ publishedOptions = void 0;
393
+ }
390
394
 
391
395
  // plugins/plugin-dashboard/src/dashboard.symbol.ts
392
396
  var DashboardConfigToken = /* @__PURE__ */ Symbol("DashboardConfig");
@@ -3691,6 +3695,90 @@ var init_cloudflare_kv = __esm({
3691
3695
  }
3692
3696
  });
3693
3697
  init_runtime();
3698
+ var IPV4_OCTET_PATTERN = /^(0|[1-9]\d{0,2})$/;
3699
+ var IPV6_GROUP_PATTERN = /^[0-9a-f]{1,4}$/;
3700
+ var IPV4_BLOCKS = compileBlocks(
3701
+ [
3702
+ ["0.0.0.0/8", "this-network"],
3703
+ ["10.0.0.0/8", "private"],
3704
+ ["100.64.0.0/10", "carrier-grade-nat"],
3705
+ ["127.0.0.0/8", "loopback"],
3706
+ ["169.254.0.0/16", "link-local"],
3707
+ ["172.16.0.0/12", "private"],
3708
+ ["192.0.0.0/24", "ietf-protocol"],
3709
+ ["192.168.0.0/16", "private"],
3710
+ ["198.18.0.0/15", "benchmarking"],
3711
+ ["224.0.0.0/4", "multicast"],
3712
+ ["255.255.255.255/32", "reserved"],
3713
+ ["240.0.0.0/4", "reserved"]
3714
+ ],
3715
+ parseIpv4
3716
+ );
3717
+ var IPV6_BLOCKS = compileBlocks(
3718
+ [
3719
+ ["::/128", "unspecified"],
3720
+ ["::1/128", "loopback"],
3721
+ ["fd00:ec2::254/128", "cloud-metadata"],
3722
+ ["fc00::/7", "private"],
3723
+ ["fe80::/10", "link-local"],
3724
+ ["fec0::/10", "site-local"],
3725
+ // RFC 8215 local-use NAT64: where the IPv4 address sits depends on the operator's prefix length.
3726
+ ["64:ff9b:1::/48", "local-use-nat64"],
3727
+ ["ff00::/8", "multicast"]
3728
+ ],
3729
+ expandIpv6
3730
+ );
3731
+ var IPV4_EMBEDDINGS = compileBlocks(
3732
+ [
3733
+ ["::ffff:0:0/96", 6],
3734
+ ["::ffff:0:0:0/96", 6],
3735
+ ["::/96", 6],
3736
+ ["64:ff9b::/96", 6],
3737
+ ["2002::/16", 1]
3738
+ ],
3739
+ expandIpv6
3740
+ );
3741
+ function parseIpv4(address) {
3742
+ const parts = address.split(".");
3743
+ if (parts.length !== 4 || !parts.every((part) => IPV4_OCTET_PATTERN.test(part))) return void 0;
3744
+ const octets = parts.map(Number);
3745
+ return octets.every((octet) => octet <= 255) ? octets : void 0;
3746
+ }
3747
+ function expandIpv6(address) {
3748
+ const zoneIndex = address.indexOf("%");
3749
+ let text = (zoneIndex === -1 ? address : address.slice(0, zoneIndex)).toLowerCase();
3750
+ const lastColonIndex = text.lastIndexOf(":");
3751
+ const trailingSegment = text.slice(lastColonIndex + 1);
3752
+ if (lastColonIndex !== -1 && trailingSegment.includes(".")) {
3753
+ const octets = parseIpv4(trailingSegment);
3754
+ if (!octets) return void 0;
3755
+ const highGroup = (octets[0] << 8 | octets[1]).toString(16);
3756
+ const lowGroup = (octets[2] << 8 | octets[3]).toString(16);
3757
+ text = `${text.slice(0, lastColonIndex + 1)}${highGroup}:${lowGroup}`;
3758
+ }
3759
+ const halves = text.split("::");
3760
+ if (halves.length > 2) return void 0;
3761
+ const head = parseIpv6Groups(halves[0]);
3762
+ if (!head) return void 0;
3763
+ if (halves.length === 1) return head.length === 8 ? head : void 0;
3764
+ const tail = parseIpv6Groups(halves[1]);
3765
+ if (!tail || head.length + tail.length > 7) return void 0;
3766
+ return [...head, ...new Array(8 - head.length - tail.length).fill(0), ...tail];
3767
+ }
3768
+ function parseIpv6Groups(part) {
3769
+ if (part === "") return [];
3770
+ const groups = part.split(":");
3771
+ if (!groups.every((group) => IPV6_GROUP_PATTERN.test(group))) return void 0;
3772
+ return groups.map((group) => parseInt(group, 16));
3773
+ }
3774
+ function compileBlocks(entries, parseNetwork) {
3775
+ return entries.map(([cidr, value]) => {
3776
+ const [networkText, prefixText] = cidr.split("/");
3777
+ const network = parseNetwork(networkText);
3778
+ if (!network) throw new Error(`Invalid network in address block "${cidr}"`);
3779
+ return { cidr, network, prefixLength: Number(prefixText), value };
3780
+ });
3781
+ }
3694
3782
  init_fs2();
3695
3783
  init_crypto();
3696
3784
  var entryAvailabilitySchema = import_lazy_zod4.z.object({
@@ -3737,6 +3825,14 @@ function tokenMatches(presented, expected) {
3737
3825
  if (presented.length === 0 || expected.length === 0) return false;
3738
3826
  return timingSafeEqual(sha256(presented), sha256(expected));
3739
3827
  }
3828
+ function readBearerToken(header) {
3829
+ if (!header) return void 0;
3830
+ const separator = header.indexOf(" ");
3831
+ if (separator === -1) return void 0;
3832
+ if (header.slice(0, separator).toLowerCase() !== "bearer") return void 0;
3833
+ const token = header.slice(separator + 1).trim();
3834
+ return token.length > 0 ? token : void 0;
3835
+ }
3740
3836
  function createDashboardAuthValidator(auth) {
3741
3837
  if (!auth?.enabled) return void 0;
3742
3838
  const expected = auth.token;
@@ -3744,8 +3840,7 @@ function createDashboardAuthValidator(auth) {
3744
3840
  if (!expected) {
3745
3841
  return { authorized: false, status: 401, message: "Dashboard authentication is misconfigured" };
3746
3842
  }
3747
- const header = readHeader(req.headers, "authorization");
3748
- const bearer = header?.startsWith("Bearer ") ? header.slice("Bearer ".length) : void 0;
3843
+ const bearer = readBearerToken(readHeader(req.headers, "authorization"));
3749
3844
  if (bearer && tokenMatches(bearer, expected)) return AUTHORIZED;
3750
3845
  const queryToken = readQuery(req.query, "token");
3751
3846
  if (queryToken && tokenMatches(queryToken, expected)) return AUTHORIZED;
@@ -4928,5 +5023,6 @@ DashboardApp = __decorateClass([
4928
5023
  ParentScopeToken,
4929
5024
  dashboardPluginOptionsSchema,
4930
5025
  defaultDashboardPluginOptions,
4931
- isDashboardEnabled
5026
+ isDashboardEnabled,
5027
+ resetDashboardOptions
4932
5028
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/plugin-dashboard",
3
- "version": "1.7.2",
3
+ "version": "1.8.1",
4
4
  "description": "Dashboard plugin for FrontMCP - visual monitoring and introspection of MCP servers",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "license": "Apache-2.0",
@@ -47,12 +47,12 @@
47
47
  }
48
48
  },
49
49
  "dependencies": {
50
- "@frontmcp/sdk": "1.7.2"
50
+ "@frontmcp/sdk": "1.8.1"
51
51
  },
52
52
  "devDependencies": {
53
53
  "reflect-metadata": "^0.2.2"
54
54
  },
55
55
  "peerDependencies": {
56
- "@frontmcp/lazy-zod": "1.7.2"
56
+ "@frontmcp/lazy-zod": "1.8.1"
57
57
  }
58
58
  }