sunpeak 0.20.51 → 0.20.53

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 (45) hide show
  1. package/bin/commands/inspect.mjs +79 -10
  2. package/dist/chatgpt/index.cjs +1 -1
  3. package/dist/chatgpt/index.js +1 -1
  4. package/dist/claude/index.cjs +1 -1
  5. package/dist/claude/index.js +1 -1
  6. package/dist/host/chatgpt/index.cjs +1 -1
  7. package/dist/host/chatgpt/index.js +1 -1
  8. package/dist/index.cjs +3 -3
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.js +3 -3
  11. package/dist/index.js.map +1 -1
  12. package/dist/inspector/index.cjs +1 -1
  13. package/dist/inspector/index.js +1 -1
  14. package/dist/{inspector-WPF8mKwk.cjs → inspector-BtYInER9.cjs} +2 -2
  15. package/dist/{inspector-WPF8mKwk.cjs.map → inspector-BtYInER9.cjs.map} +1 -1
  16. package/dist/{inspector-DQyl36w3.js → inspector-CEmRtVwc.js} +2 -2
  17. package/dist/{inspector-DQyl36w3.js.map → inspector-CEmRtVwc.js.map} +1 -1
  18. package/dist/mcp/index.cjs +1 -1
  19. package/dist/mcp/index.cjs.map +1 -1
  20. package/dist/mcp/index.js +1 -1
  21. package/dist/mcp/index.js.map +1 -1
  22. package/dist/{use-app-DzgUHmdH.cjs → use-app-DrKg-OJp.cjs} +2 -2
  23. package/dist/{use-app-DzgUHmdH.cjs.map → use-app-DrKg-OJp.cjs.map} +1 -1
  24. package/dist/{use-app-j3as_y6c.js → use-app-nZXXvUxc.js} +2 -2
  25. package/dist/{use-app-j3as_y6c.js.map → use-app-nZXXvUxc.js.map} +1 -1
  26. package/package.json +2 -2
  27. package/template/dist/albums/albums.json +1 -1
  28. package/template/dist/carousel/carousel.json +1 -1
  29. package/template/dist/map/map.json +1 -1
  30. package/template/dist/review/review.json +1 -1
  31. package/template/node_modules/.vite/deps/_metadata.json +3 -3
  32. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps.js +1 -1
  33. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps.js.map +1 -1
  34. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_app-bridge.js +1 -1
  35. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_app-bridge.js.map +1 -1
  36. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_react.js +1 -1
  37. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_react.js.map +1 -1
  38. package/template/node_modules/.vite-mcp/deps/_metadata.json +22 -22
  39. package/template/tests/e2e/visual.spec.ts-snapshots/albums-dark-chatgpt-linux.png +0 -0
  40. package/template/tests/e2e/visual.spec.ts-snapshots/albums-dark-claude-linux.png +0 -0
  41. package/template/tests/e2e/visual.spec.ts-snapshots/albums-fullscreen-chatgpt-linux.png +0 -0
  42. package/template/tests/e2e/visual.spec.ts-snapshots/albums-fullscreen-claude-darwin.png +0 -0
  43. package/template/tests/e2e/visual.spec.ts-snapshots/albums-fullscreen-claude-linux.png +0 -0
  44. package/template/tests/e2e/visual.spec.ts-snapshots/albums-light-chatgpt-linux.png +0 -0
  45. package/template/tests/e2e/visual.spec.ts-snapshots/albums-light-claude-linux.png +0 -0
@@ -19,6 +19,7 @@ const { existsSync, readdirSync, readFileSync } = fs;
19
19
  const { join, resolve, dirname, sep } = path;
20
20
  import { fileURLToPath, pathToFileURL } from 'url';
21
21
  import { execFile, spawn } from 'node:child_process';
22
+ import { randomBytes } from 'node:crypto';
22
23
  import { lookup as dnsLookup } from 'node:dns/promises';
23
24
  import { createServer as createHttpServer } from 'http';
24
25
  import { isIP } from 'node:net';
@@ -971,6 +972,42 @@ async function discoverSimulations(client) {
971
972
  return simulations;
972
973
  }
973
974
 
975
+ function createInspectorRequestToken() {
976
+ return randomBytes(32).toString('base64url');
977
+ }
978
+
979
+ function appendInspectorRequestToken(resourceUrl, requestToken) {
980
+ if (!resourceUrl || !requestToken) return resourceUrl;
981
+ try {
982
+ const parsed = new URL(resourceUrl, 'http://sunpeak.local');
983
+ parsed.searchParams.set('__sunpeak_token', requestToken);
984
+ if (resourceUrl.startsWith('http://') || resourceUrl.startsWith('https://')) {
985
+ return parsed.toString();
986
+ }
987
+ return `${parsed.pathname}${parsed.search}${parsed.hash}`;
988
+ } catch {
989
+ return resourceUrl;
990
+ }
991
+ }
992
+
993
+ function addInspectorRequestTokenToSimulations(simulations, requestToken) {
994
+ if (!requestToken || !simulations || typeof simulations !== 'object') return simulations;
995
+ return Object.fromEntries(
996
+ Object.entries(simulations).map(([name, sim]) => {
997
+ if (!sim || typeof sim !== 'object' || typeof sim.resourceUrl !== 'string') {
998
+ return [name, sim];
999
+ }
1000
+ return [
1001
+ name,
1002
+ {
1003
+ ...sim,
1004
+ resourceUrl: appendInspectorRequestToken(sim.resourceUrl, requestToken),
1005
+ },
1006
+ ];
1007
+ })
1008
+ );
1009
+ }
1010
+
974
1011
  /**
975
1012
  * Load simulation JSON fixtures from a directory and merge into discovered simulations.
976
1013
  *
@@ -1810,6 +1847,7 @@ async function runModelChat({
1810
1847
  * @param {string} appName - Display name
1811
1848
  * @param {string|null} appIcon - Icon URL or emoji
1812
1849
  * @param {string} sandboxUrl - Sandbox server URL
1850
+ * @param {string} requestToken - Unguessable token for frameable inspector resource URLs
1813
1851
  * @param {{ defaultProdResources?: boolean, hideInspectorModes?: boolean }} [modeFlags] - Mode toggles
1814
1852
  */
1815
1853
  function sunpeakInspectVirtualPlugin(
@@ -1818,6 +1856,7 @@ function sunpeakInspectVirtualPlugin(
1818
1856
  appName,
1819
1857
  appIcon,
1820
1858
  sandboxUrl,
1859
+ requestToken,
1821
1860
  modeFlags = {}
1822
1861
  ) {
1823
1862
  const ENTRY_ID = 'virtual:sunpeak-inspect-entry';
@@ -1837,7 +1876,7 @@ import { createRoot } from 'react-dom/client';
1837
1876
  import { Inspector } from 'sunpeak/inspector';
1838
1877
  import 'sunpeak/style.css';
1839
1878
 
1840
- const simulations = ${JSON.stringify(simulations)};
1879
+ const simulations = ${JSON.stringify(addInspectorRequestTokenToSimulations(simulations, requestToken))};
1841
1880
  const appName = ${JSON.stringify(appName ?? 'MCP Inspector')};
1842
1881
  const appIcon = ${JSON.stringify(appIcon ?? null)};
1843
1882
  const sandboxUrl = ${JSON.stringify(sandboxUrl)};
@@ -1897,7 +1936,7 @@ root.render(
1897
1936
  * Vite plugin for MCP server proxy endpoints.
1898
1937
  * @param {() => import('@modelcontextprotocol/sdk/client/index.js').Client} getClient
1899
1938
  * @param {(client: import('@modelcontextprotocol/sdk/client/index.js').Client) => void} setClient
1900
- * @param {{ callToolDirect?: (name: string, args: Record<string, unknown>) => Promise<object>, simulationsDir?: string | null, serverUrl?: string, liveServerUrl?: string }} [pluginOpts]
1939
+ * @param {{ callToolDirect?: (name: string, args: Record<string, unknown>) => Promise<object>, simulationsDir?: string | null, serverUrl?: string, liveServerUrl?: string, requestToken?: string }} [pluginOpts]
1901
1940
  */
1902
1941
  function sunpeakInspectEndpointsPlugin(getClient, setClient, pluginOpts = {}) {
1903
1942
  // Server URL and options for automatic session recovery.
@@ -1941,6 +1980,34 @@ function sunpeakInspectEndpointsPlugin(getClient, setClient, pluginOpts = {}) {
1941
1980
  if (pluginOpts.liveServerUrl) _liveServerUrl = pluginOpts.liveServerUrl;
1942
1981
  if (pluginOpts.connectionOpts) _connectionOpts = pluginOpts.connectionOpts;
1943
1982
 
1983
+ function sendTokenedSimulations(res, payload) {
1984
+ const body = {
1985
+ ...payload,
1986
+ ...(payload.simulations
1987
+ ? {
1988
+ simulations: addInspectorRequestTokenToSimulations(
1989
+ payload.simulations,
1990
+ pluginOpts.requestToken
1991
+ ),
1992
+ }
1993
+ : {}),
1994
+ };
1995
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1996
+ res.end(JSON.stringify(body));
1997
+ }
1998
+
1999
+ function requireInspectorRequestToken(req, res) {
2000
+ if (!pluginOpts.requestToken) return true;
2001
+ const fetchSiteHeader = req.headers['sec-fetch-site'];
2002
+ const fetchSite = Array.isArray(fetchSiteHeader) ? fetchSiteHeader[0] : fetchSiteHeader;
2003
+ if (fetchSite !== 'cross-site') return true;
2004
+ const url = new URL(req.url, 'http://localhost');
2005
+ if (url.searchParams.get('__sunpeak_token') === pluginOpts.requestToken) return true;
2006
+ res.writeHead(403, { 'Content-Type': 'text/plain' });
2007
+ res.end('Forbidden: missing or invalid inspector request token');
2008
+ return false;
2009
+ }
2010
+
1944
2011
  async function withModelChatClient(callback) {
1945
2012
  const targetUrl = _liveServerUrl || _serverUrl;
1946
2013
  if (!targetUrl?.startsWith('http://') && !targetUrl?.startsWith('https://')) {
@@ -2333,8 +2400,7 @@ function sunpeakInspectEndpointsPlugin(getClient, setClient, pluginOpts = {}) {
2333
2400
  if (pluginOpts.simulationsDir) {
2334
2401
  mergeSimulationFixtures(pluginOpts.simulationsDir, simulations);
2335
2402
  }
2336
- res.writeHead(200, { 'Content-Type': 'application/json' });
2337
- res.end(JSON.stringify({ status: 'ok', simulations }));
2403
+ sendTokenedSimulations(res, { status: 'ok', simulations });
2338
2404
  } catch (err) {
2339
2405
  res.writeHead(500, { 'Content-Type': 'application/json' });
2340
2406
  res.end(JSON.stringify({ error: err.message }));
@@ -2432,8 +2498,7 @@ function sunpeakInspectEndpointsPlugin(getClient, setClient, pluginOpts = {}) {
2432
2498
  if (pluginOpts.simulationsDir) {
2433
2499
  mergeSimulationFixtures(pluginOpts.simulationsDir, simulations);
2434
2500
  }
2435
- res.writeHead(200, { 'Content-Type': 'application/json' });
2436
- res.end(JSON.stringify({ status: 'authorized', simulations }));
2501
+ sendTokenedSimulations(res, { status: 'authorized', simulations });
2437
2502
  return;
2438
2503
  } catch {
2439
2504
  // Tokens may be expired, fall through to fresh auth below
@@ -2512,8 +2577,7 @@ function sunpeakInspectEndpointsPlugin(getClient, setClient, pluginOpts = {}) {
2512
2577
  if (pluginOpts.simulationsDir) {
2513
2578
  mergeSimulationFixtures(pluginOpts.simulationsDir, simulations);
2514
2579
  }
2515
- res.writeHead(200, { 'Content-Type': 'application/json' });
2516
- res.end(JSON.stringify({ status: 'authorized', simulations }));
2580
+ sendTokenedSimulations(res, { status: 'authorized', simulations });
2517
2581
  }
2518
2582
  } catch (err) {
2519
2583
  res.writeHead(500, { 'Content-Type': 'application/json' });
@@ -2700,8 +2764,7 @@ function sunpeakInspectEndpointsPlugin(getClient, setClient, pluginOpts = {}) {
2700
2764
  mergeSimulationFixtures(pluginOpts.simulationsDir, simulations);
2701
2765
  }
2702
2766
 
2703
- res.writeHead(200, { 'Content-Type': 'application/json' });
2704
- res.end(JSON.stringify({ status: 'ok', simulations }));
2767
+ sendTokenedSimulations(res, { status: 'ok', simulations });
2705
2768
  } catch (err) {
2706
2769
  res.writeHead(500, { 'Content-Type': 'application/json' });
2707
2770
  res.end(JSON.stringify({ error: err.message }));
@@ -2826,6 +2889,7 @@ function sunpeakInspectEndpointsPlugin(getClient, setClient, pluginOpts = {}) {
2826
2889
  // Read resource from connected server
2827
2890
  server.middlewares.use('/__sunpeak/read-resource', async (req, res) => {
2828
2891
  if (!requireSameOrigin(req, res, { allowCrossSiteIframeNavigation: true })) return;
2892
+ if (!requireInspectorRequestToken(req, res)) return;
2829
2893
  const url = new URL(req.url, 'http://localhost');
2830
2894
  const uri = url.searchParams.get('uri');
2831
2895
  if (!uri) {
@@ -2956,6 +3020,8 @@ export const _securityTestExports = {
2956
3020
  executeModelChatToolCall,
2957
3021
  formatModelVisibleToolResult,
2958
3022
  formatSharedAppContextForModel,
3023
+ addInspectorRequestTokenToSimulations,
3024
+ appendInspectorRequestToken,
2959
3025
  normalizeApiKey,
2960
3026
  normalizeModelChatMessages,
2961
3027
  normalizeModelAppContext,
@@ -3210,6 +3276,7 @@ export async function inspectServer(opts) {
3210
3276
  const inspectorServerUrl = resolvedServerUrl;
3211
3277
  const liveInspectorServerUrl =
3212
3278
  liveServerArg ?? defaultLiveMcpServerUrl(resolvedServerUrl) ?? resolvedServerUrl;
3279
+ const inspectorRequestToken = createInspectorRequestToken();
3213
3280
 
3214
3281
  // Create the Vite server.
3215
3282
  // Use the sunpeak package dir as root to avoid scanning the user's project
@@ -3268,6 +3335,7 @@ export async function inspectServer(opts) {
3268
3335
  serverAppName,
3269
3336
  serverAppIcon,
3270
3337
  sandbox.url,
3338
+ inspectorRequestToken,
3271
3339
  { defaultProdResources, hideInspectorModes: !frameworkMode }
3272
3340
  ),
3273
3341
  sunpeakInspectEndpointsPlugin(
@@ -3280,6 +3348,7 @@ export async function inspectServer(opts) {
3280
3348
  simulationsDir,
3281
3349
  serverUrl: resolvedServerUrl,
3282
3350
  liveServerUrl: liveInspectorServerUrl,
3351
+ requestToken: inspectorRequestToken,
3283
3352
  connectionOpts,
3284
3353
  }
3285
3354
  ),
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("../chunk-Cek0wNdY.cjs");
3
- const require_inspector = require("../inspector-WPF8mKwk.cjs");
3
+ const require_inspector = require("../inspector-BtYInER9.cjs");
4
4
  const require_inspector_url = require("../inspector-url-C0I97f8-.cjs");
5
5
  const require_discovery = require("../discovery-31_n0zcu.cjs");
6
6
  //#region src/chatgpt/index.ts
@@ -1,5 +1,5 @@
1
1
  import { Ct as __exportAll } from "../protocol-Cw9Op_hM.js";
2
- import { C as McpAppHost, S as extractResourceCSP, f as ThemeProvider, p as useThemeContext, r as resolveServerToolResult, t as Inspector, w as SCREEN_WIDTHS, x as IframeResource } from "../inspector-DQyl36w3.js";
2
+ import { C as McpAppHost, S as extractResourceCSP, f as ThemeProvider, p as useThemeContext, r as resolveServerToolResult, t as Inspector, w as SCREEN_WIDTHS, x as IframeResource } from "../inspector-CEmRtVwc.js";
3
3
  import { t as createInspectorUrl } from "../inspector-url-vtW8g8yB.js";
4
4
  import { c as toPascalCase, i as findResourceKey, n as extractSimulationKey, r as findResourceDirs, s as getComponentName, t as extractResourceKey } from "../discovery-DOVner--.js";
5
5
  //#region src/chatgpt/index.ts
@@ -1,4 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("../chunk-Cek0wNdY.cjs");
3
- const require_inspector = require("../inspector-WPF8mKwk.cjs");
3
+ const require_inspector = require("../inspector-BtYInER9.cjs");
4
4
  exports.Inspector = require_inspector.Inspector;
@@ -1,2 +1,2 @@
1
- import { t as Inspector } from "../inspector-DQyl36w3.js";
1
+ import { t as Inspector } from "../inspector-CEmRtVwc.js";
2
2
  export { Inspector };
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("../../chunk-Cek0wNdY.cjs");
3
- const require_use_app = require("../../use-app-DzgUHmdH.cjs");
3
+ const require_use_app = require("../../use-app-DrKg-OJp.cjs");
4
4
  let react = require("react");
5
5
  //#region src/host/chatgpt/openai-types.ts
6
6
  /**
@@ -1,4 +1,4 @@
1
- import { t as useApp } from "../../use-app-j3as_y6c.js";
1
+ import { t as useApp } from "../../use-app-nZXXvUxc.js";
2
2
  import { useCallback } from "react";
3
3
  //#region src/host/chatgpt/openai-types.ts
4
4
  /**
package/dist/index.cjs CHANGED
@@ -1,15 +1,15 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("./chunk-Cek0wNdY.cjs");
3
3
  const require_protocol = require("./protocol-BDytMFPA.cjs");
4
- const require_use_app = require("./use-app-DzgUHmdH.cjs");
5
- const require_inspector = require("./inspector-WPF8mKwk.cjs");
4
+ const require_use_app = require("./use-app-DrKg-OJp.cjs");
5
+ const require_inspector = require("./inspector-BtYInER9.cjs");
6
6
  const require_host_index = require("./host/index.cjs");
7
7
  const require_inspector_index = require("./inspector/index.cjs");
8
8
  const require_chatgpt_index = require("./chatgpt/index.cjs");
9
9
  let react = require("react");
10
10
  react = require_chunk.__toESM(react, 1);
11
11
  let react_jsx_runtime = require("react/jsx-runtime");
12
- //#region ../../node_modules/.pnpm/@modelcontextprotocol+ext-apps@1.7.3_@modelcontextprotocol+sdk@1.29.0_zod@4.4.3__react-_eeb2b05587eabe4742497eb1f1b87bd3/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/index.js
12
+ //#region ../../node_modules/.pnpm/@modelcontextprotocol+ext-apps@1.7.4_@modelcontextprotocol+sdk@1.29.0_zod@4.4.3__react-_bc4d5adeaec14d46b9a46bfff8177b13/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/index.js
13
13
  ((K) => typeof require < "u" ? require : typeof Proxy < "u" ? new Proxy(K, { get: (Q, X) => (typeof require < "u" ? require : Q)[X] }) : K)(function(K) {
14
14
  if (typeof require < "u") return require.apply(this, arguments);
15
15
  throw Error("Dynamic require of \"" + K + "\" is not supported");