@agent-native/core 0.13.1 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  2. package/dist/agent/engine/builder-engine.js +5 -1
  3. package/dist/agent/engine/builder-engine.js.map +1 -1
  4. package/dist/agent/production-agent.d.ts +23 -1
  5. package/dist/agent/production-agent.d.ts.map +1 -1
  6. package/dist/agent/production-agent.js +82 -1
  7. package/dist/agent/production-agent.js.map +1 -1
  8. package/dist/agent/run-loop-with-resume.d.ts +45 -0
  9. package/dist/agent/run-loop-with-resume.d.ts.map +1 -0
  10. package/dist/agent/run-loop-with-resume.js +121 -0
  11. package/dist/agent/run-loop-with-resume.js.map +1 -0
  12. package/dist/agent/run-store.d.ts.map +1 -1
  13. package/dist/agent/run-store.js +8 -2
  14. package/dist/agent/run-store.js.map +1 -1
  15. package/dist/agent/types.d.ts +1 -1
  16. package/dist/agent/types.d.ts.map +1 -1
  17. package/dist/agent/types.js.map +1 -1
  18. package/dist/client/AssistantChat.d.ts.map +1 -1
  19. package/dist/client/AssistantChat.js +8 -45
  20. package/dist/client/AssistantChat.js.map +1 -1
  21. package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
  22. package/dist/client/ConnectBuilderCard.js +24 -0
  23. package/dist/client/ConnectBuilderCard.js.map +1 -1
  24. package/dist/client/analytics.d.ts.map +1 -1
  25. package/dist/client/analytics.js +10 -1
  26. package/dist/client/analytics.js.map +1 -1
  27. package/dist/client/extensions/ExtensionsSidebarSection.js +1 -1
  28. package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
  29. package/dist/client/use-chat-threads.d.ts +0 -6
  30. package/dist/client/use-chat-threads.d.ts.map +1 -1
  31. package/dist/client/use-chat-threads.js +40 -52
  32. package/dist/client/use-chat-threads.js.map +1 -1
  33. package/dist/client/use-db-sync.d.ts.map +1 -1
  34. package/dist/client/use-db-sync.js +3 -1
  35. package/dist/client/use-db-sync.js.map +1 -1
  36. package/dist/db/client.d.ts.map +1 -1
  37. package/dist/db/client.js +9 -0
  38. package/dist/db/client.js.map +1 -1
  39. package/dist/db/create-get-db.d.ts.map +1 -1
  40. package/dist/db/create-get-db.js +7 -0
  41. package/dist/db/create-get-db.js.map +1 -1
  42. package/dist/extensions/actions.js +1 -1
  43. package/dist/extensions/actions.js.map +1 -1
  44. package/dist/extensions/fetch-tool.d.ts.map +1 -1
  45. package/dist/extensions/fetch-tool.js +46 -5
  46. package/dist/extensions/fetch-tool.js.map +1 -1
  47. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  48. package/dist/server/agent-chat-plugin.js +82 -75
  49. package/dist/server/agent-chat-plugin.js.map +1 -1
  50. package/dist/server/agent-discovery.d.ts +21 -0
  51. package/dist/server/agent-discovery.d.ts.map +1 -1
  52. package/dist/server/agent-discovery.js +18 -3
  53. package/dist/server/agent-discovery.js.map +1 -1
  54. package/dist/server/auth.d.ts +27 -0
  55. package/dist/server/auth.d.ts.map +1 -1
  56. package/dist/server/auth.js +71 -12
  57. package/dist/server/auth.js.map +1 -1
  58. package/dist/server/better-auth-instance.js +13 -0
  59. package/dist/server/better-auth-instance.js.map +1 -1
  60. package/dist/server/google-auth-mode.d.ts +20 -0
  61. package/dist/server/google-auth-mode.d.ts.map +1 -0
  62. package/dist/server/google-auth-mode.js +20 -0
  63. package/dist/server/google-auth-mode.js.map +1 -0
  64. package/dist/server/google-auth-plugin.d.ts +7 -0
  65. package/dist/server/google-auth-plugin.d.ts.map +1 -1
  66. package/dist/server/google-auth-plugin.js +21 -5
  67. package/dist/server/google-auth-plugin.js.map +1 -1
  68. package/dist/server/index.d.ts +1 -0
  69. package/dist/server/index.d.ts.map +1 -1
  70. package/dist/server/index.js.map +1 -1
  71. package/dist/server/onboarding-html.d.ts +7 -0
  72. package/dist/server/onboarding-html.d.ts.map +1 -1
  73. package/dist/server/onboarding-html.js +22 -3
  74. package/dist/server/onboarding-html.js.map +1 -1
  75. package/dist/server/sentry.d.ts.map +1 -1
  76. package/dist/server/sentry.js +41 -0
  77. package/dist/server/sentry.js.map +1 -1
  78. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"sentry.js","sourceRoot":"","sources":["../../src/server/sentry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Server-side Sentry initialization for Nitro.\n *\n * Errors thrown inside Nitro routes (the framework's own /_agent-native/*\n * handlers, the template's API routes, action handlers, agent-chat streams)\n * never reach the CLI's Sentry init — that only covers the developer's\n * machine. Without server-side Sentry the only signal a 500 ever produces\n * is a server-side console.error that lives and dies with the request.\n *\n * This module is the third Sentry init point in the framework:\n * - cli/index.ts → @sentry/node, hardcoded DSN, \"agent-native-cli\"\n * - client/analytics.ts → @sentry/browser, VITE_SENTRY_CLIENT_DSN / runtime config\n * - server/sentry.ts → @sentry/node, SENTRY_SERVER_DSN / SENTRY_DSN\n *\n * The browser and server can share a Sentry project/DSN. Separate projects\n * are an operational choice for noise, ownership, or quotas; not a runtime\n * requirement.\n */\nimport * as Sentry from \"@sentry/node\";\nimport path from \"node:path\";\nimport fs from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport type { AuthSession } from \"./auth.js\";\nimport {\n resolveSentryEnvironment,\n resolveServerSentryDsn,\n} from \"./sentry-config.js\";\n\nlet _initStarted = false;\nlet _initSucceeded = false;\n\n/**\n * Resolve the agent-native version baked into core's package.json so Sentry\n * \"release\" reflects the running framework version. Mirrors how the CLI\n * computes `_version` — same dist layout, same fallback string. Guarded so\n * a missing/unreadable package.json never crashes server boot.\n */\nfunction resolveServerRelease(): string {\n const explicit = process.env.AGENT_NATIVE_RELEASE;\n if (explicit) return explicit;\n try {\n const here = path.dirname(fileURLToPath(import.meta.url));\n // dist/server/sentry.js → ../../package.json\n const pkgPath = path.resolve(here, \"../../package.json\");\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\")) as {\n version?: string;\n };\n if (pkg?.version) return `agent-native-server@${pkg.version}`;\n } catch {\n // ignore — fall through to \"unknown\"\n }\n return \"agent-native-server@unknown\";\n}\n\nfunction parseTracesSampleRate(): number {\n const raw = process.env.SENTRY_SERVER_TRACES_SAMPLE_RATE;\n if (!raw) return 0;\n const n = Number(raw);\n if (!Number.isFinite(n) || n < 0 || n > 1) return 0;\n return n;\n}\n\n/**\n * Initialize server-side Sentry. Idempotent — safe to call from multiple\n * plugin entrypoints. Returns `true` if initialization actually happened\n * (DSN was set), `false` if Sentry is disabled (no DSN).\n *\n * No DSN is hardcoded: unlike the CLI (a published binary that always wants\n * to phone home crashes), the server runs in customer environments. Operators\n * set `SENTRY_SERVER_DSN` or the common `SENTRY_DSN` when they want their own\n * Sentry project to receive these events; without one the module no-ops.\n */\nexport function initServerSentry(): boolean {\n if (_initStarted) return _initSucceeded;\n _initStarted = true;\n\n const dsn = resolveServerSentryDsn();\n if (!dsn) {\n if (process.env.DEBUG) {\n console.log(\n \"[agent-native] SENTRY_SERVER_DSN/SENTRY_DSN not set — server Sentry disabled.\",\n );\n }\n return false;\n }\n\n Sentry.init({\n dsn,\n environment: resolveSentryEnvironment(),\n release: resolveServerRelease(),\n tracesSampleRate: parseTracesSampleRate(),\n // sendDefaultPii MUST stay false — the framework runs inside customer\n // environments and we never want to silently ship request headers,\n // cookies, or process.env contents to Sentry without explicit consent.\n sendDefaultPii: false,\n beforeSend(event) {\n // Drop expected user-input rejections so they don't pollute Sentry\n // with non-bug noise. Mirrors the CLI's drop list — the framework\n // and CLI both throw `ValidationError` for the same class of input\n // failures, and exception type comes through as the class name.\n const exceptionType = event.exception?.values?.[0]?.type;\n if (\n exceptionType === \"ValidationError\" ||\n event.tags?.handled === \"validation\"\n ) {\n return null;\n }\n\n // Defense in depth: scrub PII even if some integration auto-attached\n // request metadata despite sendDefaultPii: false.\n if (event.request) {\n if (event.request.headers) {\n const headers = event.request.headers as Record<string, string>;\n for (const k of Object.keys(headers)) {\n const lk = k.toLowerCase();\n if (\n lk === \"cookie\" ||\n lk === \"authorization\" ||\n lk === \"set-cookie\" ||\n lk === \"proxy-authorization\"\n ) {\n delete headers[k];\n }\n }\n }\n // Cookies live in their own field too.\n delete (event.request as Record<string, unknown>).cookies;\n }\n\n // Keep user info that was explicitly set via Sentry.setUser\n // (id/email/username) so we can attribute crashes back to a real\n // operator. Always strip ip_address — auto-collected, no consent.\n if (event.user) {\n const user = event.user as Record<string, unknown>;\n delete user.ip_address;\n const hasIdentity =\n typeof user.id === \"string\" ||\n typeof user.email === \"string\" ||\n typeof user.username === \"string\";\n if (!hasIdentity) {\n delete event.user;\n }\n }\n\n // Sentry's contexts can carry process.env snapshots — strip env-shaped\n // contexts so we don't leak deployment secrets.\n if (event.contexts && typeof event.contexts === \"object\") {\n delete (event.contexts as Record<string, unknown>).runtime_env;\n }\n\n return event;\n },\n });\n\n _initSucceeded = true;\n return true;\n}\n\n/**\n * `true` once `initServerSentry()` has succeeded with a DSN. Plugins that\n * want to skip work when Sentry is disabled can check this before calling\n * the helpers below.\n */\nexport function isServerSentryEnabled(): boolean {\n return _initSucceeded;\n}\n\n/**\n * Attach the current request's user to Sentry's isolation scope so any\n * `captureException` triggered later in the request carries the right\n * `user.id` / `user.email` / `user.username` and `orgId` tag.\n *\n * Sentry node 10 uses Node's AsyncLocalStorage to give each async context\n * its own isolation scope, so setting on `getIsolationScope()` here only\n * affects events emitted while this request's async context is active.\n *\n * No-ops gracefully when Sentry isn't initialized or no session exists —\n * never throws into the request path.\n */\nexport function setSentryUserForRequest(session: AuthSession | null): void {\n if (!_initSucceeded) return;\n try {\n const scope = Sentry.getIsolationScope();\n if (!session) {\n scope.setUser(null);\n scope.setTag(\"orgId\", null);\n return;\n }\n scope.setUser({\n id: session.userId ?? session.email,\n email: session.email,\n username: session.name,\n });\n scope.setTag(\"orgId\", session.orgId ?? null);\n if (session.orgRole) {\n scope.setTag(\"orgRole\", session.orgRole);\n }\n } catch {\n // Sentry scope APIs should never throw, but if they do we'd rather\n // continue serving the request than crash on observability.\n }\n}\n\n/**\n * Pin a user/org onto the current isolation scope from a lighter\n * `RequestContext`-shaped payload. Used by the request-context observer so\n * action handlers, agent-chat runs, and integration webhook processors —\n * all of which already wrap their work in `runWithRequestContext({ userEmail,\n * orgId, ... })` — automatically tag Sentry events with the right user even\n * when the Nitro `request` hook didn't see a cookie (e.g. webhook delivery,\n * A2A calls, internal background runs).\n *\n * Skips overwriting a richer user identity already set by\n * `setSentryUserForRequest` — the cookie-resolved session has\n * userId/username on top of email, which we shouldn't clobber.\n */\nexport function setSentryRequestContext(ctx: {\n userEmail?: string;\n orgId?: string;\n}): void {\n if (!_initSucceeded) return;\n try {\n const scope = Sentry.getIsolationScope();\n if (ctx.userEmail) {\n const existing = scope.getScopeData().user;\n if (!existing?.id && !existing?.email) {\n scope.setUser({ id: ctx.userEmail, email: ctx.userEmail });\n }\n }\n if (ctx.orgId) {\n scope.setTag(\"orgId\", ctx.orgId);\n }\n } catch {\n // never throw\n }\n}\n\n/**\n * Capture an error from one of the auth attempt routes (login / signup)\n * with the email pinned to the event so support can filter by user. Sets\n * Sentry level to `warning` (not `error`) — bad-password attempts aren't\n * actionable, but a sustained spike of warnings on a route IS the signal\n * we care about.\n *\n * Caller should still return their normal HTTP response (401/409/etc.);\n * this just records the error for observability.\n */\nexport function captureAuthError(\n error: unknown,\n context: { route: \"login\" | \"signup\" | \"logout\"; email?: string },\n): string | undefined {\n if (!_initSucceeded) return undefined;\n try {\n return Sentry.withScope((scope) => {\n scope.setLevel(\"warning\");\n scope.setTag(\"auth\", context.route);\n if (context.email) {\n scope.setUser({ id: context.email, email: context.email });\n }\n return Sentry.captureException(error);\n });\n } catch {\n return undefined;\n }\n}\n\nexport interface RouteErrorContext {\n /** The full request path (e.g. `/_agent-native/agent-chat`). */\n route?: string;\n /** HTTP method (e.g. `GET`, `POST`). */\n method?: string;\n /** Caller's `User-Agent` header. */\n userAgent?: string;\n /** Free-form extra tags to add to the event (low-cardinality). */\n tags?: Record<string, string | undefined>;\n /**\n * High-cardinality / structured payload — not searchable but visible in\n * the Sentry event detail (recording IDs, byte counts, compression\n * metadata, response body tails, etc.).\n */\n extra?: Record<string, unknown>;\n /**\n * Grouped contexts shown as separate cards in the Sentry event UI.\n */\n contexts?: Record<string, Record<string, unknown>>;\n}\n\n/**\n * Capture an exception that surfaced in a Nitro route handler with the\n * request's route/method/userAgent attached as searchable Sentry tags.\n *\n * Non-throwing: if Sentry isn't initialized or the underlying capture\n * fails, this is a no-op. Returns the Sentry event ID when capture\n * succeeded, otherwise `undefined`.\n */\nexport function captureRouteError(\n error: unknown,\n context: RouteErrorContext = {},\n): string | undefined {\n if (!_initSucceeded) return undefined;\n try {\n return Sentry.withScope((scope) => {\n if (context.route) scope.setTag(\"route\", context.route);\n if (context.method) scope.setTag(\"method\", context.method);\n if (context.userAgent) scope.setTag(\"userAgent\", context.userAgent);\n if (context.tags) {\n for (const [k, v] of Object.entries(context.tags)) {\n if (typeof v === \"string\") scope.setTag(k, v);\n }\n }\n if (context.extra) {\n for (const [k, v] of Object.entries(context.extra)) {\n if (v !== undefined) scope.setExtra(k, v);\n }\n }\n if (context.contexts) {\n for (const [k, v] of Object.entries(context.contexts)) {\n scope.setContext(k, v);\n }\n }\n return Sentry.captureException(error);\n });\n } catch {\n return undefined;\n }\n}\n"]}
1
+ {"version":3,"file":"sentry.js","sourceRoot":"","sources":["../../src/server/sentry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Server-side Sentry initialization for Nitro.\n *\n * Errors thrown inside Nitro routes (the framework's own /_agent-native/*\n * handlers, the template's API routes, action handlers, agent-chat streams)\n * never reach the CLI's Sentry init — that only covers the developer's\n * machine. Without server-side Sentry the only signal a 500 ever produces\n * is a server-side console.error that lives and dies with the request.\n *\n * This module is the third Sentry init point in the framework:\n * - cli/index.ts → @sentry/node, hardcoded DSN, \"agent-native-cli\"\n * - client/analytics.ts → @sentry/browser, VITE_SENTRY_CLIENT_DSN / runtime config\n * - server/sentry.ts → @sentry/node, SENTRY_SERVER_DSN / SENTRY_DSN\n *\n * The browser and server can share a Sentry project/DSN. Separate projects\n * are an operational choice for noise, ownership, or quotas; not a runtime\n * requirement.\n */\nimport * as Sentry from \"@sentry/node\";\nimport path from \"node:path\";\nimport fs from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport type { AuthSession } from \"./auth.js\";\nimport {\n resolveSentryEnvironment,\n resolveServerSentryDsn,\n} from \"./sentry-config.js\";\n\nlet _initStarted = false;\nlet _initSucceeded = false;\n\n/**\n * Resolve the agent-native version baked into core's package.json so Sentry\n * \"release\" reflects the running framework version. Mirrors how the CLI\n * computes `_version` — same dist layout, same fallback string. Guarded so\n * a missing/unreadable package.json never crashes server boot.\n */\nfunction resolveServerRelease(): string {\n const explicit = process.env.AGENT_NATIVE_RELEASE;\n if (explicit) return explicit;\n try {\n const here = path.dirname(fileURLToPath(import.meta.url));\n // dist/server/sentry.js → ../../package.json\n const pkgPath = path.resolve(here, \"../../package.json\");\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\")) as {\n version?: string;\n };\n if (pkg?.version) return `agent-native-server@${pkg.version}`;\n } catch {\n // ignore — fall through to \"unknown\"\n }\n return \"agent-native-server@unknown\";\n}\n\nfunction parseTracesSampleRate(): number {\n const raw = process.env.SENTRY_SERVER_TRACES_SAMPLE_RATE;\n if (!raw) return 0;\n const n = Number(raw);\n if (!Number.isFinite(n) || n < 0 || n > 1) return 0;\n return n;\n}\n\n/**\n * Initialize server-side Sentry. Idempotent — safe to call from multiple\n * plugin entrypoints. Returns `true` if initialization actually happened\n * (DSN was set), `false` if Sentry is disabled (no DSN).\n *\n * No DSN is hardcoded: unlike the CLI (a published binary that always wants\n * to phone home crashes), the server runs in customer environments. Operators\n * set `SENTRY_SERVER_DSN` or the common `SENTRY_DSN` when they want their own\n * Sentry project to receive these events; without one the module no-ops.\n */\nexport function initServerSentry(): boolean {\n if (_initStarted) return _initSucceeded;\n _initStarted = true;\n\n const dsn = resolveServerSentryDsn();\n if (!dsn) {\n if (process.env.DEBUG) {\n console.log(\n \"[agent-native] SENTRY_SERVER_DSN/SENTRY_DSN not set — server Sentry disabled.\",\n );\n }\n return false;\n }\n\n Sentry.init({\n dsn,\n environment: resolveSentryEnvironment(),\n release: resolveServerRelease(),\n tracesSampleRate: parseTracesSampleRate(),\n // sendDefaultPii MUST stay false — the framework runs inside customer\n // environments and we never want to silently ship request headers,\n // cookies, or process.env contents to Sentry without explicit consent.\n sendDefaultPii: false,\n beforeSend(event) {\n // Drop expected user-input rejections so they don't pollute Sentry\n // with non-bug noise. Mirrors the CLI's drop list — the framework\n // and CLI both throw `ValidationError` for the same class of input\n // failures, and exception type comes through as the class name.\n const exceptionType = event.exception?.values?.[0]?.type;\n if (\n exceptionType === \"ValidationError\" ||\n event.tags?.handled === \"validation\"\n ) {\n return null;\n }\n // Drop access-control rejections (caller lacks permission, signed\n // out, etc.). These are 4xx user-facing errors that propagated to\n // Nitro's error hook because a route forgot to catch them — fixing\n // the route is the right answer, but in the meantime they bury\n // real bugs and don't represent server failures. Auth-routes use\n // `captureAuthError` directly with `level: warning` so this filter\n // only sees the generic-handler escape path.\n if (\n exceptionType === \"ForbiddenError\" ||\n exceptionType === \"UnauthorizedError\"\n ) {\n return null;\n }\n // h3's `createError({ statusCode: 4xx, ... })` produces an\n // `HTTPError` (h3 v2) / `H3Error` (h3 v1). 4xx HTTPErrors are\n // handler-controlled \"expected failure\" responses (404 not found,\n // 400 bad input) that route through Nitro's error hook just\n // because they bubble out of `defineEventHandler`. They aren't\n // bugs — they're the documented way to return a 4xx in h3.\n // Capture only when the statusCode looks like 5xx (real failure)\n // or is missing (generic Error masquerading as HTTPError).\n if (exceptionType === \"HTTPError\" || exceptionType === \"H3Error\") {\n const statusCode = (event.tags?.statusCode ??\n (\n event.contexts as\n | Record<string, Record<string, unknown>>\n | undefined\n )?.h3?.statusCode) as number | string | undefined;\n const code =\n typeof statusCode === \"string\"\n ? parseInt(statusCode, 10)\n : statusCode;\n if (typeof code === \"number\" && code >= 400 && code < 500) {\n return null;\n }\n // No statusCode in the event payload — fall back to matching the\n // common 4xx messages so handler-thrown 404/400/403/401 don't\n // pollute Sentry. This is a heuristic, but the alternatives\n // (every 4xx becomes a \"real\" issue, or we patch every route to\n // catch+return) are worse.\n const value = event.exception?.values?.[0]?.value ?? \"\";\n if (\n /^Cannot find any route matching/i.test(value) ||\n / not found$/i.test(value) ||\n /Unauthenticated$/i.test(value) ||\n /^No access to /i.test(value)\n ) {\n return null;\n }\n }\n\n // Defense in depth: scrub PII even if some integration auto-attached\n // request metadata despite sendDefaultPii: false.\n if (event.request) {\n if (event.request.headers) {\n const headers = event.request.headers as Record<string, string>;\n for (const k of Object.keys(headers)) {\n const lk = k.toLowerCase();\n if (\n lk === \"cookie\" ||\n lk === \"authorization\" ||\n lk === \"set-cookie\" ||\n lk === \"proxy-authorization\"\n ) {\n delete headers[k];\n }\n }\n }\n // Cookies live in their own field too.\n delete (event.request as Record<string, unknown>).cookies;\n }\n\n // Keep user info that was explicitly set via Sentry.setUser\n // (id/email/username) so we can attribute crashes back to a real\n // operator. Always strip ip_address — auto-collected, no consent.\n if (event.user) {\n const user = event.user as Record<string, unknown>;\n delete user.ip_address;\n const hasIdentity =\n typeof user.id === \"string\" ||\n typeof user.email === \"string\" ||\n typeof user.username === \"string\";\n if (!hasIdentity) {\n delete event.user;\n }\n }\n\n // Sentry's contexts can carry process.env snapshots — strip env-shaped\n // contexts so we don't leak deployment secrets.\n if (event.contexts && typeof event.contexts === \"object\") {\n delete (event.contexts as Record<string, unknown>).runtime_env;\n }\n\n return event;\n },\n });\n\n _initSucceeded = true;\n return true;\n}\n\n/**\n * `true` once `initServerSentry()` has succeeded with a DSN. Plugins that\n * want to skip work when Sentry is disabled can check this before calling\n * the helpers below.\n */\nexport function isServerSentryEnabled(): boolean {\n return _initSucceeded;\n}\n\n/**\n * Attach the current request's user to Sentry's isolation scope so any\n * `captureException` triggered later in the request carries the right\n * `user.id` / `user.email` / `user.username` and `orgId` tag.\n *\n * Sentry node 10 uses Node's AsyncLocalStorage to give each async context\n * its own isolation scope, so setting on `getIsolationScope()` here only\n * affects events emitted while this request's async context is active.\n *\n * No-ops gracefully when Sentry isn't initialized or no session exists —\n * never throws into the request path.\n */\nexport function setSentryUserForRequest(session: AuthSession | null): void {\n if (!_initSucceeded) return;\n try {\n const scope = Sentry.getIsolationScope();\n if (!session) {\n scope.setUser(null);\n scope.setTag(\"orgId\", null);\n return;\n }\n scope.setUser({\n id: session.userId ?? session.email,\n email: session.email,\n username: session.name,\n });\n scope.setTag(\"orgId\", session.orgId ?? null);\n if (session.orgRole) {\n scope.setTag(\"orgRole\", session.orgRole);\n }\n } catch {\n // Sentry scope APIs should never throw, but if they do we'd rather\n // continue serving the request than crash on observability.\n }\n}\n\n/**\n * Pin a user/org onto the current isolation scope from a lighter\n * `RequestContext`-shaped payload. Used by the request-context observer so\n * action handlers, agent-chat runs, and integration webhook processors —\n * all of which already wrap their work in `runWithRequestContext({ userEmail,\n * orgId, ... })` — automatically tag Sentry events with the right user even\n * when the Nitro `request` hook didn't see a cookie (e.g. webhook delivery,\n * A2A calls, internal background runs).\n *\n * Skips overwriting a richer user identity already set by\n * `setSentryUserForRequest` — the cookie-resolved session has\n * userId/username on top of email, which we shouldn't clobber.\n */\nexport function setSentryRequestContext(ctx: {\n userEmail?: string;\n orgId?: string;\n}): void {\n if (!_initSucceeded) return;\n try {\n const scope = Sentry.getIsolationScope();\n if (ctx.userEmail) {\n const existing = scope.getScopeData().user;\n if (!existing?.id && !existing?.email) {\n scope.setUser({ id: ctx.userEmail, email: ctx.userEmail });\n }\n }\n if (ctx.orgId) {\n scope.setTag(\"orgId\", ctx.orgId);\n }\n } catch {\n // never throw\n }\n}\n\n/**\n * Capture an error from one of the auth attempt routes (login / signup)\n * with the email pinned to the event so support can filter by user. Sets\n * Sentry level to `warning` (not `error`) — bad-password attempts aren't\n * actionable, but a sustained spike of warnings on a route IS the signal\n * we care about.\n *\n * Caller should still return their normal HTTP response (401/409/etc.);\n * this just records the error for observability.\n */\nexport function captureAuthError(\n error: unknown,\n context: { route: \"login\" | \"signup\" | \"logout\"; email?: string },\n): string | undefined {\n if (!_initSucceeded) return undefined;\n try {\n return Sentry.withScope((scope) => {\n scope.setLevel(\"warning\");\n scope.setTag(\"auth\", context.route);\n if (context.email) {\n scope.setUser({ id: context.email, email: context.email });\n }\n return Sentry.captureException(error);\n });\n } catch {\n return undefined;\n }\n}\n\nexport interface RouteErrorContext {\n /** The full request path (e.g. `/_agent-native/agent-chat`). */\n route?: string;\n /** HTTP method (e.g. `GET`, `POST`). */\n method?: string;\n /** Caller's `User-Agent` header. */\n userAgent?: string;\n /** Free-form extra tags to add to the event (low-cardinality). */\n tags?: Record<string, string | undefined>;\n /**\n * High-cardinality / structured payload — not searchable but visible in\n * the Sentry event detail (recording IDs, byte counts, compression\n * metadata, response body tails, etc.).\n */\n extra?: Record<string, unknown>;\n /**\n * Grouped contexts shown as separate cards in the Sentry event UI.\n */\n contexts?: Record<string, Record<string, unknown>>;\n}\n\n/**\n * Capture an exception that surfaced in a Nitro route handler with the\n * request's route/method/userAgent attached as searchable Sentry tags.\n *\n * Non-throwing: if Sentry isn't initialized or the underlying capture\n * fails, this is a no-op. Returns the Sentry event ID when capture\n * succeeded, otherwise `undefined`.\n */\nexport function captureRouteError(\n error: unknown,\n context: RouteErrorContext = {},\n): string | undefined {\n if (!_initSucceeded) return undefined;\n try {\n return Sentry.withScope((scope) => {\n if (context.route) scope.setTag(\"route\", context.route);\n if (context.method) scope.setTag(\"method\", context.method);\n if (context.userAgent) scope.setTag(\"userAgent\", context.userAgent);\n if (context.tags) {\n for (const [k, v] of Object.entries(context.tags)) {\n if (typeof v === \"string\") scope.setTag(k, v);\n }\n }\n if (context.extra) {\n for (const [k, v] of Object.entries(context.extra)) {\n if (v !== undefined) scope.setExtra(k, v);\n }\n }\n if (context.contexts) {\n for (const [k, v] of Object.entries(context.contexts)) {\n scope.setContext(k, v);\n }\n }\n return Sentry.captureException(error);\n });\n } catch {\n return undefined;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.13.1",
3
+ "version": "0.14.1",
4
4
  "type": "module",
5
5
  "description": "Framework for agent-native application development — where AI agents and UI share state via files",
6
6
  "license": "MIT",