diff --git a/apps/example/nitro.config.ts b/apps/example/nitro.config.ts index a5e8bc44db..9013d8a769 100644 --- a/apps/example/nitro.config.ts +++ b/apps/example/nitro.config.ts @@ -1,6 +1,5 @@ -import { withSentryConfig } from "@sentry/nitro"; import { defineConfig } from "nitro"; -import { juniorNitro } from "@sentry/junior/nitro"; +import { juniorNitro, withSentryConfig } from "@sentry/junior/nitro"; import { exampleDashboardAuthRequired, exampleDashboardComponentGallery, diff --git a/apps/example/package.json b/apps/example/package.json index 7d80d1d4c7..1244cf3b2d 100644 --- a/apps/example/package.json +++ b/apps/example/package.json @@ -27,7 +27,6 @@ "@sentry/junior-notion": "workspace:*", "@sentry/junior-sentry": "workspace:*", "@sentry/junior-vercel": "workspace:*", - "@sentry/nitro": "10.65.0", "hono": "^4.13.11" }, "devDependencies": { diff --git a/packages/docs/src/content/docs/start-here/existing-app.md b/packages/docs/src/content/docs/start-here/existing-app.md index d9def90917..164306f0a5 100644 --- a/packages/docs/src/content/docs/start-here/existing-app.md +++ b/packages/docs/src/content/docs/start-here/existing-app.md @@ -54,9 +54,9 @@ export const plugins = defineJuniorPlugins([sentryPlugin()]); ```ts title="nitro.config.ts" import { defineConfig } from "nitro"; -import { juniorNitro } from "@sentry/junior/nitro"; +import { juniorNitro, withSentryConfig } from "@sentry/junior/nitro"; -export default defineConfig({ +const config = defineConfig({ modules: [ juniorNitro({ plugins: "./plugins", @@ -66,8 +66,20 @@ export default defineConfig({ "/**": { handler: "./server.ts" }, }, }); + +export default withSentryConfig(config, { + authToken: process.env.SENTRY_AUTH_TOKEN, + org: process.env.SENTRY_ORG, + project: process.env.SENTRY_PROJECT, +}); ``` +`withSentryConfig` uploads source maps to Sentry when the build has +`SENTRY_AUTH_TOKEN`, `SENTRY_ORG`, and `SENTRY_PROJECT`. Import it from +`@sentry/junior/nitro`. Do not add `@sentry/nitro` or `@sentry/node` to your +app. Junior pins their versions, and a different version cannot use the Sentry +client that `initSentry()` creates. + If your existing app already owns routes, make sure the Junior Hono app still receives the paths under `/api/webhooks`, `/api/oauth/callback`, `/api/internal/agent-dispatch`, `/api/internal/agent/continue`, `/api/internal/plugin/tasks`, `/api/internal/heartbeat`, and `/health`. Do not split those routes across independent runtime instances. When mounted, `@sentry/junior-dashboard` owns `/`, `/conversations`, `/conversations/*`, `/locations`, `/locations/*`, `/people`, `/people/*`, `/system`, `/system/*`, `/_junior/dashboard/client.js`, `/auth/login`, `/api/auth/*`, and the authenticated product API routes `/api/health`, `/api/runtime`, `/api/plugins`, `/api/plugins/*`, `/api/plugin-reports`, `/api/skills`, `/api/conversations`, `/api/conversations/*`, `/api/locations`, `/api/locations/*`, `/api/people`, `/api/people/*`, `/api/config`, and `/api/me`. Some packages export runtime hooks instead of `plugin.yaml`. Add those diff --git a/packages/junior/README.md b/packages/junior/README.md index 0825c8aa6d..21571724f1 100644 --- a/packages/junior/README.md +++ b/packages/junior/README.md @@ -5,7 +5,7 @@ ## Install ```bash -pnpm add @sentry/junior hono @sentry/node +pnpm add @sentry/junior hono ``` ## Quick usage diff --git a/packages/junior/package.json b/packages/junior/package.json index 41acd804d3..e4590f6f8a 100644 --- a/packages/junior/package.json +++ b/packages/junior/package.json @@ -82,6 +82,7 @@ "@opentelemetry/api": "catalog:", "@opentelemetry/core": "catalog:", "@sentry/junior-plugin-api": "workspace:*", + "@sentry/nitro": "catalog:", "@sentry/node": "catalog:", "@sinclair/typebox": "^0.34.49", "@slack/types": "^2.21.1", diff --git a/packages/junior/src/cli/init.ts b/packages/junior/src/cli/init.ts index 0ea8ec0ced..4a39c886f0 100644 --- a/packages/junior/src/cli/init.ts +++ b/packages/junior/src/cli/init.ts @@ -55,9 +55,8 @@ export const plugins = defineJuniorPlugins([ function writeNitroConfig(targetDir: string): void { fs.writeFileSync( path.join(targetDir, "nitro.config.ts"), - `import { withSentryConfig } from "@sentry/nitro"; -import { defineConfig } from "nitro"; -import { juniorNitro } from "@sentry/junior/nitro"; + `import { defineConfig } from "nitro"; +import { juniorNitro, withSentryConfig } from "@sentry/junior/nitro"; const config = defineConfig({ preset: "vercel", @@ -185,7 +184,6 @@ export async function runInit( "@sentry/junior": "latest", "@sentry/junior-memory": "latest", "@sentry/junior-maintenance": "latest", - "@sentry/nitro": "10.65.0", hono: "^4.13.11", }, devDependencies: { diff --git a/packages/junior/src/nitro.ts b/packages/junior/src/nitro.ts index 9cfd5272a5..747ebb2e3e 100644 --- a/packages/junior/src/nitro.ts +++ b/packages/junior/src/nitro.ts @@ -1,4 +1,5 @@ import path from "node:path"; +import { withSentryConfig as withSentryNitroConfig } from "@sentry/nitro"; import type { Nitro } from "nitro/types"; import { applyRolldownTreeshakeWorkaround } from "@/build/rolldown-workarounds"; import { @@ -21,6 +22,7 @@ import { JUNIOR_RETENTION_CRON_SCHEDULE, JUNIOR_RETENTION_ROUTE, JUNIOR_WORKSPACE_SNAPSHOT_JOB_CALLBACK_ROUTE, + getDeploymentServiceVersion, } from "@/deployment"; import { pluginCatalogConfigFromPluginSet, @@ -30,6 +32,31 @@ import { import { loadPluginSetFromModule, resolvePluginModule } from "./plugin-module"; import type { JuniorDashboardOptions } from "./app"; +type SentryNitroConfig = Parameters[0]; +type SentryNitroOptions = NonNullable< + Parameters[1] +>; + +/** + * Sentry's Nitro config wrapper: source map upload and Nitro request hooks. + * Junior pins `@sentry/nitro` to the same version as its `@sentry/node`. The + * SDK keeps one client for each version, so this lets the Nitro hooks use the + * client that `initSentry()` creates. Apps import it from here, not from + * `@sentry/nitro`. + * + * The build release defaults to the release that `initSentry()` reports, so + * the uploaded source maps and the runtime events use the same release. + */ +export function withSentryConfig( + config: SentryNitroConfig, + options: SentryNitroOptions = {}, +): SentryNitroConfig { + return withSentryNitroConfig(config, { + ...options, + release: { name: getDeploymentServiceVersion(), ...options.release }, + }); +} + export type JuniorNitroDashboardOptions = JuniorDashboardOptions; export interface JuniorPluginModuleReference { diff --git a/packages/junior/tests/unit/cli/init-cli.test.ts b/packages/junior/tests/unit/cli/init-cli.test.ts index a76c9a14d6..8faf003343 100644 --- a/packages/junior/tests/unit/cli/init-cli.test.ts +++ b/packages/junior/tests/unit/cli/init-cli.test.ts @@ -133,10 +133,7 @@ describe("init cli", () => { "utf8", ); expect(nitroConfig).toContain( - 'import { juniorNitro } from "@sentry/junior/nitro";', - ); - expect(nitroConfig).toContain( - 'import { withSentryConfig } from "@sentry/nitro";', + 'import { juniorNitro, withSentryConfig } from "@sentry/junior/nitro";', ); expect(nitroConfig).toContain('preset: "vercel"'); expect(nitroConfig).toContain("juniorNitro({"); @@ -171,7 +168,7 @@ describe("init cli", () => { expect(pkg.dependencies["@sentry/junior"]).toBe("latest"); expect(pkg.dependencies["@sentry/junior-memory"]).toBe("latest"); expect(pkg.dependencies["@sentry/junior-maintenance"]).toBe("latest"); - expect(pkg.dependencies["@sentry/nitro"]).toBe("10.65.0"); + expect(pkg.dependencies["@sentry/nitro"]).toBeUndefined(); expect(pkg.devDependencies.nitro).toBeDefined(); expect(pkg.devDependencies.vite).toBeUndefined(); expect(pkg.devDependencies.vercel).toBeUndefined(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d8fc65bcb5..1fc0e8dc8d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,6 +19,9 @@ catalogs: '@opentelemetry/core': specifier: 2.9.0 version: 2.9.0 + '@sentry/nitro': + specifier: 10.65.0 + version: 10.65.0 '@sentry/node': specifier: 10.65.0 version: 10.65.0 @@ -104,7 +107,7 @@ importers: version: 2.9.0(@opentelemetry/api@1.9.1) '@sentry/junior': specifier: workspace:* - version: file:packages/junior(@types/node@25.9.1) + version: file:packages/junior(@types/node@25.9.1)(nitro@3.0.260522-beta(jiti@2.7.0)) '@sentry/junior-agent-browser': specifier: workspace:* version: link:../../packages/junior-agent-browser @@ -141,9 +144,6 @@ importers: '@sentry/junior-vercel': specifier: workspace:* version: link:../../packages/junior-vercel - '@sentry/nitro': - specifier: 10.65.0 - version: 10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1))(nitro@3.0.260522-beta(jiti@2.7.0)) hono: specifier: ^4.13.11 version: 4.13.11 @@ -226,6 +226,9 @@ importers: '@sentry/junior-plugin-api': specifier: workspace:* version: link:../junior-plugin-api + '@sentry/nitro': + specifier: 'catalog:' + version: 10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1))(nitro@3.0.260522-beta(@vercel/blob@2.8.0)(@vercel/functions@3.6.0)(@vercel/queue@0.2.0)(aws4fetch@1.0.20)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(pg@8.21.0))(jiti@2.7.0)) '@sentry/node': specifier: 'catalog:' version: 10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1)) @@ -376,7 +379,7 @@ importers: version: 1.9.0(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@sentry/junior': specifier: workspace:* - version: file:packages/junior(@types/node@25.9.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.12) + version: file:packages/junior(@types/node@25.9.1)(nitro@3.0.260522-beta)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.12) '@sentry/junior-plugin-api': specifier: workspace:* version: link:../junior-plugin-api @@ -858,6 +861,7 @@ packages: '@apm-js-collab/code-transformer@0.15.0': resolution: {integrity: sha512-XmXYVs8CzJ1Aj79noVbn2weUO/XWtRyURpGqx7aU7DOXlUQhR0WKOQNF0okh7PCeY37vxf7kU3v57OAkEPm3ww==} + hasBin: true '@apm-js-collab/tracing-hooks@0.10.1': resolution: {integrity: sha512-w2OWXR7FWrKqSziuE9+QclaZrStxO/8+OwbXM635s/zs0Eez1Qo3ivSPdB2WsaPY/iznKTytONPx/PitD7IXcA==} @@ -5056,6 +5060,7 @@ packages: astring@1.9.0: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} + hasBin: true astro-expressive-code@0.44.1: resolution: {integrity: sha512-DT1LnCqbHasBKlvzJ3m6LR4VI94wwx3W9EV/YbP1te4rqjOHsvsezHYuqb5MeLWLftXms/1FA9QBbwCo43DnJQ==} @@ -12539,7 +12544,7 @@ snapshots: '@sentry/junior-dashboard@file:packages/junior-dashboard(@types/node@25.9.1)(jiti@2.7.0)': dependencies: '@base-ui/react': 1.9.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@sentry/junior': file:packages/junior(@types/node@25.9.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@sentry/junior': file:packages/junior(@types/node@25.9.1)(nitro@3.0.260522-beta(jiti@2.7.0))(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@sentry/junior-plugin-api': file:packages/junior-plugin-api '@tanstack/react-query': 5.100.14(react@19.2.6) '@uidotdev/usehooks': 2.4.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -12606,6 +12611,7 @@ snapshots: - dotenv - drizzle-kit - drizzle-orm + - encoding - expo-sqlite - gel - giget @@ -12980,7 +12986,7 @@ snapshots: - sql.js - sqlite3 - '@sentry/junior@file:packages/junior(@types/node@25.9.1)': + '@sentry/junior@file:packages/junior(@types/node@25.9.1)(nitro@3.0.260522-beta(jiti@2.7.0))': dependencies: '@agentclientprotocol/sdk': 1.3.0(zod@4.5.4) '@ai-sdk/gateway': 4.0.126(zod@4.5.4) @@ -12996,6 +13002,7 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) '@sentry/junior-plugin-api': file:packages/junior-plugin-api + '@sentry/nitro': 10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1))(nitro@3.0.260522-beta(jiti@2.7.0)) '@sentry/node': 10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1)) '@sinclair/typebox': 0.34.49 '@slack/types': 2.21.1 @@ -13052,6 +13059,7 @@ snapshots: - bun-types - debug - drizzle-kit + - encoding - expo-sqlite - gel - knex @@ -13059,6 +13067,7 @@ snapshots: - mongodb - mysql2 - next + - nitro - pg-native - postgres - prisma @@ -13075,7 +13084,7 @@ snapshots: - vue - ws - '@sentry/junior@file:packages/junior(@types/node@25.9.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@sentry/junior@file:packages/junior(@types/node@25.9.1)(nitro@3.0.260522-beta(jiti@2.7.0))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@agentclientprotocol/sdk': 1.3.0(zod@4.5.4) '@ai-sdk/gateway': 4.0.126(zod@4.5.4) @@ -13091,6 +13100,7 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) '@sentry/junior-plugin-api': file:packages/junior-plugin-api + '@sentry/nitro': 10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1))(nitro@3.0.260522-beta(jiti@2.7.0)) '@sentry/node': 10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1)) '@sinclair/typebox': 0.34.49 '@slack/types': 2.21.1 @@ -13147,6 +13157,7 @@ snapshots: - bun-types - debug - drizzle-kit + - encoding - expo-sqlite - gel - knex @@ -13154,6 +13165,7 @@ snapshots: - mongodb - mysql2 - next + - nitro - pg-native - postgres - prisma @@ -13170,7 +13182,7 @@ snapshots: - vue - ws - '@sentry/junior@file:packages/junior(@types/node@25.9.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.12)': + '@sentry/junior@file:packages/junior(@types/node@25.9.1)(nitro@3.0.260522-beta)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.12)': dependencies: '@agentclientprotocol/sdk': 1.3.0(zod@4.5.4) '@ai-sdk/gateway': 4.0.126(zod@4.5.4) @@ -13186,6 +13198,7 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) '@sentry/junior-plugin-api': file:packages/junior-plugin-api + '@sentry/nitro': 10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1))(nitro@3.0.260522-beta) '@sentry/node': 10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1)) '@sinclair/typebox': 0.34.49 '@slack/types': 2.21.1 @@ -13242,6 +13255,7 @@ snapshots: - bun-types - debug - drizzle-kit + - encoding - expo-sqlite - gel - knex @@ -13249,6 +13263,7 @@ snapshots: - mongodb - mysql2 - next + - nitro - pg-native - postgres - prisma @@ -13281,6 +13296,7 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) '@sentry/junior-plugin-api': file:packages/junior-plugin-api + '@sentry/nitro': 10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1)) '@sentry/node': 10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1)) '@sinclair/typebox': 0.34.49 '@slack/types': 2.21.1 @@ -13337,6 +13353,7 @@ snapshots: - bun-types - debug - drizzle-kit + - encoding - expo-sqlite - gel - knex @@ -13344,6 +13361,7 @@ snapshots: - mongodb - mysql2 - next + - nitro - pg-native - postgres - prisma @@ -13360,6 +13378,31 @@ snapshots: - vue - ws + '@sentry/nitro@10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1))': + dependencies: + '@sentry/bundler-plugin-core': 5.3.0 + '@sentry/core': 10.65.0 + '@sentry/node': 10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1)) + '@sentry/server-utils': 10.65.0 + transitivePeerDependencies: + - '@opentelemetry/core' + - '@opentelemetry/exporter-trace-otlp-http' + - encoding + - supports-color + + '@sentry/nitro@10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1))(nitro@3.0.260522-beta(@vercel/blob@2.8.0)(@vercel/functions@3.6.0)(@vercel/queue@0.2.0)(aws4fetch@1.0.20)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(pg@8.21.0))(jiti@2.7.0))': + dependencies: + '@sentry/bundler-plugin-core': 5.3.0 + '@sentry/core': 10.65.0 + '@sentry/node': 10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1)) + '@sentry/server-utils': 10.65.0 + nitro: 3.0.260522-beta(@vercel/blob@2.8.0)(@vercel/functions@3.6.0)(@vercel/queue@0.2.0)(aws4fetch@1.0.20)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(pg@8.21.0))(jiti@2.7.0) + transitivePeerDependencies: + - '@opentelemetry/core' + - '@opentelemetry/exporter-trace-otlp-http' + - encoding + - supports-color + '@sentry/nitro@10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1))(nitro@3.0.260522-beta(jiti@2.7.0))': dependencies: '@sentry/bundler-plugin-core': 5.3.0 @@ -13373,6 +13416,19 @@ snapshots: - encoding - supports-color + '@sentry/nitro@10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1))(nitro@3.0.260522-beta)': + dependencies: + '@sentry/bundler-plugin-core': 5.3.0 + '@sentry/core': 10.65.0 + '@sentry/node': 10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1)) + '@sentry/server-utils': 10.65.0 + nitro: 3.0.260522-beta + transitivePeerDependencies: + - '@opentelemetry/core' + - '@opentelemetry/exporter-trace-otlp-http' + - encoding + - supports-color + '@sentry/node-core@10.65.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.220.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.9.0(@opentelemetry/api@1.9.1))': dependencies: '@sentry/conventions': 0.15.1 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 2b58e49fc0..fb7c903e33 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -9,6 +9,7 @@ catalog: "@earendil-works/pi-ai": 0.85.1 "@opentelemetry/api": 1.9.1 "@opentelemetry/core": 2.9.0 + "@sentry/nitro": 10.65.0 "@sentry/node": 10.65.0 "@sentry/starlight-theme": ^0.9.1 drizzle-kit: ^0.31.8