@spotlightjs/spotlight 4.7.0 → 4.7.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 (119) hide show
  1. package/dist/_virtual/_sentry-release-injection-file.js +2 -2
  2. package/dist/node_modules/.pnpm/uri-js@4.4.1/node_modules/uri-js/dist/es5/uri.all.js +17 -17
  3. package/dist/node_modules/.pnpm/uri-js@4.4.1/node_modules/uri-js/dist/es5/uri.all.js.map +1 -1
  4. package/dist/run.js +4 -3
  5. package/dist/run.js.map +1 -1
  6. package/dist/sentry-config.js +4 -3
  7. package/dist/sentry-config.js.map +1 -1
  8. package/dist/server/cli/mcp.js.map +1 -1
  9. package/dist/server/cli/run.js +2 -2
  10. package/dist/server/cli.js +2 -2
  11. package/dist/server/formatters/human/utils.js +9 -4
  12. package/dist/server/formatters/human/utils.js.map +1 -1
  13. package/dist/server/mcp/mcp.js +2 -2
  14. package/dist/server/routes/stream/index.js +7 -4
  15. package/dist/server/routes/stream/index.js.map +1 -1
  16. package/dist/server/sdk.d.ts +1 -1
  17. package/dist/server/sdk.js.map +1 -1
  18. package/dist/server/utils/docker-compose.js +2 -2
  19. package/dist/ui/assets/index.js +64 -64
  20. package/dist/ui/assets/index.js.map +1 -1
  21. package/dist/ui/assets/instrumentation.js +15 -15
  22. package/dist/ui/assets/instrumentation.js.map +1 -1
  23. package/dist/ui/assets/main.css +1 -1
  24. package/dist/ui/assets/main.js +1 -1
  25. package/dist/ui/assets/serverTimingMeta.js +11 -11
  26. package/dist/ui/assets/serverTimingMeta.js.map +1 -1
  27. package/package.json +7 -3
  28. package/dist/_virtual/re.js +0 -13
  29. package/dist/_virtual/re.js.map +0 -1
  30. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/comparator.js +0 -132
  31. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/comparator.js.map +0 -1
  32. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/range.js +0 -397
  33. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/range.js.map +0 -1
  34. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/semver.js +0 -286
  35. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/semver.js.map +0 -1
  36. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/clean.js +0 -20
  37. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/clean.js.map +0 -1
  38. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/cmp.js +0 -62
  39. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/cmp.js.map +0 -1
  40. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/coerce.js +0 -55
  41. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/coerce.js.map +0 -1
  42. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-build.js +0 -21
  43. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-build.js.map +0 -1
  44. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-loose.js +0 -17
  45. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-loose.js.map +0 -1
  46. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare.js +0 -17
  47. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare.js.map +0 -1
  48. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/diff.js +0 -51
  49. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/diff.js.map +0 -1
  50. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/eq.js +0 -17
  51. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/eq.js.map +0 -1
  52. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gt.js +0 -17
  53. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gt.js.map +0 -1
  54. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gte.js +0 -17
  55. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gte.js.map +0 -1
  56. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/inc.js +0 -31
  57. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/inc.js.map +0 -1
  58. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lt.js +0 -17
  59. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lt.js.map +0 -1
  60. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lte.js +0 -17
  61. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lte.js.map +0 -1
  62. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/major.js +0 -17
  63. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/major.js.map +0 -1
  64. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/minor.js +0 -17
  65. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/minor.js.map +0 -1
  66. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/neq.js +0 -17
  67. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/neq.js.map +0 -1
  68. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/parse.js +0 -29
  69. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/parse.js.map +0 -1
  70. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/patch.js +0 -17
  71. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/patch.js.map +0 -1
  72. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/prerelease.js +0 -20
  73. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/prerelease.js.map +0 -1
  74. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rcompare.js +0 -17
  75. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rcompare.js.map +0 -1
  76. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rsort.js +0 -17
  77. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rsort.js.map +0 -1
  78. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/satisfies.js +0 -24
  79. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/satisfies.js.map +0 -1
  80. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/sort.js +0 -17
  81. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/sort.js.map +0 -1
  82. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/valid.js +0 -20
  83. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/valid.js.map +0 -1
  84. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/index.js +0 -143
  85. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/index.js.map +0 -1
  86. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/constants.js +0 -38
  87. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/constants.js.map +0 -1
  88. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/debug.js +0 -16
  89. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/debug.js.map +0 -1
  90. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/identifiers.js +0 -31
  91. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/identifiers.js.map +0 -1
  92. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/lrucache.js +0 -44
  93. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/lrucache.js.map +0 -1
  94. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/parse-options.js +0 -25
  95. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/parse-options.js.map +0 -1
  96. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/re.js +0 -100
  97. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/re.js.map +0 -1
  98. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/gtr.js +0 -17
  99. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/gtr.js.map +0 -1
  100. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/intersects.js +0 -21
  101. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/intersects.js.map +0 -1
  102. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/ltr.js +0 -17
  103. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/ltr.js.map +0 -1
  104. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/max-satisfying.js +0 -37
  105. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/max-satisfying.js.map +0 -1
  106. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-satisfying.js +0 -37
  107. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-satisfying.js.map +0 -1
  108. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-version.js +0 -66
  109. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-version.js.map +0 -1
  110. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/outside.js +0 -83
  111. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/outside.js.map +0 -1
  112. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/simplify.js +0 -58
  113. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/simplify.js.map +0 -1
  114. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/subset.js +0 -172
  115. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/subset.js.map +0 -1
  116. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/to-comparators.js +0 -17
  117. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/to-comparators.js.map +0 -1
  118. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/valid.js +0 -23
  119. package/dist/node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/valid.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.js","sources":["../../../src/server/cli/mcp.ts"],"sourcesContent":["import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { captureException } from \"@sentry/node\";\nimport { ServerType as ProxyServerType, startStdioServer } from \"mcp-proxy\";\nimport { logger } from \"../logger.ts\";\nimport { setShutdownHandlers, startServer } from \"../main.ts\";\nimport { createMCPInstance } from \"../mcp/mcp.ts\";\nimport type { CLIHandlerOptions } from \"../types/cli.ts\";\nimport type { NormalizedAllowedOrigins } from \"../types/utils.ts\";\nimport { normalizeAllowedOrigins } from \"../utils/cors.ts\";\nimport { isSidecarRunning } from \"../utils/extras.ts\";\n\nasync function startServerWithStdioMCP(\n port: CLIHandlerOptions[\"port\"],\n basePath: CLIHandlerOptions[\"basePath\"],\n filesToServe: CLIHandlerOptions[\"filesToServe\"],\n normalizedAllowedOrigins: NormalizedAllowedOrigins | undefined,\n) {\n const serverInstance = await startServer({\n port,\n basePath,\n filesToServe,\n normalizedAllowedOrigins,\n });\n setShutdownHandlers(serverInstance);\n\n logger.info(\"Starting MCP over stdio too...\");\n const mcpInstance = createMCPInstance();\n await mcpInstance.connect(new StdioServerTransport());\n\n const shutdownMcp = () => {\n mcpInstance.close();\n };\n\n process.on(\"SIGINT\", shutdownMcp);\n process.on(\"SIGTERM\", shutdownMcp);\n\n return serverInstance;\n}\n\nasync function startMCPStdioHTTPProxy(\n port: CLIHandlerOptions[\"port\"],\n basePath: CLIHandlerOptions[\"basePath\"],\n filesToServe: CLIHandlerOptions[\"filesToServe\"],\n normalizedAllowedOrigins: NormalizedAllowedOrigins | undefined,\n) {\n let intentionalShutdown = false;\n let client: Client | null = null;\n let server: Awaited<ReturnType<typeof startStdioServer>> | null = null;\n\n const shutdown = async () => {\n if (intentionalShutdown) {\n // If we get the signal again, exit immediately\n logger.info(\"Bye.\");\n process.exit(0);\n }\n\n intentionalShutdown = true;\n logger.info(\"Shutting down MCP stdio proxy...\");\n\n if (client) {\n await client.close();\n }\n if (server) {\n await server.close();\n }\n };\n\n // Set up signal handlers for graceful shutdown\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n server = await startStdioServer({\n // We need to hook into `initStreamClient` as the returned object from startStdioServer\n // is not a meta proxy object giving access to both the server and the client. It just\n // returns the StdioServerTransport instance without a way to access the client or its errors.\n // TODO: We should probably upstream a fix for this to close the server or bubble the errors\n initStreamClient: () => {\n client = new Client({\n name: \"Spotlight Sidecar (stdio proxy)\",\n version: \"1.0.0\",\n });\n client.onerror = async (err: Error) => {\n if (\n err.message.startsWith(\"Maximum reconnection attempts\") ||\n /disconnected|fetch failed|connection closed/i.test(err.message)\n ) {\n if (client) await client.close();\n if (server) await server.close();\n } else if (!/conflict/i.test(err.message)) {\n captureException(err);\n logger.error(`MCP stdio proxy error: ${err.name}: ${err.message}`);\n }\n };\n return Promise.resolve(client);\n },\n serverType: ProxyServerType.HTTPStream,\n url: `http://localhost:${port}/mcp`,\n });\n server.onclose = async () => {\n // If this is an intentional shutdown, don't restart\n if (intentionalShutdown) {\n logger.info(\"MCP stdio proxy server closed.\");\n return;\n }\n\n logger.info(\"MCP stdio proxy server closed unexpectedly. Attempting to restart...\");\n process.off(\"SIGINT\", shutdown);\n process.off(\"SIGTERM\", shutdown);\n // We need to manually resume stdin as `StdioServerTransport` pauses it on\n // close but does not `resume` it when a new instance is created. Probably\n // a bug in https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/server/stdio.ts\n process.stdin.resume();\n\n try {\n await startMCPStdioHTTPProxy(port, basePath, filesToServe, normalizedAllowedOrigins);\n logger.info(\"Connection restored\");\n } catch (_err) {\n try {\n return await startServerWithStdioMCP(port, basePath, filesToServe, normalizedAllowedOrigins);\n } catch (_err2) {\n logger.error(\"Failed to restart sidecar server after MCP stdio proxy closed.\");\n captureException(_err2);\n await startMCPStdioHTTPProxy(port, basePath, filesToServe, normalizedAllowedOrigins);\n }\n }\n };\n}\n\nexport default async function mcp({ port, basePath, filesToServe, allowedOrigins }: CLIHandlerOptions) {\n // Normalize allowed origins once at startup\n const normalizedAllowedOrigins = allowedOrigins ? normalizeAllowedOrigins(allowedOrigins) : undefined;\n\n if (port > 0 && (await isSidecarRunning(port))) {\n logger.info(\"Connecting to existing MCP instance with stdio proxy...\");\n await startMCPStdioHTTPProxy(port, basePath, filesToServe, normalizedAllowedOrigins);\n logger.info(`Connected to existing MCP instance on port ${port}`);\n } else {\n return await startServerWithStdioMCP(port, basePath, filesToServe, normalizedAllowedOrigins);\n }\n}\n"],"names":["ProxyServerType"],"mappings":";;;;;;;;;;;;;;;;;;AAYA,eAAe,wBACb,MACA,UACA,cACA,0BACA;AACA,QAAM,iBAAiB,MAAM,YAAY;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,CACD;AACD,sBAAoB,cAAc;AAElC,SAAO,KAAK,gCAAgC;AAC5C,QAAM,cAAc,kBAAA;AACpB,QAAM,YAAY,QAAQ,IAAI,sBAAsB;AAEpD,QAAM,cAAc,MAAM;AACxB,gBAAY,MAAA;AAAA,EACd;AAEA,UAAQ,GAAG,UAAU,WAAW;AAChC,UAAQ,GAAG,WAAW,WAAW;AAEjC,SAAO;AACT;AAEA,eAAe,uBACb,MACA,UACA,cACA,0BACA;AACA,MAAI,sBAAsB;AAC1B,MAAI,SAAwB;AAC5B,MAAI,SAA8D;AAElE,QAAM,WAAW,YAAY;AAC3B,QAAI,qBAAqB;AAEvB,aAAO,KAAK,MAAM;AAClB,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,0BAAsB;AACtB,WAAO,KAAK,kCAAkC;AAE9C,QAAI,QAAQ;AACV,YAAM,OAAO,MAAA;AAAA,IACf;AACA,QAAI,QAAQ;AACV,YAAM,OAAO,MAAA;AAAA,IACf;AAAA,EACF;AAGA,UAAQ,GAAG,UAAU,QAAQ;AAC7B,UAAQ,GAAG,WAAW,QAAQ;AAE9B,WAAS,MAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA,IAK9B,kBAAkB,MAAM;AACtB,eAAS,IAAI,OAAO;AAAA,QAClB,MAAM;AAAA,QACN,SAAS;AAAA,MAAA,CACV;AACD,aAAO,UAAU,OAAO,QAAe;AACrC,YACE,IAAI,QAAQ,WAAW,+BAA+B,KACtD,+CAA+C,KAAK,IAAI,OAAO,GAC/D;AACA,cAAI,OAAQ,OAAM,OAAO,MAAA;AACzB,cAAI,OAAQ,OAAM,OAAO,MAAA;AAAA,QAC3B,WAAW,CAAC,YAAY,KAAK,IAAI,OAAO,GAAG;AACzC,2BAAiB,GAAG;AACpB,iBAAO,MAAM,0BAA0B,IAAI,IAAI,KAAK,IAAI,OAAO,EAAE;AAAA,QACnE;AAAA,MACF;AACA,aAAO,QAAQ,QAAQ,MAAM;AAAA,IAC/B;AAAA,IACA,YAAYA,WAAgB;AAAA,IAC5B,KAAK,oBAAoB,IAAI;AAAA,EAAA,CAC9B;AACD,SAAO,UAAU,YAAY;AAE3B,QAAI,qBAAqB;AACvB,aAAO,KAAK,gCAAgC;AAC5C;AAAA,IACF;AAEA,WAAO,KAAK,sEAAsE;AAClF,YAAQ,IAAI,UAAU,QAAQ;AAC9B,YAAQ,IAAI,WAAW,QAAQ;AAI/B,YAAQ,MAAM,OAAA;AAEd,QAAI;AACF,YAAM,uBAAuB,MAAM,UAAU,cAAc,wBAAwB;AACnF,aAAO,KAAK,qBAAqB;AAAA,IACnC,SAAS,MAAM;AACb,UAAI;AACF,eAAO,MAAM,wBAAwB,MAAM,UAAU,cAAc,wBAAwB;AAAA,MAC7F,SAAS,OAAO;AACd,eAAO,MAAM,gEAAgE;AAC7E,yBAAiB,KAAK;AACtB,cAAM,uBAAuB,MAAM,UAAU,cAAc,wBAAwB;AAAA,MACrF;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAA8B,IAAI,EAAE,MAAM,UAAU,cAAc,kBAAqC;AAErG,QAAM,2BAA2B,iBAAiB,wBAAwB,cAAc,IAAI;AAE5F,MAAI,OAAO,KAAM,MAAM,iBAAiB,IAAI,GAAI;AAC9C,WAAO,KAAK,yDAAyD;AACrE,UAAM,uBAAuB,MAAM,UAAU,cAAc,wBAAwB;AACnF,WAAO,KAAK,8CAA8C,IAAI,EAAE;AAAA,EAClE,OAAO;AACL,WAAO,MAAM,wBAAwB,MAAM,UAAU,cAAc,wBAAwB;AAAA,EAC7F;AACF;"}
1
+ {"version":3,"file":"mcp.js","sources":["../../../src/server/cli/mcp.ts"],"sourcesContent":["import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { captureException } from \"@sentry/node\";\nimport { ServerType as ProxyServerType, startStdioServer } from \"mcp-proxy\";\nimport { logger } from \"../logger.ts\";\nimport { setShutdownHandlers, startServer } from \"../main.ts\";\nimport { createMCPInstance } from \"../mcp/mcp.ts\";\nimport type { CLIHandlerOptions } from \"../types/cli.ts\";\nimport type { NormalizedAllowedOrigins } from \"../utils/cors.ts\";\nimport { normalizeAllowedOrigins } from \"../utils/cors.ts\";\nimport { isSidecarRunning } from \"../utils/extras.ts\";\n\nasync function startServerWithStdioMCP(\n port: CLIHandlerOptions[\"port\"],\n basePath: CLIHandlerOptions[\"basePath\"],\n filesToServe: CLIHandlerOptions[\"filesToServe\"],\n normalizedAllowedOrigins: NormalizedAllowedOrigins | undefined,\n) {\n const serverInstance = await startServer({\n port,\n basePath,\n filesToServe,\n normalizedAllowedOrigins,\n });\n setShutdownHandlers(serverInstance);\n\n logger.info(\"Starting MCP over stdio too...\");\n const mcpInstance = createMCPInstance();\n await mcpInstance.connect(new StdioServerTransport());\n\n const shutdownMcp = () => {\n mcpInstance.close();\n };\n\n process.on(\"SIGINT\", shutdownMcp);\n process.on(\"SIGTERM\", shutdownMcp);\n\n return serverInstance;\n}\n\nasync function startMCPStdioHTTPProxy(\n port: CLIHandlerOptions[\"port\"],\n basePath: CLIHandlerOptions[\"basePath\"],\n filesToServe: CLIHandlerOptions[\"filesToServe\"],\n normalizedAllowedOrigins: NormalizedAllowedOrigins | undefined,\n) {\n let intentionalShutdown = false;\n let client: Client | null = null;\n let server: Awaited<ReturnType<typeof startStdioServer>> | null = null;\n\n const shutdown = async () => {\n if (intentionalShutdown) {\n // If we get the signal again, exit immediately\n logger.info(\"Bye.\");\n process.exit(0);\n }\n\n intentionalShutdown = true;\n logger.info(\"Shutting down MCP stdio proxy...\");\n\n if (client) {\n await client.close();\n }\n if (server) {\n await server.close();\n }\n };\n\n // Set up signal handlers for graceful shutdown\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n server = await startStdioServer({\n // We need to hook into `initStreamClient` as the returned object from startStdioServer\n // is not a meta proxy object giving access to both the server and the client. It just\n // returns the StdioServerTransport instance without a way to access the client or its errors.\n // TODO: We should probably upstream a fix for this to close the server or bubble the errors\n initStreamClient: () => {\n client = new Client({\n name: \"Spotlight Sidecar (stdio proxy)\",\n version: \"1.0.0\",\n });\n client.onerror = async (err: Error) => {\n if (\n err.message.startsWith(\"Maximum reconnection attempts\") ||\n /disconnected|fetch failed|connection closed/i.test(err.message)\n ) {\n if (client) await client.close();\n if (server) await server.close();\n } else if (!/conflict/i.test(err.message)) {\n captureException(err);\n logger.error(`MCP stdio proxy error: ${err.name}: ${err.message}`);\n }\n };\n return Promise.resolve(client);\n },\n serverType: ProxyServerType.HTTPStream,\n url: `http://localhost:${port}/mcp`,\n });\n server.onclose = async () => {\n // If this is an intentional shutdown, don't restart\n if (intentionalShutdown) {\n logger.info(\"MCP stdio proxy server closed.\");\n return;\n }\n\n logger.info(\"MCP stdio proxy server closed unexpectedly. Attempting to restart...\");\n process.off(\"SIGINT\", shutdown);\n process.off(\"SIGTERM\", shutdown);\n // We need to manually resume stdin as `StdioServerTransport` pauses it on\n // close but does not `resume` it when a new instance is created. Probably\n // a bug in https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/server/stdio.ts\n process.stdin.resume();\n\n try {\n await startMCPStdioHTTPProxy(port, basePath, filesToServe, normalizedAllowedOrigins);\n logger.info(\"Connection restored\");\n } catch (_err) {\n try {\n return await startServerWithStdioMCP(port, basePath, filesToServe, normalizedAllowedOrigins);\n } catch (_err2) {\n logger.error(\"Failed to restart sidecar server after MCP stdio proxy closed.\");\n captureException(_err2);\n await startMCPStdioHTTPProxy(port, basePath, filesToServe, normalizedAllowedOrigins);\n }\n }\n };\n}\n\nexport default async function mcp({ port, basePath, filesToServe, allowedOrigins }: CLIHandlerOptions) {\n // Normalize allowed origins once at startup\n const normalizedAllowedOrigins = allowedOrigins ? normalizeAllowedOrigins(allowedOrigins) : undefined;\n\n if (port > 0 && (await isSidecarRunning(port))) {\n logger.info(\"Connecting to existing MCP instance with stdio proxy...\");\n await startMCPStdioHTTPProxy(port, basePath, filesToServe, normalizedAllowedOrigins);\n logger.info(`Connected to existing MCP instance on port ${port}`);\n } else {\n return await startServerWithStdioMCP(port, basePath, filesToServe, normalizedAllowedOrigins);\n }\n}\n"],"names":["ProxyServerType"],"mappings":";;;;;;;;;;;;;;;;;;AAYA,eAAe,wBACb,MACA,UACA,cACA,0BACA;AACA,QAAM,iBAAiB,MAAM,YAAY;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,CACD;AACD,sBAAoB,cAAc;AAElC,SAAO,KAAK,gCAAgC;AAC5C,QAAM,cAAc,kBAAA;AACpB,QAAM,YAAY,QAAQ,IAAI,sBAAsB;AAEpD,QAAM,cAAc,MAAM;AACxB,gBAAY,MAAA;AAAA,EACd;AAEA,UAAQ,GAAG,UAAU,WAAW;AAChC,UAAQ,GAAG,WAAW,WAAW;AAEjC,SAAO;AACT;AAEA,eAAe,uBACb,MACA,UACA,cACA,0BACA;AACA,MAAI,sBAAsB;AAC1B,MAAI,SAAwB;AAC5B,MAAI,SAA8D;AAElE,QAAM,WAAW,YAAY;AAC3B,QAAI,qBAAqB;AAEvB,aAAO,KAAK,MAAM;AAClB,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,0BAAsB;AACtB,WAAO,KAAK,kCAAkC;AAE9C,QAAI,QAAQ;AACV,YAAM,OAAO,MAAA;AAAA,IACf;AACA,QAAI,QAAQ;AACV,YAAM,OAAO,MAAA;AAAA,IACf;AAAA,EACF;AAGA,UAAQ,GAAG,UAAU,QAAQ;AAC7B,UAAQ,GAAG,WAAW,QAAQ;AAE9B,WAAS,MAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA,IAK9B,kBAAkB,MAAM;AACtB,eAAS,IAAI,OAAO;AAAA,QAClB,MAAM;AAAA,QACN,SAAS;AAAA,MAAA,CACV;AACD,aAAO,UAAU,OAAO,QAAe;AACrC,YACE,IAAI,QAAQ,WAAW,+BAA+B,KACtD,+CAA+C,KAAK,IAAI,OAAO,GAC/D;AACA,cAAI,OAAQ,OAAM,OAAO,MAAA;AACzB,cAAI,OAAQ,OAAM,OAAO,MAAA;AAAA,QAC3B,WAAW,CAAC,YAAY,KAAK,IAAI,OAAO,GAAG;AACzC,2BAAiB,GAAG;AACpB,iBAAO,MAAM,0BAA0B,IAAI,IAAI,KAAK,IAAI,OAAO,EAAE;AAAA,QACnE;AAAA,MACF;AACA,aAAO,QAAQ,QAAQ,MAAM;AAAA,IAC/B;AAAA,IACA,YAAYA,WAAgB;AAAA,IAC5B,KAAK,oBAAoB,IAAI;AAAA,EAAA,CAC9B;AACD,SAAO,UAAU,YAAY;AAE3B,QAAI,qBAAqB;AACvB,aAAO,KAAK,gCAAgC;AAC5C;AAAA,IACF;AAEA,WAAO,KAAK,sEAAsE;AAClF,YAAQ,IAAI,UAAU,QAAQ;AAC9B,YAAQ,IAAI,WAAW,QAAQ;AAI/B,YAAQ,MAAM,OAAA;AAEd,QAAI;AACF,YAAM,uBAAuB,MAAM,UAAU,cAAc,wBAAwB;AACnF,aAAO,KAAK,qBAAqB;AAAA,IACnC,SAAS,MAAM;AACb,UAAI;AACF,eAAO,MAAM,wBAAwB,MAAM,UAAU,cAAc,wBAAwB;AAAA,MAC7F,SAAS,OAAO;AACd,eAAO,MAAM,gEAAgE;AAC7E,yBAAiB,KAAK;AACtB,cAAM,uBAAuB,MAAM,UAAU,cAAc,wBAAwB;AAAA,MACrF;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAA8B,IAAI,EAAE,MAAM,UAAU,cAAc,kBAAqC;AAErG,QAAM,2BAA2B,iBAAiB,wBAAwB,cAAc,IAAI;AAE5F,MAAI,OAAO,KAAM,MAAM,iBAAiB,IAAI,GAAI;AAC9C,WAAO,KAAK,yDAAyD;AACrE,UAAM,uBAAuB,MAAM,UAAU,cAAc,wBAAwB;AACnF,WAAO,KAAK,8CAA8C,IAAI,EAAE;AAAA,EAClE,OAAO;AACL,WAAO,MAAM,wBAAwB,MAAM,UAAU,cAAc,wBAAwB;AAAA,EAC7F;AACF;"}
@@ -2,7 +2,7 @@
2
2
  !function() {
3
3
  try {
4
4
  var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
5
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "9f503b77-04fa-40f8-99a2-a8cb0ebd55db", e._sentryDebugIdIdentifier = "sentry-dbid-9f503b77-04fa-40f8-99a2-a8cb0ebd55db");
5
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "d80c232c-dfe0-4e60-8770-34fe04e96b35", e._sentryDebugIdIdentifier = "sentry-dbid-d80c232c-dfe0-4e60-8770-34fe04e96b35");
6
6
  } catch (e2) {
7
7
  }
8
8
  }();
@@ -24,7 +24,7 @@ import "node:dns/promises";
24
24
  import "node:net";
25
25
  import "node:os";
26
26
  import tail from "./tail.js";
27
- const SPOTLIGHT_VERSION = "4.7.0";
27
+ const SPOTLIGHT_VERSION = "4.7.2";
28
28
  const LOCALHOST_HOST = "localhost";
29
29
  const DOCKER_HOST = "host.docker.internal";
30
30
  function detectPackageJson() {
@@ -2,7 +2,7 @@
2
2
  !function() {
3
3
  try {
4
4
  var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
5
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "dec52abc-85c7-4e57-b5d4-f48ea3ffc407", e._sentryDebugIdIdentifier = "sentry-dbid-dec52abc-85c7-4e57-b5d4-f48ea3ffc407");
5
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "2fc3f6e8-14bb-49cb-b7d3-76d936f1e359", e._sentryDebugIdIdentifier = "sentry-dbid-2fc3f6e8-14bb-49cb-b7d3-76d936f1e359");
6
6
  } catch (e2) {
7
7
  }
8
8
  }();
@@ -122,7 +122,7 @@ async function main({
122
122
  if (debug || process.env.SPOTLIGHT_DEBUG) {
123
123
  enableDebugLogging(true);
124
124
  }
125
- const spotlightVersion = "4.7.0";
125
+ const spotlightVersion = "4.7.2";
126
126
  logger.info(`Spotlight by Sentry - v${spotlightVersion}`);
127
127
  metrics.count("cli.invocation", 1, {
128
128
  attributes: {
@@ -2,7 +2,7 @@
2
2
  !function() {
3
3
  try {
4
4
  var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
5
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "6383c656-eec8-4e07-aaa9-d46d61743a55", e._sentryDebugIdIdentifier = "sentry-dbid-6383c656-eec8-4e07-aaa9-d46d61743a55");
5
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "96ff0e30-b12a-49d5-bf7e-38c6d90d3026", e._sentryDebugIdIdentifier = "sentry-dbid-96ff0e30-b12a-49d5-bf7e-38c6d90d3026");
6
6
  } catch (e2) {
7
7
  }
8
8
  }();
@@ -11,10 +11,15 @@ import { parseBrowserFromUserAgent } from "../../routes/stream/userAgent.js";
11
11
  import "../../../_virtual/_sentry-release-injection-file.js";
12
12
  const SOURCE_TYPES = ["browser", "mobile", "server"];
13
13
  const LOG_LEVELS = ["error", "warning", "log", "info", "trace", "debug"];
14
+ const SENTINEL = {
15
+ yellow: "#FDB81B",
16
+ blue: "#226DFC",
17
+ magenta: "#FF45A8"
18
+ };
14
19
  const SOURCE_COLORS = {
15
- browser: chalk.yellow,
16
- mobile: chalk.blue,
17
- server: chalk.magenta
20
+ browser: chalk.hex(SENTINEL.yellow),
21
+ mobile: chalk.hex(SENTINEL.blue),
22
+ server: chalk.hex(SENTINEL.magenta)
18
23
  };
19
24
  const LOG_LEVEL_COLORS = {
20
25
  error: chalk.red.bold,
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../../../src/server/formatters/human/utils.ts"],"sourcesContent":["import type { Envelope } from \"@sentry/core\";\nimport chalk from \"chalk\";\nimport { parseBrowserFromUserAgent } from \"../../routes/stream/userAgent.ts\";\n\nexport const SOURCE_TYPES = [\"browser\", \"mobile\", \"server\"] as const;\nexport type SourceType = (typeof SOURCE_TYPES)[number];\n\nexport const LOG_LEVELS = [\"error\", \"warning\", \"log\", \"info\", \"trace\", \"debug\"] as const;\nexport type LogLevel = (typeof LOG_LEVELS)[number];\n\nexport const SOURCE_COLORS: Record<SourceType, (text: string) => string> = {\n browser: chalk.yellow,\n mobile: chalk.blue,\n server: chalk.magenta,\n};\n\nexport const LOG_LEVEL_COLORS: Record<LogLevel, (text: string) => string> = {\n error: chalk.red.bold,\n warning: chalk.hex(\"#FFA500\"), // Orange\n log: chalk.white,\n info: chalk.cyan,\n trace: chalk.green,\n debug: chalk.dim,\n};\n\n/**\n * Helper to detect if a User-Agent string is from a browser\n */\nfunction isBrowserUserAgent(userAgent: string): boolean {\n const parsed = parseBrowserFromUserAgent(userAgent);\n return (\n parsed !== \"unknown\" &&\n (parsed.includes(\"Chrome\") || parsed.includes(\"Firefox\") || parsed.includes(\"Safari\") || parsed.includes(\"Edge\"))\n );\n}\n\n/**\n * Infer the source of an envelope as browser, mobile, or server using multiple signals\n * Priority order:\n * 1. Sender User-Agent (from HTTP request header)\n * 2. Platform & Runtime tags (from event payload)\n * 3. SDK name (fallback)\n *\n * Rules based on https://release-registry.services.sentry.io/sdks\n */\nexport function inferEnvelopeSource(envelopeHeader: Envelope[0], event?: any): SourceType {\n const sdkName = envelopeHeader?.sdk?.name || \"\";\n\n // 1. Mobile check (unchanged - already reliable from SDK name)\n // Mobile: Native mobile platforms and frameworks\n if (\n sdkName.includes(\"cocoa\") ||\n sdkName.includes(\"android\") ||\n sdkName.includes(\"react-native\") ||\n sdkName.includes(\"flutter\") ||\n sdkName.includes(\"capacitor\") ||\n sdkName.includes(\"cordova\") ||\n sdkName.includes(\"xamarin\") ||\n sdkName.includes(\"maui\") ||\n sdkName.includes(\"unity\") ||\n sdkName.includes(\"kotlin.kmp\")\n ) {\n return \"mobile\";\n }\n\n // 2. Sender User-Agent check\n const senderUserAgent = (envelopeHeader as any).__spotlight_sender_user_agent;\n if (senderUserAgent && typeof senderUserAgent === \"string\") {\n if (isBrowserUserAgent(senderUserAgent)) {\n return \"browser\";\n }\n // Server SDKs send server UAs like \"Node.js/*\", \"Python-urllib/*\", etc.\n // If we have a non-browser UA, we continue to further checks\n }\n\n // 3. Runtime tags check\n if (event?.tags?.runtime === \"browser\") {\n return \"browser\";\n }\n\n // 4. Platform & server-specific signals\n if (event?.contexts?.runtime?.name) {\n // Runtime context (node, CPython, etc.) indicates server\n return \"server\";\n }\n\n if (event?.server_name) {\n // server_name is a server-specific field\n return \"server\";\n }\n\n const platform = event?.platform;\n if (\n platform === \"node\" ||\n platform === \"python\" ||\n platform === \"ruby\" ||\n platform === \"php\" ||\n platform === \"java\" ||\n platform === \"go\" ||\n platform === \"rust\" ||\n platform === \"perl\" ||\n platform === \"elixir\" ||\n platform === \"csharp\" ||\n platform === \"dotnet\"\n ) {\n return \"server\";\n }\n\n // 5. SDK name check (existing logic as fallback)\n // Browser: JavaScript frameworks/libraries (excluding server/native runtimes and meta-frameworks)\n if (\n sdkName.startsWith(\"sentry.javascript.\") &&\n !sdkName.includes(\"node\") &&\n !sdkName.includes(\"bun\") &&\n !sdkName.includes(\"deno\") &&\n !sdkName.includes(\"electron\") &&\n !sdkName.includes(\"serverless\") &&\n !sdkName.includes(\"cloudflare\") &&\n !sdkName.includes(\"vercel-edge\") &&\n !sdkName.includes(\"wasm\") &&\n !sdkName.includes(\"opentelemetry\") &&\n !sdkName.includes(\"nextjs\") &&\n !sdkName.includes(\"remix\") &&\n !sdkName.includes(\"gatsby\") &&\n !sdkName.includes(\"astro\") &&\n !sdkName.includes(\"nuxt\") &&\n !sdkName.includes(\"sveltekit\") &&\n !sdkName.includes(\"solidstart\") &&\n !sdkName.includes(\"nestjs\") &&\n !sdkName.includes(\"tanstackstart\")\n ) {\n return \"browser\";\n }\n\n // Special case: Blazor WebAssembly runs in browser\n if (sdkName.includes(\"blazor.webassembly\")) {\n return \"browser\";\n }\n\n // Server: Everything else (node, python, ruby, go, php, java, dotnet, etc.)\n return \"server\";\n}\n\n/**\n * Format timestamp as local time HH:MM:SS\n */\nexport function formatLocalTime(timestamp?: number | string): string {\n let date: Date;\n\n if (!timestamp) {\n date = new Date();\n } else if (typeof timestamp === \"string\") {\n // Handle ISO string format (e.g., \"2023-11-22T16:23:50.406684Z\")\n date = new Date(timestamp);\n } else {\n // Handle Unix timestamp\n date = new Date(timestamp * 1000);\n }\n\n if (Number.isNaN(date.getTime())) {\n // placeholder with same width as valid timestamp for alignment in the logs\n return \"??:??:??\";\n }\n\n const hours = date.getHours().toString().padStart(2, \"0\");\n const minutes = date.getMinutes().toString().padStart(2, \"0\");\n const seconds = date.getSeconds().toString().padStart(2, \"0\");\n return `${hours}:${minutes}:${seconds}`;\n}\n\n/**\n * Padding helper for vertical alignment\n */\nexport function padLabel(label: string, width: number): string {\n return label.padEnd(width);\n}\n\n// Constants for consistent padding (adding brackets)\nexport const SOURCE_WIDTH = Math.max(...SOURCE_TYPES.map(s => `[${s.toUpperCase()}]`.length));\nexport const TYPE_WIDTH = Math.max(...LOG_LEVELS.map(l => `[${l.toUpperCase()}]`.length));\n\n/**\n * Colorize time with dim gray\n */\nexport function colorizeTime(time: string): string {\n return chalk.gray(time);\n}\n\n/**\n * Colorize source based on envelope source\n */\nexport function colorizeSource(source: string): string {\n const bracketed = `[${source}]`;\n const padded = padLabel(bracketed, SOURCE_WIDTH);\n const colorFn = SOURCE_COLORS[source as SourceType] || chalk.white;\n return colorFn(padded);\n}\n\n/**\n * Colorize event type\n */\nexport function colorizeType(type: string): string {\n const bracketed = `[${type.toUpperCase()}]`;\n const padded = padLabel(bracketed, TYPE_WIDTH);\n const colorFn = LOG_LEVEL_COLORS[type.toLowerCase() as LogLevel] || chalk.white;\n return colorFn(padded);\n}\n\n/**\n * Format a complete log line with proper alignment and colors\n */\nexport function formatLogLine(\n timestamp: number | string | undefined,\n source: SourceType,\n type: string,\n message: string,\n): string {\n const time = colorizeTime(formatLocalTime(timestamp));\n const coloredSource = colorizeSource(source);\n const coloredType = colorizeType(type);\n\n return `${time} ${coloredType} ${coloredSource} ${message}`;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sources":["../../../../src/server/formatters/human/utils.ts"],"sourcesContent":["import type { Envelope } from \"@sentry/core\";\nimport chalk from \"chalk\";\nimport { parseBrowserFromUserAgent } from \"../../routes/stream/userAgent.ts\";\n\nexport const SOURCE_TYPES = [\"browser\", \"mobile\", \"server\"] as const;\nexport type SourceType = (typeof SOURCE_TYPES)[number];\n\nexport const LOG_LEVELS = [\"error\", \"warning\", \"log\", \"info\", \"trace\", \"debug\"] as const;\nexport type LogLevel = (typeof LOG_LEVELS)[number];\n\n/**\n * Sentinel theme terminal colors\n * Based on https://github.com/getsentry/sentinel\n */\nconst SENTINEL = {\n red: \"#fe4144\",\n green: \"#83da90\",\n yellow: \"#FDB81B\",\n blue: \"#226DFC\",\n magenta: \"#FF45A8\",\n white: \"#f9f8f9\",\n muted: \"#898294\",\n} as const;\n\nexport const SOURCE_COLORS: Record<SourceType, (text: string) => string> = {\n browser: chalk.hex(SENTINEL.yellow),\n mobile: chalk.hex(SENTINEL.blue),\n server: chalk.hex(SENTINEL.magenta),\n};\n\nexport const LOG_LEVEL_COLORS: Record<LogLevel, (text: string) => string> = {\n error: chalk.red.bold,\n warning: chalk.hex(\"#FFA500\"), // Orange\n log: chalk.white,\n info: chalk.cyan,\n trace: chalk.green,\n debug: chalk.dim,\n};\n\n/**\n * Helper to detect if a User-Agent string is from a browser\n */\nfunction isBrowserUserAgent(userAgent: string): boolean {\n const parsed = parseBrowserFromUserAgent(userAgent);\n return (\n parsed !== \"unknown\" &&\n (parsed.includes(\"Chrome\") || parsed.includes(\"Firefox\") || parsed.includes(\"Safari\") || parsed.includes(\"Edge\"))\n );\n}\n\n/**\n * Infer the source of an envelope as browser, mobile, or server using multiple signals\n * Priority order:\n * 1. Sender User-Agent (from HTTP request header)\n * 2. Platform & Runtime tags (from event payload)\n * 3. SDK name (fallback)\n *\n * Rules based on https://release-registry.services.sentry.io/sdks\n */\nexport function inferEnvelopeSource(envelopeHeader: Envelope[0], event?: any): SourceType {\n const sdkName = envelopeHeader?.sdk?.name || \"\";\n\n // 1. Mobile check (unchanged - already reliable from SDK name)\n // Mobile: Native mobile platforms and frameworks\n if (\n sdkName.includes(\"cocoa\") ||\n sdkName.includes(\"android\") ||\n sdkName.includes(\"react-native\") ||\n sdkName.includes(\"flutter\") ||\n sdkName.includes(\"capacitor\") ||\n sdkName.includes(\"cordova\") ||\n sdkName.includes(\"xamarin\") ||\n sdkName.includes(\"maui\") ||\n sdkName.includes(\"unity\") ||\n sdkName.includes(\"kotlin.kmp\")\n ) {\n return \"mobile\";\n }\n\n // 2. Sender User-Agent check\n const senderUserAgent = (envelopeHeader as any).__spotlight_sender_user_agent;\n if (senderUserAgent && typeof senderUserAgent === \"string\") {\n if (isBrowserUserAgent(senderUserAgent)) {\n return \"browser\";\n }\n // Server SDKs send server UAs like \"Node.js/*\", \"Python-urllib/*\", etc.\n // If we have a non-browser UA, we continue to further checks\n }\n\n // 3. Runtime tags check\n if (event?.tags?.runtime === \"browser\") {\n return \"browser\";\n }\n\n // 4. Platform & server-specific signals\n if (event?.contexts?.runtime?.name) {\n // Runtime context (node, CPython, etc.) indicates server\n return \"server\";\n }\n\n if (event?.server_name) {\n // server_name is a server-specific field\n return \"server\";\n }\n\n const platform = event?.platform;\n if (\n platform === \"node\" ||\n platform === \"python\" ||\n platform === \"ruby\" ||\n platform === \"php\" ||\n platform === \"java\" ||\n platform === \"go\" ||\n platform === \"rust\" ||\n platform === \"perl\" ||\n platform === \"elixir\" ||\n platform === \"csharp\" ||\n platform === \"dotnet\"\n ) {\n return \"server\";\n }\n\n // 5. SDK name check (existing logic as fallback)\n // Browser: JavaScript frameworks/libraries (excluding server/native runtimes and meta-frameworks)\n if (\n sdkName.startsWith(\"sentry.javascript.\") &&\n !sdkName.includes(\"node\") &&\n !sdkName.includes(\"bun\") &&\n !sdkName.includes(\"deno\") &&\n !sdkName.includes(\"electron\") &&\n !sdkName.includes(\"serverless\") &&\n !sdkName.includes(\"cloudflare\") &&\n !sdkName.includes(\"vercel-edge\") &&\n !sdkName.includes(\"wasm\") &&\n !sdkName.includes(\"opentelemetry\") &&\n !sdkName.includes(\"nextjs\") &&\n !sdkName.includes(\"remix\") &&\n !sdkName.includes(\"gatsby\") &&\n !sdkName.includes(\"astro\") &&\n !sdkName.includes(\"nuxt\") &&\n !sdkName.includes(\"sveltekit\") &&\n !sdkName.includes(\"solidstart\") &&\n !sdkName.includes(\"nestjs\") &&\n !sdkName.includes(\"tanstackstart\")\n ) {\n return \"browser\";\n }\n\n // Special case: Blazor WebAssembly runs in browser\n if (sdkName.includes(\"blazor.webassembly\")) {\n return \"browser\";\n }\n\n // Server: Everything else (node, python, ruby, go, php, java, dotnet, etc.)\n return \"server\";\n}\n\n/**\n * Format timestamp as local time HH:MM:SS\n */\nexport function formatLocalTime(timestamp?: number | string): string {\n let date: Date;\n\n if (!timestamp) {\n date = new Date();\n } else if (typeof timestamp === \"string\") {\n // Handle ISO string format (e.g., \"2023-11-22T16:23:50.406684Z\")\n date = new Date(timestamp);\n } else {\n // Handle Unix timestamp\n date = new Date(timestamp * 1000);\n }\n\n if (Number.isNaN(date.getTime())) {\n // placeholder with same width as valid timestamp for alignment in the logs\n return \"??:??:??\";\n }\n\n const hours = date.getHours().toString().padStart(2, \"0\");\n const minutes = date.getMinutes().toString().padStart(2, \"0\");\n const seconds = date.getSeconds().toString().padStart(2, \"0\");\n return `${hours}:${minutes}:${seconds}`;\n}\n\n/**\n * Padding helper for vertical alignment\n */\nexport function padLabel(label: string, width: number): string {\n return label.padEnd(width);\n}\n\n// Constants for consistent padding (adding brackets)\nexport const SOURCE_WIDTH = Math.max(...SOURCE_TYPES.map(s => `[${s.toUpperCase()}]`.length));\nexport const TYPE_WIDTH = Math.max(...LOG_LEVELS.map(l => `[${l.toUpperCase()}]`.length));\n\n/**\n * Colorize time with dim gray\n */\nexport function colorizeTime(time: string): string {\n return chalk.gray(time);\n}\n\n/**\n * Colorize source based on envelope source\n */\nexport function colorizeSource(source: string): string {\n const bracketed = `[${source}]`;\n const padded = padLabel(bracketed, SOURCE_WIDTH);\n const colorFn = SOURCE_COLORS[source as SourceType] || chalk.white;\n return colorFn(padded);\n}\n\n/**\n * Colorize event type\n */\nexport function colorizeType(type: string): string {\n const bracketed = `[${type.toUpperCase()}]`;\n const padded = padLabel(bracketed, TYPE_WIDTH);\n const colorFn = LOG_LEVEL_COLORS[type.toLowerCase() as LogLevel] || chalk.white;\n return colorFn(padded);\n}\n\n/**\n * Format a complete log line with proper alignment and colors\n */\nexport function formatLogLine(\n timestamp: number | string | undefined,\n source: SourceType,\n type: string,\n message: string,\n): string {\n const time = colorizeTime(formatLocalTime(timestamp));\n const coloredSource = colorizeSource(source);\n const coloredType = colorizeType(type);\n\n return `${time} ${coloredType} ${coloredSource} ${message}`;\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAIO,MAAM,eAAe,CAAC,WAAW,UAAU,QAAQ;AAGnD,MAAM,aAAa,CAAC,SAAS,WAAW,OAAO,QAAQ,SAAS,OAAO;AAO9E,MAAM,WAAW;AAAA,EAGf,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,SAAS;AAGX;AAEO,MAAM,gBAA8D;AAAA,EACzE,SAAS,MAAM,IAAI,SAAS,MAAM;AAAA,EAClC,QAAQ,MAAM,IAAI,SAAS,IAAI;AAAA,EAC/B,QAAQ,MAAM,IAAI,SAAS,OAAO;AACpC;AAEO,MAAM,mBAA+D;AAAA,EAC1E,OAAO,MAAM,IAAI;AAAA,EACjB,SAAS,MAAM,IAAI,SAAS;AAAA;AAAA,EAC5B,KAAK,MAAM;AAAA,EACX,MAAM,MAAM;AAAA,EACZ,OAAO,MAAM;AAAA,EACb,OAAO,MAAM;AACf;AAKA,SAAS,mBAAmB,WAA4B;AACtD,QAAM,SAAS,0BAA0B,SAAS;AAClD,SACE,WAAW,cACV,OAAO,SAAS,QAAQ,KAAK,OAAO,SAAS,SAAS,KAAK,OAAO,SAAS,QAAQ,KAAK,OAAO,SAAS,MAAM;AAEnH;AAWO,SAAS,oBAAoB,gBAA6B,OAAyB;AACxF,QAAM,UAAU,gBAAgB,KAAK,QAAQ;AAI7C,MACE,QAAQ,SAAS,OAAO,KACxB,QAAQ,SAAS,SAAS,KAC1B,QAAQ,SAAS,cAAc,KAC/B,QAAQ,SAAS,SAAS,KAC1B,QAAQ,SAAS,WAAW,KAC5B,QAAQ,SAAS,SAAS,KAC1B,QAAQ,SAAS,SAAS,KAC1B,QAAQ,SAAS,MAAM,KACvB,QAAQ,SAAS,OAAO,KACxB,QAAQ,SAAS,YAAY,GAC7B;AACA,WAAO;AAAA,EACT;AAGA,QAAM,kBAAmB,eAAuB;AAChD,MAAI,mBAAmB,OAAO,oBAAoB,UAAU;AAC1D,QAAI,mBAAmB,eAAe,GAAG;AACvC,aAAO;AAAA,IACT;AAAA,EAGF;AAGA,MAAI,OAAO,MAAM,YAAY,WAAW;AACtC,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,UAAU,SAAS,MAAM;AAElC,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,aAAa;AAEtB,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,OAAO;AACxB,MACE,aAAa,UACb,aAAa,YACb,aAAa,UACb,aAAa,SACb,aAAa,UACb,aAAa,QACb,aAAa,UACb,aAAa,UACb,aAAa,YACb,aAAa,YACb,aAAa,UACb;AACA,WAAO;AAAA,EACT;AAIA,MACE,QAAQ,WAAW,oBAAoB,KACvC,CAAC,QAAQ,SAAS,MAAM,KACxB,CAAC,QAAQ,SAAS,KAAK,KACvB,CAAC,QAAQ,SAAS,MAAM,KACxB,CAAC,QAAQ,SAAS,UAAU,KAC5B,CAAC,QAAQ,SAAS,YAAY,KAC9B,CAAC,QAAQ,SAAS,YAAY,KAC9B,CAAC,QAAQ,SAAS,aAAa,KAC/B,CAAC,QAAQ,SAAS,MAAM,KACxB,CAAC,QAAQ,SAAS,eAAe,KACjC,CAAC,QAAQ,SAAS,QAAQ,KAC1B,CAAC,QAAQ,SAAS,OAAO,KACzB,CAAC,QAAQ,SAAS,QAAQ,KAC1B,CAAC,QAAQ,SAAS,OAAO,KACzB,CAAC,QAAQ,SAAS,MAAM,KACxB,CAAC,QAAQ,SAAS,WAAW,KAC7B,CAAC,QAAQ,SAAS,YAAY,KAC9B,CAAC,QAAQ,SAAS,QAAQ,KAC1B,CAAC,QAAQ,SAAS,eAAe,GACjC;AACA,WAAO;AAAA,EACT;AAGA,MAAI,QAAQ,SAAS,oBAAoB,GAAG;AAC1C,WAAO;AAAA,EACT;AAGA,SAAO;AACT;AAKO,SAAS,gBAAgB,WAAqC;AACnE,MAAI;AAEJ,MAAI,CAAC,WAAW;AACd,+BAAW,KAAA;AAAA,EACb,WAAW,OAAO,cAAc,UAAU;AAExC,WAAO,IAAI,KAAK,SAAS;AAAA,EAC3B,OAAO;AAEL,WAAO,IAAI,KAAK,YAAY,GAAI;AAAA,EAClC;AAEA,MAAI,OAAO,MAAM,KAAK,QAAA,CAAS,GAAG;AAEhC,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,KAAK,SAAA,EAAW,WAAW,SAAS,GAAG,GAAG;AACxD,QAAM,UAAU,KAAK,WAAA,EAAa,WAAW,SAAS,GAAG,GAAG;AAC5D,QAAM,UAAU,KAAK,WAAA,EAAa,WAAW,SAAS,GAAG,GAAG;AAC5D,SAAO,GAAG,KAAK,IAAI,OAAO,IAAI,OAAO;AACvC;AAKO,SAAS,SAAS,OAAe,OAAuB;AAC7D,SAAO,MAAM,OAAO,KAAK;AAC3B;AAGO,MAAM,eAAe,KAAK,IAAI,GAAG,aAAa,IAAI,CAAA,MAAK,IAAI,EAAE,YAAA,CAAa,IAAI,MAAM,CAAC;AACrF,MAAM,aAAa,KAAK,IAAI,GAAG,WAAW,IAAI,CAAA,MAAK,IAAI,EAAE,YAAA,CAAa,IAAI,MAAM,CAAC;AAKjF,SAAS,aAAa,MAAsB;AACjD,SAAO,MAAM,KAAK,IAAI;AACxB;AAKO,SAAS,eAAe,QAAwB;AACrD,QAAM,YAAY,IAAI,MAAM;AAC5B,QAAM,SAAS,SAAS,WAAW,YAAY;AAC/C,QAAM,UAAU,cAAc,MAAoB,KAAK,MAAM;AAC7D,SAAO,QAAQ,MAAM;AACvB;AAKO,SAAS,aAAa,MAAsB;AACjD,QAAM,YAAY,IAAI,KAAK,YAAA,CAAa;AACxC,QAAM,SAAS,SAAS,WAAW,UAAU;AAC7C,QAAM,UAAU,iBAAiB,KAAK,YAAA,CAAyB,KAAK,MAAM;AAC1E,SAAO,QAAQ,MAAM;AACvB;AAKO,SAAS,cACd,WACA,QACA,MACA,SACQ;AACR,QAAM,OAAO,aAAa,gBAAgB,SAAS,CAAC;AACpD,QAAM,gBAAgB,eAAe,MAAM;AAC3C,QAAM,cAAc,aAAa,IAAI;AAErC,SAAO,GAAG,IAAI,IAAI,WAAW,IAAI,aAAa,IAAI,OAAO;AAC3D;"}
@@ -2,7 +2,7 @@
2
2
  !function() {
3
3
  try {
4
4
  var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
5
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "27aa1f85-1b72-47cd-9933-f1093a410864", e._sentryDebugIdIdentifier = "sentry-dbid-27aa1f85-1b72-47cd-9933-f1093a410864");
5
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "cfc20e89-a00d-417d-82ac-ae68b723eab0", e._sentryDebugIdIdentifier = "sentry-dbid-cfc20e89-a00d-417d-82ac-ae68b723eab0");
6
6
  } catch (e2) {
7
7
  }
8
8
  }();
@@ -58,7 +58,7 @@ function createMCPInstance() {
58
58
  const mcp = wrapMcpServerWithSentry(
59
59
  new McpServer({
60
60
  name: "spotlight-mcp",
61
- version: String("4.7.0")
61
+ version: String("4.7.2")
62
62
  })
63
63
  );
64
64
  mcp.registerTool(
@@ -2,15 +2,15 @@
2
2
  !function() {
3
3
  try {
4
4
  var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
5
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "30c2a21d-0350-4802-a8cb-86dc2894fef5", e._sentryDebugIdIdentifier = "sentry-dbid-30c2a21d-0350-4802-a8cb-86dc2894fef5");
5
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "c8123de6-5e77-41da-8100-10d99b558d5f", e._sentryDebugIdIdentifier = "sentry-dbid-c8123de6-5e77-41da-8100-10d99b558d5f");
6
6
  } catch (e2) {
7
7
  }
8
8
  }();
9
9
  import { createWriteStream } from "node:fs";
10
- import { decompressBody, pushToSpotlightBuffer } from "../../sdk.js";
11
- import { SENTRY_CONTENT_TYPE } from "../../../shared/constants.js";
12
10
  import { Hono } from "hono";
11
+ import { SENTRY_CONTENT_TYPE } from "../../../shared/constants.js";
13
12
  import { logger } from "../../logger.js";
13
+ import { decompressBody, pushToSpotlightBuffer } from "../../sdk.js";
14
14
  import { getBuffer } from "../../utils/getBuffer.js";
15
15
  import "../../parser/helpers.js";
16
16
  import "uuidv7";
@@ -69,7 +69,10 @@ const router = new Hono().get("/stream", (ctx) => {
69
69
  if (ctx.req.query("sentry_client")?.startsWith("sentry.javascript.browser") && ctx.req.header("Origin")) {
70
70
  contentType = SENTRY_CONTENT_TYPE;
71
71
  }
72
- const body = decompressBody(Buffer.from(await ctx.req.arrayBuffer()), ctx.req.header("Content-Encoding"));
72
+ const body = decompressBody(
73
+ Buffer.from(await ctx.req.arrayBuffer()),
74
+ ctx.req.header("Content-Encoding")
75
+ );
73
76
  const container = pushToSpotlightBuffer({
74
77
  body,
75
78
  spotlightBuffer: getBuffer(),
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/server/routes/stream/index.ts"],"sourcesContent":["import { createWriteStream } from \"node:fs\";\nimport { decompressBody, pushToSpotlightBuffer } from \"../../sdk.ts\";\nimport { SENTRY_CONTENT_TYPE } from \"../../../shared/constants.ts\";\nimport { Hono } from \"hono\";\nimport { logger } from \"../../logger.ts\";\nimport type { HonoEnv } from \"../../types/env.ts\";\nimport { getBuffer } from \"../../utils/index.ts\";\nimport { logIncomingEvent, logOutgoingEvent } from \"./debugLogging.ts\";\nimport { streamSSE } from \"./streaming.ts\";\nimport { parseBrowserFromUserAgent } from \"./userAgent.ts\";\n\nconst router = new Hono<HonoEnv>()\n .get(\"/stream\", ctx => {\n const buffer = getBuffer();\n\n const useBase64 = ctx.req.query(\"base64\") != null;\n const base64Indicator = useBase64 ? \";base64\" : \"\";\n\n // Capture client information for debug logging\n let clientId = ctx.req.query(\"client\");\n if (!clientId) {\n // Fallback to parsing User-Agent if no client param\n const userAgent = ctx.req.header(\"User-Agent\") || \"unknown\";\n clientId = parseBrowserFromUserAgent(userAgent);\n }\n // Sanitize to prevent log injection - keep only safe printable characters\n // Allow alphanumeric, spaces, dots, dashes, underscores, slashes, parentheses\n clientId = clientId.replace(/[^\\w\\s.\\-/()]/g, \"\");\n // Ensure we always have a non-empty clientId\n if (!clientId) clientId = \"unknown\";\n\n return streamSSE(ctx, async stream => {\n // Check for Last-Event-ID header to support reconnection\n const lastEventId = ctx.req.header(\"Last-Event-ID\");\n\n // Subscribe to events, optionally starting from after the lastEventId\n const sub = buffer.subscribe(container => {\n logOutgoingEvent(container, clientId);\n\n const parsedEnvelope = container.getParsedEnvelope();\n if (parsedEnvelope) {\n stream.writeSSE({\n id: parsedEnvelope.envelope[0].__spotlight_envelope_id.toString(),\n event: `${container.getContentType()}${base64Indicator}`,\n data: JSON.stringify(parsedEnvelope.envelope),\n });\n }\n }, lastEventId);\n\n stream.onAbort(() => {\n buffer.unsubscribe(sub);\n });\n });\n })\n .get(\"/envelope/:id\", ctx => {\n const buffer = getBuffer();\n\n const envelopeId = ctx.req.param(\"id\");\n const container = buffer.read({ envelopeId });\n\n if (container.length === 0) {\n return ctx.notFound();\n }\n\n return ctx.body(new Uint8Array(container[0].getData()), 200, {\n \"Content-Type\": container[0].getContentType(),\n \"Cache-Control\": \"no-cache\",\n \"Content-Disposition\": `attachment; filename=\"${envelopeId}.bin\"`,\n Connection: \"keep-alive\",\n });\n })\n .on(\"POST\", [\"/stream\", \"/api/:id/envelope\"], async ctx => {\n let contentType = ctx.req.header(\"content-type\")?.split(\";\")[0].toLocaleLowerCase();\n if (ctx.req.query(\"sentry_client\")?.startsWith(\"sentry.javascript.browser\") && ctx.req.header(\"Origin\")) {\n // This is a correction we make as Sentry Browser SDK may send messages with text/plain to avoid CORS issues\n contentType = SENTRY_CONTENT_TYPE;\n }\n\n // manually decompress body to use it below without another decompression\n const body = decompressBody(Buffer.from(await ctx.req.arrayBuffer()), ctx.req.header(\"Content-Encoding\"));\n\n const container = pushToSpotlightBuffer({\n body,\n spotlightBuffer: getBuffer(),\n contentType,\n userAgent: ctx.req.header(\"User-Agent\"),\n });\n\n if (container) {\n // Log incoming event details when debug is enabled\n logIncomingEvent(container);\n } else {\n logger.warn(\"No content type, skipping payload...\");\n }\n\n const incomingPayload = ctx.get(\"incomingPayload\");\n\n if (process.env.SPOTLIGHT_CAPTURE || incomingPayload) {\n const contentType = container?.getContentType();\n const timestamp = BigInt(Date.now()) * 1_000_000n + (process.hrtime.bigint() % 1_000_000n);\n const filename = `${contentType?.replace(/[^a-z0-9]/gi, \"_\") || \"no_content_type\"}-${timestamp}.txt`;\n\n if (incomingPayload) {\n incomingPayload(body.toString(\"binary\"));\n } else {\n const stream = createWriteStream(filename);\n stream.on(\"error\", err => {\n logger.error(`Failed to save data to ${filename}: ${err}`);\n stream.destroy();\n });\n stream.end(body, () => {\n logger.info(`🗃️ Saved data to ${filename}`);\n });\n }\n }\n\n // 204 would be more appropriate but returning 200 to match what /envelope returns\n return ctx.body(null, 200, {\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n });\n\nexport default router;\n"],"names":["contentType"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/server/routes/stream/index.ts"],"sourcesContent":["import { createWriteStream } from \"node:fs\";\nimport { Hono } from \"hono\";\nimport { SENTRY_CONTENT_TYPE } from \"../../../shared/constants.ts\";\nimport { logger } from \"../../logger.ts\";\nimport { decompressBody, pushToSpotlightBuffer } from \"../../sdk.ts\";\nimport type { ContentEncoding } from \"../../sdk.ts\";\nimport type { HonoEnv } from \"../../types/env.ts\";\nimport { getBuffer } from \"../../utils/index.ts\";\nimport { logIncomingEvent, logOutgoingEvent } from \"./debugLogging.ts\";\nimport { streamSSE } from \"./streaming.ts\";\nimport { parseBrowserFromUserAgent } from \"./userAgent.ts\";\n\nconst router = new Hono<HonoEnv>()\n .get(\"/stream\", ctx => {\n const buffer = getBuffer();\n\n const useBase64 = ctx.req.query(\"base64\") != null;\n const base64Indicator = useBase64 ? \";base64\" : \"\";\n\n // Capture client information for debug logging\n let clientId = ctx.req.query(\"client\");\n if (!clientId) {\n // Fallback to parsing User-Agent if no client param\n const userAgent = ctx.req.header(\"User-Agent\") || \"unknown\";\n clientId = parseBrowserFromUserAgent(userAgent);\n }\n // Sanitize to prevent log injection - keep only safe printable characters\n // Allow alphanumeric, spaces, dots, dashes, underscores, slashes, parentheses\n clientId = clientId.replace(/[^\\w\\s.\\-/()]/g, \"\");\n // Ensure we always have a non-empty clientId\n if (!clientId) clientId = \"unknown\";\n\n return streamSSE(ctx, async stream => {\n // Check for Last-Event-ID header to support reconnection\n const lastEventId = ctx.req.header(\"Last-Event-ID\");\n\n // Subscribe to events, optionally starting from after the lastEventId\n const sub = buffer.subscribe(container => {\n logOutgoingEvent(container, clientId);\n\n const parsedEnvelope = container.getParsedEnvelope();\n if (parsedEnvelope) {\n stream.writeSSE({\n id: parsedEnvelope.envelope[0].__spotlight_envelope_id.toString(),\n event: `${container.getContentType()}${base64Indicator}`,\n data: JSON.stringify(parsedEnvelope.envelope),\n });\n }\n }, lastEventId);\n\n stream.onAbort(() => {\n buffer.unsubscribe(sub);\n });\n });\n })\n .get(\"/envelope/:id\", ctx => {\n const buffer = getBuffer();\n\n const envelopeId = ctx.req.param(\"id\");\n const container = buffer.read({ envelopeId });\n\n if (container.length === 0) {\n return ctx.notFound();\n }\n\n return ctx.body(new Uint8Array(container[0].getData()), 200, {\n \"Content-Type\": container[0].getContentType(),\n \"Cache-Control\": \"no-cache\",\n \"Content-Disposition\": `attachment; filename=\"${envelopeId}.bin\"`,\n Connection: \"keep-alive\",\n });\n })\n .on(\"POST\", [\"/stream\", \"/api/:id/envelope\"], async ctx => {\n let contentType = ctx.req.header(\"content-type\")?.split(\";\")[0].toLocaleLowerCase();\n if (ctx.req.query(\"sentry_client\")?.startsWith(\"sentry.javascript.browser\") && ctx.req.header(\"Origin\")) {\n // This is a correction we make as Sentry Browser SDK may send messages with text/plain to avoid CORS issues\n contentType = SENTRY_CONTENT_TYPE;\n }\n\n // manually decompress body to use it below without another decompression\n const body = decompressBody(\n Buffer.from(await ctx.req.arrayBuffer()),\n ctx.req.header(\"Content-Encoding\") as ContentEncoding,\n );\n\n const container = pushToSpotlightBuffer({\n body,\n spotlightBuffer: getBuffer(),\n contentType,\n userAgent: ctx.req.header(\"User-Agent\"),\n });\n\n if (container) {\n // Log incoming event details when debug is enabled\n logIncomingEvent(container);\n } else {\n logger.warn(\"No content type, skipping payload...\");\n }\n\n const incomingPayload = ctx.get(\"incomingPayload\");\n\n if (process.env.SPOTLIGHT_CAPTURE || incomingPayload) {\n const contentType = container?.getContentType();\n const timestamp = BigInt(Date.now()) * 1_000_000n + (process.hrtime.bigint() % 1_000_000n);\n const filename = `${contentType?.replace(/[^a-z0-9]/gi, \"_\") || \"no_content_type\"}-${timestamp}.txt`;\n\n if (incomingPayload) {\n incomingPayload(body.toString(\"binary\"));\n } else {\n const stream = createWriteStream(filename);\n stream.on(\"error\", err => {\n logger.error(`Failed to save data to ${filename}: ${err}`);\n stream.destroy();\n });\n stream.end(body, () => {\n logger.info(`🗃️ Saved data to ${filename}`);\n });\n }\n }\n\n // 204 would be more appropriate but returning 200 to match what /envelope returns\n return ctx.body(null, 200, {\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n });\n\nexport default router;\n"],"names":["contentType"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { MessageBuffer } from './messageBuffer.ts';
2
2
  import { EventContainer } from './utils/eventContainer.ts';
3
3
  declare const decompressors: Record<"gzip" | "deflate" | "br", (buf: Buffer) => Buffer>;
4
- type ContentEncoding = keyof typeof decompressors;
4
+ export type ContentEncoding = keyof typeof decompressors;
5
5
  export declare function createSpotlightBuffer(): MessageBuffer<EventContainer>;
6
6
  type PushToSpotlightBufferOptions = {
7
7
  spotlightBuffer: MessageBuffer<EventContainer>;
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.js","sources":["../../src/server/sdk.ts"],"sourcesContent":["import { brotliDecompressSync, gunzipSync, inflateSync } from \"node:zlib\";\nimport { MessageBuffer } from \"./messageBuffer.ts\";\nimport { EventContainer } from \"./utils/eventContainer.ts\";\n\nconst decompressors: Record<\"gzip\" | \"deflate\" | \"br\", (buf: Buffer) => Buffer> = {\n gzip: gunzipSync,\n deflate: inflateSync,\n br: brotliDecompressSync,\n};\ntype ContentEncoding = keyof typeof decompressors;\n\nexport function createSpotlightBuffer() {\n return new MessageBuffer<EventContainer>();\n}\n\ntype PushToSpotlightBufferOptions = {\n spotlightBuffer: MessageBuffer<EventContainer>;\n body: Buffer;\n encoding?: ContentEncoding;\n contentType?: string;\n userAgent?: string;\n};\n\nexport function pushToSpotlightBuffer(options: PushToSpotlightBufferOptions) {\n const body = decompressBody(options.body, options.encoding);\n\n const contentType = options.contentType?.split(\";\")[0].toLocaleLowerCase();\n\n if (contentType) {\n // Create event container and add to buffer\n const container = new EventContainer(contentType, body, options.userAgent);\n\n // Add to buffer - this will automatically trigger all subscribers\n // including the onEnvelope callback if one is registered\n options.spotlightBuffer.put(container);\n\n return container;\n }\n}\n\nexport function decompressBody(body: Buffer, contentEncoding?: ContentEncoding) {\n if (!contentEncoding) {\n return body;\n }\n return decompressors[contentEncoding](body);\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAIA,MAAM,gBAA4E;AAAA,EAChF,MAAM;AAAA,EACN,SAAS;AAAA,EACT,IAAI;AACN;AAGO,SAAS,wBAAwB;AACtC,SAAO,IAAI,cAAA;AACb;AAUO,SAAS,sBAAsB,SAAuC;AAC3E,QAAM,OAAO,eAAe,QAAQ,MAAM,QAAQ,QAAQ;AAE1D,QAAM,cAAc,QAAQ,aAAa,MAAM,GAAG,EAAE,CAAC,EAAE,kBAAA;AAEvD,MAAI,aAAa;AAEf,UAAM,YAAY,IAAI,eAAe,aAAa,MAAM,QAAQ,SAAS;AAIzE,YAAQ,gBAAgB,IAAI,SAAS;AAErC,WAAO;AAAA,EACT;AACF;AAEO,SAAS,eAAe,MAAc,iBAAmC;AAC9E,MAAI,CAAC,iBAAiB;AACpB,WAAO;AAAA,EACT;AACA,SAAO,cAAc,eAAe,EAAE,IAAI;AAC5C;"}
1
+ {"version":3,"file":"sdk.js","sources":["../../src/server/sdk.ts"],"sourcesContent":["import { brotliDecompressSync, gunzipSync, inflateSync } from \"node:zlib\";\nimport { MessageBuffer } from \"./messageBuffer.ts\";\nimport { EventContainer } from \"./utils/eventContainer.ts\";\n\nconst decompressors: Record<\"gzip\" | \"deflate\" | \"br\", (buf: Buffer) => Buffer> = {\n gzip: gunzipSync,\n deflate: inflateSync,\n br: brotliDecompressSync,\n};\n\nexport type ContentEncoding = keyof typeof decompressors;\n\nexport function createSpotlightBuffer() {\n return new MessageBuffer<EventContainer>();\n}\n\ntype PushToSpotlightBufferOptions = {\n spotlightBuffer: MessageBuffer<EventContainer>;\n body: Buffer;\n encoding?: ContentEncoding;\n contentType?: string;\n userAgent?: string;\n};\n\nexport function pushToSpotlightBuffer(options: PushToSpotlightBufferOptions) {\n const body = decompressBody(options.body, options.encoding);\n\n const contentType = options.contentType?.split(\";\")[0].toLocaleLowerCase();\n\n if (contentType) {\n // Create event container and add to buffer\n const container = new EventContainer(contentType, body, options.userAgent);\n\n // Add to buffer - this will automatically trigger all subscribers\n // including the onEnvelope callback if one is registered\n options.spotlightBuffer.put(container);\n\n return container;\n }\n}\n\nexport function decompressBody(body: Buffer, contentEncoding?: ContentEncoding) {\n if (!contentEncoding) {\n return body;\n }\n return decompressors[contentEncoding](body);\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAIA,MAAM,gBAA4E;AAAA,EAChF,MAAM;AAAA,EACN,SAAS;AAAA,EACT,IAAI;AACN;AAIO,SAAS,wBAAwB;AACtC,SAAO,IAAI,cAAA;AACb;AAUO,SAAS,sBAAsB,SAAuC;AAC3E,QAAM,OAAO,eAAe,QAAQ,MAAM,QAAQ,QAAQ;AAE1D,QAAM,cAAc,QAAQ,aAAa,MAAM,GAAG,EAAE,CAAC,EAAE,kBAAA;AAEvD,MAAI,aAAa;AAEf,UAAM,YAAY,IAAI,eAAe,aAAa,MAAM,QAAQ,SAAS;AAIzE,YAAQ,gBAAgB,IAAI,SAAS;AAErC,WAAO;AAAA,EACT;AACF;AAEO,SAAS,eAAe,MAAc,iBAAmC;AAC9E,MAAI,CAAC,iBAAiB;AACpB,WAAO;AAAA,EACT;AACA,SAAO,cAAc,eAAe,EAAE,IAAI;AAC5C;"}
@@ -2,12 +2,12 @@
2
2
  !function() {
3
3
  try {
4
4
  var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
5
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "9ad90655-f477-4509-801c-7553667734cb", e._sentryDebugIdIdentifier = "sentry-dbid-9ad90655-f477-4509-801c-7553667734cb");
5
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "30f1ede9-afbf-41ac-af87-60295da846a2", e._sentryDebugIdIdentifier = "sentry-dbid-30f1ede9-afbf-41ac-af87-60295da846a2");
6
6
  } catch (e2) {
7
7
  }
8
8
  }();
9
9
  import { execSync } from "node:child_process";
10
- import semver from "../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/index.js";
10
+ import semver from "semver";
11
11
  import { stringify } from "yaml";
12
12
  import { logger } from "../logger.js";
13
13
  import { getComposeFilesFromEnv, findComposeFile, findOverrideFile, getDockerComposeServices } from "./docker-compose-parser.js";