From f392685838f3583c1aa47112066020419b5aaf1d Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Thu, 29 Oct 2026 15:27:29 +0000 Subject: [PATCH 1/5] feat(sentry): Upgrade Sentry SDKs to v11 Upgrade @sentry/node and @sentry/nitro to 11.10.0. v11 replaces import-in-the-middle with diagnostics-channel instrumentation. juniorNitro() now adds the orchestrion Rollup plugin, so library instrumentation is injected at build time and apps no longer need a runtime --import hook. Remove instrument.mjs, cross-env and the NODE_OPTIONS scripts from the example app and the init scaffold. Use Sentry's automatic pg, Neon, HTTP server and fetch spans instead of the manual DB, webhook and Slack file download spans. Keep the manual gen_ai spans and filter the AI provider integrations, because pi-ai parses provider streams itself and the SDK spans would have no usage or cost. Replace sendDefaultPii with dataCollection and drop the options v11 removed. withSpan keeps a caller-set error.type instead of overwriting it with the error name. Refs #2334 Co-Authored-By: David Cramer --- TELEMETRY.md | 18 +- apps/example/instrument.mjs | 3 - apps/example/package.json | 5 +- .../src/content/docs/operate/observability.md | 2 +- packages/junior/package.json | 1 + packages/junior/src/chat/logging.ts | 52 +- packages/junior/src/chat/sandbox/errors.ts | 3 +- packages/junior/src/chat/sandbox/sandbox.ts | 59 +- .../junior/src/chat/sentry-payload-filter.ts | 21 +- packages/junior/src/chat/sentry.ts | 1 - packages/junior/src/chat/slack/client.ts | 40 +- packages/junior/src/cli/init.ts | 16 +- packages/junior/src/db/neon.ts | 17 +- packages/junior/src/db/postgres.ts | 17 +- packages/junior/src/db/tracing.ts | 395 --------- packages/junior/src/handlers/webhooks.ts | 69 +- packages/junior/src/instrumentation.ts | 45 +- packages/junior/src/nitro.ts | 32 +- .../component/slack/inbound-telemetry.test.ts | 13 +- .../outbound-normalization-contract.test.ts | 8 +- .../unit/build/nitro-plugin-module.test.ts | 7 +- .../junior/tests/unit/cli/init-cli.test.ts | 21 +- .../junior/tests/unit/instrumentation.test.ts | 34 +- .../tests/unit/logging/with-span.test.ts | 51 +- .../tests/unit/sentry-payload-filter.test.ts | 41 +- .../junior/tests/unit/sql/tracing.test.ts | 210 ----- packages/junior/tsdown.config.ts | 1 + pnpm-lock.yaml | 787 ++++++++---------- pnpm-workspace.yaml | 17 +- 29 files changed, 571 insertions(+), 1415 deletions(-) delete mode 100644 apps/example/instrument.mjs delete mode 100644 packages/junior/src/db/tracing.ts delete mode 100644 packages/junior/tests/unit/sql/tracing.test.ts diff --git a/TELEMETRY.md b/TELEMETRY.md index a6593ad617..bf57b00468 100644 --- a/TELEMETRY.md +++ b/TELEMETRY.md @@ -169,15 +169,15 @@ Do not add app-specific keys under `user.*`. Put facts about the request in PostgreSQL queries that are slow, frequent, or failing. -Spans: `db.query` +Spans: Sentry's automatic `pg` and Neon spans (`sentry.op` `db`, origin +`auto.db.postgres` or `auto.db.neon`). Node Postgres also adds `pg-pool.connect` +and `pg.connect` spans. -Attributes: `db.system.name`, `db.namespace`, `db.operation.name`, -`db.collection.name`, `db.query.summary`, `db.query.text`, -`db.response.status_code`, `error.type`, `server.address`, `server.port`, -`app.db.driver` +Attributes: `db.system.name`, `db.namespace`, `db.user`, `db.query.summary`, +`db.query.text`, `server.address`, `server.port`, `error.type` `db.query.text` keeps parameter placeholders and never includes parameter values. -All inline SQL literals use `?`. SQL comments are removed. +The SDK replaces inline SQL literals with `?` and removes SQL comments. Group by `db.query.text` to identify one query shape. Group by `db.query.summary` for a lower-cardinality operation and target view. @@ -189,10 +189,10 @@ Events: `webhook.response.unsuccessful`, `webhook.handler.failed`, `slack.event.persist.failed`, `slack.event.routing.failed`, `slack.event.enqueue.failed` -Spans: `http.server.request`, `slack.message.ingress` +Spans: Sentry's automatic `http.server` span, `slack.message.ingress` -Attributes: `http.request.method`, `http.response.status_code`, `url.path`, -`app.request.id` +Attributes: `http.request.method`, `http.response.status_code`, `url.path`. +Webhook logs carry `app.request.id`. Signed Slack message and mention events get a `slack.message.ingress` span before membership checks. It carries conversation, channel, and message IDs, diff --git a/apps/example/instrument.mjs b/apps/example/instrument.mjs deleted file mode 100644 index 5574c51d1b..0000000000 --- a/apps/example/instrument.mjs +++ /dev/null @@ -1,3 +0,0 @@ -import { initSentry } from "@sentry/junior/instrumentation"; - -initSentry(); diff --git a/apps/example/package.json b/apps/example/package.json index 1244cf3b2d..deb9d37789 100644 --- a/apps/example/package.json +++ b/apps/example/package.json @@ -4,11 +4,11 @@ "type": "module", "scripts": { "predev": "pnpm --filter @sentry/junior build && pnpm --filter @sentry/junior-dashboard build && pnpm --filter @sentry/junior-memory build", - "dev": "cross-env NODE_OPTIONS=--import=./instrument.mjs nitro dev", + "dev": "nitro dev", "prebuild": "pnpm --filter @sentry/junior build && pnpm --filter @sentry/junior-dashboard build && pnpm --filter @sentry/junior-memory build", "build": "junior snapshot create && nitro build", "postbuild": "node scripts/check-vercel-output.mjs", - "preview": "cross-env NODE_OPTIONS=--import=./instrument.mjs nitro preview", + "preview": "nitro preview", "typecheck": "tsc --noEmit" }, "dependencies": { @@ -31,7 +31,6 @@ }, "devDependencies": { "@types/node": "^25.9.1", - "cross-env": "^10.1.0", "jiti": "^2.7.0", "nitro": "3.0.260522-beta", "typescript": "^7.0.2" diff --git a/packages/docs/src/content/docs/operate/observability.md b/packages/docs/src/content/docs/operate/observability.md index dfa9c4b33f..63189371dc 100644 --- a/packages/docs/src/content/docs/operate/observability.md +++ b/packages/docs/src/content/docs/operate/observability.md @@ -21,7 +21,7 @@ related: ## Key spans -- `http.server.request` +- `http.server` - `queue.publish` - `queue.process` - `chat.turn` diff --git a/packages/junior/package.json b/packages/junior/package.json index e4590f6f8a..13c6130ebd 100644 --- a/packages/junior/package.json +++ b/packages/junior/package.json @@ -84,6 +84,7 @@ "@sentry/junior-plugin-api": "workspace:*", "@sentry/nitro": "catalog:", "@sentry/node": "catalog:", + "@sentry/server-utils": "catalog:", "@sinclair/typebox": "^0.34.49", "@slack/types": "^2.21.1", "@slack/web-api": "^7.16.0", diff --git a/packages/junior/src/chat/logging.ts b/packages/junior/src/chat/logging.ts index 4bd3eedb47..5fcb779471 100644 --- a/packages/junior/src/chat/logging.ts +++ b/packages/junior/src/chat/logging.ts @@ -1372,17 +1372,10 @@ export function getLogContextAttributes(): LogAttributes { /** Return inherited log context filtered to attributes valid for the span operation. */ export function getLogContextAttributesForSpan(op: string): LogAttributes { const attributes = { ...getLogContextAttributes() }; - if (op === "gen_ai.invoke_agent" || op === "gen_ai.execute_tool") { - delete attributes["gen_ai.request.model"]; - return attributes; - } - if (op === "gen_ai.chat" || op === "gen_ai.embeddings") { + delete attributes["gen_ai.request.model"]; + if (op !== "gen_ai.invoke_agent" && op !== "gen_ai.execute_tool") { delete attributes["gen_ai.agent.name"]; - delete attributes["gen_ai.request.model"]; - return attributes; } - delete attributes["gen_ai.agent.name"]; - delete attributes["gen_ai.request.model"]; return attributes; } @@ -1524,11 +1517,7 @@ function setAttributesOnSpan( span: Sentry.Span, attributes: Record, ): void { - for (const [key, value] of Object.entries( - normalizeSpanAttributes(attributes), - )) { - span.setAttribute(key, value); - } + span.setAttributes(normalizeSpanAttributes(attributes)); } /** @@ -1653,36 +1642,39 @@ export async function withSpan( callback: (setSpanAttributes: SetSpanAttributes) => Promise, attributes: Record = {}, ): Promise { - const normalizedAttributes = normalizeSpanAttributes(attributes); - - return withLogContext(context, () => { - // Child spans inherit the active log context so nested GenAI spans keep - // conversation/session correlation even when callers pass only delta - // context such as modelId or tool metadata. - const inheritedAttributes = getLogContextAttributesForSpan(op); - return Sentry.startSpan( + return withLogContext(context, () => + Sentry.startSpan( { name, op, attributes: { - ...inheritedAttributes, - ...normalizedAttributes, + // Child spans inherit the active log context so nested GenAI spans + // keep conversation correlation when callers pass only delta context. + ...getLogContextAttributesForSpan(op), + ...normalizeSpanAttributes(attributes), }, }, - async (span: Sentry.Span) => { + async (span) => { try { return await callback((attributes) => setAttributesOnSpan(span, attributes), ); } catch (error) { - setAttributesOnSpan(span, { - "error.type": error instanceof Error ? error.name : typeof error, - }); + // Sentry sets the error status but not `error.type`. Keep a more + // specific type that the callback already set. + if ( + Sentry.spanToJSON(span).attributes?.["error.type"] === undefined + ) { + span.setAttribute( + "error.type", + error instanceof Error ? error.name : typeof error, + ); + } throw error; } }, - ); - }); + ), + ); } /** Return Sentry-standard trace propagation headers for the active span. */ diff --git a/packages/junior/src/chat/sandbox/errors.ts b/packages/junior/src/chat/sandbox/errors.ts index e44a6db9e9..bb3e35f31c 100644 --- a/packages/junior/src/chat/sandbox/errors.ts +++ b/packages/junior/src/chat/sandbox/errors.ts @@ -1,4 +1,4 @@ -import { setSpanAttributes, setSpanStatus } from "@/chat/logging"; +import { setSpanAttributes } from "@/chat/logging"; import { extractHttpErrorDetails } from "@/chat/sandbox/http-error-details"; import { getWorkspaceSnapshotNotReadyError } from "@/chat/sandbox/snapshot/not-ready-error"; @@ -137,7 +137,6 @@ export function throwSandboxOperationError( : undefined), "app.sandbox.success": false, }); - setSpanStatus("error"); throw new Error( details.summary ? `${action} failed (${details.summary})` diff --git a/packages/junior/src/chat/sandbox/sandbox.ts b/packages/junior/src/chat/sandbox/sandbox.ts index 8ecf291bf0..ddd91429f4 100644 --- a/packages/junior/src/chat/sandbox/sandbox.ts +++ b/packages/junior/src/chat/sandbox/sandbox.ts @@ -372,40 +372,31 @@ export function createSandbox(options: SandboxOptions): SandboxAccess { "process.executable.name": "bash", }, async () => { - try { - const response = await executeBash({ - command, - cwd, - ...(env ? { env } : undefined), - ...(timeoutMs ? { timeoutMs } : undefined), - ...(context.signal ? { signal: context.signal } : undefined), - }); - setSpanAttributes({ - "process.exit.code": response.exitCode, - "app.sandbox.stdout_bytes": Buffer.byteLength( - response.stdout ?? "", - "utf8", - ), - "app.sandbox.stderr_bytes": Buffer.byteLength( - response.stderr ?? "", - "utf8", - ), - ...(response.aborted - ? { "error.type": "outcome_unknown" } - : response.exitCode !== 0 - ? { "error.type": "nonzero_exit" } - : {}), - }); - setSpanStatus(response.exitCode === 0 ? "ok" : "error"); - return response; - } catch (error) { - setSpanAttributes({ - "error.type": - error instanceof Error ? error.name : "sandbox_execute_error", - }); - setSpanStatus("error"); - throw error; - } + const response = await executeBash({ + command, + cwd, + ...(env ? { env } : undefined), + ...(timeoutMs ? { timeoutMs } : undefined), + ...(context.signal ? { signal: context.signal } : undefined), + }); + setSpanAttributes({ + "process.exit.code": response.exitCode, + "app.sandbox.stdout_bytes": Buffer.byteLength( + response.stdout ?? "", + "utf8", + ), + "app.sandbox.stderr_bytes": Buffer.byteLength( + response.stderr ?? "", + "utf8", + ), + ...(response.aborted + ? { "error.type": "outcome_unknown" } + : response.exitCode !== 0 + ? { "error.type": "nonzero_exit" } + : {}), + }); + setSpanStatus(response.exitCode === 0 ? "ok" : "error"); + return response; }, ); // Always consume egress auth/permission signals regardless of exit code. diff --git a/packages/junior/src/chat/sentry-payload-filter.ts b/packages/junior/src/chat/sentry-payload-filter.ts index c261e5f70e..74df8e059e 100644 --- a/packages/junior/src/chat/sentry-payload-filter.ts +++ b/packages/junior/src/chat/sentry-payload-filter.ts @@ -16,10 +16,9 @@ type RequestContainer = { type SentryErrorEvent = Parameters< NonNullable >[0]; -type SentryTransactionEvent = Parameters< - NonNullable +type SentrySpan = Parameters< + NonNullable >[0]; -type SentrySpan = Parameters[0]>[0]; type SentryLog = Parameters< NonNullable >[0]; @@ -175,22 +174,6 @@ export function scrubPrivateSentryEvent( return event; } -/** Remove private conversation payloads and boundary secrets from transactions. */ -export function scrubPrivateSentryTransaction( - event: SentryTransactionEvent, -): SentryTransactionEvent | null { - const eventRecord = event as AttributeContainer; - scrubContainer(eventRecord); - scrubSensitiveRequest(event.request as RequestContainer | undefined); - scrubContainer(event.contexts?.trace as AttributeContainer); - - for (const span of event.spans ?? []) { - scrubContainer(span); - } - - return event; -} - /** Remove private conversation payloads and boundary secrets from streamed spans. */ export function scrubPrivateSentrySpan(span: SentrySpan): SentrySpan { scrubContainer(span); diff --git a/packages/junior/src/chat/sentry.ts b/packages/junior/src/chat/sentry.ts index dd36885ebb..5db3283578 100644 --- a/packages/junior/src/chat/sentry.ts +++ b/packages/junior/src/chat/sentry.ts @@ -19,6 +19,5 @@ export { vercelAIIntegration, withActiveSpan, withScope, - withStreamedSpan, } from "@sentry/node"; export * from "@sentry/node"; diff --git a/packages/junior/src/chat/slack/client.ts b/packages/junior/src/chat/slack/client.ts index fd56ba2294..7500adae61 100644 --- a/packages/junior/src/chat/slack/client.ts +++ b/packages/junior/src/chat/slack/client.ts @@ -1,12 +1,7 @@ import { AsyncLocalStorage } from "node:async_hooks"; import { WebClient } from "@slack/web-api"; import { getSlackBotToken } from "@/chat/config"; -import { - logWarn, - setSpanAttributes, - setSpanStatus, - withSpan, -} from "@/chat/logging"; +import { logWarn, setSpanAttributes, withSpan } from "@/chat/logging"; import { parseSlackChannelReferenceId, type SlackChannelId, @@ -498,7 +493,6 @@ export async function withSlackRetries( errorAttrs["http.response.status_code"] = mapped.statusCode; } setSpanAttributes(errorAttrs); - setSpanStatus("error"); throw error; } }, @@ -667,29 +661,13 @@ export async function downloadPrivateSlackFile(url: string): Promise { // destination-installation token resolution as Web API calls. const token = resolveSlackToken(); - return withSpan( - "GET files.slack.com", - "http.client", - {}, - async () => { - const response = await fetch(url, { - headers: { - Authorization: `Bearer ${token}`, - }, - }); - setSpanAttributes({ "http.response.status_code": response.status }); - if (!response.ok) { - setSpanAttributes({ "error.type": String(response.status) }); - setSpanStatus("error"); - throw new Error(`Slack file download failed: ${response.status}`); - } - return Buffer.from(await response.arrayBuffer()); + const response = await fetch(url, { + headers: { + Authorization: `Bearer ${token}`, }, - { - "http.request.method": "GET", - "server.address": "files.slack.com", - "url.scheme": "https", - "app.slack.method": "files.download", - }, - ); + }); + if (!response.ok) { + throw new Error(`Slack file download failed: ${response.status}`); + } + return Buffer.from(await response.arrayBuffer()); } diff --git a/packages/junior/src/cli/init.ts b/packages/junior/src/cli/init.ts index 4a39c886f0..20013c05ed 100644 --- a/packages/junior/src/cli/init.ts +++ b/packages/junior/src/cli/init.ts @@ -28,16 +28,6 @@ export default app; ); } -function writeInstrumentFile(targetDir: string): void { - fs.writeFileSync( - path.join(targetDir, "instrument.mjs"), - `import { initSentry } from "@sentry/junior/instrumentation"; - -initSentry(); -`, - ); -} - function writePluginsFile(targetDir: string): void { fs.writeFileSync( path.join(targetDir, "plugins.ts"), @@ -172,10 +162,10 @@ export async function runInit( private: true, type: "module", scripts: { - dev: "cross-env NODE_OPTIONS=--import=./instrument.mjs nitro dev", + dev: "nitro dev", check: "junior check", build: "junior snapshot create && nitro build", - preview: "cross-env NODE_OPTIONS=--import=./instrument.mjs nitro preview", + preview: "nitro preview", typecheck: "tsc --noEmit", }, dependencies: { @@ -188,7 +178,6 @@ export async function runInit( }, devDependencies: { "@types/node": "^25.9.1", - "cross-env": "^10.1.0", jiti: "^2.7.0", nitro: "3.0.260522-beta", typescript: "^7.0.2", @@ -265,7 +254,6 @@ SENTRY_AUTH_TOKEN= ); writeServerEntry(target); - writeInstrumentFile(target); writePluginsFile(target); writeNitroConfig(target); writeTsConfig(target); diff --git a/packages/junior/src/db/neon.ts b/packages/junior/src/db/neon.ts index 810f6ee37d..b50c860e35 100644 --- a/packages/junior/src/db/neon.ts +++ b/packages/junior/src/db/neon.ts @@ -10,7 +10,6 @@ import { migrate } from "drizzle-orm/neon-serverless/migrator"; import type { MigrationConfig } from "drizzle-orm/migrator"; import type { JuniorDatabase, JuniorSqlExecutor } from "./db"; import { juniorSqlSchema } from "./schema"; -import { traceQueries } from "./tracing"; import { logException } from "@/chat/logging"; type QueryClient = Pool | PoolClient | Client; @@ -24,11 +23,9 @@ class NeonExecutor implements NeonJuniorSqlExecutor { private isolatedQueryId = 0; private readonly pool: Pool; - private readonly connectionString: string; - constructor(pool: Pool, connectionString: string) { + constructor(pool: Pool) { this.pool = pool; - this.connectionString = connectionString; } db(): JuniorDatabase { @@ -58,10 +55,7 @@ class NeonExecutor implements NeonJuniorSqlExecutor { statement: string, params: readonly unknown[] = [], ): Promise { - const client = traceQueries(await this.pool.connect(), { - connectionString: this.connectionString, - driver: "neon", - }); + const client = await this.pool.connect(); try { // A named statement uses the extended protocol, which accepts one statement only. const result = await client.query({ @@ -165,10 +159,7 @@ class NeonExecutor implements NeonJuniorSqlExecutor { } private queryClient(): QueryClient { - return traceQueries(this.transactionClient.getStore() ?? this.pool, { - connectionString: this.connectionString, - driver: "neon", - }); + return this.transactionClient.getStore() ?? this.pool; } } @@ -187,5 +178,5 @@ export function createNeonJuniorSqlExecutor(args: { pool.on("error", (error: Error) => { logException(error, "db.pool.client.failed", { "app.db.driver": "neon" }); }); - return new NeonExecutor(pool, args.connectionString); + return new NeonExecutor(pool); } diff --git a/packages/junior/src/db/postgres.ts b/packages/junior/src/db/postgres.ts index e71e89a5d6..648d271431 100644 --- a/packages/junior/src/db/postgres.ts +++ b/packages/junior/src/db/postgres.ts @@ -9,7 +9,6 @@ import { migrate } from "drizzle-orm/node-postgres/migrator"; import type { MigrationConfig } from "drizzle-orm/migrator"; import type { JuniorDatabase, JuniorSqlExecutor } from "./db"; import { juniorSqlSchema } from "./schema"; -import { traceQueries } from "./tracing"; import { logException } from "@/chat/logging"; const { Pool } = pg; @@ -22,11 +21,9 @@ class PostgresExecutor implements JuniorSqlExecutor { private isolatedQueryId = 0; private readonly pool: PgPool; - private readonly connectionString: string; - constructor(pool: PgPool, connectionString: string) { + constructor(pool: PgPool) { this.pool = pool; - this.connectionString = connectionString; } db(): JuniorDatabase { @@ -56,10 +53,7 @@ class PostgresExecutor implements JuniorSqlExecutor { statement: string, params: readonly unknown[] = [], ): Promise { - const client = traceQueries(await this.pool.connect(), { - connectionString: this.connectionString, - driver: "postgres", - }); + const client = await this.pool.connect(); try { // A named statement uses the extended protocol, which accepts one statement only. const result = await client.query({ @@ -163,10 +157,7 @@ class PostgresExecutor implements JuniorSqlExecutor { } private queryClient(): QueryClient { - return traceQueries(this.transactionClient.getStore() ?? this.pool, { - connectionString: this.connectionString, - driver: "postgres", - }); + return this.transactionClient.getStore() ?? this.pool; } } @@ -189,5 +180,5 @@ export function createPostgresJuniorSqlExecutor(args: { "app.db.driver": "postgres", }); }); - return new PostgresExecutor(pool, args.connectionString); + return new PostgresExecutor(pool); } diff --git a/packages/junior/src/db/tracing.ts b/packages/junior/src/db/tracing.ts deleted file mode 100644 index 542063babf..0000000000 --- a/packages/junior/src/db/tracing.ts +++ /dev/null @@ -1,395 +0,0 @@ -import { SpanKind } from "@opentelemetry/api"; -import * as Sentry from "@/chat/sentry"; - -const traced = Symbol("junior.db.traced"); -const MAX_QUERY_TEXT_LENGTH = 10_000; -const MAX_QUERY_SUMMARY_LENGTH = 255; - -interface QueryClient { - [traced]?: true; - query: (...args: any[]) => unknown; -} - -interface DatabaseConnectionAttributes { - "db.namespace"?: string; - "server.address"?: string; - "server.port"?: number; -} - -interface QueryDetails { - collection?: string; - operation?: string; - storedProcedure?: string; - summary?: string; - text?: string; -} - -const SQL_OPERATIONS = new Set([ - "ALTER", - "ANALYZE", - "BEGIN", - "CALL", - "COMMIT", - "COPY", - "CREATE", - "DELETE", - "DROP", - "EXPLAIN", - "GRANT", - "INSERT", - "MERGE", - "RELEASE", - "REVOKE", - "ROLLBACK", - "SAVEPOINT", - "SELECT", - "SET", - "SHOW", - "TRUNCATE", - "UPDATE", - "VACUUM", -]); -const SQL_IDENTIFIER = String.raw`(?:(?:U&)?"(?:""|[^"])*"|[A-Za-z_][A-Za-z0-9_$]*)(?:\.(?:(?:U&)?"(?:""|[^"])*"|[A-Za-z_][A-Za-z0-9_$]*))*`; - -function targetPattern(prefix: string): RegExp { - return new RegExp(`${prefix}(${SQL_IDENTIFIER})`, "i"); -} - -const SQL_TARGET: Record = { - ALTER: targetPattern(String.raw`\bALTER\s+TABLE\s+`), - CALL: targetPattern(String.raw`\bCALL\s+`), - CREATE: targetPattern( - String.raw`\bCREATE\s+(?:OR\s+REPLACE\s+)?(?:TABLE|VIEW)\s+(?:IF\s+NOT\s+EXISTS\s+)?`, - ), - DELETE: targetPattern(String.raw`\bDELETE\s+FROM\s+`), - DROP: targetPattern( - String.raw`\bDROP\s+(?:TABLE|VIEW)\s+(?:IF\s+EXISTS\s+)?`, - ), - INSERT: targetPattern(String.raw`\bINSERT\s+INTO\s+`), - MERGE: targetPattern(String.raw`\bMERGE\s+INTO\s+`), - SELECT: targetPattern(String.raw`\bFROM\s+`), - TRUNCATE: targetPattern(String.raw`\bTRUNCATE\s+(?:TABLE\s+)?`), - UPDATE: targetPattern(String.raw`\bUPDATE\s+`), -}; - -function queryText(query: unknown): string | undefined { - if (typeof query === "string") return query; - if (!query || typeof query !== "object" || !("text" in query)) { - return undefined; - } - return typeof query.text === "string" ? query.text : undefined; -} - -function safeSqlText(text: string): string { - let safe = ""; - for (let index = 0; index < text.length; ) { - if (text.startsWith("--", index)) { - const end = text.indexOf("\n", index + 2); - safe += " "; - index = end === -1 ? text.length : end; - continue; - } - if (text.startsWith("/*", index)) { - let depth = 1; - index += 2; - while (index < text.length && depth > 0) { - if (text.startsWith("/*", index)) { - depth += 1; - index += 2; - } else if (text.startsWith("*/", index)) { - depth -= 1; - index += 2; - } else { - index += 1; - } - } - safe += " "; - continue; - } - - const dollarTag = /^\$(?:[A-Za-z_][A-Za-z0-9_]*)?\$/.exec( - text.slice(index), - )?.[0]; - if (dollarTag) { - const end = text.indexOf(dollarTag, index + dollarTag.length); - index = end === -1 ? text.length : end + dollarTag.length; - safe += "?"; - continue; - } - - const identifierPrefix = /^(?:U&)?"/i.exec(text.slice(index))?.[0]; - if (identifierPrefix) { - let end = index + identifierPrefix.length; - while (end < text.length) { - if (text[end] !== '"') { - end += 1; - continue; - } - if (text[end + 1] === '"') { - end += 2; - continue; - } - end += 1; - break; - } - safe += text.slice(index, end); - index = end; - continue; - } - - const stringPrefix = /^(?:E|U&|B|X)?'/i.exec(text.slice(index))?.[0]; - if (stringPrefix) { - const supportsBackslashEscapes = /^E'/i.test(stringPrefix); - let end = index + stringPrefix.length; - while (end < text.length) { - if (supportsBackslashEscapes && text[end] === "\\") { - end += 2; - continue; - } - if (text[end] !== "'") { - end += 1; - continue; - } - if (text[end + 1] === "'") { - end += 2; - continue; - } - end += 1; - break; - } - safe += "?"; - index = end; - continue; - } - - const token = - /^(?:TRUE|FALSE|NULL|0x[\da-f_]+|0b[01_]+|0o[0-7_]+|\d[\d_]*(?:\.[\d_]*)?(?:e[+-]?[\d_]+)?)(?![A-Za-z0-9_$])/i.exec( - text.slice(index), - )?.[0]; - const previous = text[index - 1]; - if (token && (!previous || !/[A-Za-z0-9_$]/.test(previous))) { - safe += "?"; - index += token.length; - continue; - } - - safe += text[index]; - index += 1; - } - - return safe; -} - -function normalizeQueryText(text: string): string { - return safeSqlText(text.slice(0, MAX_QUERY_TEXT_LENGTH)) - .replace(/\s+/g, " ") - .trim() - .slice(0, MAX_QUERY_TEXT_LENGTH); -} - -function operationFromText( - text: string, -): { index: number; name: string } | undefined { - const tokens = /(?:U&)?"(?:""|[^"])*"|[A-Za-z_][A-Za-z0-9_$]*|[()]/gi; - let depth = 0; - for (const match of text.matchAll(tokens)) { - const token = match[0]; - if (token === "(") { - depth += 1; - } else if (token === ")") { - depth = Math.max(0, depth - 1); - } else if (depth === 0 && !token.includes('"')) { - if (SQL_OPERATIONS.has(token.toUpperCase())) { - return { index: match.index, name: token }; - } - } - } - return undefined; -} - -function targetFromOperation( - operation: string, - text: string, -): string | undefined { - if (operation.toUpperCase() !== "SELECT") { - return SQL_TARGET[operation.toUpperCase()]?.exec(text)?.[1]; - } - - const tokens = /(?:U&)?"(?:""|[^"])*"|[A-Za-z_][A-Za-z0-9_$]*|[()]/gi; - let depth = 0; - for (const match of text.matchAll(tokens)) { - const token = match[0]; - if (token === "(") { - depth += 1; - } else if (token === ")") { - depth = Math.max(0, depth - 1); - } else if (depth === 0 && token.toUpperCase() === "FROM") { - const targetText = text.slice(match.index + token.length).trimStart(); - return new RegExp(`^(${SQL_IDENTIFIER})`, "i").exec(targetText)?.[1]; - } - } - return undefined; -} - -function querySummary( - operation: string | undefined, - target: string | undefined, -): string | undefined { - if (!operation) return undefined; - const summary = target ? `${operation} ${target}` : operation; - return summary.length <= MAX_QUERY_SUMMARY_LENGTH ? summary : operation; -} - -function detailsFromQuery(args: unknown[]): QueryDetails { - const rawText = queryText(args[0]); - if (!rawText) return {}; - - const text = normalizeQueryText(rawText); - const operationMatch = operationFromText(text); - const operation = operationMatch?.name; - const operationText = operationMatch ? text.slice(operationMatch.index) : ""; - const target = operation - ? targetFromOperation(operation, operationText) - : undefined; - const summary = querySummary(operation, target); - const isCall = operation?.toUpperCase() === "CALL"; - - return { - collection: isCall ? undefined : target, - operation, - storedProcedure: isCall ? target : undefined, - summary, - text: text || undefined, - }; -} - -function connectionAttributes( - connectionString: string, -): DatabaseConnectionAttributes { - try { - const url = new URL(connectionString); - const namespace = decodeURIComponent(url.pathname.replace(/^\//, "")); - const port = url.port ? Number(url.port) : undefined; - return { - ...(namespace ? { "db.namespace": namespace } : undefined), - ...(url.hostname ? { "server.address": url.hostname } : undefined), - ...(port && port !== 5432 ? { "server.port": port } : undefined), - }; - } catch { - return {}; - } -} - -function responseStatusCode(error: unknown): string | undefined { - if (!error || typeof error !== "object" || !("code" in error)) { - return undefined; - } - return typeof error.code === "string" || typeof error.code === "number" - ? String(error.code) - : undefined; -} - -function errorType(error: unknown): string { - return ( - responseStatusCode(error) ?? - (error instanceof Error ? error.name : typeof error) - ); -} - -function markFailed(span: Sentry.Span, error: unknown): void { - const statusCode = responseStatusCode(error); - span.setAttribute("error.type", statusCode ?? errorType(error)); - if (statusCode && /^[0-9A-Z]{5}$/i.test(statusCode)) { - span.setAttribute("db.response.status_code", statusCode); - } - span.setStatus({ code: 2 }); -} - -/** Add OpenTelemetry database client spans to an owned PostgreSQL query client. */ -export function traceQueries( - client: T, - options: { - connectionString: string; - driver: "neon" | "postgres"; - }, -): T { - if (client[traced]) return client; - client[traced] = true; - - const query = client.query.bind(client); - const connection = connectionAttributes(options.connectionString); - client.query = ((...originalArgs: Parameters) => { - const details = detailsFromQuery(originalArgs); - const args = [...originalArgs]; - const callbackIndex = - typeof args.at(-1) === "function" ? args.length - 1 : undefined; - - return Sentry.startSpanManual( - { - name: details.summary ?? details.operation ?? "postgresql", - op: "db.query", - kind: SpanKind.CLIENT, - onlyIfParent: true, - attributes: { - "db.system.name": "postgresql", - ...connection, - ...(details.operation - ? { "db.operation.name": details.operation } - : undefined), - ...(details.summary - ? { "db.query.summary": details.summary } - : undefined), - ...(details.text ? { "db.query.text": details.text } : undefined), - ...(details.storedProcedure - ? { "db.stored_procedure.name": details.storedProcedure } - : undefined), - ...(details.collection - ? { "db.collection.name": details.collection } - : undefined), - "app.db.driver": options.driver, - }, - }, - (span, finish) => { - if (callbackIndex !== undefined) { - const callback = args[callbackIndex] as ( - error: unknown, - ...callbackArgs: unknown[] - ) => unknown; - args[callbackIndex] = (( - error: unknown, - ...callbackArgs: unknown[] - ) => { - if (error) markFailed(span, error); - finish(); - return callback(error, ...callbackArgs); - }) as Parameters[number]; - } - - try { - const result = query(...args); - if (callbackIndex !== undefined) return result; - if (result && typeof result === "object" && "then" in result) { - return Promise.resolve(result).then( - (value) => { - finish(); - return value; - }, - (error: unknown) => { - markFailed(span, error); - finish(); - throw error; - }, - ); - } - finish(); - return result; - } catch (error) { - markFailed(span, error); - finish(); - throw error; - } - }, - ); - }) as T["query"]; - return client; -} diff --git a/packages/junior/src/handlers/webhooks.ts b/packages/junior/src/handlers/webhooks.ts index 20d7e3a7a7..5c1f2890d0 100644 --- a/packages/junior/src/handlers/webhooks.ts +++ b/packages/junior/src/handlers/webhooks.ts @@ -5,10 +5,7 @@ import { createRequestContext, logException, logWarn, - setSpanAttributes, - setSpanStatus, withContext, - withSpan, } from "@/chat/logging"; import type { WaitUntilFn } from "@/handlers/types"; @@ -68,62 +65,38 @@ function parseJson(body: string): unknown { } } -/** Run a platform webhook with shared request tracing and error logging. */ +/** Run a platform webhook with shared request log context and error logging. */ export async function handleWebhookRequest( request: Request, platform: string, run: WebhookRunner, ): Promise { const requestContext = createRequestContext(request, { platform }); - const requestUrl = new URL(request.url); return await withContext(requestContext, async () => { try { - return await withSpan( - "http.server.request", - "http.server", - requestContext, - async () => { - try { - const response = await run(); + const response = await run(); - if (response.status >= 400) { - let responseBodySnippet: string | undefined; - try { - responseBodySnippet = (await response.clone().text()).slice( - 0, - 300, - ); - } catch { - responseBodySnippet = undefined; - } - logWarn("webhook.response.unsuccessful", { - "http.response.status_code": response.status, - "http.request.header.x_slack_signature": - request.headers.get("x-slack-signature") ?? undefined, - "http.request.header.x_slack_request_timestamp": - request.headers.get("x-slack-request-timestamp") ?? undefined, - ...(responseBodySnippet - ? { "app.webhook.response_body": responseBodySnippet } - : undefined), - }); - } + if (response.status >= 400) { + let responseBodySnippet: string | undefined; + try { + responseBodySnippet = (await response.clone().text()).slice(0, 300); + } catch { + responseBodySnippet = undefined; + } + logWarn("webhook.response.unsuccessful", { + "http.response.status_code": response.status, + "http.request.header.x_slack_signature": + request.headers.get("x-slack-signature") ?? undefined, + "http.request.header.x_slack_request_timestamp": + request.headers.get("x-slack-request-timestamp") ?? undefined, + ...(responseBodySnippet + ? { "app.webhook.response_body": responseBodySnippet } + : undefined), + }); + } - setSpanAttributes({ - "http.response.status_code": response.status, - }); - setSpanStatus(response.status >= 500 ? "error" : "ok"); - return response; - } catch (error) { - setSpanStatus("error"); - throw error; - } - }, - { - "http.request.method": request.method, - "url.path": requestUrl.pathname, - }, - ); + return response; } catch (error) { logException(error, "webhook.handler.failed"); throw error; diff --git a/packages/junior/src/instrumentation.ts b/packages/junior/src/instrumentation.ts index 4b0e727639..dfc51700e1 100644 --- a/packages/junior/src/instrumentation.ts +++ b/packages/junior/src/instrumentation.ts @@ -3,13 +3,26 @@ import { scrubPrivateSentryEvent, scrubPrivateSentryLog, scrubPrivateSentrySpan, - scrubPrivateSentryTransaction, } from "@/chat/sentry-payload-filter"; import { getDeploymentServiceVersion, getDeploymentTelemetryAttributes, } from "@/deployment"; +// Junior's own gen_ai spans own model calls. Pi parses provider streams itself, +// so these SDK spans would duplicate them without usage or cost. +// Remove this filter once Sentry ships a pi-ai integration +// (getsentry/sentry-javascript#25869). +const MANUAL_GEN_AI_INTEGRATIONS = new Set([ + "Anthropic_AI", + "Google_GenAI", + "Groq", + "Mistral", + "OpenAI", + "TogetherAI", + "VercelAI", +]); + function getSampleRate(value: string | undefined, fallback: number): number { if (!value) return fallback; const parsed = Number(value); @@ -43,24 +56,20 @@ export function initSentry(): void { process.env.NODE_ENV, release: serviceVersion, tracesSampleRate: getSampleRate(process.env.SENTRY_TRACES_SAMPLE_RATE, 1), - traceLifecycle: "stream", - sendDefaultPii: true, - enableLogs, - registerEsmLoaderHooks: false, - streamGenAiSpans: true, - beforeSend: scrubPrivateSentryEvent, - beforeSendLog: scrubPrivateSentryLog, - beforeSendSpan: Sentry.withStreamedSpan(scrubPrivateSentrySpan), - beforeSendTransaction: scrubPrivateSentryTransaction, - integrations(defaultIntegrations) { - return [ - ...defaultIntegrations, - Sentry.vercelAIIntegration({ - recordInputs: true, - recordOutputs: true, - }), - ]; + dataCollection: { + // Outgoing calls carry model prompts and provider responses that the + // payload filter cannot see. Keep only incoming request bodies. + httpBodies: ["incomingRequest"], + // Query spans must not carry bound parameter values. + databaseQueryData: false, }, + beforeSend: scrubPrivateSentryEvent, + beforeSendLog: enableLogs ? scrubPrivateSentryLog : () => null, + beforeSendSpan: scrubPrivateSentrySpan, + integrations: (defaultIntegrations) => + defaultIntegrations.filter( + (integration) => !MANUAL_GEN_AI_INTEGRATIONS.has(integration.name), + ), }); // Keep deployment identity centralized so every emitted span, log, and metric carries it. diff --git a/packages/junior/src/nitro.ts b/packages/junior/src/nitro.ts index 747ebb2e3e..b90150573d 100644 --- a/packages/junior/src/nitro.ts +++ b/packages/junior/src/nitro.ts @@ -1,5 +1,6 @@ import path from "node:path"; import { withSentryConfig as withSentryNitroConfig } from "@sentry/nitro"; +import { sentryOrchestrionPlugin } from "@sentry/server-utils/orchestrion/rollup"; import type { Nitro } from "nitro/types"; import { applyRolldownTreeshakeWorkaround } from "@/build/rolldown-workarounds"; import { @@ -143,35 +144,6 @@ function runtimeModuleForResolvedPluginModule( }; } -/** - * Prevent import-in-the-middle and require-in-the-middle from being - * externalized so Rolldown bundles them inline. - * - * @sentry/node (via @opentelemetry/instrumentation) statically imports these - * packages. Nitro already lists them in nf3's NonBundleablePackages, which - * means it externalizes them and relies on traceNodeModules to copy the - * package directories into the Vercel function output. In practice that trace - * step fails to materialize the packages at runtime, causing an - * ERR_MODULE_NOT_FOUND startup crash. - * - * Adding them to noExternals overrides the NonBundleablePackages default and - * forces Rolldown to bundle their CJS code inline. The trade-off is that - * Node.js ESM loader hooks (hook.mjs) are not active, which limits OTEL - * auto-instrumentation of modules loaded after initialization. That is an - * acceptable cost compared to a fatal startup failure. - */ -function bundleOpenTelemetryLoaderHooks(nitro: Nitro): void { - const existing = Array.isArray(nitro.options.noExternals) - ? nitro.options.noExternals - : []; - const additions = ["import-in-the-middle", "require-in-the-middle"].filter( - (pkg) => !existing.includes(pkg), - ); - if (additions.length > 0) { - nitro.options.noExternals = [...existing, ...additions]; - } -} - function configureVercelDeployment( nitro: Nitro, options: JuniorNitroOptions, @@ -302,7 +274,6 @@ export function juniorNitro(options: JuniorNitroOptions = {}): { nitro, options, ); - bundleOpenTelemetryLoaderHooks(nitro); applyRolldownTreeshakeWorkaround(nitro); const pluginSource = options.plugins; @@ -364,6 +335,7 @@ export function juniorNitro(options: JuniorNitroOptions = {}): { nitro.hooks.hook("rollup:before", (_nitro, config) => { const buildConfig = config as RollupLikeConfig; buildConfig.plugins ??= []; + buildConfig.plugins.push(sentryOrchestrionPlugin()); buildConfig.plugins.push({ name: "junior:copy-build-content", async writeBundle() { diff --git a/packages/junior/tests/component/slack/inbound-telemetry.test.ts b/packages/junior/tests/component/slack/inbound-telemetry.test.ts index 30ed3ba291..2451f09ba4 100644 --- a/packages/junior/tests/component/slack/inbound-telemetry.test.ts +++ b/packages/junior/tests/component/slack/inbound-telemetry.test.ts @@ -12,7 +12,11 @@ import { import { slackEventsApiEnvelope } from "../../fixtures/slack/factories/events"; const { span, startSpan } = vi.hoisted(() => { - const span = { setAttribute: vi.fn(), setStatus: vi.fn() }; + const span = { + setAttribute: vi.fn(), + setAttributes: vi.fn(), + setStatus: vi.fn(), + }; return { span, startSpan: vi.fn( @@ -78,10 +82,9 @@ describe("Slack inbound telemetry", () => { }), expect.any(Function), ); - expect(span.setAttribute).toHaveBeenCalledWith( - "app.slack.membership", - "unverified", - ); + expect(span.setAttributes).toHaveBeenCalledWith({ + "app.slack.membership": "unverified", + }); } finally { await state.disconnect(); } diff --git a/packages/junior/tests/integration/slack/outbound-normalization-contract.test.ts b/packages/junior/tests/integration/slack/outbound-normalization-contract.test.ts index 3323096ecc..92a53cbc3e 100644 --- a/packages/junior/tests/integration/slack/outbound-normalization-contract.test.ts +++ b/packages/junior/tests/integration/slack/outbound-normalization-contract.test.ts @@ -46,7 +46,7 @@ describe("Slack contract: outbound normalization", () => { }); client?.on("spanEnd", (span) => { const json = Sentry.spanToJSON(span); - if (json.description === "POST slack.com/api/chat.postMessage") { + if (json.name === "POST slack.com/api/chat.postMessage") { spans.push(json); } }); @@ -158,7 +158,7 @@ describe("Slack contract: outbound normalization", () => { expect(JSON.stringify(events)).not.toContain("private-"); expect(JSON.stringify(events)).not.toContain("private.example"); expect(spans).toHaveLength(1); - const attributes = spans[0]?.data; + const attributes = spans[0]?.attributes; expect(attributes).toMatchObject({ "app.slack.channel_id": "C123", "app.slack.thread_ts": "1700000000.000100", @@ -182,8 +182,8 @@ describe("Slack contract: outbound normalization", () => { ).rejects.toMatchObject({ apiError: "invalid_metadata_schema" }); expect(spans).toHaveLength(1); - expect(spans[0]?.status).not.toBe("ok"); - expect(spans[0]?.data).toMatchObject({ + expect(spans[0]?.status).toBe("error"); + expect(spans[0]?.attributes).toMatchObject({ "app.slack.work_object.count": 0, "app.slack.api_error_code": "invalid_metadata_schema", }); diff --git a/packages/junior/tests/unit/build/nitro-plugin-module.test.ts b/packages/junior/tests/unit/build/nitro-plugin-module.test.ts index 1d978daf29..729d600808 100644 --- a/packages/junior/tests/unit/build/nitro-plugin-module.test.ts +++ b/packages/junior/tests/unit/build/nitro-plugin-module.test.ts @@ -454,8 +454,11 @@ describe("juniorNitro plugin modules", () => { expect(rollupBeforeHooks).toHaveLength(1); await rollupBeforeHooks[0]!({}, { plugins: buildPlugins }); - expect(buildPlugins).toHaveLength(1); - await buildPlugins[0]?.writeBundle?.(); + expect(buildPlugins.map((plugin) => plugin.name)).toEqual([ + "code-transformer", + "junior:copy-build-content", + ]); + await buildPlugins[1]?.writeBundle?.(); await expect( fs.readFile( diff --git a/packages/junior/tests/unit/cli/init-cli.test.ts b/packages/junior/tests/unit/cli/init-cli.test.ts index 8faf003343..32b2d608d7 100644 --- a/packages/junior/tests/unit/cli/init-cli.test.ts +++ b/packages/junior/tests/unit/cli/init-cli.test.ts @@ -74,7 +74,7 @@ describe("init cli", () => { expect(fs.existsSync(path.join(target, "package.json"))).toBe(true); expect(fs.existsSync(path.join(target, "server.ts"))).toBe(true); - expect(fs.existsSync(path.join(target, "instrument.mjs"))).toBe(true); + expect(fs.existsSync(path.join(target, "instrument.mjs"))).toBe(false); expect(fs.existsSync(path.join(target, "api"))).toBe(false); expect(fs.existsSync(path.join(target, "vercel.json"))).toBe(true); expect(fs.existsSync(path.join(target, "nitro.config.ts"))).toBe(true); @@ -117,17 +117,6 @@ describe("init cli", () => { expect(serverEntry).toContain("createApp({"); expect(serverEntry).toContain("plugins,"); - const instrumentFile = fs.readFileSync( - path.join(target, "instrument.mjs"), - "utf8", - ); - expect(instrumentFile).toBe( - fs.readFileSync( - path.join(repoRoot, "apps", "example", "instrument.mjs"), - "utf8", - ), - ); - const nitroConfig = fs.readFileSync( path.join(target, "nitro.config.ts"), "utf8", @@ -172,14 +161,10 @@ describe("init cli", () => { expect(pkg.devDependencies.nitro).toBeDefined(); expect(pkg.devDependencies.vite).toBeUndefined(); expect(pkg.devDependencies.vercel).toBeUndefined(); - expect(pkg.scripts.dev).toBe( - "cross-env NODE_OPTIONS=--import=./instrument.mjs nitro dev", - ); + expect(pkg.scripts.dev).toBe("nitro dev"); expect(pkg.scripts.check).toBe("junior check"); expect(pkg.scripts.build).toBe("junior snapshot create && nitro build"); - expect(pkg.scripts.preview).toBe( - "cross-env NODE_OPTIONS=--import=./instrument.mjs nitro preview", - ); + expect(pkg.scripts.preview).toBe("nitro preview"); expect(pkg.scripts.typecheck).toBe("tsc --noEmit"); const pnpmWorkspace = fs.readFileSync( diff --git a/packages/junior/tests/unit/instrumentation.test.ts b/packages/junior/tests/unit/instrumentation.test.ts index dd8183b7cf..0725ae4d35 100644 --- a/packages/junior/tests/unit/instrumentation.test.ts +++ b/packages/junior/tests/unit/instrumentation.test.ts @@ -38,13 +38,6 @@ async function loadInstrumentationModule() { getClient: () => undefined, init, getGlobalScope: () => globalScope, - vercelAIIntegration: vi.fn((options) => ({ - name: "vercel-ai", - options, - })), - withStreamedSpan: vi.fn((callback) => - Object.assign(callback, { _streamed: true }), - ), })); const instrumentation = await import("@/instrumentation"); return { init, globalScope, instrumentation }; @@ -71,26 +64,21 @@ describe("initSentry", () => { expect(init).toHaveBeenCalledTimes(1); const options = init.mock.calls[0]?.[0]; expect(options?.release).toBe(`${JUNIOR_VERSION}+git-sha`); - expect(options).toMatchObject({ - sendDefaultPii: true, - streamGenAiSpans: true, + expect(options?.dataCollection).toEqual({ + httpBodies: ["incomingRequest"], + databaseQueryData: false, }); expect(options?.beforeSend).toEqual(expect.any(Function)); expect(options?.beforeSendLog).toEqual(expect.any(Function)); expect(options?.beforeSendSpan).toEqual(expect.any(Function)); - expect(options?.beforeSendSpan?._streamed).toBe(true); - expect(options?.beforeSendTransaction).toEqual(expect.any(Function)); - expect(options?.integrations).toEqual(expect.any(Function)); - const defaultIntegration = { name: "default" }; - expect(options?.integrations?.([defaultIntegration])).toEqual([ - defaultIntegration, - expect.objectContaining({ - options: { - recordInputs: true, - recordOutputs: true, - }, - }), - ]); + const http = { name: "Http", setupOnce: () => {} }; + expect( + options?.integrations?.([ + http, + { name: "Anthropic_AI", setupOnce: () => {} }, + { name: "VercelAI", setupOnce: () => {} }, + ]), + ).toEqual([http]); const span: { attributes: Record; end_timestamp: number; diff --git a/packages/junior/tests/unit/logging/with-span.test.ts b/packages/junior/tests/unit/logging/with-span.test.ts index f63915de85..8581f2cb4e 100644 --- a/packages/junior/tests/unit/logging/with-span.test.ts +++ b/packages/junior/tests/unit/logging/with-span.test.ts @@ -1,22 +1,27 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -const { activeSpan, getTraceData, startSpan } = vi.hoisted(() => ({ - activeSpan: { - setAttribute: vi.fn(), - setStatus: vi.fn(), - }, - getTraceData: vi.fn(), - startSpan: vi.fn( - async ( - _options: unknown, - callback: (span: typeof activeSpan) => Promise, - ) => callback(activeSpan), - ), -})); +const { activeSpan, getTraceData, spanAttributes, startSpan } = vi.hoisted( + () => ({ + activeSpan: { + setAttribute: vi.fn(), + setAttributes: vi.fn(), + setStatus: vi.fn(), + }, + spanAttributes: {} as Record, + getTraceData: vi.fn(), + startSpan: vi.fn( + async ( + _options: unknown, + callback: (span: typeof activeSpan) => Promise, + ) => callback(activeSpan), + ), + }), +); vi.mock("@/chat/sentry", () => ({ getActiveSpan: () => activeSpan, getTraceData, + spanToJSON: () => ({ attributes: spanAttributes }), startSpan, })); @@ -24,6 +29,7 @@ describe("withSpan", () => { afterEach(() => { vi.clearAllMocks(); getTraceData.mockReset(); + for (const key of Object.keys(spanAttributes)) delete spanAttributes[key]; vi.resetModules(); }); @@ -82,13 +88,12 @@ describe("withSpan", () => { expect(spanOptions.attributes["gen_ai.response.finish_reasons"]).toEqual([ "tool_call", ]); - expect(activeSpan.setAttribute).toHaveBeenCalledWith( - "gen_ai.response.finish_reasons", - ["tool_call"], - ); + expect(activeSpan.setAttributes).toHaveBeenCalledWith({ + "gen_ai.response.finish_reasons": ["tool_call"], + }); }); - it("sets error.type on the span that throws", async () => { + it("sets error.type on the span that throws unless the callback set one", async () => { const { withSpan } = await import("@/chat/logging"); await expect( @@ -101,6 +106,16 @@ describe("withSpan", () => { "error.type", "TypeError", ); + + activeSpan.setAttribute.mockClear(); + spanAttributes["error.type"] = { type: "string", value: "rate_limited" }; + await expect( + withSpan("POST slack.com/api/chat.postMessage", "http.client", {}, () => + Promise.reject(new Error("rate limited")), + ), + ).rejects.toThrow("rate limited"); + + expect(activeSpan.setAttribute).not.toHaveBeenCalled(); }); it("sets status on the active Sentry span", async () => { diff --git a/packages/junior/tests/unit/sentry-payload-filter.test.ts b/packages/junior/tests/unit/sentry-payload-filter.test.ts index 10fb3408be..5f44c5ad9a 100644 --- a/packages/junior/tests/unit/sentry-payload-filter.test.ts +++ b/packages/junior/tests/unit/sentry-payload-filter.test.ts @@ -2,14 +2,14 @@ import { describe, expect, it } from "vitest"; import { runWithConversationPrivacy } from "@/chat/conversation-privacy"; import { privateTraceResultAttributes } from "@/chat/tool-support/private-trace-result"; import { + scrubPrivateSentryEvent, scrubPrivateSentryLog, scrubPrivateSentrySpan, - scrubPrivateSentryTransaction, } from "@/chat/sentry-payload-filter"; type SentrySpan = Parameters[0]; type SentryLog = Parameters[0]; -type SentryTransaction = Parameters[0]; +type SentryEvent = Parameters[0]; function messageAttribute(text: string): string { return JSON.stringify([{ role: "user", content: text }]); @@ -45,7 +45,7 @@ describe("Sentry private payload filtering", () => { it("removes OAuth secrets from captured request data", () => { const event = { - type: "transaction", + type: undefined, request: { data: "credential-body", headers: { @@ -55,9 +55,9 @@ describe("Sentry private payload filtering", () => { query_string: "code=secret&state=signed-state", url: "https://junior.example/api/oauth/callback/github?code=secret&state=signed-state", }, - } as SentryTransaction; + } as SentryEvent; - scrubPrivateSentryTransaction(event); + scrubPrivateSentryEvent(event); expect(event.request?.url).toBe( "https://junior.example/api/oauth/callback/github", @@ -68,7 +68,7 @@ describe("Sentry private payload filtering", () => { it("removes local credential bodies and normalized secret header spans", () => { const event = { - type: "transaction", + type: undefined, request: { data: '{"tokens":{"accessToken":"secret"}}', headers: { @@ -76,7 +76,7 @@ describe("Sentry private payload filtering", () => { }, url: "http://127.0.0.1/api/internal/local-oauth-credentials", }, - } as SentryTransaction; + } as SentryEvent; const span = { attributes: { "http.request.body.data": '{"tokens":{"accessToken":"span-secret"}}', @@ -92,7 +92,7 @@ describe("Sentry private payload filtering", () => { trace_id: "trace", } as SentrySpan; - scrubPrivateSentryTransaction(event); + scrubPrivateSentryEvent(event); scrubPrivateSentrySpan(span); expect(event.request?.data).toBeUndefined(); @@ -240,29 +240,4 @@ describe("Sentry private payload filtering", () => { expect(span.attributes?.["gen_ai.tool.call.result"]).toBeUndefined(); expect(span.attributes?.["app.conversation.payload_redacted"]).toBe(true); }); - - it("uses the current conversation privacy for transaction child spans", () => { - const payload = messageAttribute("public answer"); - const transaction = { - type: "transaction", - spans: [ - { - data: { - "gen_ai.output.messages": payload, - }, - span_id: "child", - start_timestamp: 1, - trace_id: "trace", - }, - ], - } as SentryTransaction; - - runWithConversationPrivacy("public", () => - scrubPrivateSentryTransaction(transaction), - ); - - expect(transaction.spans?.[0]?.data["gen_ai.output.messages"]).toBe( - payload, - ); - }); }); diff --git a/packages/junior/tests/unit/sql/tracing.test.ts b/packages/junior/tests/unit/sql/tracing.test.ts deleted file mode 100644 index 252f41b595..0000000000 --- a/packages/junior/tests/unit/sql/tracing.test.ts +++ /dev/null @@ -1,210 +0,0 @@ -import { SpanKind } from "@opentelemetry/api"; -import { beforeEach, describe, expect, it, vi } from "vitest"; - -const { finish, span, startSpanManual } = vi.hoisted(() => { - const finish = vi.fn(); - const span = { - setAttribute: vi.fn(), - setStatus: vi.fn(), - }; - return { - finish, - span, - startSpanManual: vi.fn( - ( - _options: unknown, - callback: ( - span: { - setAttribute: (key: string, value: unknown) => unknown; - setStatus: (status: unknown) => unknown; - }, - finish: () => void, - ) => unknown, - ) => callback(span, finish), - ), - }; -}); - -vi.mock("@/chat/sentry", () => ({ startSpanManual })); - -import { traceQueries } from "@/db/tracing"; - -const OPTIONS = { - connectionString: "postgres://private@example.test:6432/junior", - driver: "neon" as const, -}; - -describe("SQL tracing", () => { - beforeEach(() => { - finish.mockClear(); - span.setAttribute.mockClear(); - span.setStatus.mockClear(); - startSpanManual.mockClear(); - }); - - it("adds OpenTelemetry query metadata without changing parameters", async () => { - const result = Promise.resolve({ rows: [{ id: "1" }] }); - const queryClient = vi.fn((_query: unknown) => result); - const client = { query: queryClient }; - const traced = traceQueries(client, OPTIONS); - const query = { - text: " select * from junior_conversations where id = $1 and kind = 'private-kind'", - values: ["private-id"], - }; - - await expect(traced.query(query)).resolves.toEqual({ rows: [{ id: "1" }] }); - - expect(queryClient).toHaveBeenCalledWith(query); - expect(startSpanManual).toHaveBeenCalledWith( - { - name: "select junior_conversations", - op: "db.query", - kind: SpanKind.CLIENT, - onlyIfParent: true, - attributes: { - "app.db.driver": "neon", - "db.collection.name": "junior_conversations", - "db.namespace": "junior", - "db.operation.name": "select", - "db.query.summary": "select junior_conversations", - "db.query.text": - "select * from junior_conversations where id = $1 and kind = ?", - "db.system.name": "postgresql", - "server.address": "example.test", - "server.port": 6432, - }, - }, - expect.any(Function), - ); - expect(finish).toHaveBeenCalledOnce(); - expect(JSON.stringify(startSpanManual.mock.calls[0]?.[0])).not.toContain( - "private-id", - ); - expect(JSON.stringify(startSpanManual.mock.calls[0]?.[0])).not.toContain( - "private", - ); - }); - - it("replaces literals and comments in non-parameterized query text", async () => { - const client = { - query: vi.fn((..._args: unknown[]) => - Promise.resolve({ - rows: [], - }), - ), - }; - const traced = traceQueries(client, OPTIONS); - - await traced.query( - `UPDATE "users--active" SET email = E'private\\'--value@example.test', active = true WHERE id = 42 -- secret`, - ); - - expect(startSpanManual.mock.calls[0]?.[0]).toMatchObject({ - name: 'UPDATE "users--active"', - attributes: { - "db.query.summary": 'UPDATE "users--active"', - "db.query.text": - 'UPDATE "users--active" SET email = ?, active = ? WHERE id = ?', - }, - }); - }); - - it("uses the outer operation and records stored procedures", async () => { - const cteClient = { - query: vi.fn((..._args: unknown[]) => Promise.resolve({ rows: [] })), - }; - await traceQueries(cteClient, OPTIONS).query( - "WITH recent AS (SELECT * FROM events) SELECT EXTRACT(DAY FROM created_at) FROM conversations", - ); - - expect(startSpanManual.mock.calls[0]?.[0]).toMatchObject({ - name: "SELECT conversations", - attributes: { - "db.collection.name": "conversations", - "db.operation.name": "SELECT", - "db.query.summary": "SELECT conversations", - }, - }); - - const callClient = { - query: vi.fn((..._args: unknown[]) => Promise.resolve({ rows: [] })), - }; - await traceQueries(callClient, OPTIONS).query( - "CALL public.refresh_stats() ", - ); - - expect(startSpanManual.mock.calls[1]?.[0]).toMatchObject({ - name: "CALL public.refresh_stats", - attributes: { - "db.operation.name": "CALL", - "db.query.summary": "CALL public.refresh_stats", - "db.stored_procedure.name": "public.refresh_stats", - }, - }); - expect(startSpanManual.mock.calls[1]?.[0]).not.toHaveProperty( - "attributes.db.collection.name", - ); - - const transactionClient = { - query: vi.fn((..._args: unknown[]) => Promise.resolve({ rows: [] })), - }; - await traceQueries(transactionClient, OPTIONS).query( - "ROLLBACK TO SAVEPOINT s1", - ); - - expect(startSpanManual.mock.calls[2]?.[0]).toMatchObject({ - name: "ROLLBACK", - attributes: { - "db.operation.name": "ROLLBACK", - "db.query.summary": "ROLLBACK", - }, - }); - }); - - it("records PostgreSQL failures and keeps the original rejection", async () => { - const error = Object.assign(new Error("private database detail"), { - code: "57014", - }); - const client = { - query: vi.fn((..._args: unknown[]) => Promise.reject(error)), - }; - const traced = traceQueries(client, OPTIONS); - - await expect(traced.query("SELECT pg_sleep(1)")).rejects.toBe(error); - - expect(span.setAttribute).toHaveBeenCalledWith("error.type", "57014"); - expect(span.setAttribute).toHaveBeenCalledWith( - "db.response.status_code", - "57014", - ); - expect(span.setStatus).toHaveBeenCalledWith({ code: 2 }); - expect(finish).toHaveBeenCalledOnce(); - expect(JSON.stringify(startSpanManual.mock.calls[0]?.[0])).not.toContain( - "private database detail", - ); - }); - - it("finishes callback queries and records callback errors", async () => { - const callback = vi.fn(); - const error = Object.assign(new Error("query failed"), { code: "42P01" }); - const client = { - query: vi.fn( - (_text: string, wrappedCallback: (...args: unknown[]) => void) => { - wrappedCallback(error); - }, - ), - }; - const traced = traceQueries(client, OPTIONS); - - traced.query("SELECT 1", callback); - - expect(callback).toHaveBeenCalledWith(error); - expect(span.setAttribute).toHaveBeenCalledWith("error.type", "42P01"); - expect(span.setAttribute).toHaveBeenCalledWith( - "db.response.status_code", - "42P01", - ); - expect(span.setStatus).toHaveBeenCalledWith({ code: 2 }); - expect(finish).toHaveBeenCalledOnce(); - }); -}); diff --git a/packages/junior/tsdown.config.ts b/packages/junior/tsdown.config.ts index 3506b74e79..ff3f18ae6a 100644 --- a/packages/junior/tsdown.config.ts +++ b/packages/junior/tsdown.config.ts @@ -33,6 +33,7 @@ export default defineConfig({ "#junior/config", "hono", "@sentry/node", + "@sentry/server-utils", "@agentclientprotocol/sdk", "@ai-sdk/gateway", "@chat-adapter/slack", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1fc0e8dc8d..2000fccb0a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,11 +20,14 @@ catalogs: specifier: 2.9.0 version: 2.9.0 '@sentry/nitro': - specifier: 10.65.0 - version: 10.65.0 + specifier: 11.10.0 + version: 11.10.0 '@sentry/node': - specifier: 10.65.0 - version: 10.65.0 + specifier: 11.10.0 + version: 11.10.0 + '@sentry/server-utils': + specifier: 11.10.0 + version: 11.10.0 '@sentry/starlight-theme': specifier: ^0.9.1 version: 0.9.1 @@ -151,9 +154,6 @@ importers: '@types/node': specifier: ^25.9.1 version: 25.9.1 - cross-env: - specifier: ^10.1.0 - version: 10.1.0 jiti: specifier: ^2.7.0 version: 2.7.0 @@ -228,10 +228,13 @@ importers: 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)) + version: 11.10.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)) '@sentry/node': specifier: 'catalog:' - version: 10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1)) + version: 11.10.0 + '@sentry/server-utils': + specifier: 'catalog:' + version: 11.10.0 '@sinclair/typebox': specifier: ^0.34.49 version: 0.34.49 @@ -855,17 +858,6 @@ packages: zod: optional: true - '@apm-js-collab/code-transformer-bundler-plugins@0.5.0': - resolution: {integrity: sha512-YxLBY5nGlurL7QeJLq6e5g0ouBpAp0pwgyA/5rHXEXwhiPLn9ZHbT+Y2LlP90GT872cSocfjWRYu/fnpuBudNQ==} - engines: {node: '>=18.0.0'} - - '@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==} - '@arethetypeswrong/cli@0.18.5': resolution: {integrity: sha512-gM+8vRsQOD/Uc7EnBedUhkG5OCsDWE4uoak5QvomGpMpaky0Eh41p04nIMgrWb8EOmqZUJGc6zz9hsP6E56R7g==} engines: {node: '>=20'} @@ -1656,9 +1648,6 @@ packages: '@emnapi/wasi-threads@1.2.2': resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} - '@epic-web/invariant@1.0.0': - resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} - '@esbuild-kit/core-utils@3.3.2': resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} deprecated: 'Merged into tsx: https://tsx.hirok.io' @@ -3034,10 +3023,6 @@ packages: '@open-draft/until@2.1.0': resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} - '@opentelemetry/api-logs@0.220.0': - resolution: {integrity: sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==} - engines: {node: '>=8.0.0'} - '@opentelemetry/api@1.9.0': resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} @@ -3052,35 +3037,6 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/instrumentation@0.220.0': - resolution: {integrity: sha512-xQx3E2WxP1mDvKzxLxX+CTCtNLa560YJZ3087qYHerl2YmiKpv7AH+dAy7vmx+eVrZ5BwhfWUAVoKOoxCNHcpw==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/resources@2.9.0': - resolution: {integrity: sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': '>=1.3.0 <1.10.0' - - '@opentelemetry/sdk-trace-base@2.9.0': - resolution: {integrity: sha512-cp9zmTl62R8PJrpvFcmc8N2JQU/xfa0S+61q511Nji+QxCfZ8Ifvg7H27G8cANe4crg4RTrWsVvanHiXjSp6ag==} - engines: {node: ^18.19.0 || >=20.6.0} - deprecated: Use @opentelemetry/sdk-trace package - peerDependencies: - '@opentelemetry/api': '>=1.3.0 <1.10.0' - - '@opentelemetry/sdk-trace@2.9.0': - resolution: {integrity: sha512-sGA19HvtrrSKYsseHphluH6j3p6Xa3fqc7c7y8f/7mYWejc1lyDFcpSdD1kYa50HCLUeEo4zA5bW0pniaPszuw==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': '>=1.3.0 <1.10.0' - - '@opentelemetry/semantic-conventions@1.41.1': - resolution: {integrity: sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==} - engines: {node: '>=14'} - '@opentelemetry/semantic-conventions@1.43.0': resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} engines: {node: '>=14'} @@ -3088,12 +3044,137 @@ packages: '@oslojs/encoding@1.1.0': resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + '@oxc-parser/binding-android-arm-eabi@0.152.0': + resolution: {integrity: sha512-393VtirINkae4XHBTkq/yQxhOwEr4V+r0et37P2fp+sYZSdYgZTRDPo5Um8vBh0QjMZ+RmaMy4PP0qwr4cTMwA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxc-parser/binding-android-arm64@0.152.0': + resolution: {integrity: sha512-iYFcExATJNZ0rZj0o02THbD1Nc9jAW0nVgIQPee6ejbSASpbZXlIMw8jxtpzaG14JQTWwGSZ6U5dEtRJXE6V3Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxc-parser/binding-darwin-arm64@0.152.0': + resolution: {integrity: sha512-fnU+DfUzi5/rFy0LzmipYRz06PAUUkOS8kCJQ3Eg6oqlunC1XZXoffFqxmdL51RmcbYtUG3P8DVG1U5fckoa2A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxc-parser/binding-darwin-x64@0.152.0': + resolution: {integrity: sha512-Y3U2okryWTs7hDld6UhjJwLNf8/do+x4g4C+1U5SiGwrTLwbO83WJYJA8+l9iFSilWBgnfpd/+U76tfeNxUHzA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxc-parser/binding-freebsd-x64@0.152.0': + resolution: {integrity: sha512-XkhkRrrPffEw+ZLv/d/5pEni0buxinm/E/N6fLbJCunD1DBbeCTtVP23ESV+4CWCWdSz397asks1ViGslpmWiQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxc-parser/binding-linux-arm-gnueabihf@0.152.0': + resolution: {integrity: sha512-MLzsRRbdfmdzo6JEhbC1yKU9ItfvM8tEf18HM32jCiNYZEz6J3bRBRl3cTkKR0vBdrk9ZVlcARXtwHccs+epDA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-parser/binding-linux-arm-musleabihf@0.152.0': + resolution: {integrity: sha512-HHerTEJz7Iy10Ji6BGsk4gqG6PU0UzFuBu91jIEOX89FnrI5ECWSEr7BLpkYQhp7U0QFtMnBhNfQKI0hYZK78w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-parser/binding-linux-arm64-gnu@0.152.0': + resolution: {integrity: sha512-9Bb8GyzZ2uSLzRDZ27usaKokr07mxiBe2dDF5b6bd2janmaJTT1gL51UfP7AU30yFiXrJvcRyFKREAgKwZYs0w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxc-parser/binding-linux-arm64-musl@0.152.0': + resolution: {integrity: sha512-om7iDMUroI74A/lfRRWY9/Ev3VWrVsrUZ4tyvyh8raBey/sdcfyAD7tYWc+iykAiotnmftyKTpUKFr1QnaBrAQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxc-parser/binding-linux-ppc64-gnu@0.152.0': + resolution: {integrity: sha512-Lf1OL2lMTqwDMFC6jnRb30B+WYHKV0XT+bPHcFM6xHtNVwxpobiTzUIvKH6a0LWpvfwyru8Yu6zCGHqqFHH+gg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxc-parser/binding-linux-riscv64-gnu@0.152.0': + resolution: {integrity: sha512-BYWSMQK+YJ9ZILStPcmmiSVq8KEG9Qdq/c4BHPC3rUEq/fEDCVjUIwdj5ZzjgZ9P9is9PKu0tcAXzq1ZXg4urQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxc-parser/binding-linux-riscv64-musl@0.152.0': + resolution: {integrity: sha512-d2LqHNNNqdH185sRK5dPKWZu201JrNu9/CRFuVEuT+ht7n/QaVblEMWT9MALQPrDWYvhG10P+NSKJFquDWZ09w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxc-parser/binding-linux-s390x-gnu@0.152.0': + resolution: {integrity: sha512-8gBeHt5rA/8+pKhHl+zLggfa3L/V/L2at96p7ty6pBE7id6lFO19nFUc15u2PcjC4OYeYK465MKy1fhhbpFIGw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@oxc-parser/binding-linux-x64-gnu@0.152.0': + resolution: {integrity: sha512-ltgrSF6L+yPTVsIdaAyqKq3zTqzj/1VlNbxWZuxAe8flR3sWdyNsKvdXukoO8/ucJbLickhmieRBge+o/e8Ugw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxc-parser/binding-linux-x64-musl@0.152.0': + resolution: {integrity: sha512-LcMp6BvrBnewSfdkLHoSqidhoAq4syKOTBV5TYHWd+2VnGkfD/nPRRVIzTBt/Lkbt7pfOFDGtkiTntFS0p6sQQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxc-parser/binding-openharmony-arm64@0.152.0': + resolution: {integrity: sha512-jbhoMCslVxzRCRNQ8TSHxjYdSKRvk8O6ciLVDkahJvmyHDzBqba/bMQHM6ULKj/rgHNNbSzlIiakdx8SEfkJzA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxc-parser/binding-win32-arm64-msvc@0.152.0': + resolution: {integrity: sha512-JZYVlhv36mr/nertnRB7vchJECOBb1Lz6lltalILsB+o9M/is+H6BEDRLQKdqA4JKs6NjJszo46+iM5sfwj6jQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxc-parser/binding-win32-ia32-msvc@0.152.0': + resolution: {integrity: sha512-1X9oganvVsunRH0lH10UU05N+H9atpX6WsOybByUjwnfcd3h/0tYwvuv16XuHglrIUOnxV2TodbLVEwwafd64g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxc-parser/binding-win32-x64-msvc@0.152.0': + resolution: {integrity: sha512-sw0M80/dn9rcpu+Rqqph/C+MjvDDce6MlXmFjsNQtPEymha0eJy3ml6+foSUTqFfpDIDyHZZ4eoJ43IoMe8bJw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@oxc-project/types@0.110.0': resolution: {integrity: sha512-6Ct21OIlrEnFEJk5LT4e63pk3btsI6/TusD/GStLi7wYlGJNOl1GI9qvXAnRAxQU9zqA2Oz+UwhfTOU2rPZVow==} '@oxc-project/types@0.132.0': resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==} + '@oxc-project/types@0.152.0': + resolution: {integrity: sha512-oM/5rLBm2tPkg0iBgkH/FOeR3PCDpY19GTgAZjMFM8h9WI9VW7cLgzp6nwtarYKmovavIQZ+Fe/RKX/8C8O/Rw==} + '@oxc-project/types@0.155.0': resolution: {integrity: sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==} @@ -3988,73 +4069,25 @@ packages: '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} - '@sentry/babel-plugin-component-annotate@5.3.0': - resolution: {integrity: sha512-p4q8gn8wcFqZGP/s2MnJCAAd8fTikaU6A0mM97RDHQgStcrYiaS0Sc5zUNfb1V+UOLPuvdEdL6MwyxfzjYJQTA==} - engines: {node: '>= 18'} - - '@sentry/bundler-plugin-core@5.3.0': - resolution: {integrity: sha512-L5T60sWdAI3qWwdg3Ptwek/0TY59PERrxyqp4XMUkroayQvGd9r5dIW9Q1kSeXX9iJ442nXbFZKAOyCKV4Z13Q==} - engines: {node: '>= 18'} - - '@sentry/cli-darwin@2.58.6': - resolution: {integrity: sha512-udAVvcyfNa0R+95GvPz/+43/N3TC0TYKdkQ7D7jhPSzbcMc7l2fxRNN5yB3UpCA5fWFnW4toeaqwDBhb/Wh3LA==} - engines: {node: '>=10'} - os: [darwin] - - '@sentry/cli-linux-arm64@2.58.6': - resolution: {integrity: sha512-q8mEcNNmeXMy5i+jWT30TVpH7LcP4HD21CD5XRSPAd/a912HF6EpK0ybf/1USO14WOhoXbAGi9txwaWabSe33g==} - engines: {node: '>=10'} - cpu: [arm64] - os: [linux, freebsd, android] - - '@sentry/cli-linux-arm@2.58.6': - resolution: {integrity: sha512-pD0LAt5PcUzAinBwvDqc66x9+2CabHEv486yP0gRjWO7SakbaxmfVq/EXd8VLq/Tzi39LAu422UYK1lpW3MILw==} - engines: {node: '>=10'} - cpu: [arm] - os: [linux, freebsd, android] - - '@sentry/cli-linux-i686@2.58.6': - resolution: {integrity: sha512-q8vNJi1eOV/4vxAFWBsEwLHoSYapaZHIf4j76KJGJXFKTkEbsjCOOsKbwUIBTQQhRgV4DFWh3ryfsPS/que4Kg==} - engines: {node: '>=10'} - cpu: [x86, ia32] - os: [linux, freebsd, android] - - '@sentry/cli-linux-x64@2.58.6': - resolution: {integrity: sha512-DZu956Mhi3ZRjTBe1WdbGV46ldVbA8d2rgp/fh51GsI25zjBHah4wZnPTSzpc+YqxU6pJpg579B/r3jrIK530Q==} - engines: {node: '>=10'} - cpu: [x64] - os: [linux, freebsd, android] - - '@sentry/cli-win32-arm64@2.58.6': - resolution: {integrity: sha512-nj0Ff/kmAB73EPDhR8B4O9r+NUHK5GkPCkGWC+kXVemqAJWL5jcJ5KdxG0l/S0z6RoEoltID8/43/B+TaMlT7A==} - engines: {node: '>=10'} - cpu: [arm64] - os: [win32] - - '@sentry/cli-win32-i686@2.58.6': - resolution: {integrity: sha512-WNZiDzPbgsEMQWq4avsQ391v/xWKJDIWWWo9GYl+N/w5qcYKkoDW7wQG7T9FasI6ENn68phChTOAPXXxbfAdOg==} - engines: {node: '>=10'} - cpu: [x86, ia32] - os: [win32] - - '@sentry/cli-win32-x64@2.58.6': - resolution: {integrity: sha512-R35WJ17oF4D2eqI1DR2sQQqr0fjRTt5xoP16WrTu91XM2lndRMFsnjh+/GttbxapLCBNlrjzia99MJ0PZHZpgA==} - engines: {node: '>=10'} - cpu: [x64] - os: [win32] - - '@sentry/cli@2.58.6': - resolution: {integrity: sha512-baBcNPLLfUi9WuL+Tpri9BFaAdvugZIKelC5X0tt0Zdy+K0K+PCVSrnNmwMWU/HyaF/SEv6b6UHnXIdqanBlcg==} - engines: {node: '>= 10'} - hasBin: true + '@sentry/bundler-plugins@11.10.0': + resolution: {integrity: sha512-+ngJ485rIYll5uOhWSvSO+Vx4S24MGe5KcLKlUZghr+BXK+ib32uBOZNG294wGyeauLTDvdjncLEYwiaBnP/5w==} + engines: {node: '>=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0'} + peerDependencies: + rollup: '>=3.2.0' + webpack: '>=5.1.0' + peerDependenciesMeta: + rollup: + optional: true + webpack: + optional: true - '@sentry/conventions@0.15.1': - resolution: {integrity: sha512-ZLP8bRdMON3prWE2tJyImuYscCxdcJeIPIhrOs/rgyFm3C1nCh1B6gdvPj3AZ5zW08oSFFCsq7T+tYEW3h8MNA==} + '@sentry/conventions@0.29.0': + resolution: {integrity: sha512-kYq9/HJ/l6MYP/srIc20dy1W4mWyJfCF0OWFF+RhBGZwyr/wCmtabRFKyw7kqM+DTwZXQOjSTSZUcJhDowcInQ==} engines: {node: '>=14'} - '@sentry/core@10.65.0': - resolution: {integrity: sha512-3aqtmM5NgNGo45BNaaBzi0LPQZAw//NEL4HKS5fXm12pJMa4KEkze8DEKnkTEIrGnWaOJKamecHKlnNg/Mqf/Q==} - engines: {node: '>=18'} + '@sentry/core@11.10.0': + resolution: {integrity: sha512-l/OtTo1v+TQgZtHG2Q5N4IX+gFdAE1tZ27K/P21UCzJglWk54TPEm+d9T2lulPqMK06kZcLwDgRAhE2GO4YS5w==} + engines: {node: '>=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0'} '@sentry/junior-dashboard@file:packages/junior-dashboard': resolution: {directory: packages/junior-dashboard, type: directory} @@ -4077,48 +4110,29 @@ packages: '@sentry/junior@file:packages/junior': resolution: {directory: packages/junior, type: directory} - '@sentry/nitro@10.65.0': - resolution: {integrity: sha512-whySjTbpvV2/iWTl/smFO9BAbJ9kaUL2UK3PT4tTZYeXBdTGXE1JBNir5kmYO/sFzswS/RCElcs0IhpcqKQKEQ==} - engines: {node: '>=18.19.1'} + '@sentry/nitro@11.10.0': + resolution: {integrity: sha512-RuIH5u98J+a9KcFXSFb/CJ7j7ecQ7RtBB9WMr5oDPTZyLxJkkDVUMvGfeuiSsliyNBtSOP420rL9+NntOgArig==} + engines: {node: '>=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0'} peerDependencies: - nitro: '>=3.0.0-0 <4.0.0 || 3.0.260311-beta || 3.0.260415-beta' + nitro: '>=3.0.0-0 <4.0.0 || 3.0.260311-beta || 3.0.260415-beta || 3.0.260429-beta || 3.0.260522-beta || 3.0.260603-beta || 3.0.260610-beta || 3.0.260903-beta' - '@sentry/node-core@10.65.0': - resolution: {integrity: sha512-U01X9mPT+jZnsLPmPWfBU67Ka+t/Sdd9RGAuvGoKdrI6N47a/9PDkM9oCW+kj0fmZwogZHTgSnzJU5oi3pImgA==} - engines: {node: '>=18'} - peerDependencies: - '@opentelemetry/api': ^1.9.0 - '@opentelemetry/core': ^1.30.1 || ^2.1.0 - '@opentelemetry/exporter-trace-otlp-http': '>=0.57.0 <1' - '@opentelemetry/instrumentation': '>=0.57.1 <1' - '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@opentelemetry/core': - optional: true - '@opentelemetry/exporter-trace-otlp-http': - optional: true - '@opentelemetry/instrumentation': - optional: true - '@opentelemetry/sdk-trace-base': - optional: true - - '@sentry/node@10.65.0': - resolution: {integrity: sha512-t35dcdyksysVch/m/XdLgGJqGKJhr9eMD30Ctn3TeQ8yMB0wNXySfjPR5Yg93fpjmfaHtzc6iYIXRAvgNVfrvA==} - engines: {node: '>=18'} + '@sentry/node@11.10.0': + resolution: {integrity: sha512-ZsndrSn1NjL9AslpUdxz/kYPcv/i+plVZoyPe1ivlr5XPUpocB8pUL5noYbIUl96Wd/yGvPBw6zqO8d69rRKQQ==} + engines: {node: '>=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0'} - '@sentry/opentelemetry@10.65.0': - resolution: {integrity: sha512-8C6FPvm3XBvUrkM52dX3Gz0p2H0Ij8t4sahUA+GTiCz0WM0fnyPeQPGC/b6I4jamV9UXyCZRnE1UEEGCoD+c7A==} - engines: {node: '>=18'} + '@sentry/opentelemetry@11.10.0': + resolution: {integrity: sha512-YMV4ZgaRlW7QPCcMScVpSBvYOdvDlY+alqRT3KOTcmPKFZtf8O2hXHWFhl/M33kKDEfqOk2XtEVeHs3mZFOCaw==} + engines: {node: '>=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0'} peerDependencies: '@opentelemetry/api': ^1.9.0 - '@opentelemetry/core': ^1.30.1 || ^2.1.0 - '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 - '@sentry/server-utils@10.65.0': - resolution: {integrity: sha512-80toEFD6s+0Le7jrYB6pHWLF703WSg0WyavAWqrBGWG8JkREHgedAxzFYgoY5GlMI756qk6Ea7UzhJTHd2zAXA==} - engines: {node: '>=18'} + '@sentry/server-runtime-injection@11.10.0': + resolution: {integrity: sha512-1nc+HNPldrPEov16sL5m2cOLVgNJ+FsR7QtaWGOOv8qYFJkSp95lyc2qzLnaG2L72UzSMOv10peGRioAKrrZQQ==} + engines: {node: '>=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0'} + + '@sentry/server-utils@11.10.0': + resolution: {integrity: sha512-m/MVCvPzQJJZZCTFlVPCrTuoncT7SR80+QKg1K7ul25AsL0byABr5KsHCbXVpOYXLVz04Omk+pOOR5Cv2IAlrA==} + engines: {node: '>=20.19.0 <22.0.0 || >=22.12.0 <23.0.0 || >=23.2.0'} '@sentry/starlight-theme@0.9.1': resolution: {integrity: sha512-85DzcVqkgAbJz5cTXtGYit+f6yE/83egTNJOlwnMFBEVt+uGWVYT3BtgtPCtAlDh9mHnnfDCk6keuedRBaaCPg==} @@ -5060,7 +5074,6 @@ packages: astring@1.9.0: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} - hasBin: true astro-expressive-code@0.44.1: resolution: {integrity: sha512-DT1LnCqbHasBKlvzJ3m6LR4VI94wwx3W9EV/YbP1te4rqjOHsvsezHYuqb5MeLWLftXms/1FA9QBbwCo43DnJQ==} @@ -5388,9 +5401,6 @@ packages: cjs-module-lexer@1.2.3: resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} - cjs-module-lexer@2.2.0: - resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} - class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} @@ -5554,11 +5564,6 @@ packages: resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} engines: {node: '>= 0.10'} - cross-env@10.1.0: - resolution: {integrity: sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==} - engines: {node: '>=20'} - hasBin: true - cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -5768,10 +5773,6 @@ packages: resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==} engines: {node: '>=10'} - dotenv@16.6.1: - resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} - engines: {node: '>=12'} - dotenv@17.4.2: resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} engines: {node: '>=12'} @@ -6640,10 +6641,6 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} - import-in-the-middle@3.0.1: - resolution: {integrity: sha512-pYkiyXVL2Mf3pozdlDGV6NAObxQx13Ae8knZk1UJRJ6uRW/ZRmTGHlQYtrsSl7ubuE5F8CD1z+s1n4RHNuTtuA==} - engines: {node: '>=18'} - import-without-cache@0.4.1: resolution: {integrity: sha512-vXoV9PjKHEednCUu01e98TkImxy67e3BJXbTIOmIq4Hyzw3IAwYRcuPkfeTzJzwyyts4kjuA73x+pWJLc4f86A==} engines: {node: ^22.18.0 || >=24.0.0} @@ -7270,10 +7267,6 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - meriyah@6.1.4: - resolution: {integrity: sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ==} - engines: {node: '>=18.0.0'} - micro@9.3.5-canary.3: resolution: {integrity: sha512-viYIo9PefV+w9dvoIBh1gI44Mvx1BOk67B4BpC2QK77qdY0xZF0Q+vWLt/BII6cLkIc8rLmSIcJaB/OrXXKe1g==} engines: {node: '>= 8.0.0'} @@ -7462,9 +7455,6 @@ packages: resolution: {integrity: sha512-sweCIVXzx1aIGTCdzcMlSZt1h8k5Tmk08VNAuRk3IU28XamGiOH5ypi11g6De2CH7PhYqSSnGy2A/EFhbWnVKg==} engines: {node: '>=18.0.0'} - module-details-from-path@1.0.4: - resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} - mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -7766,6 +7756,10 @@ packages: outvariant@1.4.3: resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} + oxc-parser@0.152.0: + resolution: {integrity: sha512-ZztsZgaCWmPeKYMdoTT5e0oV/oxD1NeLWNR3kAtr/G707cUPYaaozRlVDHLCGnszHJRszN9mJwmPNpqgwloC0A==} + engines: {node: ^20.19.0 || >=22.12.0} + oxc-transform@0.111.0: resolution: {integrity: sha512-oa5KKSDNLHZGaiqIGAbCWXeN9IJUAz9MElWcQX90epDxdKc9Hrt/BsLj3K4gDqfAYa5dwdH+ZCFJG9hR74fiGg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -8107,10 +8101,6 @@ packages: resolution: {integrity: sha512-tGqJW/UnclpYASFcM6Xh8D8l/BMtaQ9+CSG0vlJSJTcdMM4lDRv4c6H0Pdcsfted+bVczdYSfk2fdukg2gQkZg==} engines: {node: '>=18.0.0'} - progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - promisepipe@3.0.0: resolution: {integrity: sha512-V6TbZDJ/ZswevgkDNpGt/YqNCiZP9ASfgU+p83uJE6NrGtvSGoOcHLiDCqkMs2+yg7F5qHdLV8d0aS8O26G/KA==} @@ -8321,10 +8311,6 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - require-in-the-middle@8.0.1: - resolution: {integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==} - engines: {node: '>=9.3.0 || >=8.10.0 <9.0.0'} - reselect@5.3.0: resolution: {integrity: sha512-XGoLeRAVzUTcJ1qkxPQhDJyIZ5d6zzZD9nT7AEZOaaU9UbWclhycElmhO+VD5bFeLuzhPBaOV2oXC8uG35ZSpg==} @@ -8463,9 +8449,6 @@ packages: seek-bzip@2.0.0: resolution: {integrity: sha512-SMguiTnYrhpLdk3PwfzHeotrcwi8bNV4iemL9tx9poR/yeaMYwB9VzR1w7b57DuWpuqR8n6oZboi0hj3AxZxQg==} - semifies@1.0.0: - resolution: {integrity: sha512-xXR3KGeoxTNWPD4aBvL5NUpMTT7WMANr3EWnaS190QVkY52lqqcVRD7Q05UVbBhiWDGWMlJEUam9m7uFFGVScw==} - semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -8488,6 +8471,11 @@ packages: resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} + sentry@0.45.0: + resolution: {integrity: sha512-kgmEbLlC22lL7uneeUm9Sjz65rp5cvwYOMTxXbZCmBum4sbVre/lLT3zTV3kwXHJ9/BM8ZS0/GhZe9Cl1t6WyA==} + engines: {node: '>=20.0'} + hasBin: true + sentry@0.47.0: resolution: {integrity: sha512-BDhgsAJYm99Xbx+YTREec7lME0FN8Z66YzrQ+eEWDqwigcLqs90cEx5nrhVlneL9bbDCVyt5O/7Z3RqKpHNh2A==} engines: {node: '>=20.0'} @@ -8778,6 +8766,10 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + supports-hyperlinks@3.2.0: resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} engines: {node: '>=14.18'} @@ -9792,30 +9784,6 @@ snapshots: optionalDependencies: zod: 4.5.4 - '@apm-js-collab/code-transformer-bundler-plugins@0.5.0': - dependencies: - '@apm-js-collab/code-transformer': 0.15.0 - es-module-lexer: 2.3.1 - magic-string: 0.30.21 - module-details-from-path: 1.0.4 - - '@apm-js-collab/code-transformer@0.15.0': - dependencies: - '@types/estree': 1.0.9 - astring: 1.9.0 - esquery: 1.7.0 - meriyah: 6.1.4 - semifies: 1.0.0 - source-map: 0.6.1 - - '@apm-js-collab/tracing-hooks@0.10.1': - dependencies: - '@apm-js-collab/code-transformer': 0.15.0 - debug: 4.4.3 - module-details-from-path: 1.0.4 - transitivePeerDependencies: - - supports-color - '@arethetypeswrong/cli@0.18.5': dependencies: '@arethetypeswrong/core': 0.18.5 @@ -10948,8 +10916,6 @@ snapshots: tslib: 2.8.1 optional: true - '@epic-web/invariant@1.0.0': {} - '@esbuild-kit/core-utils@3.3.2': dependencies: esbuild: 0.18.20 @@ -11927,10 +11893,6 @@ snapshots: '@open-draft/until@2.1.0': {} - '@opentelemetry/api-logs@0.220.0': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/api@1.9.0': {} '@opentelemetry/api@1.9.1': {} @@ -11940,46 +11902,73 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/semantic-conventions': 1.43.0 - '@opentelemetry/instrumentation@0.220.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.220.0 - import-in-the-middle: 3.0.1 - require-in-the-middle: 8.0.1 - transitivePeerDependencies: - - supports-color + '@opentelemetry/semantic-conventions@1.43.0': {} - '@opentelemetry/resources@2.9.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.43.0 + '@oslojs/encoding@1.1.0': {} - '@opentelemetry/sdk-trace-base@2.9.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.41.1 + '@oxc-parser/binding-android-arm-eabi@0.152.0': + optional: true - '@opentelemetry/sdk-trace@2.9.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.43.0 + '@oxc-parser/binding-android-arm64@0.152.0': + optional: true - '@opentelemetry/semantic-conventions@1.41.1': {} + '@oxc-parser/binding-darwin-arm64@0.152.0': + optional: true - '@opentelemetry/semantic-conventions@1.43.0': {} + '@oxc-parser/binding-darwin-x64@0.152.0': + optional: true - '@oslojs/encoding@1.1.0': {} + '@oxc-parser/binding-freebsd-x64@0.152.0': + optional: true + + '@oxc-parser/binding-linux-arm-gnueabihf@0.152.0': + optional: true + + '@oxc-parser/binding-linux-arm-musleabihf@0.152.0': + optional: true + + '@oxc-parser/binding-linux-arm64-gnu@0.152.0': + optional: true + + '@oxc-parser/binding-linux-arm64-musl@0.152.0': + optional: true + + '@oxc-parser/binding-linux-ppc64-gnu@0.152.0': + optional: true + + '@oxc-parser/binding-linux-riscv64-gnu@0.152.0': + optional: true + + '@oxc-parser/binding-linux-riscv64-musl@0.152.0': + optional: true + + '@oxc-parser/binding-linux-s390x-gnu@0.152.0': + optional: true + + '@oxc-parser/binding-linux-x64-gnu@0.152.0': + optional: true + + '@oxc-parser/binding-linux-x64-musl@0.152.0': + optional: true + + '@oxc-parser/binding-openharmony-arm64@0.152.0': + optional: true + + '@oxc-parser/binding-win32-arm64-msvc@0.152.0': + optional: true + + '@oxc-parser/binding-win32-ia32-msvc@0.152.0': + optional: true + + '@oxc-parser/binding-win32-x64-msvc@0.152.0': + optional: true '@oxc-project/types@0.110.0': {} '@oxc-project/types@0.132.0': {} + '@oxc-project/types@0.152.0': {} + '@oxc-project/types@0.155.0': {} '@oxc-transform/binding-android-arm-eabi@0.111.0': @@ -12476,70 +12465,21 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} - '@sentry/babel-plugin-component-annotate@5.3.0': {} - - '@sentry/bundler-plugin-core@5.3.0': + '@sentry/bundler-plugins@11.10.0': dependencies: - '@babel/core': 7.29.7 - '@sentry/babel-plugin-component-annotate': 5.3.0 - '@sentry/cli': 2.58.6 - dotenv: 16.6.1 - find-up: 5.0.0 + '@sentry/core': 11.10.0 + dotenv: 17.4.2 glob: 13.0.6 - magic-string: 0.30.21 - transitivePeerDependencies: - - encoding - - supports-color - - '@sentry/cli-darwin@2.58.6': - optional: true - - '@sentry/cli-linux-arm64@2.58.6': - optional: true - - '@sentry/cli-linux-arm@2.58.6': - optional: true - - '@sentry/cli-linux-i686@2.58.6': - optional: true - - '@sentry/cli-linux-x64@2.58.6': - optional: true - - '@sentry/cli-win32-arm64@2.58.6': - optional: true - - '@sentry/cli-win32-i686@2.58.6': - optional: true - - '@sentry/cli-win32-x64@2.58.6': - optional: true - - '@sentry/cli@2.58.6': - dependencies: - https-proxy-agent: 5.0.1 - node-fetch: 2.7.0 - progress: 2.0.3 - proxy-from-env: 1.1.0 - which: 2.0.2 - optionalDependencies: - '@sentry/cli-darwin': 2.58.6 - '@sentry/cli-linux-arm': 2.58.6 - '@sentry/cli-linux-arm64': 2.58.6 - '@sentry/cli-linux-i686': 2.58.6 - '@sentry/cli-linux-x64': 2.58.6 - '@sentry/cli-win32-arm64': 2.58.6 - '@sentry/cli-win32-i686': 2.58.6 - '@sentry/cli-win32-x64': 2.58.6 - transitivePeerDependencies: - - encoding - - supports-color + magic-string: 1.4.5 + oxc-parser: 0.152.0 + sentry: 0.45.0 + supports-color: 8.1.1 - '@sentry/conventions@0.15.1': {} + '@sentry/conventions@0.29.0': {} - '@sentry/core@10.65.0': + '@sentry/core@11.10.0': dependencies: - '@sentry/conventions': 0.15.1 + '@sentry/conventions': 0.29.0 '@sentry/junior-dashboard@file:packages/junior-dashboard(@types/node@25.9.1)(jiti@2.7.0)': dependencies: @@ -12581,7 +12521,6 @@ snapshots: - '@netlify/runtime' - '@node-rs/xxhash' - '@op-engineering/op-sqlite' - - '@opentelemetry/exporter-trace-otlp-http' - '@planetscale/database' - '@prisma/client' - '@sveltejs/kit' @@ -12611,7 +12550,6 @@ snapshots: - dotenv - drizzle-kit - drizzle-orm - - encoding - expo-sqlite - gel - giget @@ -12640,6 +12578,7 @@ snapshots: - vite - vitest - vue + - webpack - ws - xml2js - zephyr-agent @@ -13002,8 +12941,9 @@ 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)) + '@sentry/nitro': 11.10.0(nitro@3.0.260522-beta(jiti@2.7.0)) + '@sentry/node': 11.10.0 + '@sentry/server-utils': 11.10.0 '@sinclair/typebox': 0.34.49 '@slack/types': 2.21.1 '@slack/web-api': 7.16.0 @@ -13039,7 +12979,6 @@ snapshots: - '@lynx-js/react' - '@node-rs/xxhash' - '@op-engineering/op-sqlite' - - '@opentelemetry/exporter-trace-otlp-http' - '@planetscale/database' - '@prisma/client' - '@sveltejs/kit' @@ -13059,7 +12998,6 @@ snapshots: - bun-types - debug - drizzle-kit - - encoding - expo-sqlite - gel - knex @@ -13074,6 +13012,7 @@ snapshots: - react - react-dom - react-native-b4a + - rollup - solid-js - sql.js - sqlite3 @@ -13082,6 +13021,7 @@ snapshots: - utf-8-validate - vitest - vue + - webpack - ws '@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)': @@ -13100,8 +13040,9 @@ 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)) + '@sentry/nitro': 11.10.0(nitro@3.0.260522-beta(jiti@2.7.0)) + '@sentry/node': 11.10.0 + '@sentry/server-utils': 11.10.0 '@sinclair/typebox': 0.34.49 '@slack/types': 2.21.1 '@slack/web-api': 7.16.0 @@ -13137,7 +13078,6 @@ snapshots: - '@lynx-js/react' - '@node-rs/xxhash' - '@op-engineering/op-sqlite' - - '@opentelemetry/exporter-trace-otlp-http' - '@planetscale/database' - '@prisma/client' - '@sveltejs/kit' @@ -13157,7 +13097,6 @@ snapshots: - bun-types - debug - drizzle-kit - - encoding - expo-sqlite - gel - knex @@ -13172,6 +13111,7 @@ snapshots: - react - react-dom - react-native-b4a + - rollup - solid-js - sql.js - sqlite3 @@ -13180,6 +13120,7 @@ snapshots: - utf-8-validate - vitest - vue + - webpack - ws '@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)': @@ -13198,8 +13139,9 @@ 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)) + '@sentry/nitro': 11.10.0(nitro@3.0.260522-beta) + '@sentry/node': 11.10.0 + '@sentry/server-utils': 11.10.0 '@sinclair/typebox': 0.34.49 '@slack/types': 2.21.1 '@slack/web-api': 7.16.0 @@ -13235,7 +13177,6 @@ snapshots: - '@lynx-js/react' - '@node-rs/xxhash' - '@op-engineering/op-sqlite' - - '@opentelemetry/exporter-trace-otlp-http' - '@planetscale/database' - '@prisma/client' - '@sveltejs/kit' @@ -13255,7 +13196,6 @@ snapshots: - bun-types - debug - drizzle-kit - - encoding - expo-sqlite - gel - knex @@ -13270,6 +13210,7 @@ snapshots: - react - react-dom - react-native-b4a + - rollup - solid-js - sql.js - sqlite3 @@ -13278,6 +13219,7 @@ snapshots: - utf-8-validate - vitest - vue + - webpack - ws '@sentry/junior@file:packages/junior(vitest@4.1.12(msw@2.14.6(typescript@7.0.2))(tsx@4.22.3))': @@ -13296,8 +13238,9 @@ 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)) + '@sentry/nitro': 11.10.0 + '@sentry/node': 11.10.0 + '@sentry/server-utils': 11.10.0 '@sinclair/typebox': 0.34.49 '@slack/types': 2.21.1 '@slack/web-api': 7.16.0 @@ -13333,7 +13276,6 @@ snapshots: - '@lynx-js/react' - '@node-rs/xxhash' - '@op-engineering/op-sqlite' - - '@opentelemetry/exporter-trace-otlp-http' - '@planetscale/database' - '@prisma/client' - '@sveltejs/kit' @@ -13353,7 +13295,6 @@ snapshots: - bun-types - debug - drizzle-kit - - encoding - expo-sqlite - gel - knex @@ -13368,6 +13309,7 @@ snapshots: - react - react-dom - react-native-b4a + - rollup - solid-js - sql.js - sqlite3 @@ -13376,105 +13318,89 @@ snapshots: - utf-8-validate - vitest - vue + - webpack - ws - '@sentry/nitro@10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1))': + '@sentry/nitro@11.10.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 + '@sentry/bundler-plugins': 11.10.0 + '@sentry/conventions': 0.29.0 + '@sentry/core': 11.10.0 + '@sentry/node': 11.10.0 + '@sentry/server-runtime-injection': 11.10.0 + '@sentry/server-utils': 11.10.0 transitivePeerDependencies: - - '@opentelemetry/core' - - '@opentelemetry/exporter-trace-otlp-http' - - encoding - - supports-color + - rollup + - webpack - '@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))': + '@sentry/nitro@11.10.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))': 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 + '@sentry/bundler-plugins': 11.10.0 + '@sentry/conventions': 0.29.0 + '@sentry/core': 11.10.0 + '@sentry/node': 11.10.0 + '@sentry/server-runtime-injection': 11.10.0 + '@sentry/server-utils': 11.10.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 + - rollup + - webpack - '@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/nitro@11.10.0(nitro@3.0.260522-beta(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 + '@sentry/bundler-plugins': 11.10.0 + '@sentry/conventions': 0.29.0 + '@sentry/core': 11.10.0 + '@sentry/node': 11.10.0 + '@sentry/server-runtime-injection': 11.10.0 + '@sentry/server-utils': 11.10.0 nitro: 3.0.260522-beta(jiti@2.7.0) transitivePeerDependencies: - - '@opentelemetry/core' - - '@opentelemetry/exporter-trace-otlp-http' - - encoding - - supports-color + - rollup + - webpack - '@sentry/nitro@10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1))(nitro@3.0.260522-beta)': + '@sentry/nitro@11.10.0(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 + '@sentry/bundler-plugins': 11.10.0 + '@sentry/conventions': 0.29.0 + '@sentry/core': 11.10.0 + '@sentry/node': 11.10.0 + '@sentry/server-runtime-injection': 11.10.0 + '@sentry/server-utils': 11.10.0 nitro: 3.0.260522-beta transitivePeerDependencies: - - '@opentelemetry/core' - - '@opentelemetry/exporter-trace-otlp-http' - - encoding - - supports-color + - rollup + - webpack - '@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))': + '@sentry/node@11.10.0': dependencies: - '@sentry/conventions': 0.15.1 - '@sentry/core': 10.65.0 - '@sentry/opentelemetry': 10.65.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.9.0(@opentelemetry/api@1.9.1)) - import-in-the-middle: 3.0.1 - optionalDependencies: '@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) + '@sentry/bundler-plugins': 11.10.0 + '@sentry/conventions': 0.29.0 + '@sentry/core': 11.10.0 + '@sentry/opentelemetry': 11.10.0(@opentelemetry/api@1.9.1) + '@sentry/server-runtime-injection': 11.10.0 + '@sentry/server-utils': 11.10.0 + transitivePeerDependencies: + - rollup + - webpack - '@sentry/node@10.65.0(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1))': + '@sentry/opentelemetry@11.10.0(@opentelemetry/api@1.9.1)': dependencies: '@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) - '@sentry/conventions': 0.15.1 - '@sentry/core': 10.65.0 - '@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)) - '@sentry/opentelemetry': 10.65.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.9.0(@opentelemetry/api@1.9.1)) - '@sentry/server-utils': 10.65.0 - import-in-the-middle: 3.0.1 - transitivePeerDependencies: - - '@opentelemetry/core' - - '@opentelemetry/exporter-trace-otlp-http' - - supports-color + '@sentry/conventions': 0.29.0 + '@sentry/core': 11.10.0 - '@sentry/opentelemetry@10.65.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.9.0(@opentelemetry/api@1.9.1))': + '@sentry/server-runtime-injection@11.10.0': dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.9.0(@opentelemetry/api@1.9.1) - '@sentry/conventions': 0.15.1 - '@sentry/core': 10.65.0 + '@sentry/core': 11.10.0 + '@sentry/server-utils': 11.10.0 - '@sentry/server-utils@10.65.0': + '@sentry/server-utils@11.10.0': dependencies: - '@apm-js-collab/code-transformer': 0.15.0 - '@apm-js-collab/code-transformer-bundler-plugins': 0.5.0 - '@apm-js-collab/tracing-hooks': 0.10.1 - '@sentry/conventions': 0.15.1 - '@sentry/core': 10.65.0 - magic-string: 0.30.21 - transitivePeerDependencies: - - supports-color + '@opentelemetry/api': 1.9.1 + '@sentry/conventions': 0.29.0 + '@sentry/core': 11.10.0 '@sentry/starlight-theme@0.9.1(@astrojs/starlight@0.41.5(astro@7.3.3(tsx@4.22.3))(typescript@6.0.3))': dependencies: @@ -15123,8 +15049,6 @@ snapshots: cjs-module-lexer@1.2.3: {} - cjs-module-lexer@2.2.0: {} - class-variance-authority@0.7.1: dependencies: clsx: 2.1.1 @@ -15255,11 +15179,6 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 - cross-env@10.1.0: - dependencies: - '@epic-web/invariant': 1.0.0 - cross-spawn: 7.0.6 - cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -15431,8 +15350,6 @@ snapshots: dependencies: is-obj: 2.0.0 - dotenv@16.6.1: {} - dotenv@17.4.2: {} drizzle-kit@0.31.10: @@ -16587,13 +16504,6 @@ snapshots: ignore@7.0.5: {} - import-in-the-middle@3.0.1: - dependencies: - acorn: 8.16.0 - acorn-import-attributes: 1.9.5(acorn@8.16.0) - cjs-module-lexer: 2.2.0 - module-details-from-path: 1.0.4 - import-without-cache@0.4.1: {} imurmurhash@0.1.4: {} @@ -17232,8 +17142,6 @@ snapshots: merge2@1.4.1: {} - meriyah@6.1.4: {} - micro@9.3.5-canary.3: dependencies: arg: 4.1.0 @@ -17576,8 +17484,6 @@ snapshots: modern-tar@0.7.6: {} - module-details-from-path@1.0.4: {} - mri@1.2.0: {} mrmime@2.0.1: {} @@ -17996,6 +17902,30 @@ snapshots: outvariant@1.4.3: {} + oxc-parser@0.152.0: + dependencies: + '@oxc-project/types': 0.152.0 + optionalDependencies: + '@oxc-parser/binding-android-arm-eabi': 0.152.0 + '@oxc-parser/binding-android-arm64': 0.152.0 + '@oxc-parser/binding-darwin-arm64': 0.152.0 + '@oxc-parser/binding-darwin-x64': 0.152.0 + '@oxc-parser/binding-freebsd-x64': 0.152.0 + '@oxc-parser/binding-linux-arm-gnueabihf': 0.152.0 + '@oxc-parser/binding-linux-arm-musleabihf': 0.152.0 + '@oxc-parser/binding-linux-arm64-gnu': 0.152.0 + '@oxc-parser/binding-linux-arm64-musl': 0.152.0 + '@oxc-parser/binding-linux-ppc64-gnu': 0.152.0 + '@oxc-parser/binding-linux-riscv64-gnu': 0.152.0 + '@oxc-parser/binding-linux-riscv64-musl': 0.152.0 + '@oxc-parser/binding-linux-s390x-gnu': 0.152.0 + '@oxc-parser/binding-linux-x64-gnu': 0.152.0 + '@oxc-parser/binding-linux-x64-musl': 0.152.0 + '@oxc-parser/binding-openharmony-arm64': 0.152.0 + '@oxc-parser/binding-win32-arm64-msvc': 0.152.0 + '@oxc-parser/binding-win32-ia32-msvc': 0.152.0 + '@oxc-parser/binding-win32-x64-msvc': 0.152.0 + oxc-transform@0.111.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0): optionalDependencies: '@oxc-transform/binding-android-arm-eabi': 0.111.0 @@ -18337,8 +18267,6 @@ snapshots: process-ancestry@0.1.0: {} - progress@2.0.3: {} - promisepipe@3.0.0: {} prompts@2.4.2: @@ -18648,13 +18576,6 @@ snapshots: require-from-string@2.0.2: {} - require-in-the-middle@8.0.1: - dependencies: - debug: 4.4.3 - module-details-from-path: 1.0.4 - transitivePeerDependencies: - - supports-color - reselect@5.3.0: {} resolve-from@5.0.0: {} @@ -18901,8 +18822,6 @@ snapshots: dependencies: commander: 6.2.1 - semifies@1.0.0: {} - semver@6.3.1: {} semver@7.5.4: @@ -18929,6 +18848,8 @@ snapshots: transitivePeerDependencies: - supports-color + sentry@0.45.0: {} + sentry@0.47.0: {} serve-static@2.2.1: @@ -19340,6 +19261,10 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + supports-hyperlinks@3.2.0: dependencies: has-flag: 4.0.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index fb7c903e33..09bad3e913 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -9,8 +9,9 @@ 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/nitro": 11.10.0 + "@sentry/node": 11.10.0 + "@sentry/server-utils": 11.10.0 "@sentry/starlight-theme": ^0.9.1 drizzle-kit: ^0.31.8 drizzle-orm: ^0.45.2 @@ -45,11 +46,13 @@ minimumReleaseAgeExclude: - "@vitest-evals/core@0.16.1" - "@vitest-evals/report-ui@0.16.1" - "vitest-evals@0.16.1" - - "@sentry/core@10.65.0" - - "@sentry/node-core@10.65.0" - - "@sentry/node@10.65.0" - - "@sentry/opentelemetry@10.65.0" - - "@sentry/server-utils@10.65.0" + - "@sentry/bundler-plugins@11.10.0" + - "@sentry/core@11.10.0" + - "@sentry/nitro@11.10.0" + - "@sentry/node@11.10.0" + - "@sentry/opentelemetry@11.10.0" + - "@sentry/server-runtime-injection@11.10.0" + - "@sentry/server-utils@11.10.0" - "@earendil-works/pi-agent-core" - "@earendil-works/pi-ai" - sentry From 5cb69bd71081655c90fa8bac163e31c7f5a42d98 Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Thu, 29 Oct 2026 15:27:29 +0000 Subject: [PATCH 2/5] test(sentry): Read queue spans in the v11 span JSON shape Co-Authored-By: David Cramer --- .../conversation-work-telemetry.test.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/junior/tests/component/task-execution/conversation-work-telemetry.test.ts b/packages/junior/tests/component/task-execution/conversation-work-telemetry.test.ts index 80a7d4b3c0..f9edea2cbf 100644 --- a/packages/junior/tests/component/task-execution/conversation-work-telemetry.test.ts +++ b/packages/junior/tests/component/task-execution/conversation-work-telemetry.test.ts @@ -38,7 +38,8 @@ describe("conversation work telemetry", () => { }); client?.on("spanEnd", (span) => { const json = Sentry.spanToJSON(span); - if (json.op === "queue.publish" || json.op === "queue.process") { + const op = json.attributes?.["sentry.op"]; + if (op === "queue.publish" || op === "queue.process") { spans.push(json); } }); @@ -86,9 +87,9 @@ describe("conversation work telemetry", () => { expect(spans).toEqual([ expect.objectContaining({ - description: "conversation.work.publish", - op: "queue.publish", - data: expect.objectContaining({ + name: "conversation.work.publish", + attributes: expect.objectContaining({ + "sentry.op": "queue.publish", "gen_ai.conversation.id": CONVERSATION_ID, "messaging.destination.name": "junior_test_work", "messaging.message.body.size": expect.any(Number), @@ -97,9 +98,9 @@ describe("conversation work telemetry", () => { }), }), expect.objectContaining({ - description: "conversation.work.process", - op: "queue.process", - data: expect.objectContaining({ + name: "conversation.work.process", + attributes: expect.objectContaining({ + "sentry.op": "queue.process", "gen_ai.conversation.id": CONVERSATION_ID, "messaging.destination.name": "junior_test_work", "messaging.message.id": "msg_1", From 743734d55567c3e0356dc693727035225dd1d941 Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Thu, 29 Oct 2026 15:27:29 +0000 Subject: [PATCH 3/5] fix(sentry): Trace web search model calls The filtered VercelAI integration used to record the web search generateText call. Add a gen_ai.chat span with usage instead. Co-Authored-By: David Cramer --- packages/junior/src/chat/tools/web/search.ts | 56 ++++++++++++++------ 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/packages/junior/src/chat/tools/web/search.ts b/packages/junior/src/chat/tools/web/search.ts index ccb38f38d2..a1ac0e024c 100644 --- a/packages/junior/src/chat/tools/web/search.ts +++ b/packages/junior/src/chat/tools/web/search.ts @@ -3,6 +3,12 @@ import { juniorToolOutputSchema } from "@/chat/tool-support/structured-result"; import { zodTool } from "@/chat/tool-support/zod-tool"; import { generateText } from "ai"; import { createGatewayProvider } from "@ai-sdk/gateway"; +import { extractGenAiUsageAttributes, withSpan } from "@/chat/logging"; +import { + GEN_AI_PROVIDER_NAME, + GEN_AI_SERVER_ADDRESS, + GEN_AI_SERVER_PORT, +} from "@/chat/pi/client"; import { resolveGatewayCredential } from "@/chat/pi/gateway-auth"; import { withTimeout } from "@/chat/tools/web/network"; import type { WebSearchToolDeps } from "@/chat/tools/types"; @@ -101,22 +107,42 @@ export function createWebSearchTool( const provider = createGatewayProvider( credential ? { apiKey: credential.token } : {}, ); - const response = await withTimeout( - generateText({ - model: provider.chat(modelId), - prompt: query, - tools: { - [SEARCH_TOOL_NAME]: provider.tools.parallelSearch({ - mode: "agentic", - maxResults, + const response = await withSpan( + `chat ${modelId}`, + "gen_ai.chat", + {}, + async (setSpanAttributes) => { + const response = await withTimeout( + generateText({ + model: provider.chat(modelId), + prompt: query, + tools: { + [SEARCH_TOOL_NAME]: provider.tools.parallelSearch({ + mode: "agentic", + maxResults, + }), + }, + toolChoice: { type: "tool", toolName: SEARCH_TOOL_NAME }, + abortSignal: controller.signal, }), - }, - toolChoice: { type: "tool", toolName: SEARCH_TOOL_NAME }, - abortSignal: controller.signal, - }), - SEARCH_TIMEOUT_MS, - "webSearch", - { onTimeout: () => controller.abort() }, + SEARCH_TIMEOUT_MS, + "webSearch", + { onTimeout: () => controller.abort() }, + ); + setSpanAttributes({ + "gen_ai.response.finish_reasons": [response.finishReason], + ...extractGenAiUsageAttributes(response.usage), + }); + return response; + }, + { + "gen_ai.provider.name": GEN_AI_PROVIDER_NAME, + "gen_ai.operation.name": "chat", + "gen_ai.request.model": modelId, + "server.address": GEN_AI_SERVER_ADDRESS, + "server.port": GEN_AI_SERVER_PORT, + "gen_ai.provider.auth_mode": credential?.mode ?? "api_key", + }, ); const results = parseSearchResults(response.toolResults, maxResults); From 7fab8ba5d3ef335625569240e305e43acf18226b Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Thu, 29 Oct 2026 15:27:29 +0000 Subject: [PATCH 4/5] fix(sentry): Keep private Slack file URLs out of telemetry Automatic fetch spans and breadcrumbs record the request URL. Private Slack file URLs name the workspace and file, so keep only the files.slack.com host and drop URL fragments with the query. Co-Authored-By: David Cramer --- .../junior/src/chat/sentry-payload-filter.ts | 39 +++++++++++++++++- .../tests/unit/sentry-payload-filter.test.ts | 40 +++++++++++++++++++ 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/packages/junior/src/chat/sentry-payload-filter.ts b/packages/junior/src/chat/sentry-payload-filter.ts index 74df8e059e..7eb77ddd80 100644 --- a/packages/junior/src/chat/sentry-payload-filter.ts +++ b/packages/junior/src/chat/sentry-payload-filter.ts @@ -35,9 +35,12 @@ const PAYLOAD_ATTRIBUTE_KEYS = new Set([ const URL_ATTRIBUTE_KEYS = new Set([ "http.target", "http.url", + // Fetch and HTTP breadcrumbs keep the request URL under `url`. + "url", "url.full", "url.path", ]); +const SLACK_FILE_HOST = "files.slack.com"; const OAUTH_CALLBACK_PATH = "/api/oauth/callback/"; const LOCAL_CREDENTIAL_PATH = "/api/internal/local-oauth-credentials"; const SECRET_HEADER_NAMES = new Set([ @@ -58,15 +61,43 @@ function isSecretHeaderAttribute(key: string): boolean { ); } +function isSlackFileRequest(attributes: AttributeMap): boolean { + return ( + attributes["server.address"] === SLACK_FILE_HOST || + [...URL_ATTRIBUTE_KEYS].some((key) => { + const value = attributes[key]; + return ( + typeof value === "string" && value.includes(`//${SLACK_FILE_HOST}/`) + ); + }) + ); +} + +/** Keep only the host of private Slack file URLs, which name the workspace and file. */ +function scrubSlackFileUrls(attributes: AttributeMap): void { + for (const key of URL_ATTRIBUTE_KEYS) { + const value = attributes[key]; + if (typeof value !== "string") { + continue; + } + if (value.includes("://")) { + attributes[key] = `https://${SLACK_FILE_HOST}`; + } else { + delete attributes[key]; + } + } +} + function scrubSensitiveUrlAttributes( attributes: AttributeMap | undefined, ): void { if (!attributes) { return; } - // Query strings are not useful enough in telemetry to justify retaining - // OAuth codes, signed state, or other caller-supplied secrets. + // Query strings and fragments are not useful enough in telemetry to justify + // retaining OAuth codes, signed state, or other caller-supplied secrets. delete attributes["url.query"]; + delete attributes["url.fragment"]; const hasLocalCredentialUrl = [...URL_ATTRIBUTE_KEYS].some((key) => { const value = attributes[key]; @@ -80,6 +111,10 @@ function scrubSensitiveUrlAttributes( delete attributes[key]; } } + if (isSlackFileRequest(attributes)) { + scrubSlackFileUrls(attributes); + return; + } for (const key of URL_ATTRIBUTE_KEYS) { const value = attributes[key]; if (typeof value !== "string" || !value.includes(OAUTH_CALLBACK_PATH)) { diff --git a/packages/junior/tests/unit/sentry-payload-filter.test.ts b/packages/junior/tests/unit/sentry-payload-filter.test.ts index 5f44c5ad9a..d1e06328d4 100644 --- a/packages/junior/tests/unit/sentry-payload-filter.test.ts +++ b/packages/junior/tests/unit/sentry-payload-filter.test.ts @@ -43,6 +43,46 @@ describe("Sentry private payload filtering", () => { expect(span.attributes?.["url.query"]).toBeUndefined(); }); + it("keeps only the host of private Slack file URLs", () => { + const fileUrl = + "https://files.slack.com/files-pri/T123-F456/private-plan.pdf"; + const span = { + attributes: { + "server.address": "files.slack.com", + "url.full": `${fileUrl}?pub_secret=abc`, + "url.path": "/files-pri/T123-F456/private-plan.pdf", + "url.query": "pub_secret=abc", + }, + end_timestamp: 2, + is_segment: false, + name: "GET files.slack.com", + span_id: "span", + start_timestamp: 1, + status: "ok", + trace_id: "trace", + } as SentrySpan; + const event = { + type: undefined, + breadcrumbs: [ + { + category: "http", + data: { url: fileUrl, "url.query": "pub_secret=abc" }, + }, + ], + } as SentryEvent; + + scrubPrivateSentrySpan(span); + scrubPrivateSentryEvent(event); + + expect(span.attributes).toEqual({ + "server.address": "files.slack.com", + "url.full": "https://files.slack.com", + }); + expect(event.breadcrumbs?.[0]?.data).toEqual({ + url: "https://files.slack.com", + }); + }); + it("removes OAuth secrets from captured request data", () => { const event = { type: undefined, From fa76dfff76842560f75811ff0f5686eff08b04ae Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Thu, 29 Oct 2026 15:28:31 +0000 Subject: [PATCH 5/5] ref(sentry): Remove leftovers from the v11 upgrade - Drop @opentelemetry/api and @opentelemetry/core; nothing imports them. - Drop the @sentry/cli build allowance; v11 no longer installs it. - Drop the AI SDK telemetry flag; no integration reads it now. - Drop the unused vercelAIIntegration re-export and the @sentry/node install step from the README. - Tighten the withSpan and juniorNitro tests. Co-Authored-By: David Cramer --- apps/example/package.json | 2 - packages/junior/package.json | 2 - packages/junior/src/chat/guardian/reviewer.ts | 1 - packages/junior/src/chat/logging.ts | 4 +- packages/junior/src/chat/pi/client.ts | 14 - packages/junior/src/chat/sentry.ts | 1 - packages/junior/src/cli/init.ts | 4 - packages/junior/src/instrumentation.ts | 7 +- .../unit/build/nitro-plugin-module.test.ts | 8 +- .../junior/tests/unit/cli/init-cli.test.ts | 2 - .../tests/unit/guardian/reviewer.test.ts | 1 - .../tests/unit/logging/with-span.test.ts | 9 +- packages/junior/tests/unit/pi/client.test.ts | 6 - pnpm-lock.yaml | 250 ++++++++++-------- pnpm-workspace.yaml | 3 - 15 files changed, 150 insertions(+), 164 deletions(-) diff --git a/apps/example/package.json b/apps/example/package.json index deb9d37789..213215ff60 100644 --- a/apps/example/package.json +++ b/apps/example/package.json @@ -12,8 +12,6 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@opentelemetry/api": "1.9.1", - "@opentelemetry/core": "2.9.0", "@sentry/junior": "workspace:*", "@sentry/junior-agent-browser": "workspace:*", "@sentry/junior-amplitude": "workspace:*", diff --git a/packages/junior/package.json b/packages/junior/package.json index 13c6130ebd..ad8d7a7358 100644 --- a/packages/junior/package.json +++ b/packages/junior/package.json @@ -79,8 +79,6 @@ "@logtape/logtape": "^2.1.1", "@modelcontextprotocol/sdk": "1.32.0", "@neondatabase/serverless": "^1.1.0", - "@opentelemetry/api": "catalog:", - "@opentelemetry/core": "catalog:", "@sentry/junior-plugin-api": "workspace:*", "@sentry/nitro": "catalog:", "@sentry/node": "catalog:", diff --git a/packages/junior/src/chat/guardian/reviewer.ts b/packages/junior/src/chat/guardian/reviewer.ts index 625a35b819..ac44b542ef 100644 --- a/packages/junior/src/chat/guardian/reviewer.ts +++ b/packages/junior/src/chat/guardian/reviewer.ts @@ -195,7 +195,6 @@ export function createGuardianActionReviewer(options: { system: GUARDIAN_ACTION_POLICY, prompt: guardianPrompt(proposal), maxTokens: GUARDIAN_REVIEW_MAX_TOKENS, - recordTelemetryPayloads: false, temperature: 0, promptName: "junior.guardian_action_review", signal, diff --git a/packages/junior/src/chat/logging.ts b/packages/junior/src/chat/logging.ts index 5fcb779471..8d45a22ec2 100644 --- a/packages/junior/src/chat/logging.ts +++ b/packages/junior/src/chat/logging.ts @@ -1662,9 +1662,7 @@ export async function withSpan( } catch (error) { // Sentry sets the error status but not `error.type`. Keep a more // specific type that the callback already set. - if ( - Sentry.spanToJSON(span).attributes?.["error.type"] === undefined - ) { + if (spanToJSON(span).attributes?.["error.type"] === undefined) { span.setAttribute( "error.type", error instanceof Error ? error.name : typeof error, diff --git a/packages/junior/src/chat/pi/client.ts b/packages/junior/src/chat/pi/client.ts index fdcd5a5a9b..2db51caa9c 100644 --- a/packages/junior/src/chat/pi/client.ts +++ b/packages/junior/src/chat/pi/client.ts @@ -487,11 +487,6 @@ export async function completeObject(params: { thinkingLevel?: ThinkingLevel; temperature?: number; maxTokens?: number; - /** - * `false` retains telemetry spans and metrics while omitting model inputs and - * outputs. Omission preserves the existing payload-recording behavior. - */ - recordTelemetryPayloads?: boolean; signal?: AbortSignal; metadata?: Record; promptName?: string; @@ -520,15 +515,6 @@ export async function completeObject(params: { ...(params.maxTokens !== undefined ? { maxOutputTokens: params.maxTokens } : undefined), - ...(params.recordTelemetryPayloads === false - ? { - experimental_telemetry: { - isEnabled: true, - recordInputs: false, - recordOutputs: false, - }, - } - : undefined), ...(params.signal !== undefined ? { abortSignal: params.signal } : undefined), diff --git a/packages/junior/src/chat/sentry.ts b/packages/junior/src/chat/sentry.ts index 5db3283578..2f0f8a3acc 100644 --- a/packages/junior/src/chat/sentry.ts +++ b/packages/junior/src/chat/sentry.ts @@ -16,7 +16,6 @@ export { startInactiveSpan, startSpan, startSpanManual, - vercelAIIntegration, withActiveSpan, withScope, } from "@sentry/node"; diff --git a/packages/junior/src/cli/init.ts b/packages/junior/src/cli/init.ts index 20013c05ed..af15df3c68 100644 --- a/packages/junior/src/cli/init.ts +++ b/packages/junior/src/cli/init.ts @@ -89,8 +89,6 @@ function writePnpmWorkspace(targetDir: string): void { `minimumReleaseAge: 1440 minimumReleaseAgeExclude: - "@sentry/*" -allowBuilds: - "@sentry/cli": true `, ); } @@ -169,8 +167,6 @@ export async function runInit( typecheck: "tsc --noEmit", }, dependencies: { - "@opentelemetry/api": "1.9.1", - "@opentelemetry/core": "2.9.0", "@sentry/junior": "latest", "@sentry/junior-memory": "latest", "@sentry/junior-maintenance": "latest", diff --git a/packages/junior/src/instrumentation.ts b/packages/junior/src/instrumentation.ts index dfc51700e1..efdc48027e 100644 --- a/packages/junior/src/instrumentation.ts +++ b/packages/junior/src/instrumentation.ts @@ -9,10 +9,9 @@ import { getDeploymentTelemetryAttributes, } from "@/deployment"; -// Junior's own gen_ai spans own model calls. Pi parses provider streams itself, -// so these SDK spans would duplicate them without usage or cost. -// Remove this filter once Sentry ships a pi-ai integration -// (getsentry/sentry-javascript#25869). +// Junior records its own gen_ai spans with usage and cost. These SDK spans +// would duplicate them, and Pi reads provider streams itself, so they have no +// usage. Remove this filter after getsentry/sentry-javascript#25869. const MANUAL_GEN_AI_INTEGRATIONS = new Set([ "Anthropic_AI", "Google_GenAI", diff --git a/packages/junior/tests/unit/build/nitro-plugin-module.test.ts b/packages/junior/tests/unit/build/nitro-plugin-module.test.ts index 729d600808..97fd82aaa8 100644 --- a/packages/junior/tests/unit/build/nitro-plugin-module.test.ts +++ b/packages/junior/tests/unit/build/nitro-plugin-module.test.ts @@ -454,11 +454,9 @@ describe("juniorNitro plugin modules", () => { expect(rollupBeforeHooks).toHaveLength(1); await rollupBeforeHooks[0]!({}, { plugins: buildPlugins }); - expect(buildPlugins.map((plugin) => plugin.name)).toEqual([ - "code-transformer", - "junior:copy-build-content", - ]); - await buildPlugins[1]?.writeBundle?.(); + await buildPlugins + .find((plugin) => plugin.name === "junior:copy-build-content") + ?.writeBundle?.(); await expect( fs.readFile( diff --git a/packages/junior/tests/unit/cli/init-cli.test.ts b/packages/junior/tests/unit/cli/init-cli.test.ts index 32b2d608d7..5c4601cfcf 100644 --- a/packages/junior/tests/unit/cli/init-cli.test.ts +++ b/packages/junior/tests/unit/cli/init-cli.test.ts @@ -174,8 +174,6 @@ describe("init cli", () => { expect(pnpmWorkspace).toBe(`minimumReleaseAge: 1440 minimumReleaseAgeExclude: - "@sentry/*" -allowBuilds: - "@sentry/cli": true `); const envExample = fs.readFileSync( diff --git a/packages/junior/tests/unit/guardian/reviewer.test.ts b/packages/junior/tests/unit/guardian/reviewer.test.ts index 86d235ff21..f59a7d1fee 100644 --- a/packages/junior/tests/unit/guardian/reviewer.test.ts +++ b/packages/junior/tests/unit/guardian/reviewer.test.ts @@ -89,7 +89,6 @@ describe("Guardian action review", () => { maxTokens: 2_000, modelId: "test/guardian", prompt: expect.stringContaining('"cadence": "weekly"'), - recordTelemetryPayloads: false, }), ); }); diff --git a/packages/junior/tests/unit/logging/with-span.test.ts b/packages/junior/tests/unit/logging/with-span.test.ts index 8581f2cb4e..9438e7d0df 100644 --- a/packages/junior/tests/unit/logging/with-span.test.ts +++ b/packages/junior/tests/unit/logging/with-span.test.ts @@ -93,7 +93,7 @@ describe("withSpan", () => { }); }); - it("sets error.type on the span that throws unless the callback set one", async () => { + it("sets error.type on the span that throws", async () => { const { withSpan } = await import("@/chat/logging"); await expect( @@ -106,9 +106,12 @@ describe("withSpan", () => { "error.type", "TypeError", ); + }); + + it("keeps an error.type that the callback set", async () => { + const { withSpan } = await import("@/chat/logging"); - activeSpan.setAttribute.mockClear(); - spanAttributes["error.type"] = { type: "string", value: "rate_limited" }; + spanAttributes["error.type"] = "rate_limited"; await expect( withSpan("POST slack.com/api/chat.postMessage", "http.client", {}, () => Promise.reject(new Error("rate limited")), diff --git a/packages/junior/tests/unit/pi/client.test.ts b/packages/junior/tests/unit/pi/client.test.ts index 488dc744ff..18b6c78299 100644 --- a/packages/junior/tests/unit/pi/client.test.ts +++ b/packages/junior/tests/unit/pi/client.test.ts @@ -301,7 +301,6 @@ describe("completeText", () => { modelId: "openai/gpt-4o-mini", schema, prompt: "return json", - recordTelemetryPayloads: false, system: "structured only", }); @@ -314,11 +313,6 @@ describe("completeText", () => { model: { modelId: "openai/gpt-4o-mini" }, schema, prompt: "return json", - experimental_telemetry: { - isEnabled: true, - recordInputs: false, - recordOutputs: false, - }, system: "structured only", }), ); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2000fccb0a..03203a3a34 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,12 +13,6 @@ catalogs: '@earendil-works/pi-ai': specifier: 0.85.1 version: 0.85.1 - '@opentelemetry/api': - specifier: 1.9.1 - version: 1.9.1 - '@opentelemetry/core': - specifier: 2.9.0 - version: 2.9.0 '@sentry/nitro': specifier: 11.10.0 version: 11.10.0 @@ -102,15 +96,9 @@ importers: apps/example: dependencies: - '@opentelemetry/api': - specifier: 1.9.1 - version: 1.9.1 - '@opentelemetry/core': - specifier: 2.9.0 - version: 2.9.0(@opentelemetry/api@1.9.1) '@sentry/junior': specifier: workspace:* - version: file:packages/junior(@types/node@25.9.1)(nitro@3.0.260522-beta(jiti@2.7.0)) + version: file:packages/junior(@opentelemetry/api@1.9.1)(@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 @@ -198,7 +186,7 @@ importers: version: 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) '@chat-adapter/state-redis': specifier: 4.29.0 - version: 4.29.0(@opentelemetry/api@1.9.1)(ai@7.0.153(zod@4.5.4))(zod@4.5.4) + version: 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) '@earendil-works/pi-agent-core': specifier: 'catalog:' version: 0.84.1(@modelcontextprotocol/sdk@1.32.0(zod@4.5.4))(zod@4.5.4) @@ -217,12 +205,6 @@ importers: '@neondatabase/serverless': specifier: ^1.1.0 version: 1.1.0 - '@opentelemetry/api': - specifier: 'catalog:' - version: 1.9.1 - '@opentelemetry/core': - specifier: 'catalog:' - version: 2.9.0(@opentelemetry/api@1.9.1) '@sentry/junior-plugin-api': specifier: workspace:* version: link:../junior-plugin-api @@ -322,10 +304,10 @@ importers: version: 1.79.0 '@sentry/junior-github': specifier: workspace:* - version: file:packages/junior-github(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(pg@8.21.0) + version: file:packages/junior-github(@neondatabase/serverless@1.1.0)(@types/pg@8.15.6)(pg@8.21.0) '@sentry/junior-memory': specifier: workspace:* - version: file:packages/junior-memory(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(pg@8.21.0) + version: file:packages/junior-memory(@neondatabase/serverless@1.1.0)(@types/pg@8.15.6)(pg@8.21.0) '@sentry/junior-testing': specifier: workspace:* version: file:packages/junior-testing(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.15.6) @@ -3031,12 +3013,6 @@ packages: resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} engines: {node: '>=8.0.0'} - '@opentelemetry/core@2.9.0': - resolution: {integrity: sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/semantic-conventions@1.43.0': resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} engines: {node: '>=14'} @@ -10556,6 +10532,18 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.1 + '@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1)': + dependencies: + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.2 + '@opentelemetry/semantic-conventions': 1.43.0 + '@standard-schema/spec': 1.1.0 + better-call: 1.4.0(zod@4.5.4) + jose: 6.2.4 + kysely: 0.29.4 + nanostores: 1.4.1 + zod: 4.5.4 + '@better-auth/drizzle-adapter@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(pg@8.21.0))': dependencies: '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) @@ -10563,13 +10551,20 @@ snapshots: optionalDependencies: drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(pg@8.21.0) - '@better-auth/drizzle-adapter@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0))': + '@better-auth/drizzle-adapter@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0))': dependencies: - '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) '@better-auth/utils': 0.4.2 optionalDependencies: drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0) + '@better-auth/drizzle-adapter@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0))': + dependencies: + '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/utils': 0.4.2 + optionalDependencies: + drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0) + '@better-auth/kysely-adapter@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(kysely@0.29.4)': dependencies: '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) @@ -10577,27 +10572,55 @@ snapshots: optionalDependencies: kysely: 0.29.4 + '@better-auth/kysely-adapter@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(kysely@0.29.4)': + dependencies: + '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/utils': 0.4.2 + optionalDependencies: + kysely: 0.29.4 + '@better-auth/memory-adapter@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)': dependencies: '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) '@better-auth/utils': 0.4.2 + '@better-auth/memory-adapter@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)': + dependencies: + '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/utils': 0.4.2 + '@better-auth/mongo-adapter@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)': dependencies: '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) '@better-auth/utils': 0.4.2 + '@better-auth/mongo-adapter@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)': + dependencies: + '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/utils': 0.4.2 + '@better-auth/prisma-adapter@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)': dependencies: '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) '@better-auth/utils': 0.4.2 + '@better-auth/prisma-adapter@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)': + dependencies: + '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/utils': 0.4.2 + '@better-auth/telemetry@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)': dependencies: '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) '@better-auth/utils': 0.4.2 '@better-fetch/fetch': 1.3.2 + '@better-auth/telemetry@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)': + dependencies: + '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.2 + '@better-auth/utils@0.4.2': dependencies: '@noble/hashes': 2.2.0 @@ -10712,10 +10735,10 @@ snapshots: - supports-color - zod - '@chat-adapter/state-redis@4.29.0(@opentelemetry/api@1.9.1)(ai@7.0.153(zod@4.5.4))(zod@4.5.4)': + '@chat-adapter/state-redis@4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4)': dependencies: chat: 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) - redis: 5.12.1(@opentelemetry/api@1.9.1) + redis: 5.12.1 transitivePeerDependencies: - '@node-rs/xxhash' - '@opentelemetry/api' @@ -11897,11 +11920,6 @@ snapshots: '@opentelemetry/api@1.9.1': {} - '@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/semantic-conventions': 1.43.0 - '@opentelemetry/semantic-conventions@1.43.0': {} '@oslojs/encoding@1.1.0': {} @@ -12216,27 +12234,25 @@ snapshots: dependencies: quansync: 1.0.0 - '@redis/bloom@5.12.1(@redis/client@5.12.1(@opentelemetry/api@1.9.1))': + '@redis/bloom@5.12.1(@redis/client@5.12.1)': dependencies: - '@redis/client': 5.12.1(@opentelemetry/api@1.9.1) + '@redis/client': 5.12.1 - '@redis/client@5.12.1(@opentelemetry/api@1.9.1)': + '@redis/client@5.12.1': dependencies: cluster-key-slot: 1.1.2 - optionalDependencies: - '@opentelemetry/api': 1.9.1 - '@redis/json@5.12.1(@redis/client@5.12.1(@opentelemetry/api@1.9.1))': + '@redis/json@5.12.1(@redis/client@5.12.1)': dependencies: - '@redis/client': 5.12.1(@opentelemetry/api@1.9.1) + '@redis/client': 5.12.1 - '@redis/search@5.12.1(@redis/client@5.12.1(@opentelemetry/api@1.9.1))': + '@redis/search@5.12.1(@redis/client@5.12.1)': dependencies: - '@redis/client': 5.12.1(@opentelemetry/api@1.9.1) + '@redis/client': 5.12.1 - '@redis/time-series@5.12.1(@redis/client@5.12.1(@opentelemetry/api@1.9.1))': + '@redis/time-series@5.12.1(@redis/client@5.12.1)': dependencies: - '@redis/client': 5.12.1(@opentelemetry/api@1.9.1) + '@redis/client': 5.12.1 '@renovatebot/pep440@4.2.1': {} @@ -12521,6 +12537,7 @@ snapshots: - '@netlify/runtime' - '@node-rs/xxhash' - '@op-engineering/op-sqlite' + - '@opentelemetry/api' - '@planetscale/database' - '@prisma/client' - '@sveltejs/kit' @@ -12621,11 +12638,11 @@ snapshots: - sql.js - sqlite3 - '@sentry/junior-github@file:packages/junior-github(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(pg@8.21.0)': + '@sentry/junior-github@file:packages/junior-github(@neondatabase/serverless@1.1.0)(@types/pg@8.15.6)(pg@8.21.0)': dependencies: '@sentry/junior-plugin-api': file:packages/junior-plugin-api '@sinclair/typebox': 0.34.52 - drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(pg@8.21.0) + drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(@types/pg@8.15.6)(pg@8.21.0) marked: 18.1.2 zod: 4.5.4 transitivePeerDependencies: @@ -12772,12 +12789,12 @@ snapshots: - sql.js - sqlite3 - '@sentry/junior-memory@file:packages/junior-memory(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(pg@8.21.0)': + '@sentry/junior-memory@file:packages/junior-memory(@neondatabase/serverless@1.1.0)(@types/pg@8.15.6)(pg@8.21.0)': dependencies: '@sentry/junior-plugin-api': file:packages/junior-plugin-api '@sinclair/typebox': 0.34.52 commander: 14.0.3 - drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(pg@8.21.0) + drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(@types/pg@8.15.6)(pg@8.21.0) zod: 4.5.4 transitivePeerDependencies: - '@aws-sdk/client-rds-data' @@ -12925,21 +12942,19 @@ snapshots: - sql.js - sqlite3 - '@sentry/junior@file:packages/junior(@types/node@25.9.1)(nitro@3.0.260522-beta(jiti@2.7.0))': + '@sentry/junior@file:packages/junior(@opentelemetry/api@1.9.1)(@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) '@chat-adapter/slack': 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) '@chat-adapter/state-memory': 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) - '@chat-adapter/state-redis': 4.29.0(@opentelemetry/api@1.9.1)(ai@7.0.153(zod@4.5.4))(zod@4.5.4) + '@chat-adapter/state-redis': 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) '@earendil-works/pi-agent-core': 0.84.1(@modelcontextprotocol/sdk@1.32.0(zod@4.5.4))(zod@4.5.4) '@earendil-works/pi-ai': 0.84.1(@modelcontextprotocol/sdk@1.32.0(zod@4.5.4))(zod@4.5.4) '@hono/zod-validator': 0.9.0(hono@4.13.11)(zod@4.5.4) '@logtape/logtape': 2.1.1 '@modelcontextprotocol/sdk': 1.32.0(zod@4.5.4) '@neondatabase/serverless': 1.1.0 - '@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': 11.10.0(nitro@3.0.260522-beta(jiti@2.7.0)) '@sentry/node': 11.10.0 @@ -12954,7 +12969,7 @@ snapshots: '@vercel/sandbox': 2.8.0 ai: 7.0.153(zod@4.5.4) aws4fetch: 1.0.20 - better-auth: 1.7.7(@opentelemetry/api@1.9.1)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0))(pg@8.21.0) + better-auth: 1.7.7(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0))(pg@8.21.0) chat: 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) commander: 14.0.3 diff: 8.0.4 @@ -12979,6 +12994,7 @@ snapshots: - '@lynx-js/react' - '@node-rs/xxhash' - '@op-engineering/op-sqlite' + - '@opentelemetry/api' - '@planetscale/database' - '@prisma/client' - '@sveltejs/kit' @@ -13030,15 +13046,13 @@ snapshots: '@ai-sdk/gateway': 4.0.126(zod@4.5.4) '@chat-adapter/slack': 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) '@chat-adapter/state-memory': 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) - '@chat-adapter/state-redis': 4.29.0(@opentelemetry/api@1.9.1)(ai@7.0.153(zod@4.5.4))(zod@4.5.4) + '@chat-adapter/state-redis': 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) '@earendil-works/pi-agent-core': 0.84.1(@modelcontextprotocol/sdk@1.32.0(zod@4.5.4))(zod@4.5.4) '@earendil-works/pi-ai': 0.84.1(@modelcontextprotocol/sdk@1.32.0(zod@4.5.4))(zod@4.5.4) '@hono/zod-validator': 0.9.0(hono@4.13.11)(zod@4.5.4) '@logtape/logtape': 2.1.1 '@modelcontextprotocol/sdk': 1.32.0(zod@4.5.4) '@neondatabase/serverless': 1.1.0 - '@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': 11.10.0(nitro@3.0.260522-beta(jiti@2.7.0)) '@sentry/node': 11.10.0 @@ -13053,11 +13067,11 @@ snapshots: '@vercel/sandbox': 2.8.0 ai: 7.0.153(zod@4.5.4) aws4fetch: 1.0.20 - better-auth: 1.7.7(@opentelemetry/api@1.9.1)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + better-auth: 1.7.7(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) chat: 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) commander: 14.0.3 diff: 8.0.4 - drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0) + drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0) hono: 4.13.11 jiti: 2.7.0 jose: 6.2.3 @@ -13078,6 +13092,7 @@ snapshots: - '@lynx-js/react' - '@node-rs/xxhash' - '@op-engineering/op-sqlite' + - '@opentelemetry/api' - '@planetscale/database' - '@prisma/client' - '@sveltejs/kit' @@ -13129,15 +13144,13 @@ snapshots: '@ai-sdk/gateway': 4.0.126(zod@4.5.4) '@chat-adapter/slack': 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) '@chat-adapter/state-memory': 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) - '@chat-adapter/state-redis': 4.29.0(@opentelemetry/api@1.9.1)(ai@7.0.153(zod@4.5.4))(zod@4.5.4) + '@chat-adapter/state-redis': 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) '@earendil-works/pi-agent-core': 0.84.1(@modelcontextprotocol/sdk@1.32.0(zod@4.5.4))(zod@4.5.4) '@earendil-works/pi-ai': 0.84.1(@modelcontextprotocol/sdk@1.32.0(zod@4.5.4))(zod@4.5.4) '@hono/zod-validator': 0.9.0(hono@4.13.11)(zod@4.5.4) '@logtape/logtape': 2.1.1 '@modelcontextprotocol/sdk': 1.32.0(zod@4.5.4) '@neondatabase/serverless': 1.1.0 - '@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': 11.10.0(nitro@3.0.260522-beta) '@sentry/node': 11.10.0 @@ -13152,11 +13165,11 @@ snapshots: '@vercel/sandbox': 2.8.0 ai: 7.0.153(zod@4.5.4) aws4fetch: 1.0.20 - better-auth: 1.7.7(@opentelemetry/api@1.9.1)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.12) + better-auth: 1.7.7(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.12) chat: 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) commander: 14.0.3 diff: 8.0.4 - drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0) + drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0) hono: 4.13.11 jiti: 2.7.0 jose: 6.2.3 @@ -13177,6 +13190,7 @@ snapshots: - '@lynx-js/react' - '@node-rs/xxhash' - '@op-engineering/op-sqlite' + - '@opentelemetry/api' - '@planetscale/database' - '@prisma/client' - '@sveltejs/kit' @@ -13228,15 +13242,13 @@ snapshots: '@ai-sdk/gateway': 4.0.126(zod@4.5.4) '@chat-adapter/slack': 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) '@chat-adapter/state-memory': 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) - '@chat-adapter/state-redis': 4.29.0(@opentelemetry/api@1.9.1)(ai@7.0.153(zod@4.5.4))(zod@4.5.4) + '@chat-adapter/state-redis': 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) '@earendil-works/pi-agent-core': 0.84.1(@modelcontextprotocol/sdk@1.32.0(zod@4.5.4))(zod@4.5.4) '@earendil-works/pi-ai': 0.84.1(@modelcontextprotocol/sdk@1.32.0(zod@4.5.4))(zod@4.5.4) '@hono/zod-validator': 0.9.0(hono@4.13.11)(zod@4.5.4) '@logtape/logtape': 2.1.1 '@modelcontextprotocol/sdk': 1.32.0(zod@4.5.4) '@neondatabase/serverless': 1.1.0 - '@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': 11.10.0 '@sentry/node': 11.10.0 @@ -13251,11 +13263,11 @@ snapshots: '@vercel/sandbox': 2.8.0 ai: 7.0.153(zod@4.5.4) aws4fetch: 1.0.20 - better-auth: 1.7.7(@opentelemetry/api@1.9.1)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0))(pg@8.21.0)(vitest@4.1.12(msw@2.14.6(typescript@7.0.2))(tsx@4.22.3)) + better-auth: 1.7.7(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0))(pg@8.21.0)(vitest@4.1.12(msw@2.14.6(typescript@7.0.2))(tsx@4.22.3)) chat: 4.29.0(ai@7.0.153(zod@4.5.4))(zod@4.5.4) commander: 14.0.3 diff: 8.0.4 - drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0) + drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0) hono: 4.13.11 jiti: 2.7.0 jose: 6.2.3 @@ -13276,6 +13288,7 @@ snapshots: - '@lynx-js/react' - '@node-rs/xxhash' - '@op-engineering/op-sqlite' + - '@opentelemetry/api' - '@planetscale/database' - '@prisma/client' - '@sveltejs/kit' @@ -14774,15 +14787,15 @@ snapshots: transitivePeerDependencies: - '@opentelemetry/api' - better-auth@1.7.7(@opentelemetry/api@1.9.1)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0))(pg@8.21.0): + better-auth@1.7.7(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0))(pg@8.21.0): dependencies: - '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) - '@better-auth/drizzle-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0)) - '@better-auth/kysely-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(kysely@0.29.4) - '@better-auth/memory-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) - '@better-auth/mongo-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) - '@better-auth/prisma-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) - '@better-auth/telemetry': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2) + '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/drizzle-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0)) + '@better-auth/kysely-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(kysely@0.29.4) + '@better-auth/memory-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) + '@better-auth/mongo-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) + '@better-auth/prisma-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) + '@better-auth/telemetry': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2) '@better-auth/utils': 0.4.2 '@better-fetch/fetch': 1.3.2 '@noble/ciphers': 2.2.0 @@ -14799,15 +14812,15 @@ snapshots: transitivePeerDependencies: - '@opentelemetry/api' - better-auth@1.7.7(@opentelemetry/api@1.9.1)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + better-auth@1.7.7(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) - '@better-auth/drizzle-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0)) - '@better-auth/kysely-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(kysely@0.29.4) - '@better-auth/memory-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) - '@better-auth/mongo-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) - '@better-auth/prisma-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) - '@better-auth/telemetry': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2) + '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/drizzle-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0)) + '@better-auth/kysely-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(kysely@0.29.4) + '@better-auth/memory-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) + '@better-auth/mongo-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) + '@better-auth/prisma-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) + '@better-auth/telemetry': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2) '@better-auth/utils': 0.4.2 '@better-fetch/fetch': 1.3.2 '@noble/ciphers': 2.2.0 @@ -14819,22 +14832,22 @@ snapshots: nanostores: 1.4.1 zod: 4.5.4 optionalDependencies: - drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0) + drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0) pg: 8.21.0 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - '@opentelemetry/api' - better-auth@1.7.7(@opentelemetry/api@1.9.1)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.12): + better-auth@1.7.7(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.12): dependencies: - '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) - '@better-auth/drizzle-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0)) - '@better-auth/kysely-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(kysely@0.29.4) - '@better-auth/memory-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) - '@better-auth/mongo-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) - '@better-auth/prisma-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) - '@better-auth/telemetry': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2) + '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/drizzle-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0)) + '@better-auth/kysely-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(kysely@0.29.4) + '@better-auth/memory-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) + '@better-auth/mongo-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) + '@better-auth/prisma-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) + '@better-auth/telemetry': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2) '@better-auth/utils': 0.4.2 '@better-fetch/fetch': 1.3.2 '@noble/ciphers': 2.2.0 @@ -14846,7 +14859,7 @@ snapshots: nanostores: 1.4.1 zod: 4.5.4 optionalDependencies: - drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0) + drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0) pg: 8.21.0 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) @@ -14854,15 +14867,15 @@ snapshots: transitivePeerDependencies: - '@opentelemetry/api' - better-auth@1.7.7(@opentelemetry/api@1.9.1)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0))(pg@8.21.0)(vitest@4.1.12(msw@2.14.6(typescript@7.0.2))(tsx@4.22.3)): + better-auth@1.7.7(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0))(pg@8.21.0)(vitest@4.1.12(msw@2.14.6(typescript@7.0.2))(tsx@4.22.3)): dependencies: - '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) - '@better-auth/drizzle-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0)) - '@better-auth/kysely-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(kysely@0.29.4) - '@better-auth/memory-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) - '@better-auth/mongo-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) - '@better-auth/prisma-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) - '@better-auth/telemetry': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2) + '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1) + '@better-auth/drizzle-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0)) + '@better-auth/kysely-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(kysely@0.29.4) + '@better-auth/memory-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) + '@better-auth/mongo-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) + '@better-auth/prisma-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2) + '@better-auth/telemetry': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(better-call@1.4.0(zod@4.5.4))(jose@6.2.4)(kysely@0.29.4)(nanostores@1.4.1))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2) '@better-auth/utils': 0.4.2 '@better-fetch/fetch': 1.3.2 '@noble/ciphers': 2.2.0 @@ -14874,7 +14887,7 @@ snapshots: nanostores: 1.4.1 zod: 4.5.4 optionalDependencies: - drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(pg@8.21.0) + drizzle-orm: 0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0) pg: 8.21.0 vitest: 4.1.12(msw@2.14.6(typescript@7.0.2))(tsx@4.22.3) transitivePeerDependencies: @@ -15393,6 +15406,17 @@ snapshots: '@opentelemetry/api': 1.9.1 pg: 8.21.0 + drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(@types/pg@8.15.6)(pg@8.21.0): + optionalDependencies: + '@neondatabase/serverless': 1.1.0 + '@types/pg': 8.15.6 + pg: 8.21.0 + + drizzle-orm@0.45.2(@neondatabase/serverless@1.1.0)(pg@8.21.0): + optionalDependencies: + '@neondatabase/serverless': 1.1.0 + pg: 8.21.0 + drizzle-orm@0.45.2(@opentelemetry/api@1.9.1): optionalDependencies: '@opentelemetry/api': 1.9.1 @@ -18444,13 +18468,13 @@ snapshots: unified: 11.0.5 vfile: 6.0.3 - redis@5.12.1(@opentelemetry/api@1.9.1): + redis@5.12.1: dependencies: - '@redis/bloom': 5.12.1(@redis/client@5.12.1(@opentelemetry/api@1.9.1)) - '@redis/client': 5.12.1(@opentelemetry/api@1.9.1) - '@redis/json': 5.12.1(@redis/client@5.12.1(@opentelemetry/api@1.9.1)) - '@redis/search': 5.12.1(@redis/client@5.12.1(@opentelemetry/api@1.9.1)) - '@redis/time-series': 5.12.1(@redis/client@5.12.1(@opentelemetry/api@1.9.1)) + '@redis/bloom': 5.12.1(@redis/client@5.12.1) + '@redis/client': 5.12.1 + '@redis/json': 5.12.1(@redis/client@5.12.1) + '@redis/search': 5.12.1(@redis/client@5.12.1) + '@redis/time-series': 5.12.1(@redis/client@5.12.1) transitivePeerDependencies: - '@node-rs/xxhash' - '@opentelemetry/api' diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 09bad3e913..dee9bbed16 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -7,8 +7,6 @@ dedupePeerDependents: false catalog: "@earendil-works/pi-agent-core": 0.84.1 "@earendil-works/pi-ai": 0.85.1 - "@opentelemetry/api": 1.9.1 - "@opentelemetry/core": 2.9.0 "@sentry/nitro": 11.10.0 "@sentry/node": 11.10.0 "@sentry/server-utils": 11.10.0 @@ -62,7 +60,6 @@ allowBuilds: "@google/genai": true "@mongodb-js/zstd": true "@parcel/watcher": true - "@sentry/cli": true agent-browser: true esbuild: true msw: true