@danieljvdm/dev-kit 1.0.1 → 2.0.0

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 (330) hide show
  1. package/README.md +6 -6
  2. package/package.json +1 -1
  3. package/skill-sources.jsonc +6 -29
  4. package/skill-sources.lock.json +23 -109
  5. package/skills/animate/LICENSE +21 -0
  6. package/skills/animate/NOTICE +10 -0
  7. package/skills/animate/SKILL.md +34 -0
  8. package/skills/animate/references/gestures.md +27 -0
  9. package/skills/animate/references/glossary.md +136 -0
  10. package/skills/animate/references/implementation.md +22 -0
  11. package/skills/animate/references/opportunities.md +18 -0
  12. package/skills/animate/references/principles.md +48 -0
  13. package/skills/animate/references/review.md +19 -0
  14. package/skills/cloudflare-workers/LICENSE +202 -0
  15. package/skills/cloudflare-workers/NOTICE +9 -0
  16. package/skills/cloudflare-workers/SKILL.md +26 -0
  17. package/skills/cloudflare-workers/references/durable-objects.md +68 -0
  18. package/skills/cloudflare-workers/references/sandbox.md +48 -0
  19. package/skills/cloudflare-workers/references/workers.md +63 -0
  20. package/skills/cloudflare-workers/references/wrangler.md +56 -0
  21. package/skills/design-ui/LICENSE +21 -0
  22. package/skills/design-ui/NOTICE +8 -0
  23. package/skills/design-ui/SKILL.md +29 -0
  24. package/skills/design-ui/references/appearance.md +22 -0
  25. package/skills/design-ui/references/components.md +33 -0
  26. package/skills/design-ui/references/exploration.md +50 -0
  27. package/skills/design-ui/references/libraries.md +39 -0
  28. package/skills/design-ui/references/themes.md +23 -0
  29. package/skills/dev-kit/SKILL.md +19 -38
  30. package/skills/dev-kit/references/cloudflare-worker-api.md +1 -1
  31. package/skills/dev-kit/references/skills.md +2 -2
  32. package/skills/effect-development/SKILL.md +27 -0
  33. package/skills/effect-development/agents/openai.yaml +4 -0
  34. package/skills/effect-development/references/api/index.md +32 -0
  35. package/skills/effect-development/references/api/schema-codecs.md +15 -0
  36. package/skills/{build-effect-apis/references → effect-development/references/api}/verification.md +10 -5
  37. package/skills/{effect-architecture-audit/SKILL.md → effect-development/references/architecture/index.md} +1 -6
  38. package/skills/{effect-atom-state/references → effect-development/references/atom}/effect-atom-client.md +8 -6
  39. package/skills/{effect-atom-state/references → effect-development/references/atom}/effect-atom-testing.md +7 -2
  40. package/skills/effect-development/references/atom/index.md +40 -0
  41. package/skills/{build-effect-clis/references → effect-development/references/cli}/entrypoints-and-testing.md +6 -2
  42. package/skills/effect-development/references/cli/index.md +39 -0
  43. package/skills/effect-development/references/setup.md +15 -0
  44. package/skills/open-pull-request/SKILL.md +11 -115
  45. package/skills/open-pull-request/agents/openai.yaml +3 -3
  46. package/skills/open-pull-request/references/evidence.md +22 -0
  47. package/skills/open-pull-request/references/explanation.md +21 -0
  48. package/skills/open-pull-request/references/publication.md +21 -0
  49. package/skills/sentry/LICENSE +202 -0
  50. package/skills/sentry/LICENSE-UPSTREAM +21 -0
  51. package/skills/sentry/NOTICE +14 -0
  52. package/skills/sentry/SKILL.md +33 -0
  53. package/skills/sentry/references/alert-payloads.md +105 -0
  54. package/skills/sentry/references/alerts.md +17 -0
  55. package/skills/sentry/references/artifacts.md +25 -0
  56. package/skills/sentry/references/auth-token.md +65 -0
  57. package/skills/sentry/references/concepts/ai-monitoring.md +131 -0
  58. package/skills/sentry/references/concepts/choosing-a-signal.md +78 -0
  59. package/skills/sentry/references/concepts/crons.md +50 -0
  60. package/skills/sentry/references/concepts/data-scrubbing.md +43 -0
  61. package/skills/sentry/references/concepts/errors.md +40 -0
  62. package/skills/sentry/references/concepts/logging.md +85 -0
  63. package/skills/sentry/references/concepts/metrics.md +49 -0
  64. package/skills/sentry/references/concepts/monitors.md +78 -0
  65. package/skills/sentry/references/concepts/profiling.md +38 -0
  66. package/skills/sentry/references/concepts/reduce-volume.md +49 -0
  67. package/skills/sentry/references/concepts/releases.md +43 -0
  68. package/skills/sentry/references/concepts/session-replay.md +35 -0
  69. package/skills/sentry/references/concepts/tracing.md +54 -0
  70. package/skills/sentry/references/concepts/user-feedback.md +36 -0
  71. package/skills/sentry/references/debug-artifacts/android.md +68 -0
  72. package/skills/sentry/references/debug-artifacts/apple.md +96 -0
  73. package/skills/sentry/references/debug-artifacts/dotnet.md +70 -0
  74. package/skills/sentry/references/debug-artifacts/flutter.md +65 -0
  75. package/skills/sentry/references/debug-artifacts/index.md +75 -0
  76. package/skills/sentry/references/debug-artifacts/javascript.md +94 -0
  77. package/skills/sentry/references/debug-artifacts/matching.md +73 -0
  78. package/skills/sentry/references/debug-artifacts/react-native.md +75 -0
  79. package/skills/sentry/references/first-error-setup.md +25 -0
  80. package/skills/sentry/references/instrumentation.md +30 -0
  81. package/skills/sentry/references/issues.md +32 -0
  82. package/skills/sentry/references/new-project.md +17 -0
  83. package/skills/sentry/references/otel-exporter.md +30 -0
  84. package/skills/sentry/references/release-workflow.md +31 -0
  85. package/skills/sentry/references/releases/ci-pipeline.md +214 -0
  86. package/skills/sentry/references/releases/index.md +93 -0
  87. package/skills/sentry/references/releases/suspect-commits.md +155 -0
  88. package/skills/sentry/references/releases/tagging.md +131 -0
  89. package/skills/sentry/references/releases/troubleshooting.md +67 -0
  90. package/skills/sentry/references/sdks/android/crons.md +305 -0
  91. package/skills/sentry/references/sdks/android/error-monitoring.md +800 -0
  92. package/skills/sentry/references/sdks/android/index.md +748 -0
  93. package/skills/sentry/references/sdks/android/integrations.md +48 -0
  94. package/skills/sentry/references/sdks/android/logging.md +374 -0
  95. package/skills/sentry/references/sdks/android/metrics.md +288 -0
  96. package/skills/sentry/references/sdks/android/profiling.md +397 -0
  97. package/skills/sentry/references/sdks/android/session-replay.md +406 -0
  98. package/skills/sentry/references/sdks/android/tracing.md +861 -0
  99. package/skills/sentry/references/sdks/browser/error-monitoring.md +861 -0
  100. package/skills/sentry/references/sdks/browser/index.md +714 -0
  101. package/skills/sentry/references/sdks/browser/logging.md +315 -0
  102. package/skills/sentry/references/sdks/browser/profiling.md +236 -0
  103. package/skills/sentry/references/sdks/browser/session-replay.md +586 -0
  104. package/skills/sentry/references/sdks/browser/tracing.md +561 -0
  105. package/skills/sentry/references/sdks/browser/user-feedback.md +354 -0
  106. package/skills/sentry/references/sdks/cloudflare/ai-monitoring.md +661 -0
  107. package/skills/sentry/references/sdks/cloudflare/crons.md +231 -0
  108. package/skills/sentry/references/sdks/cloudflare/durable-objects.md +381 -0
  109. package/skills/sentry/references/sdks/cloudflare/error-monitoring.md +329 -0
  110. package/skills/sentry/references/sdks/cloudflare/index.md +698 -0
  111. package/skills/sentry/references/sdks/cloudflare/logging.md +169 -0
  112. package/skills/sentry/references/sdks/cloudflare/nodejs-compat.md +134 -0
  113. package/skills/sentry/references/sdks/cloudflare/tracing.md +475 -0
  114. package/skills/sentry/references/sdks/cocoa/error-monitoring.md +394 -0
  115. package/skills/sentry/references/sdks/cocoa/index.md +497 -0
  116. package/skills/sentry/references/sdks/cocoa/logging.md +209 -0
  117. package/skills/sentry/references/sdks/cocoa/metrics.md +136 -0
  118. package/skills/sentry/references/sdks/cocoa/profiling.md +223 -0
  119. package/skills/sentry/references/sdks/cocoa/session-replay.md +257 -0
  120. package/skills/sentry/references/sdks/cocoa/tracing.md +524 -0
  121. package/skills/sentry/references/sdks/cocoa/user-feedback.md +310 -0
  122. package/skills/sentry/references/sdks/dotnet/crons.md +465 -0
  123. package/skills/sentry/references/sdks/dotnet/error-monitoring.md +1100 -0
  124. package/skills/sentry/references/sdks/dotnet/index.md +614 -0
  125. package/skills/sentry/references/sdks/dotnet/logging.md +556 -0
  126. package/skills/sentry/references/sdks/dotnet/metrics.md +229 -0
  127. package/skills/sentry/references/sdks/dotnet/profiling.md +296 -0
  128. package/skills/sentry/references/sdks/dotnet/tracing.md +897 -0
  129. package/skills/sentry/references/sdks/elixir/crons.md +371 -0
  130. package/skills/sentry/references/sdks/elixir/error-monitoring.md +335 -0
  131. package/skills/sentry/references/sdks/elixir/index.md +383 -0
  132. package/skills/sentry/references/sdks/elixir/logging.md +239 -0
  133. package/skills/sentry/references/sdks/elixir/tracing.md +233 -0
  134. package/skills/sentry/references/sdks/flutter/ecosystem-integrations.md +70 -0
  135. package/skills/sentry/references/sdks/flutter/error-monitoring.md +312 -0
  136. package/skills/sentry/references/sdks/flutter/index.md +728 -0
  137. package/skills/sentry/references/sdks/flutter/logging.md +387 -0
  138. package/skills/sentry/references/sdks/flutter/metrics.md +310 -0
  139. package/skills/sentry/references/sdks/flutter/profiling.md +214 -0
  140. package/skills/sentry/references/sdks/flutter/session-replay.md +308 -0
  141. package/skills/sentry/references/sdks/flutter/tracing.md +502 -0
  142. package/skills/sentry/references/sdks/go/crons.md +270 -0
  143. package/skills/sentry/references/sdks/go/error-monitoring.md +361 -0
  144. package/skills/sentry/references/sdks/go/index.md +324 -0
  145. package/skills/sentry/references/sdks/go/logging.md +354 -0
  146. package/skills/sentry/references/sdks/go/metrics.md +273 -0
  147. package/skills/sentry/references/sdks/go/profiling.md +46 -0
  148. package/skills/sentry/references/sdks/go/tracing.md +366 -0
  149. package/skills/sentry/references/sdks/index.md +41 -0
  150. package/skills/sentry/references/sdks/nestjs/ai-monitoring.md +410 -0
  151. package/skills/sentry/references/sdks/nestjs/crons.md +268 -0
  152. package/skills/sentry/references/sdks/nestjs/error-monitoring.md +729 -0
  153. package/skills/sentry/references/sdks/nestjs/index.md +699 -0
  154. package/skills/sentry/references/sdks/nestjs/logging.md +174 -0
  155. package/skills/sentry/references/sdks/nestjs/metrics.md +243 -0
  156. package/skills/sentry/references/sdks/nestjs/profiling.md +127 -0
  157. package/skills/sentry/references/sdks/nestjs/tracing.md +762 -0
  158. package/skills/sentry/references/sdks/nextjs/ai-monitoring.md +494 -0
  159. package/skills/sentry/references/sdks/nextjs/crons.md +383 -0
  160. package/skills/sentry/references/sdks/nextjs/error-monitoring.md +974 -0
  161. package/skills/sentry/references/sdks/nextjs/index.md +491 -0
  162. package/skills/sentry/references/sdks/nextjs/logging.md +381 -0
  163. package/skills/sentry/references/sdks/nextjs/metrics.md +411 -0
  164. package/skills/sentry/references/sdks/nextjs/profiling.md +403 -0
  165. package/skills/sentry/references/sdks/nextjs/session-replay.md +462 -0
  166. package/skills/sentry/references/sdks/nextjs/tracing.md +628 -0
  167. package/skills/sentry/references/sdks/node/ai-monitoring.md +303 -0
  168. package/skills/sentry/references/sdks/node/crons.md +432 -0
  169. package/skills/sentry/references/sdks/node/error-monitoring.md +1125 -0
  170. package/skills/sentry/references/sdks/node/index.md +942 -0
  171. package/skills/sentry/references/sdks/node/logging.md +380 -0
  172. package/skills/sentry/references/sdks/node/metrics.md +278 -0
  173. package/skills/sentry/references/sdks/node/profiling.md +373 -0
  174. package/skills/sentry/references/sdks/node/tracing.md +878 -0
  175. package/skills/sentry/references/sdks/php/ai-monitoring.md +310 -0
  176. package/skills/sentry/references/sdks/php/crons.md +265 -0
  177. package/skills/sentry/references/sdks/php/error-monitoring.md +626 -0
  178. package/skills/sentry/references/sdks/php/index.md +362 -0
  179. package/skills/sentry/references/sdks/php/laravel.md +542 -0
  180. package/skills/sentry/references/sdks/php/logging.md +242 -0
  181. package/skills/sentry/references/sdks/php/metrics.md +193 -0
  182. package/skills/sentry/references/sdks/php/profiling.md +115 -0
  183. package/skills/sentry/references/sdks/php/symfony.md +552 -0
  184. package/skills/sentry/references/sdks/php/tracing.md +516 -0
  185. package/skills/sentry/references/sdks/python/ai-monitoring.md +351 -0
  186. package/skills/sentry/references/sdks/python/crons.md +218 -0
  187. package/skills/sentry/references/sdks/python/error-monitoring.md +292 -0
  188. package/skills/sentry/references/sdks/python/index.md +361 -0
  189. package/skills/sentry/references/sdks/python/logging.md +234 -0
  190. package/skills/sentry/references/sdks/python/metrics.md +154 -0
  191. package/skills/sentry/references/sdks/python/profiling.md +120 -0
  192. package/skills/sentry/references/sdks/python/tracing.md +364 -0
  193. package/skills/sentry/references/sdks/react/error-monitoring.md +1607 -0
  194. package/skills/sentry/references/sdks/react/index.md +492 -0
  195. package/skills/sentry/references/sdks/react/logging.md +364 -0
  196. package/skills/sentry/references/sdks/react/profiling.md +322 -0
  197. package/skills/sentry/references/sdks/react/react-features.md +1272 -0
  198. package/skills/sentry/references/sdks/react/session-replay.md +1193 -0
  199. package/skills/sentry/references/sdks/react/tracing.md +1415 -0
  200. package/skills/sentry/references/sdks/react-native/error-monitoring.md +1481 -0
  201. package/skills/sentry/references/sdks/react-native/expo-config-plugin.md +45 -0
  202. package/skills/sentry/references/sdks/react-native/index.md +1030 -0
  203. package/skills/sentry/references/sdks/react-native/logging.md +444 -0
  204. package/skills/sentry/references/sdks/react-native/profiling.md +386 -0
  205. package/skills/sentry/references/sdks/react-native/session-replay.md +704 -0
  206. package/skills/sentry/references/sdks/react-native/tracing.md +1086 -0
  207. package/skills/sentry/references/sdks/react-native/user-feedback.md +815 -0
  208. package/skills/sentry/references/sdks/react-router-framework/error-monitoring.md +127 -0
  209. package/skills/sentry/references/sdks/react-router-framework/index.md +411 -0
  210. package/skills/sentry/references/sdks/react-router-framework/logging.md +66 -0
  211. package/skills/sentry/references/sdks/react-router-framework/profiling.md +57 -0
  212. package/skills/sentry/references/sdks/react-router-framework/react-router-framework-features.md +110 -0
  213. package/skills/sentry/references/sdks/react-router-framework/session-replay.md +67 -0
  214. package/skills/sentry/references/sdks/react-router-framework/tracing.md +96 -0
  215. package/skills/sentry/references/sdks/react-router-framework/user-feedback.md +71 -0
  216. package/skills/sentry/references/sdks/ruby/crons.md +184 -0
  217. package/skills/sentry/references/sdks/ruby/error-monitoring.md +248 -0
  218. package/skills/sentry/references/sdks/ruby/index.md +297 -0
  219. package/skills/sentry/references/sdks/ruby/logging.md +168 -0
  220. package/skills/sentry/references/sdks/ruby/metrics.md +196 -0
  221. package/skills/sentry/references/sdks/ruby/migration.md +321 -0
  222. package/skills/sentry/references/sdks/ruby/profiling.md +107 -0
  223. package/skills/sentry/references/sdks/ruby/tracing.md +388 -0
  224. package/skills/sentry/references/sdks/svelte/error-monitoring.md +456 -0
  225. package/skills/sentry/references/sdks/svelte/index.md +467 -0
  226. package/skills/sentry/references/sdks/svelte/logging.md +344 -0
  227. package/skills/sentry/references/sdks/svelte/session-replay.md +369 -0
  228. package/skills/sentry/references/sdks/svelte/tracing.md +406 -0
  229. package/skills/sentry/references/sdks/tanstack-start/error-monitoring.md +149 -0
  230. package/skills/sentry/references/sdks/tanstack-start/index.md +381 -0
  231. package/skills/sentry/references/sdks/tanstack-start/logging.md +74 -0
  232. package/skills/sentry/references/sdks/tanstack-start/session-replay.md +76 -0
  233. package/skills/sentry/references/sdks/tanstack-start/tanstackstart-features.md +128 -0
  234. package/skills/sentry/references/sdks/tanstack-start/tracing.md +123 -0
  235. package/skills/sentry/references/sdks/tanstack-start/user-feedback.md +81 -0
  236. package/skills/sentry/references/search-query-language.md +226 -0
  237. package/skills/sentry/references/semantics/angular.md +7 -0
  238. package/skills/sentry/references/semantics/app.md +28 -0
  239. package/skills/sentry/references/semantics/art.md +17 -0
  240. package/skills/sentry/references/semantics/aws.md +43 -0
  241. package/skills/sentry/references/semantics/browser.md +34 -0
  242. package/skills/sentry/references/semantics/cache.md +12 -0
  243. package/skills/sentry/references/semantics/client.md +8 -0
  244. package/skills/sentry/references/semantics/cloud.md +12 -0
  245. package/skills/sentry/references/semantics/cloudflare.md +23 -0
  246. package/skills/sentry/references/semantics/code.md +11 -0
  247. package/skills/sentry/references/semantics/culture.md +11 -0
  248. package/skills/sentry/references/semantics/db.md +21 -0
  249. package/skills/sentry/references/semantics/device.md +43 -0
  250. package/skills/sentry/references/semantics/error.md +7 -0
  251. package/skills/sentry/references/semantics/event.md +8 -0
  252. package/skills/sentry/references/semantics/exception.md +10 -0
  253. package/skills/sentry/references/semantics/faas.md +19 -0
  254. package/skills/sentry/references/semantics/file.md +8 -0
  255. package/skills/sentry/references/semantics/flag.md +7 -0
  256. package/skills/sentry/references/semantics/gcp.md +16 -0
  257. package/skills/sentry/references/semantics/gen_ai.md +53 -0
  258. package/skills/sentry/references/semantics/general.md +11 -0
  259. package/skills/sentry/references/semantics/graphql.md +9 -0
  260. package/skills/sentry/references/semantics/grpc.md +19 -0
  261. package/skills/sentry/references/semantics/http.md +34 -0
  262. package/skills/sentry/references/semantics/index.md +63 -0
  263. package/skills/sentry/references/semantics/jsonrpc.md +8 -0
  264. package/skills/sentry/references/semantics/jvm.md +12 -0
  265. package/skills/sentry/references/semantics/koa.md +7 -0
  266. package/skills/sentry/references/semantics/logger.md +7 -0
  267. package/skills/sentry/references/semantics/mcp.md +37 -0
  268. package/skills/sentry/references/semantics/mdc.md +7 -0
  269. package/skills/sentry/references/semantics/messaging.md +23 -0
  270. package/skills/sentry/references/semantics/middleware.md +7 -0
  271. package/skills/sentry/references/semantics/navigation.md +9 -0
  272. package/skills/sentry/references/semantics/nel.md +11 -0
  273. package/skills/sentry/references/semantics/network.md +17 -0
  274. package/skills/sentry/references/semantics/os.md +15 -0
  275. package/skills/sentry/references/semantics/otel.md +10 -0
  276. package/skills/sentry/references/semantics/params.md +7 -0
  277. package/skills/sentry/references/semantics/process.md +14 -0
  278. package/skills/sentry/references/semantics/react.md +7 -0
  279. package/skills/sentry/references/semantics/remix.md +7 -0
  280. package/skills/sentry/references/semantics/resource.md +7 -0
  281. package/skills/sentry/references/semantics/rpc.md +10 -0
  282. package/skills/sentry/references/semantics/score.md +10 -0
  283. package/skills/sentry/references/semantics/sentry.md +69 -0
  284. package/skills/sentry/references/semantics/server.md +8 -0
  285. package/skills/sentry/references/semantics/service.md +8 -0
  286. package/skills/sentry/references/semantics/session.md +7 -0
  287. package/skills/sentry/references/semantics/state.md +7 -0
  288. package/skills/sentry/references/semantics/thread.md +8 -0
  289. package/skills/sentry/references/semantics/timber.md +7 -0
  290. package/skills/sentry/references/semantics/trpc.md +8 -0
  291. package/skills/sentry/references/semantics/ui.md +18 -0
  292. package/skills/sentry/references/semantics/url.md +15 -0
  293. package/skills/sentry/references/semantics/user.md +17 -0
  294. package/skills/sentry/references/semantics/user_agent.md +7 -0
  295. package/skills/sentry/references/semantics/vercel.md +42 -0
  296. package/skills/sentry/references/setup-verification.md +39 -0
  297. package/skills/sentry/references/snapshots/github-actions-fanout.md +206 -0
  298. package/skills/sentry/references/snapshots/github-actions-simple.md +102 -0
  299. package/skills/sentry/references/snapshots/github-actions-swift-snapshot-testing.md +118 -0
  300. package/skills/sentry/references/snapshots/index.md +19 -0
  301. package/skills/sentry/references/snapshots/snapshot-previews.md +100 -0
  302. package/skills/sentry/references/snapshots/snapshots.md +123 -0
  303. package/skills/sentry/references/snapshots/wizard-setup.md +134 -0
  304. package/skills/testing/LICENSE +21 -0
  305. package/skills/testing/NOTICE +7 -0
  306. package/skills/testing/SKILL.md +13 -19
  307. package/skills/testing/agents/openai.yaml +1 -2
  308. package/skills/testing/references/selection.md +23 -0
  309. package/skills/testing/references/tdd.md +19 -0
  310. package/skills/testing/references/test-design.md +17 -0
  311. package/src/catalog.ts +1 -7
  312. package/skills/build-effect-apis/SKILL.md +0 -81
  313. package/skills/build-effect-apis/agents/openai.yaml +0 -4
  314. package/skills/build-effect-clis/SKILL.md +0 -92
  315. package/skills/build-effect-clis/agents/openai.yaml +0 -4
  316. package/skills/effect-architecture-audit/agents/openai.yaml +0 -4
  317. package/skills/effect-atom-state/SKILL.md +0 -97
  318. package/skills/effect-atom-state/agents/openai.yaml +0 -4
  319. package/skills/effect-ts/SKILL.md +0 -35
  320. package/skills/effect-ts/agents/openai.yaml +0 -4
  321. /package/skills/{build-effect-apis/references → effect-development/references/api}/cloudflare-workers.md +0 -0
  322. /package/skills/{build-effect-apis/references → effect-development/references/api}/runtime-assembly.md +0 -0
  323. /package/skills/{build-effect-apis/references → effect-development/references/api}/server-and-middleware.md +0 -0
  324. /package/skills/{build-effect-apis/references → effect-development/references/api}/shared-contracts.md +0 -0
  325. /package/skills/{effect-architecture-audit/references → effect-development/references/architecture}/service-and-boundary-audit.md +0 -0
  326. /package/skills/{effect-atom-state/references → effect-development/references/atom}/effect-atom-lifecycle.md +0 -0
  327. /package/skills/{effect-atom-state/references → effect-development/references/atom}/effect-atom-workflows.md +0 -0
  328. /package/skills/{effect-atom-state/references → effect-development/references/atom}/tanstack-start.md +0 -0
  329. /package/skills/{build-effect-clis/references → effect-development/references/cli}/command-design.md +0 -0
  330. /package/skills/{build-effect-clis/references → effect-development/references/cli}/processes-and-platform.md +0 -0
@@ -0,0 +1,1607 @@
1
+ # Error Monitoring — Sentry React SDK
2
+
3
+ > Minimum SDK: `@sentry/react` ≥8.0.0+\
4
+ > `captureReactException()` requires `@sentry/react` ≥9.8.0\
5
+ > `reactErrorHandler()` requires `@sentry/react` ≥8.6.0
6
+
7
+ ---
8
+
9
+ ## How Automatic Capture Works
10
+
11
+ The React SDK hooks into the browser environment and captures errors automatically from
12
+ multiple layers:
13
+
14
+ | Layer | Mechanism | Integration |
15
+ | ---------------------------------------------------------------- | ----------------------------------------- | ------------------------------- |
16
+ | Uncaught JS exceptions | `window.onerror` | `GlobalHandlers` (default on) |
17
+ | Unhandled promise rejections | `window.onunhandledrejection` | `GlobalHandlers` (default on) |
18
+ | Errors in `setTimeout` / `setInterval` / `requestAnimationFrame` | Patched browser APIs | `BrowserApiErrors` (default on) |
19
+ | React render errors (React <19) | `componentDidCatch` via `<ErrorBoundary>` | `Sentry.ErrorBoundary` |
20
+ | React render errors (React 19+) | `createRoot` hooks | `Sentry.reactErrorHandler()` |
21
+ | Console errors (optional) | Patched `console.error` | `CaptureConsole` (opt-in) |
22
+
23
+ ### What Requires Manual Instrumentation
24
+
25
+ The global handlers only catch errors that **escape** your code.
26
+ These are silently swallowed without manual calls:
27
+
28
+ - Errors caught by your own `try/catch` blocks
29
+ - Errors swallowed by React Router’s default error boundary
30
+ - Business-logic failures (validation errors, unexpected states)
31
+ - Async errors inside `Promise.then()` chains where `.catch()` is attached
32
+ - User-visible conditions that aren’t exceptions (use `captureMessage`)
33
+
34
+ ### Disabling or Customizing Automatic Capture
35
+
36
+ ```javascript
37
+ Sentry.init({
38
+ integrations: [
39
+ Sentry.globalHandlersIntegration({
40
+ onerror: true,
41
+ onunhandledrejection: false, // handle rejections manually
42
+ }),
43
+ ],
44
+ });
45
+
46
+ // Manual rejection handler:
47
+ window.addEventListener("unhandledrejection", (event) => {
48
+ Sentry.captureException(event.reason);
49
+ });
50
+ ```
51
+
52
+ ---
53
+
54
+ ## React Error Boundaries
55
+
56
+ ### Strategy: React 19+ vs. React ≤18
57
+
58
+ | | React ≤18 | React 19+ |
59
+ | -------------------------- | ----------------------------------------- | -------------------------------------------- |
60
+ | **Global error reporting** | `window.onerror` + `Sentry.ErrorBoundary` | `Sentry.reactErrorHandler()` on `createRoot` |
61
+ | **Scoped fallback UI** | `<Sentry.ErrorBoundary>` | `<Sentry.ErrorBoundary>` (still required) |
62
+ | **Complementary?** | N/A | ✅ Use both together |
63
+
64
+ ---
65
+
66
+ ### React 19+ — `Sentry.reactErrorHandler()` with `createRoot`
67
+
68
+ React 19 exposes three hooks on `createRoot` and `hydrateRoot`. Pass
69
+ `Sentry.reactErrorHandler()` to each one.
70
+ Requires `@sentry/react` ≥8.6.0.
71
+
72
+ ```jsx
73
+ // src/main.tsx
74
+ import { createRoot } from "react-dom/client";
75
+ import * as Sentry from "@sentry/react";
76
+
77
+ Sentry.init({ dsn: "___PUBLIC_DSN___" });
78
+
79
+ const container = document.getElementById("app")!;
80
+
81
+ createRoot(container, {
82
+ // Fires for errors that bubble up WITHOUT any ErrorBoundary catching them.
83
+ // These are fatal — the entire React tree unmounts.
84
+ onUncaughtError: Sentry.reactErrorHandler((error, errorInfo) => {
85
+ // Optional: runs AFTER Sentry has already captured the error
86
+ console.warn("Uncaught React error:", error.message);
87
+ console.warn("Component stack:", errorInfo.componentStack);
88
+ }),
89
+
90
+ // Fires for errors caught BY an ErrorBoundary (React 19 re-routes caught errors here).
91
+ // The boundary still renders its fallback UI — this is just the reporting hook.
92
+ onCaughtError: Sentry.reactErrorHandler(),
93
+
94
+ // Fires when React recovers from an error automatically (e.g. hydration mismatch).
95
+ onRecoverableError: Sentry.reactErrorHandler(),
96
+ }).render(<App />);
97
+ ```
98
+
99
+ **SSR / `hydrateRoot`:**
100
+
101
+ ```jsx
102
+ import { hydrateRoot } from "react-dom/client";
103
+ import * as Sentry from "@sentry/react";
104
+
105
+ hydrateRoot(document.getElementById("app")!, <App />, {
106
+ onUncaughtError: Sentry.reactErrorHandler(),
107
+ onCaughtError: Sentry.reactErrorHandler(),
108
+ onRecoverableError: Sentry.reactErrorHandler(),
109
+ });
110
+ ```
111
+
112
+ **Key behavior differences between the three hooks:**
113
+
114
+ | Hook | Fires when … | Tree state after |
115
+ | -------------------- | ------------------------------------ | ------------------------- |
116
+ | `onUncaughtError` | Error escapes all boundaries | Tree unmounts (fatal) |
117
+ | `onCaughtError` | ErrorBoundary catches the error | Boundary renders fallback |
118
+ | `onRecoverableError` | React auto-recovers (e.g. hydration) | Tree continues rendering |
119
+
120
+ #### React 19 + ErrorBoundary Together (Recommended Pattern)
121
+
122
+ `reactErrorHandler()` is the global net.
123
+ `<Sentry.ErrorBoundary>` provides scoped fallback UIs.
124
+ Use both:
125
+
126
+ ```jsx
127
+ // src/main.tsx — global net via reactErrorHandler
128
+ createRoot(document.getElementById("root")!, {
129
+ onUncaughtError: Sentry.reactErrorHandler(),
130
+ onCaughtError: Sentry.reactErrorHandler(),
131
+ onRecoverableError: Sentry.reactErrorHandler(),
132
+ }).render(<App />);
133
+
134
+ // src/App.tsx — scoped fallback UIs via ErrorBoundary
135
+ function App() {
136
+ return (
137
+ <Layout>
138
+ <Sentry.ErrorBoundary fallback={<NavError />}>
139
+ <Navigation />
140
+ </Sentry.ErrorBoundary>
141
+ <Sentry.ErrorBoundary fallback={<DashboardError />}>
142
+ <Dashboard />
143
+ </Sentry.ErrorBoundary>
144
+ </Layout>
145
+ );
146
+ }
147
+ ```
148
+
149
+ ---
150
+
151
+ ### `<Sentry.ErrorBoundary>` — Full Props Reference
152
+
153
+ Works with React 16+. Catches errors in its subtree, reports them to Sentry, and renders
154
+ a fallback UI.
155
+
156
+ ```typescript
157
+ // Full TypeScript signature
158
+ interface ErrorBoundaryProps {
159
+ // Fallback UI — static element or render function
160
+ fallback?: React.ReactNode | FallbackRender;
161
+ // FallbackRender receives: { error: Error; componentStack: string; resetError: () => void }
162
+
163
+ // Called immediately when a child throws
164
+ onError?: (error: Error, componentStack: string, eventId: string) => void;
165
+
166
+ // Called with the Sentry Scope before the error is captured — enrich here
167
+ beforeCapture?: (scope: Scope, error: Error, componentStack: string) => void;
168
+
169
+ // Called when resetError() is invoked from the fallback
170
+ onReset?: (error: Error | null, componentStack: string | null, eventId: string | null) => void;
171
+
172
+ // Lifecycle hooks
173
+ onMount?: () => void;
174
+ onUnmount?: (error: Error | null) => void;
175
+
176
+ // User feedback dialog — shown automatically on error
177
+ showDialog?: boolean;
178
+ dialogOptions?: ReportDialogOptions;
179
+ }
180
+ ```
181
+
182
+ ---
183
+
184
+ #### `fallback` — Render Fallback UI on Error
185
+
186
+ ```jsx
187
+ // 1. Static element
188
+ <Sentry.ErrorBoundary fallback={<p>Something went wrong. Please refresh.</p>}>
189
+ <Dashboard />
190
+ </Sentry.ErrorBoundary>
191
+
192
+ // 2. Render function — access error details and reset handler
193
+ <Sentry.ErrorBoundary
194
+ fallback={({ error, componentStack, resetError }) => (
195
+ <div className="error-state">
196
+ <h2>Something broke</h2>
197
+ <p><strong>Error:</strong> {error.message}</p>
198
+ <details>
199
+ <summary>Component stack</summary>
200
+ <pre style={{ fontSize: 12 }}>{componentStack}</pre>
201
+ </details>
202
+ <button onClick={resetError}>↺ Try Again</button>
203
+ </div>
204
+ )}
205
+ >
206
+ <Dashboard />
207
+ </Sentry.ErrorBoundary>
208
+ ```
209
+
210
+ **`resetError()`** resets the boundary’s internal state and re-attempts rendering
211
+ children. Use it for retry UIs.
212
+
213
+ ---
214
+
215
+ #### `onError` — React to a Captured Error
216
+
217
+ Called immediately when a child throws.
218
+ Receives the error, component stack, and the Sentry event ID (useful for linking user
219
+ feedback to the event).
220
+
221
+ ```jsx
222
+ <Sentry.ErrorBoundary
223
+ onError={(error, componentStack, eventId) => {
224
+ // Report to your own analytics
225
+ myAnalytics.track("error_boundary_triggered", {
226
+ errorMessage: error.message,
227
+ sentryEventId: eventId,
228
+ });
229
+ // Dispatch to Redux or Zustand
230
+ store.dispatch(setGlobalError({ error, eventId }));
231
+ // Show feedback dialog linked to this event
232
+ Sentry.showReportDialog({ eventId });
233
+ }}
234
+ fallback={<ErrorScreen />}
235
+ >
236
+ <App />
237
+ </Sentry.ErrorBoundary>
238
+ ```
239
+
240
+ ---
241
+
242
+ #### `beforeCapture` — Enrich the Event Before Sending
243
+
244
+ Called with the Sentry `Scope` before the error is captured.
245
+ Use it to add tags, context, or level enrichment specific to this boundary’s location in
246
+ the tree.
247
+
248
+ ```jsx
249
+ <Sentry.ErrorBoundary
250
+ beforeCapture={(scope, error, componentStack) => {
251
+ scope.setTag("section", "checkout");
252
+ scope.setTag("error_type", error.constructor.name);
253
+ scope.setExtra("componentStack", componentStack);
254
+ scope.setLevel("fatal");
255
+ scope.setContext("payment", { step: "card-entry" });
256
+ }}
257
+ fallback={<CheckoutError />}
258
+ >
259
+ <CheckoutFlow />
260
+ </Sentry.ErrorBoundary>
261
+ ```
262
+
263
+ ---
264
+
265
+ #### `onReset` — Cleanup When the Boundary Resets
266
+
267
+ Called when `resetError()` is invoked.
268
+ Clear stale state in stores or invalidate caches here.
269
+
270
+ ```jsx
271
+ <Sentry.ErrorBoundary
272
+ onReset={(error, componentStack, eventId) => {
273
+ queryClient.clear();
274
+ store.dispatch(clearCheckoutState());
275
+ }}
276
+ fallback={({ resetError }) => (
277
+ <div>
278
+ <p>Payment failed to load.</p>
279
+ <button onClick={resetError}>Retry</button>
280
+ </div>
281
+ )}
282
+ >
283
+ <CheckoutFlow />
284
+ </Sentry.ErrorBoundary>
285
+ ```
286
+
287
+ ---
288
+
289
+ #### `showDialog` + `dialogOptions` — Crash-Report Modal on Error
290
+
291
+ ```jsx
292
+ <Sentry.ErrorBoundary
293
+ showDialog
294
+ dialogOptions={{
295
+ title: "It looks like something went wrong.",
296
+ subtitle: "Our engineering team has been notified.",
297
+ subtitle2: "Want to help us fix it? Tell us what happened.",
298
+ labelName: "Your name",
299
+ labelEmail: "Your email",
300
+ labelComments: "What happened before this error?",
301
+ labelSubmit: "Send Report",
302
+ successMessage: "Thanks! Your report helps us improve.",
303
+ user: { email: "currentuser@example.com", name: "Jane Smith" },
304
+ }}
305
+ fallback={<p>We've logged this issue and are working on a fix.</p>}
306
+ >
307
+ <Dashboard />
308
+ </Sentry.ErrorBoundary>
309
+ ```
310
+
311
+ ---
312
+
313
+ #### `onMount` / `onUnmount` — Lifecycle Hooks
314
+
315
+ ```jsx
316
+ <Sentry.ErrorBoundary
317
+ onMount={() => analytics.track("error_boundary_mounted", { section: "dashboard" })}
318
+ onUnmount={(error) => {
319
+ if (error) analytics.track("error_boundary_active_on_unmount");
320
+ }}
321
+ fallback={<DashboardError />}
322
+ >
323
+ <Dashboard />
324
+ </Sentry.ErrorBoundary>
325
+ ```
326
+
327
+ ---
328
+
329
+ ### `Sentry.withErrorBoundary(Component, options)` — HOC Pattern
330
+
331
+ Equivalent to wrapping with `<Sentry.ErrorBoundary>`. Useful when you want to wrap at
332
+ the import or module level instead of in JSX.
333
+
334
+ ```jsx
335
+ import * as Sentry from "@sentry/react";
336
+
337
+ // Basic
338
+ const SafeDashboard = Sentry.withErrorBoundary(Dashboard, {
339
+ fallback: <p>Dashboard failed to load.</p>,
340
+ });
341
+
342
+ // Full options — identical to ErrorBoundary props
343
+ const SafeCheckout = Sentry.withErrorBoundary(CheckoutFlow, {
344
+ fallback: ({ error, resetError }) => (
345
+ <div>
346
+ <p>Checkout error: {error.message}</p>
347
+ <button onClick={resetError}>Retry</button>
348
+ </div>
349
+ ),
350
+ onError: (error, componentStack, eventId) => {
351
+ analytics.track("checkout_boundary_triggered", { eventId });
352
+ },
353
+ beforeCapture: (scope) => {
354
+ scope.setTag("section", "checkout");
355
+ scope.setLevel("fatal");
356
+ },
357
+ showDialog: true,
358
+ });
359
+
360
+ // Use exactly like the unwrapped component
361
+ function App() {
362
+ return <SafeCheckout />;
363
+ }
364
+ ```
365
+
366
+ ---
367
+
368
+ ### Nested Error Boundaries — Isolation Pattern
369
+
370
+ Each boundary only catches errors from **its own subtree**. Nesting lets one broken
371
+ feature fail in isolation without crashing the whole page.
372
+
373
+ ```jsx
374
+ function App() {
375
+ return (
376
+ // Outermost — catches anything that escapes inner boundaries
377
+ <Sentry.ErrorBoundary
378
+ fallback={<FullPageError />}
379
+ beforeCapture={(scope) => scope.setTag("level", "app")}
380
+ >
381
+ <Layout>
382
+ <Sentry.ErrorBoundary
383
+ fallback={<NavError />}
384
+ beforeCapture={(scope) => scope.setTag("section", "navigation")}
385
+ >
386
+ <Navigation />
387
+ </Sentry.ErrorBoundary>
388
+
389
+ <main>
390
+ <Sentry.ErrorBoundary
391
+ fallback={<SidebarError />}
392
+ beforeCapture={(scope) => scope.setTag("section", "sidebar")}
393
+ >
394
+ <Sidebar />
395
+ </Sentry.ErrorBoundary>
396
+
397
+ <Sentry.ErrorBoundary
398
+ fallback={<ContentError />}
399
+ beforeCapture={(scope) => scope.setTag("section", "content")}
400
+ >
401
+ <MainContent />
402
+ </Sentry.ErrorBoundary>
403
+ </main>
404
+ </Layout>
405
+ </Sentry.ErrorBoundary>
406
+ );
407
+ }
408
+ ```
409
+
410
+ **Recommended placement strategy:**
411
+
412
+ | Boundary location | Purpose |
413
+ | -------------------------- | ---------------------------------------------------- |
414
+ | Outermost (around `<App>`) | Last resort — prevents total blank page |
415
+ | Route level | Isolate route failures; different fallback per route |
416
+ | Widget / panel level | Let other panels stay functional when one fails |
417
+ | Data-fetching components | Catch errors from async rendering |
418
+
419
+ ---
420
+
421
+ ### Custom Class-Based Error Boundaries — `captureReactException`
422
+
423
+ > Requires `@sentry/react` ≥9.8.0
424
+
425
+ If you need a custom class boundary, use `captureReactException` instead of
426
+ `captureException`. It correctly attaches the React `componentStack` as a linked cause
427
+ via the `LinkedErrors` integration, producing readable component traces in Sentry.
428
+
429
+ ```jsx
430
+ import * as Sentry from "@sentry/react";
431
+
432
+ class CustomBoundary extends React.Component {
433
+ state = { hasError: false };
434
+
435
+ static getDerivedStateFromError() {
436
+ return { hasError: true };
437
+ }
438
+
439
+ componentDidCatch(error, errorInfo) {
440
+ // errorInfo = { componentStack: "\n at Dashboard\n at App..." }
441
+ // captureReactException wires up the componentStack correctly
442
+ Sentry.captureReactException(error, errorInfo);
443
+ }
444
+
445
+ render() {
446
+ if (this.state.hasError) return <p>Something went wrong.</p>;
447
+ return this.props.children;
448
+ }
449
+ }
450
+ ```
451
+
452
+ > **Why not plain `captureException`?** Calling `captureException` inside
453
+ > `componentDidCatch` loses the component stack linkage.
454
+ > `captureReactException` correctly wires `error.cause` so the component tree appears as
455
+ > a linked error in Sentry’s issue detail view.
456
+
457
+ **What linked errors look like in Sentry:**
458
+
459
+ ```
460
+ Error: Cannot read properties of undefined (reading 'map')
461
+ at Dashboard (Dashboard.tsx:42)
462
+ Caused by: React component stack:
463
+ at Dashboard
464
+ at Sentry.ErrorBoundary
465
+ at App
466
+ ```
467
+
468
+ > Requires React 17+ and the `LinkedErrors` integration (enabled by default).
469
+ > Set up source maps for readable component file paths.
470
+
471
+ ---
472
+
473
+ ## Manual Error Capture
474
+
475
+ ### `Sentry.captureException(error, captureContext?)`
476
+
477
+ Captures an error and sends it to Sentry.
478
+ Prefer `Error` objects (they include stack traces).
479
+ Non-`Error` values (strings, plain objects) are accepted but may lack stack traces.
480
+
481
+ ```javascript
482
+ // Basic usage
483
+ try {
484
+ riskyOperation();
485
+ } catch (err) {
486
+ Sentry.captureException(err);
487
+ }
488
+
489
+ // With full capture context
490
+ try {
491
+ await chargeCard(order);
492
+ } catch (err) {
493
+ Sentry.captureException(err, {
494
+ level: "fatal", // "fatal"|"error"|"warning"|"log"|"info"|"debug"
495
+ tags: { module: "checkout", retried: "true" },
496
+ extra: { cartItems: 3, coupon: "SAVE20" },
497
+ user: { id: "u_123", email: "user@example.com" },
498
+ fingerprint: ["checkout-payment-fail"], // custom grouping key
499
+ contexts: {
500
+ payment: { provider: "stripe", amount: 9999, currency: "usd" },
501
+ },
502
+ });
503
+ }
504
+ ```
505
+
506
+ **React-specific tip:** Avoid calling Sentry in the render path.
507
+ Wrap Sentry calls in `useEffect` to prevent firing on every render:
508
+
509
+ ```jsx
510
+ function UserProfile({ userId }) {
511
+ const { data: profile, error } = useQuery(["user", userId], fetchUser);
512
+
513
+ useEffect(() => {
514
+ if (error) {
515
+ Sentry.captureException(error, {
516
+ tags: { component: "UserProfile" },
517
+ extra: { userId },
518
+ });
519
+ }
520
+ }, [error, userId]);
521
+
522
+ if (error) return <p>Failed to load profile.</p>;
523
+ return profile ? <Profile data={profile} /> : null;
524
+ }
525
+ ```
526
+
527
+ ---
528
+
529
+ ### `Sentry.captureMessage(message, level?)`
530
+
531
+ Captures a plain-text message as a Sentry issue.
532
+ Useful for non-exception events: deprecated API calls, suspicious conditions, rate-limit
533
+ hits.
534
+
535
+ ```javascript
536
+ // With level as second argument
537
+ Sentry.captureMessage("Payment gateway timeout — fallback triggered", "warning");
538
+
539
+ // All valid levels: "fatal" | "error" | "warning" | "log" | "info" | "debug"
540
+ // Default when omitted: "info"
541
+
542
+ // With full capture context as second argument
543
+ Sentry.captureMessage("Feature flag evaluation failed", {
544
+ level: "error",
545
+ tags: { flagName: "new-checkout", service: "feature-flags" },
546
+ extra: { userId: "u_42", evaluationContext: { country: "DE" } },
547
+ });
548
+ ```
549
+
550
+ ---
551
+
552
+ ### `Sentry.captureEvent(event)`
553
+
554
+ Low-level API for sending a fully constructed Sentry event object.
555
+ Use `captureException` or `captureMessage` in application code.
556
+ `captureEvent` is for custom integrations or forwarding events from legacy loggers.
557
+
558
+ ```javascript
559
+ Sentry.captureEvent({
560
+ message: "Legacy logger forwarded event",
561
+ level: "warning",
562
+ tags: { source: "legacy-logger", module: "billing" },
563
+ extra: { rawLog: "something went wrong at line 42" },
564
+ timestamp: Date.now() / 1000, // Unix timestamp in seconds
565
+ fingerprint: ["legacy-billing-error"],
566
+ });
567
+ ```
568
+
569
+ ---
570
+
571
+ ### Try/Catch Patterns in React
572
+
573
+ **Event handlers** — errors here are NOT caught by error boundaries (boundaries only
574
+ catch render errors):
575
+
576
+ ```jsx
577
+ function PaymentForm() {
578
+ const [status, setStatus] = useState("idle");
579
+
580
+ async function handleSubmit(event) {
581
+ event.preventDefault();
582
+ setStatus("loading");
583
+ try {
584
+ await processPayment(getFormValues(event.target));
585
+ setStatus("success");
586
+ } catch (err) {
587
+ setStatus("error");
588
+ Sentry.captureException(err, {
589
+ tags: { component: "PaymentForm", action: "submit" },
590
+ extra: { formFields: Object.fromEntries(new FormData(event.target)) },
591
+ });
592
+ }
593
+ }
594
+
595
+ return (
596
+ <form onSubmit={handleSubmit}>
597
+ {/* form fields */}
598
+ <button type="submit" disabled={status === "loading"}>
599
+ {status === "loading" ? "Processing..." : "Pay"}
600
+ </button>
601
+ {status === "error" && <p>Payment failed. Please try again.</p>}
602
+ </form>
603
+ );
604
+ }
605
+ ```
606
+
607
+ **Async operations in effects:**
608
+
609
+ ```jsx
610
+ useEffect(() => {
611
+ async function loadData() {
612
+ try {
613
+ const data = await fetchDashboardData();
614
+ setData(data);
615
+ } catch (err) {
616
+ Sentry.captureException(err, {
617
+ tags: { hook: "useEffect", data: "dashboard" },
618
+ });
619
+ setError(err);
620
+ }
621
+ }
622
+ loadData();
623
+ }, []);
624
+ ```
625
+
626
+ **Promise chains:**
627
+
628
+ ```javascript
629
+ fetchUserData(userId)
630
+ .then(processUser)
631
+ .catch((err) => {
632
+ Sentry.captureException(err, {
633
+ tags: { operation: "fetchUserData" },
634
+ extra: { userId },
635
+ });
636
+ return null; // graceful fallback
637
+ });
638
+ ```
639
+
640
+ ---
641
+
642
+ ## Context Enrichment
643
+
644
+ ### `Sentry.setUser(user)` — Identify the Current User
645
+
646
+ Associates a user identity with all subsequent events.
647
+ Call after login; call `Sentry.setUser(null)` on logout.
648
+
649
+ ```typescript
650
+ // Accepted fields (all optional):
651
+ interface SentryUser {
652
+ id?: string | number; // your internal user ID
653
+ email?: string;
654
+ username?: string;
655
+ ip_address?: string; // "{{ auto }}" to infer from request
656
+ segment?: string; // e.g. "paid", "trial", "beta", "enterprise"
657
+ // Any additional custom fields are accepted
658
+ }
659
+ ```
660
+
661
+ ```javascript
662
+ // On login:
663
+ Sentry.setUser({
664
+ id: "usr_abc123",
665
+ email: "jane.smith@example.com",
666
+ username: "janesmith",
667
+ segment: "enterprise",
668
+ // Custom fields:
669
+ plan: "pro",
670
+ team_id: "team_789",
671
+ account_age_days: 365,
672
+ });
673
+
674
+ // On logout — clears user from all subsequent events:
675
+ Sentry.setUser(null);
676
+
677
+ // Auto-infer IP address (userInfo defaults to true):
678
+ Sentry.setUser({
679
+ id: "usr_abc123",
680
+ ip_address: "{{ auto }}",
681
+ });
682
+ ```
683
+
684
+ > **Privacy:** `userInfo` (in `dataCollection`) defaults to `true`, which enables
685
+ > automatic IP inference.
686
+ > Set `dataCollection: { userInfo: false }` to opt out, or enable “Prevent Storing of IP
687
+ > Addresses” in your project’s Security & Privacy settings in Sentry to prevent IP
688
+ > storage entirely.
689
+
690
+ ---
691
+
692
+ ### `Sentry.setContext(name, data)` — Attach Structured Custom Data
693
+
694
+ Attaches arbitrary structured data to all subsequent events.
695
+ Context is **not indexed or searchable** — use tags for filterable data.
696
+ Context appears in the issue detail view.
697
+
698
+ ```javascript
699
+ // E-commerce checkout context
700
+ Sentry.setContext("checkout", {
701
+ step: "payment",
702
+ cart_items: 3,
703
+ total_usd: 99.99,
704
+ coupon_applied: "SAVE20",
705
+ payment_provider: "stripe",
706
+ });
707
+
708
+ // Feature flags in effect
709
+ Sentry.setContext("feature_flags", {
710
+ new_checkout: true,
711
+ dark_mode: false,
712
+ experiment_group: "variant_b",
713
+ });
714
+
715
+ // Remove a context:
716
+ Sentry.setContext("checkout", null);
717
+ ```
718
+
719
+ > **Depth:** Sentry normalizes context to **3 levels deep** by default.
720
+ > Adjust via `normalizeDepth` in `Sentry.init`. The key `type` is reserved — don’t use
721
+ > it in context objects.
722
+
723
+ ---
724
+
725
+ ### `Sentry.setTag(key, value)` / `Sentry.setTags(tags)` — Searchable Key-Value Pairs
726
+
727
+ Tags are **indexed and searchable**. They power Sentry’s filter sidebar, tag
728
+ distribution charts, and issue similarity detection.
729
+ Use tags for any data you want to filter or aggregate on.
730
+
731
+ **Constraints:** Key ≤32 chars (`a-z A-Z 0-9 _ . : -`, no spaces).
732
+ Value ≤200 chars, no newlines.
733
+
734
+ ```javascript
735
+ // Single tag
736
+ Sentry.setTag("page_locale", "de-at");
737
+ Sentry.setTag("user_plan", "enterprise");
738
+ Sentry.setTag("app_version", "2.4.1");
739
+
740
+ // Multiple at once
741
+ Sentry.setTags({
742
+ "release.stage": "canary",
743
+ "tenant.id": "tenant_abc",
744
+ "browser.engine": "blink",
745
+ });
746
+
747
+ // Per-event inline (does not persist to subsequent events)
748
+ Sentry.captureException(err, {
749
+ tags: { component: "PaymentForm", retry_attempt: "2" },
750
+ });
751
+
752
+ // Scoped — only applies within the callback
753
+ Sentry.withScope((scope) => {
754
+ scope.setTag("operation", "bulk-delete");
755
+ Sentry.captureException(deleteError);
756
+ });
757
+ // "operation" tag does NOT appear on subsequent events
758
+ ```
759
+
760
+ > Do not overwrite Sentry’s built-in tags (`browser`, `os`, `url`, `environment`,
761
+ > `release`). Use your own namespaced keys.
762
+
763
+ ---
764
+
765
+ ### `Sentry.setExtra(key, value)` / `Sentry.setExtras(extras)` — Arbitrary Data
766
+
767
+ For loosely-typed supplementary data.
768
+ Prefer `setContext` for structured data with a meaningful group name.
769
+
770
+ ```javascript
771
+ Sentry.setExtra("raw_api_response", responseText);
772
+ Sentry.setExtra("debug_state_dump", JSON.stringify(stateSnapshot));
773
+
774
+ Sentry.setExtras({
775
+ component_version: "3.2.1",
776
+ last_action: "submit_form",
777
+ form_fields: { total: 5, valid: 3, invalid: 2 },
778
+ });
779
+ ```
780
+
781
+ ---
782
+
783
+ ### Inline Context on Capture Calls
784
+
785
+ All context can be provided per-event using the second argument to `captureException` or
786
+ `captureMessage`. This is the cleanest approach for one-off enrichment:
787
+
788
+ ```javascript
789
+ Sentry.captureException(err, {
790
+ user: { id: "u_42", email: "user@example.com" },
791
+ level: "fatal",
792
+ tags: { module: "checkout", payment_provider: "stripe" },
793
+ extra: { formState: JSON.stringify(formValues) },
794
+ contexts: {
795
+ payment: { provider: "stripe", last4: "4242", amount_cents: 9999 },
796
+ },
797
+ fingerprint: ["{{ default }}", "stripe-card-error"],
798
+ });
799
+ ```
800
+
801
+ ---
802
+
803
+ ## Breadcrumbs
804
+
805
+ Breadcrumbs are a structured trail of events leading up to an error.
806
+ They’re buffered locally and attached to the next event sent to Sentry.
807
+
808
+ ### Automatic Breadcrumbs (Zero Config)
809
+
810
+ | Type | What’s Captured |
811
+ | ------------ | ------------------------------------------------------------------------- |
812
+ | `ui.click` | DOM element clicks (CSS selector or component name if annotation enabled) |
813
+ | `ui.input` | Keyboard/input interactions |
814
+ | `navigation` | URL changes: `pushState`, `popstate`, hash changes |
815
+ | `http` | XHR and `fetch` requests (URL, method, status code) |
816
+ | `console` | `console.log`, `warn`, `error`, `info`, `debug` output |
817
+ | `sentry` | SDK-internal events |
818
+
819
+ ---
820
+
821
+ ### `Sentry.addBreadcrumb(breadcrumb)` — Manual Breadcrumbs
822
+
823
+ ```typescript
824
+ interface Breadcrumb {
825
+ type?: "default" | "debug" | "error" | "info" | "navigation" | "http" | "query" | "ui" | "user";
826
+ category?: string; // dot-namespaced: "auth", "ui.click", "api.request"
827
+ message?: string; // human-readable description
828
+ level?: "fatal" | "error" | "warning" | "log" | "info" | "debug";
829
+ timestamp?: number; // Unix timestamp in seconds (auto-set if omitted)
830
+ data?: Record<string, unknown>;
831
+ }
832
+ ```
833
+
834
+ ```javascript
835
+ // Auth events
836
+ Sentry.addBreadcrumb({
837
+ category: "auth",
838
+ message: "User logged in",
839
+ level: "info",
840
+ data: { userId: "u_42", method: "oauth2", provider: "google" },
841
+ });
842
+
843
+ Sentry.addBreadcrumb({
844
+ category: "auth",
845
+ message: "Token refresh failed",
846
+ level: "warning",
847
+ type: "error",
848
+ data: { reason: "expired", expiredAt: "2024-01-15T10:00:00Z" },
849
+ });
850
+
851
+ // Navigation
852
+ Sentry.addBreadcrumb({
853
+ type: "navigation",
854
+ category: "navigation",
855
+ message: "User navigated to checkout",
856
+ data: { from: "/cart", to: "/checkout/payment" },
857
+ });
858
+
859
+ // API call outcome
860
+ Sentry.addBreadcrumb({
861
+ type: "http",
862
+ category: "api.request",
863
+ message: "POST /api/orders",
864
+ level: "info",
865
+ data: {
866
+ url: "/api/orders",
867
+ method: "POST",
868
+ status_code: 422,
869
+ reason: "Validation failed",
870
+ },
871
+ });
872
+
873
+ // User actions
874
+ Sentry.addBreadcrumb({
875
+ type: "user",
876
+ category: "ui.click",
877
+ message: "Clicked 'Place Order' button",
878
+ data: { orderId: "ord_xyz", itemCount: 3, total: 99.99 },
879
+ });
880
+
881
+ // State machine transitions
882
+ Sentry.addBreadcrumb({
883
+ category: "state",
884
+ type: "debug",
885
+ message: "State machine transitioned",
886
+ level: "debug",
887
+ data: { from: "PENDING", to: "PROCESSING", trigger: "user_submit" },
888
+ });
889
+ ```
890
+
891
+ ---
892
+
893
+ ### Filtering Breadcrumbs — `beforeBreadcrumb`
894
+
895
+ Configured in `Sentry.init`. Return `null` to discard a breadcrumb entirely.
896
+
897
+ ```javascript
898
+ Sentry.init({
899
+ beforeBreadcrumb(breadcrumb, hint) {
900
+ // Drop clicks on password fields (privacy)
901
+ if (breadcrumb.category === "ui.click") {
902
+ const target = hint?.event?.target;
903
+ if (target?.type === "password") return null;
904
+ }
905
+
906
+ // Enrich XHR breadcrumbs with request body size
907
+ if (breadcrumb.type === "http" && hint?.xhr) {
908
+ breadcrumb.data = {
909
+ ...breadcrumb.data,
910
+ requestBodySize: hint.xhr.requestBody?.length ?? 0,
911
+ };
912
+ }
913
+
914
+ // Drop verbose console.debug breadcrumbs in production
915
+ if (breadcrumb.category === "console" && breadcrumb.level === "debug") {
916
+ return null;
917
+ }
918
+
919
+ return breadcrumb;
920
+ },
921
+ });
922
+ ```
923
+
924
+ **`maxBreadcrumbs`** — Controls how many breadcrumbs are stored.
925
+ Default: 100. Set in `Sentry.init`:
926
+
927
+ ```javascript
928
+ Sentry.init({ maxBreadcrumbs: 50 });
929
+ ```
930
+
931
+ ---
932
+
933
+ ## Scopes
934
+
935
+ Scopes are how Sentry attaches context (tags, user, breadcrumbs, extras) to events.
936
+ Three scope types are merged before each event is sent.
937
+
938
+ ### The Three Scope Types
939
+
940
+ | Scope | API | Lifetime | Written by |
941
+ | ------------- | ---------------------------- | -------------------- | ---------------------- |
942
+ | **Global** | `Sentry.getGlobalScope()` | Entire process | You (set once) |
943
+ | **Isolation** | `Sentry.getIsolationScope()` | Current page/request | `Sentry.setTag()` etc. |
944
+ | **Current** | `Sentry.getCurrentScope()` | Innermost execution | `Sentry.withScope()` |
945
+
946
+ **Merge priority (later wins):**
947
+
948
+ ```
949
+ Global → Isolation → Current → Event Sent
950
+ (lowest priority) (highest priority)
951
+ ```
952
+
953
+ ---
954
+
955
+ ### Global Scope — `Sentry.getGlobalScope()`
956
+
957
+ Applied to **every event** from anywhere in the app.
958
+ Use for universal data: app version, build ID, deployment region.
959
+
960
+ ```javascript
961
+ const globalScope = Sentry.getGlobalScope();
962
+ globalScope.setTag("app_version", "2.4.1");
963
+ globalScope.setTag("build_id", import.meta.env.VITE_BUILD_ID);
964
+ globalScope.setContext("deployment", {
965
+ region: "us-east-1",
966
+ datacenter: "aws",
967
+ env: "production",
968
+ });
969
+ ```
970
+
971
+ > **Cannot capture events** — only stores data.
972
+
973
+ ---
974
+
975
+ ### Isolation Scope — `Sentry.getIsolationScope()`
976
+
977
+ In the **browser**, the isolation scope is effectively global — only one ever exists per
978
+ page load (unlike Node where it’s forked per request).
979
+ All top-level `Sentry.setXxx()` methods write here.
980
+
981
+ ```javascript
982
+ // These two are identical in the browser:
983
+ Sentry.setTag("user_plan", "pro");
984
+ Sentry.getIsolationScope().setTag("user_plan", "pro");
985
+
986
+ // On login — persists for all subsequent events on this page:
987
+ Sentry.setUser({ id: "u_42", email: "user@example.com" });
988
+
989
+ // On logout — clears user from isolation scope:
990
+ Sentry.setUser(null);
991
+ ```
992
+
993
+ > **Cannot capture events** — only stores data.
994
+
995
+ ---
996
+
997
+ ### `Sentry.withScope(callback)` — Scoped Modifications
998
+
999
+ Creates a **fork** of the current scope, active only within the callback.
1000
+ Modifications do not leak to subsequent events.
1001
+ The most important tool for per-event enrichment without polluting global state.
1002
+
1003
+ ```javascript
1004
+ // Add context to one specific capture only
1005
+ Sentry.withScope((scope) => {
1006
+ scope.setTag("operation", "bulk-delete");
1007
+ scope.setLevel("warning");
1008
+ scope.setContext("bulk", { count: items.length, userId: currentUser.id });
1009
+ Sentry.captureException(deleteError);
1010
+ });
1011
+ // "operation" tag does NOT appear on any subsequent events
1012
+
1013
+ // Rich per-operation isolation
1014
+ async function processPayment(order) {
1015
+ try {
1016
+ await stripe.charge(order);
1017
+ } catch (err) {
1018
+ Sentry.withScope((scope) => {
1019
+ scope.setTag("module", "payments");
1020
+ scope.setTag("payment_provider", "stripe");
1021
+ scope.setLevel("fatal");
1022
+ scope.setUser({ id: order.userId });
1023
+ scope.setContext("order", {
1024
+ id: order.id,
1025
+ amount: order.amount,
1026
+ currency: order.currency,
1027
+ items: order.items.length,
1028
+ });
1029
+ scope.setExtra("stripe_error_code", err.code);
1030
+ scope.addBreadcrumb({
1031
+ category: "payment",
1032
+ message: "Stripe charge attempt failed",
1033
+ level: "error",
1034
+ data: { stripeCode: err.code, message: err.message },
1035
+ });
1036
+ Sentry.captureException(err);
1037
+ });
1038
+ }
1039
+ }
1040
+
1041
+ // addEventProcessor inside a scope — transform the event before it's sent
1042
+ Sentry.withScope((scope) => {
1043
+ scope.addEventProcessor((event) => {
1044
+ event.tags = { ...event.tags, processed_by: "payment_handler" };
1045
+ return event;
1046
+ });
1047
+ Sentry.captureException(err);
1048
+ });
1049
+ ```
1050
+
1051
+ ---
1052
+
1053
+ ### Scope Decision Guide
1054
+
1055
+ | Goal | API |
1056
+ | ------------------------------------------ | ------------------------------------------------------ |
1057
+ | Data on ALL events (app version, build ID) | `Sentry.getGlobalScope().setTag(...)` |
1058
+ | Data on current page view / user session | `Sentry.setTag(...)` (isolation scope) |
1059
+ | Data on ONE specific capture | `Sentry.withScope((scope) => { ... })` |
1060
+ | Data inline on a single event | Second arg to `captureException(err, { tags: {...} })` |
1061
+
1062
+ > **Do NOT use `Sentry.configureScope()`** — deprecated since SDK v8. Use
1063
+ > `getIsolationScope()` or `getGlobalScope()` instead.
1064
+
1065
+ ---
1066
+
1067
+ ## Event Filtering
1068
+
1069
+ ### `beforeSend(event, hint)` — Modify or Drop Events
1070
+
1071
+ Called before every error event is sent.
1072
+ Return `null` to drop the event.
1073
+ Mutate `event` to scrub or enrich it.
1074
+
1075
+ ```javascript
1076
+ Sentry.init({
1077
+ beforeSend(event, hint) {
1078
+ const originalError = hint.originalException;
1079
+
1080
+ // Drop non-Error rejections (e.g. cancelled requests)
1081
+ if (originalError && !(originalError instanceof Error)) {
1082
+ return null;
1083
+ }
1084
+
1085
+ // Drop browser extension errors
1086
+ if (
1087
+ event.exception?.values?.[0]?.stacktrace?.frames?.some((frame) =>
1088
+ frame.filename?.includes("extension://"),
1089
+ )
1090
+ ) {
1091
+ return null;
1092
+ }
1093
+
1094
+ // Drop 404 errors from event handlers
1095
+ if (originalError?.message?.includes("404")) {
1096
+ return null;
1097
+ }
1098
+
1099
+ // Scrub PII from user context
1100
+ if (event.user?.email) {
1101
+ event.user = { ...event.user, email: "[filtered]" };
1102
+ }
1103
+
1104
+ // Override fingerprint for known error patterns
1105
+ if (originalError?.message?.includes("ChunkLoadError")) {
1106
+ event.fingerprint = ["chunk-load-error"];
1107
+ }
1108
+
1109
+ return event;
1110
+ },
1111
+ });
1112
+ ```
1113
+
1114
+ **Accessing the original error from `hint`:**
1115
+
1116
+ ```javascript
1117
+ beforeSend(event, hint) {
1118
+ const error = hint.originalException; // The original Error object
1119
+ const syntheticEvent = hint.syntheticException; // SDK-generated error for messages
1120
+
1121
+ if (error instanceof TypeError && error.message === "Failed to fetch") {
1122
+ // Enrich with tag instead of dropping
1123
+ event.tags = { ...event.tags, network_error: "true" };
1124
+ }
1125
+ return event;
1126
+ }
1127
+ ```
1128
+
1129
+ ---
1130
+
1131
+ ### `ignoreErrors` — Pattern-Based Filtering
1132
+
1133
+ Array of string or RegExp patterns.
1134
+ Events whose error message matches any pattern are silently dropped before `beforeSend`.
1135
+
1136
+ ```javascript
1137
+ Sentry.init({
1138
+ ignoreErrors: [
1139
+ // Exact strings (substring match):
1140
+ "ResizeObserver loop limit exceeded",
1141
+ "Non-Error exception captured",
1142
+ "Object Not Found Matching Id",
1143
+
1144
+ // Regular expressions:
1145
+ /^Network Error$/,
1146
+ /ChunkLoadError/,
1147
+ /Loading chunk \d+ failed/,
1148
+ /^Script error\.?$/, // cross-origin script errors with no details
1149
+
1150
+ // Browser extension noise:
1151
+ "from accessing a cross-origin frame",
1152
+ /webkit-masked-url/,
1153
+ ],
1154
+ });
1155
+ ```
1156
+
1157
+ ---
1158
+
1159
+ ### `allowUrls` / `denyUrls` — URL-Based Filtering
1160
+
1161
+ Only capture errors (or skip errors) from scripts at specific URLs.
1162
+
1163
+ ```javascript
1164
+ Sentry.init({
1165
+ // Only capture errors originating from your own scripts:
1166
+ allowUrls: [/https:\/\/yourapp\.com/, /https:\/\/cdn\.yourapp\.com/],
1167
+
1168
+ // Skip errors from known third-party noise:
1169
+ denyUrls: [
1170
+ /extensions\//i,
1171
+ /^chrome:\/\//i,
1172
+ /^safari-extension:\/\//i,
1173
+ /gtm\.js/,
1174
+ /analytics\.js/,
1175
+ ],
1176
+ });
1177
+ ```
1178
+
1179
+ ---
1180
+
1181
+ ### `sampleRate` — Capture Only a Fraction of Errors
1182
+
1183
+ ```javascript
1184
+ Sentry.init({
1185
+ sampleRate: 0.25, // Capture 25% of errors (randomly sampled)
1186
+ });
1187
+ ```
1188
+
1189
+ > Use `beforeSend` for conditional filtering (based on error type, URL, user).
1190
+ > Use `sampleRate` for volume reduction when error rates are very high.
1191
+
1192
+ ---
1193
+
1194
+ ## Fingerprinting
1195
+
1196
+ ### Default Grouping Behavior
1197
+
1198
+ Sentry groups errors into issues by default using a combination of: exception type,
1199
+ exception message, and stack trace.
1200
+ This works well for most cases but can produce false groupings for dynamic error
1201
+ messages.
1202
+
1203
+ ### Custom Fingerprinting
1204
+
1205
+ Override grouping by providing a `fingerprint` array on the event.
1206
+
1207
+ ```javascript
1208
+ // All Stripe card errors grouped together regardless of message:
1209
+ Sentry.captureException(err, {
1210
+ fingerprint: ["stripe-card-error"],
1211
+ });
1212
+
1213
+ // Use {{ default }} to extend (not replace) Sentry's default grouping:
1214
+ Sentry.captureException(err, {
1215
+ fingerprint: ["{{ default }}", "payment-module"],
1216
+ });
1217
+
1218
+ // Dynamic component — group by component name + error type:
1219
+ Sentry.captureException(err, {
1220
+ fingerprint: ["DataGrid", err.constructor.name],
1221
+ });
1222
+ ```
1223
+
1224
+ **Via `beforeSend` for pattern-based fingerprinting:**
1225
+
1226
+ ```javascript
1227
+ Sentry.init({
1228
+ beforeSend(event, hint) {
1229
+ const error = hint.originalException;
1230
+
1231
+ // Group all network timeouts as one issue:
1232
+ if (error?.message?.includes("timeout")) {
1233
+ event.fingerprint = ["network-timeout"];
1234
+ }
1235
+
1236
+ // Group chunk load failures as one issue:
1237
+ if (error?.name === "ChunkLoadError") {
1238
+ event.fingerprint = ["chunk-load-failure"];
1239
+ }
1240
+
1241
+ return event;
1242
+ },
1243
+ });
1244
+ ```
1245
+
1246
+ ---
1247
+
1248
+ ## User Feedback
1249
+
1250
+ ### When to Use Which Mechanism
1251
+
1252
+ | | `feedbackIntegration()` Widget | `Sentry.showReportDialog()` |
1253
+ | ------------------- | ------------------------------ | --------------------------- |
1254
+ | **Trigger** | Anytime — user-initiated | On error — automatic |
1255
+ | **UI** | Floating button (bottom-right) | Modal overlay |
1256
+ | **Requires error?** | No | Yes (`eventId` required) |
1257
+ | **Screenshots** | Yes (SDK ≥8.0.0) | No |
1258
+ | **Best for** | General feedback, bug reports | Post-crash reports |
1259
+
1260
+ ---
1261
+
1262
+ ### `feedbackIntegration()` — Persistent Feedback Widget
1263
+
1264
+ Adds a floating feedback button to the page.
1265
+ Users submit feedback at any time — no error required.
1266
+
1267
+ ```javascript
1268
+ import * as Sentry from "@sentry/react";
1269
+
1270
+ Sentry.init({
1271
+ dsn: "___PUBLIC_DSN___",
1272
+ integrations: [
1273
+ Sentry.feedbackIntegration({
1274
+ colorScheme: "system", // "system" | "light" | "dark"
1275
+ }),
1276
+ ],
1277
+ });
1278
+ ```
1279
+
1280
+ #### Complete Configuration Reference
1281
+
1282
+ ```javascript
1283
+ Sentry.feedbackIntegration({
1284
+ // ── Behavior ──────────────────────────────────────────────────────────
1285
+ autoInject: true, // Auto-inject button into DOM. Set false for programmatic control.
1286
+ colorScheme: "system", // "system" | "light" | "dark"
1287
+ showBranding: true, // Show "Powered by Sentry" logo
1288
+ id: "sentry-feedback", // Container div ID
1289
+ tags: {
1290
+ // Sentry tags on all feedback submissions
1291
+ product_area: "checkout",
1292
+ version: "2.4.1",
1293
+ },
1294
+
1295
+ // ── User Fields ───────────────────────────────────────────────────────
1296
+ showName: true,
1297
+ showEmail: true,
1298
+ isNameRequired: false,
1299
+ isEmailRequired: false,
1300
+ enableScreenshot: true, // Allow screenshot attachment (SDK ≥8.0.0, hidden on mobile)
1301
+ useSentryUser: {
1302
+ email: "email", // Which Sentry user field maps to the email input
1303
+ name: "username", // Which Sentry user field maps to the name input
1304
+ },
1305
+
1306
+ // ── Labels / Text ─────────────────────────────────────────────────────
1307
+ triggerLabel: "Report a Bug",
1308
+ triggerAriaLabel: "Report a Bug", // v8.20.0+
1309
+ formTitle: "Report a Bug",
1310
+ submitButtonLabel: "Send Bug Report",
1311
+ cancelButtonLabel: "Cancel",
1312
+ confirmButtonLabel: "Confirm",
1313
+ addScreenshotButtonLabel: "Add a screenshot",
1314
+ removeScreenshotButtonLabel: "Remove screenshot",
1315
+ nameLabel: "Name",
1316
+ namePlaceholder: "Your Name",
1317
+ emailLabel: "Email",
1318
+ emailPlaceholder: "your.email@example.org",
1319
+ isRequiredLabel: "(required)",
1320
+ messageLabel: "Description",
1321
+ messagePlaceholder: "What's the bug? What did you expect?",
1322
+ successMessageText: "Thank you for your report!",
1323
+ // Screenshot annotation labels (v10.10.0+):
1324
+ highlightToolText: "Highlight",
1325
+ hideToolText: "Hide",
1326
+ removeHighlightText: "Remove",
1327
+
1328
+ // ── Theme Overrides ───────────────────────────────────────────────────
1329
+ themeLight: {
1330
+ foreground: "#2b2233",
1331
+ background: "#ffffff",
1332
+ accentForeground: "#ffffff",
1333
+ accentBackground: "#6a3fc8",
1334
+ successColor: "#268d75",
1335
+ errorColor: "#df3338",
1336
+ },
1337
+ themeDark: {
1338
+ foreground: "#ebe6ef",
1339
+ background: "#29232f",
1340
+ accentForeground: "#ffffff",
1341
+ accentBackground: "#6a3fc8",
1342
+ successColor: "#2da98c",
1343
+ errorColor: "#f55459",
1344
+ },
1345
+
1346
+ // ── Callbacks ─────────────────────────────────────────────────────────
1347
+ onFormOpen: () => analytics.track("feedback_form_opened"),
1348
+ onFormClose: () => analytics.track("feedback_form_closed_without_submit"),
1349
+ onSubmitSuccess: (data, eventId) => {
1350
+ // data: { name, email, message }
1351
+ toast.success(`Thanks! Reference: ${eventId}`);
1352
+ },
1353
+ onSubmitError: (error) => {
1354
+ toast.error("Failed to submit feedback. Please try again.");
1355
+ },
1356
+ });
1357
+ ```
1358
+
1359
+ **Programmatic control (when `autoInject: false`):**
1360
+
1361
+ ```javascript
1362
+ // In Sentry.init
1363
+ const feedbackIntegration = Sentry.feedbackIntegration({ autoInject: false });
1364
+ Sentry.init({ integrations: [feedbackIntegration] });
1365
+
1366
+ // Elsewhere — open the widget from a button:
1367
+ document.getElementById("feedback-btn").addEventListener("click", () => {
1368
+ feedbackIntegration.openDialog();
1369
+ });
1370
+
1371
+ // Or attach to a DOM element (converts it to a trigger):
1372
+ feedbackIntegration.attachTo(document.getElementById("help-menu-item"));
1373
+ ```
1374
+
1375
+ ---
1376
+
1377
+ ### `Sentry.captureFeedback(feedback, hints?)` — Programmatic Feedback API
1378
+
1379
+ Submit feedback without any UI. Ideal for custom feedback forms you build yourself.
1380
+
1381
+ ```javascript
1382
+ // Basic
1383
+ Sentry.captureFeedback({
1384
+ name: "John Doe",
1385
+ email: "john@example.com",
1386
+ message: "The export button does nothing on Firefox.",
1387
+ });
1388
+
1389
+ // With capture context and attachments
1390
+ Sentry.captureFeedback(
1391
+ {
1392
+ name: "Jane Smith",
1393
+ email: "jane@example.com",
1394
+ message: "Chart data looks wrong after filtering by date.",
1395
+ },
1396
+ {
1397
+ captureContext: {
1398
+ tags: { page: "analytics-dashboard", browser: navigator.userAgent },
1399
+ extra: { chartConfig: JSON.stringify(currentChartConfig) },
1400
+ },
1401
+ attachments: [
1402
+ {
1403
+ filename: "screenshot.png",
1404
+ data: new Uint8Array(screenshotBuffer),
1405
+ contentType: "image/png",
1406
+ },
1407
+ ],
1408
+ },
1409
+ );
1410
+ ```
1411
+
1412
+ ---
1413
+
1414
+ ### `Sentry.showReportDialog(options)` — Crash-Report Modal
1415
+
1416
+ Shows a user-facing modal after an error.
1417
+ **Requires** an `eventId` to link the feedback to a Sentry event.
1418
+
1419
+ **From `onError` in `ErrorBoundary`:**
1420
+
1421
+ ```jsx
1422
+ <Sentry.ErrorBoundary
1423
+ onError={(error, componentStack, eventId) => {
1424
+ Sentry.showReportDialog({
1425
+ eventId,
1426
+ user: { name: currentUser.name, email: currentUser.email },
1427
+ });
1428
+ }}
1429
+ fallback={<ErrorScreen />}
1430
+ >
1431
+ <App />
1432
+ </Sentry.ErrorBoundary>
1433
+ ```
1434
+
1435
+ **From `beforeSend`:**
1436
+
1437
+ ```javascript
1438
+ Sentry.init({
1439
+ beforeSend(event, hint) {
1440
+ if (event.exception && event.event_id) {
1441
+ Sentry.showReportDialog({ eventId: event.event_id });
1442
+ }
1443
+ return event;
1444
+ },
1445
+ });
1446
+ ```
1447
+
1448
+ **From a manual catch:**
1449
+
1450
+ ```javascript
1451
+ function handleCriticalError(err) {
1452
+ const eventId = Sentry.captureException(err);
1453
+ Sentry.showReportDialog({
1454
+ eventId,
1455
+ user: { name: auth.user.displayName, email: auth.user.email },
1456
+ title: "It looks like we're having issues.",
1457
+ subtitle: "Our team has been notified.",
1458
+ subtitle2: "If you'd like to help, tell us what happened below.",
1459
+ labelComments: "Steps to reproduce:",
1460
+ labelSubmit: "Send Report",
1461
+ successMessage: "Your feedback has been sent. Thank you!",
1462
+ });
1463
+ }
1464
+ ```
1465
+
1466
+ #### Complete `showReportDialog` Options
1467
+
1468
+ | Option | Type | Notes |
1469
+ | ---------------- | ------------ | ------------------------------------------------ |
1470
+ | `eventId` | `string` | **Required.** Links feedback to the Sentry event |
1471
+ | `dsn` | `string` | Override DSN (defaults to `Sentry.init` DSN) |
1472
+ | `user.name` | `string` | Pre-fill the name field |
1473
+ | `user.email` | `string` | Pre-fill the email field |
1474
+ | `lang` | `string` | ISO language code (e.g. `"de"`, `"fr"`, `"ja"`) |
1475
+ | `title` | `string` | Modal header text |
1476
+ | `subtitle` | `string` | First subtitle line |
1477
+ | `subtitle2` | `string` | Second subtitle line |
1478
+ | `labelName` | `string` | Label for the name field |
1479
+ | `labelEmail` | `string` | Label for the email field |
1480
+ | `labelComments` | `string` | Label for the description field |
1481
+ | `labelSubmit` | `string` | Submit button text |
1482
+ | `labelClose` | `string` | Close button text |
1483
+ | `successMessage` | `string` | Shown after successful submission |
1484
+ | `onLoad` | `() => void` | Called when dialog opens |
1485
+ | `onClose` | `() => void` | Called when dialog closes (v7.82.0+) |
1486
+
1487
+ ---
1488
+
1489
+ ## React Router — Critical Error Boundary Note
1490
+
1491
+ React Router’s **default error boundary silently discards errors in production**. Always
1492
+ provide a custom `errorElement` that captures to Sentry:
1493
+
1494
+ ```jsx
1495
+ import { useRouteError } from "react-router-dom";
1496
+ import * as Sentry from "@sentry/react";
1497
+
1498
+ function RootErrorBoundary() {
1499
+ const error = useRouteError();
1500
+
1501
+ React.useEffect(() => {
1502
+ if (error instanceof Error) {
1503
+ Sentry.captureException(error, {
1504
+ tags: { source: "react-router-error-element" },
1505
+ });
1506
+ }
1507
+ }, [error]);
1508
+
1509
+ return (
1510
+ <div>
1511
+ <h1>Something went wrong</h1>
1512
+ <p>{error instanceof Error ? error.message : "An unexpected error occurred."}</p>
1513
+ <button onClick={() => window.location.reload()}>Reload page</button>
1514
+ </div>
1515
+ );
1516
+ }
1517
+
1518
+ const router = Sentry.wrapCreateBrowserRouterV6(createBrowserRouter)([
1519
+ {
1520
+ path: "/",
1521
+ element: <Layout />,
1522
+ errorElement: <RootErrorBoundary />, // ← required
1523
+ children: [/* your routes */],
1524
+ },
1525
+ ]);
1526
+ ```
1527
+
1528
+ ---
1529
+
1530
+ ## Quick Reference
1531
+
1532
+ ```javascript
1533
+ // ── Capture APIs ──────────────────────────────────────────────────────
1534
+ Sentry.captureException(error)
1535
+ Sentry.captureException(error, { level, tags, extra, contexts, fingerprint, user })
1536
+ Sentry.captureMessage("text", "warning")
1537
+ Sentry.captureMessage("text", { level, tags, extra })
1538
+ Sentry.captureEvent({ message, level, tags, extra, timestamp })
1539
+ Sentry.captureReactException(error, reactErrorInfo) // ≥9.8.0 — custom class boundaries
1540
+
1541
+ // ── React 19+ Error Hooks ─────────────────────────────────────────────
1542
+ createRoot(el, {
1543
+ onUncaughtError: Sentry.reactErrorHandler(optionalCallback),
1544
+ onCaughtError: Sentry.reactErrorHandler(),
1545
+ onRecoverableError: Sentry.reactErrorHandler(),
1546
+ })
1547
+ hydrateRoot(el, <App />, { /* same three hooks */ })
1548
+
1549
+ // ── Error Boundaries (React 16+) ──────────────────────────────────────
1550
+ <Sentry.ErrorBoundary
1551
+ fallback={<UI /> | ({ error, componentStack, resetError }) => <UI />}
1552
+ onError={(error, stack, eventId) => {}}
1553
+ beforeCapture={(scope, error, stack) => {}}
1554
+ onReset={(error, stack, eventId) => {}}
1555
+ showDialog dialogOptions={{}}
1556
+ onMount={() => {}} onUnmount={(error) => {}}
1557
+ >
1558
+ Sentry.withErrorBoundary(Component, options) // HOC equivalent
1559
+
1560
+ // ── Context ───────────────────────────────────────────────────────────
1561
+ Sentry.setUser({ id, email, username, ip_address, segment, ...custom })
1562
+ Sentry.setUser(null) // clear on logout
1563
+ Sentry.setTag("key", "value")
1564
+ Sentry.setTags({ key1: "v1", key2: "v2" })
1565
+ Sentry.setContext("name", { key: value }) // structured, not searchable
1566
+ Sentry.setContext("name", null) // remove context
1567
+ Sentry.setExtra("key", value)
1568
+ Sentry.setExtras({ key1: v1 })
1569
+
1570
+ // ── Breadcrumbs ───────────────────────────────────────────────────────
1571
+ Sentry.addBreadcrumb({ type, category, message, level, data, timestamp })
1572
+
1573
+ // ── Scopes ────────────────────────────────────────────────────────────
1574
+ Sentry.withScope((scope) => { scope.setTag(...); Sentry.captureException(...) })
1575
+ Sentry.getGlobalScope() // all events, process lifetime
1576
+ Sentry.getIsolationScope() // current page/session (= Sentry.setTag etc.)
1577
+ // DON'T: Sentry.configureScope() — deprecated since SDK v8
1578
+
1579
+ // ── Filtering ─────────────────────────────────────────────────────────
1580
+ // Sentry.init({ beforeSend, ignoreErrors, allowUrls, denyUrls, sampleRate })
1581
+
1582
+ // ── User Feedback ─────────────────────────────────────────────────────
1583
+ Sentry.feedbackIntegration({ colorScheme, autoInject, showName, isEmailRequired, ... })
1584
+ Sentry.captureFeedback({ name, email, message }, { captureContext, attachments })
1585
+ Sentry.showReportDialog({ eventId, user, title, subtitle, ... })
1586
+ ```
1587
+
1588
+ ---
1589
+
1590
+ ## Troubleshooting
1591
+
1592
+ | Issue | Solution |
1593
+ | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
1594
+ | Errors appearing twice in development | Expected behavior — React Strict Mode re-throws caught errors to the global handler. Validate in production builds only. |
1595
+ | Missing component stack in issues | Requires React 17+. Ensure `LinkedErrors` integration is enabled (it is by default). |
1596
+ | React Router errors not captured | React Router’s default boundary swallows errors. Add a custom `errorElement` that calls `captureException`. |
1597
+ | `CaptureConsole` causing duplicates | React logs caught errors via `console.error`. Remove `CaptureConsole` or exclude `console.error` from its config. |
1598
+ | `captureReactException` not available | Upgrade to `@sentry/react` ≥9.8.0. |
1599
+ | `reactErrorHandler` not available | Upgrade to `@sentry/react` ≥8.6.0. |
1600
+ | Errors captured without user context | Call `Sentry.setUser()` after login, not inside `Sentry.init`. It must be called after authentication completes. |
1601
+ | `configureScope is not a function` | Deprecated in SDK v8. Replace with `getIsolationScope()` or `withScope()`. |
1602
+ | Tags not appearing on events | Tags set via `Sentry.setTag()` go to the isolation scope; verify you’re not clearing it unexpectedly. |
1603
+ | `showReportDialog` shows but has no event | Pass `eventId` from `Sentry.captureException(err)` return value or from `onError` prop. |
1604
+ | `feedbackIntegration` button not appearing | Confirm `feedbackIntegration()` is in the `integrations` array in `Sentry.init`. Check for z-index conflicts. |
1605
+ | `beforeSend` returning `null` but events still sent | Check `beforeSendTransaction` — a separate hook for performance events. Also verify no other SDK instance is active. |
1606
+ | High event volume from known errors | Add patterns to `ignoreErrors`, or use `sampleRate` to reduce volume. Use `beforeSend` for type-specific filtering. |
1607
+ | Errors from browser extensions captured | Add `/extensions\//i` and `/^chrome:\/\//i` to `denyUrls`. |