Skip to content

Commit 13e1079

Browse files
jherrFatahChan
andauthored
fix: sentry updates (#92)
Fixes the sentry add-on --------- Co-authored-by: FatahChan <[email protected]>
1 parent d42ef85 commit 13e1079

File tree

13 files changed

+130
-101
lines changed

13 files changed

+130
-101
lines changed

packages/cta-engine/src/create-app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,6 @@ Use the following commands to start your app:
792792
% cd ${options.projectName}
793793
% ${startCommand}
794794
795-
Please read the README.md for more information on testing, styling, adding routes, react-query, etc.${errorStatement}`)
795+
Please check the README.md for more information on testing, styling, adding routes, react-query, etc.${errorStatement}`)
796796
}
797797
}

packages/cta-engine/templates/react/add-on/sentry/assets/_dot_cursorrules.append

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ Error collection is automatic and configured in `src/router.tsx`.
66

77
## Instrumentation
88

9-
We want our server functions intstrumented. So if you see a function name like `createServerFn`, you can instrument it with Sentry. You'll need to import `Sentry`:
9+
We want our server functions instrumented. So if you see a function name like `createServerFn`, you can instrument it with Sentry. You'll need to import `Sentry`:
1010

1111
```tsx
12-
import * as Sentry from '@sentry/browser'
12+
import * as Sentry from '@sentry/tanstackstart-react'
1313
```
1414

15-
And then wrap the implementation of the server function with `Sentry.startSpan`, liks so:
15+
And then wrap the implementation of the server function with `Sentry.startSpan`, like so:
1616

1717
```tsx
1818
Sentry.startSpan({ name: 'Requesting all the pokemon' }, async () => {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,11 @@
11
# Your Sentry DSN (from your Sentry account)
22
VITE_SENTRY_DSN=
3+
4+
# Your Sentry organization (from your Sentry account)
5+
VITE_SENTRY_ORG=
6+
7+
# Your Sentry project (from your Sentry account)
8+
VITE_SENTRY_PROJECT=
9+
10+
# Your Sentry authentication token (from your Sentry account)
11+
SENTRY_AUTH_TOKEN=
Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,11 @@
1-
import { createIsomorphicFn } from '@tanstack/react-start'
2-
import * as Sentry from "@sentry/react";
3-
import * as SentryServer from "@sentry/node";
1+
import * as Sentry from "@sentry/tanstackstart-react";
2+
import {
3+
createMiddleware,
4+
registerGlobalMiddleware,
5+
} from "@tanstack/react-start";
46

5-
createIsomorphicFn().server(() => {
6-
console.log('Sentry init server')
7-
SentryServer.init({
8-
dsn: import.meta.env.VITE_SENTRY_DSN,
9-
tracesSampleRate: 1.0,
10-
profilesSampleRate: 1.0,
11-
})
12-
}).client(() => {
13-
console.log('Sentry init client')
14-
Sentry.init({
15-
dsn: import.meta.env.VITE_SENTRY_DSN,
16-
tracesSampleRate: 1.0,
17-
profilesSampleRate: 1.0,
18-
integrations: [
19-
Sentry.replayIntegration({
20-
maskAllText: false,
21-
blockAllMedia: false,
22-
})
23-
]
24-
})
25-
})()
7+
registerGlobalMiddleware({
8+
middleware: [
9+
createMiddleware().server(Sentry.sentryGlobalServerMiddlewareHandler()),
10+
],
11+
});

packages/cta-engine/templates/react/add-on/sentry/assets/src/routes/demo.sentry.testing.tsx

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99
import * as fs from 'node:fs/promises'
1010
import { createFileRoute } from '@tanstack/react-router'
1111
import { createServerFn } from '@tanstack/react-start'
12-
import * as Sentry from '@sentry/react'
13-
import * as SentryServer from '@sentry/node'
12+
import * as Sentry from "@sentry/tanstackstart-react";
1413
import { useState, useEffect, useRef } from 'react'
1514

1615
export const Route = createFileRoute('/demo/sentry/testing')({
@@ -21,7 +20,7 @@ export const Route = createFileRoute('/demo/sentry/testing')({
2120
const badServerFunc = createServerFn({
2221
method: 'GET',
2322
}).handler(async () => {
24-
return await SentryServer.startSpan(
23+
return await Sentry.startSpan(
2524
{
2625
name: 'Reading non-existent file',
2726
op: 'file.read'
@@ -31,7 +30,7 @@ const badServerFunc = createServerFn({
3130
await fs.readFile('./doesnt-exist', 'utf-8')
3231
return true
3332
} catch (error) {
34-
SentryServer.captureException(error)
33+
Sentry.captureException(error)
3534
throw error
3635
}
3736
}
@@ -42,7 +41,7 @@ const badServerFunc = createServerFn({
4241
const goodServerFunc = createServerFn({
4342
method: 'GET',
4443
}).handler(async () => {
45-
return await SentryServer.startSpan(
44+
return await Sentry.startSpan(
4645
{
4746
name: 'Successful server operation',
4847
op: 'demo.success'
@@ -244,6 +243,7 @@ function RouteComponent() {
244243
<div className="space-y-6">
245244
<div>
246245
<button
246+
type="button"
247247
onClick={() => {
248248
setDemoStep(prev => prev + 1)
249249
handleClientError()
@@ -267,22 +267,24 @@ function RouteComponent() {
267267
<div className="bg-red-900/20 border border-red-500/50 rounded-lg p-2">
268268
<div className="flex items-center text-red-400 text-sm">
269269
<svg className="w-4 h-4 mr-2" fill="none" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" viewBox="0 0 24 24" stroke="currentColor">
270-
<path d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
270+
<title>Red Warning Sign</title>
271+
<path d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
271272
</svg>
272273
Client-side error captured and traced
273274
</div>
274275
</div>
275276
<div className="bg-purple-900/20 border border-purple-500/50 rounded-lg p-3">
276277
<div className="flex items-center justify-between">
277278
<div className="relative">
278-
<div
279+
<button
280+
type="button"
279281
className={`inline-flex items-center bg-purple-900/40 px-3 py-1.5 rounded-lg border border-purple-500/50 cursor-pointer hover:bg-purple-900/60 transition-all ${copiedSpan === spanOps.clientError ? 'scale-95' : ''}`}
280282
onClick={() => handleCopy(spanOps.clientError)}
281283
title="Click to copy operation name"
282284
>
283285
<span className="text-purple-300 text-sm font-medium mr-2">span.op</span>
284286
<code className="text-purple-400 text-sm font-mono">{spanOps.clientError}</code>
285-
</div>
287+
</button>
286288
{copiedSpan === spanOps.clientError && (
287289
<div className="absolute -top-8 left-1/2 -translate-x-1/2 bg-green-500/90 text-white text-xs px-2 py-1 rounded animate-fade-out">
288290
Copied!
@@ -297,6 +299,7 @@ function RouteComponent() {
297299

298300
<div>
299301
<button
302+
type="button"
300303
onClick={() => {
301304
setDemoStep(prev => prev + 1)
302305
handleClientTrace()
@@ -332,14 +335,15 @@ function RouteComponent() {
332335
<div className="bg-purple-900/20 border border-purple-500/50 rounded-lg p-3">
333336
<div className="flex items-center justify-between">
334337
<div className="relative">
335-
<div
338+
<button
339+
type="button"
336340
className={`inline-flex items-center bg-purple-900/40 px-3 py-1.5 rounded-lg border border-purple-500/50 cursor-pointer hover:bg-purple-900/60 transition-all ${copiedSpan === spanOps.client ? 'scale-95' : ''}`}
337341
onClick={() => handleCopy(spanOps.client)}
338342
title="Click to copy operation name"
339343
>
340344
<span className="text-purple-300 text-sm font-medium mr-2">span.op</span>
341345
<code className="text-purple-400 text-sm font-mono">{spanOps.client}</code>
342-
</div>
346+
</button>
343347
{copiedSpan === spanOps.client && (
344348
<div className="absolute -top-8 left-1/2 -translate-x-1/2 bg-green-500/90 text-white text-xs px-2 py-1 rounded animate-fade-out">
345349
Copied!
@@ -361,6 +365,7 @@ function RouteComponent() {
361365
<div className="space-y-6">
362366
<div>
363367
<button
368+
type="button"
364369
onClick={() => {
365370
setDemoStep(prev => prev + 1)
366371
handleServerError()
@@ -384,6 +389,7 @@ function RouteComponent() {
384389
<div className="bg-red-900/20 border border-red-500/50 rounded-lg p-3">
385390
<div className="flex items-center text-red-400 text-sm">
386391
<svg className="w-4 h-4 mr-2" fill="none" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" viewBox="0 0 24 24" stroke="currentColor">
392+
<title>Red Warning Sign</title>
387393
<path d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
388394
</svg>
389395
Server-side error captured and traced
@@ -392,14 +398,15 @@ function RouteComponent() {
392398
<div className="bg-purple-900/20 border border-purple-500/50 rounded-lg p-3">
393399
<div className="flex items-center justify-between">
394400
<div className="relative">
395-
<div
401+
<button
402+
type="button"
396403
className={`inline-flex items-center bg-purple-900/40 px-3 py-1.5 rounded-lg border border-purple-500/50 cursor-pointer hover:bg-purple-900/60 transition-all ${copiedSpan === spanOps.serverError ? 'scale-95' : ''}`}
397404
onClick={() => handleCopy(spanOps.serverError)}
398405
title="Click to copy operation name"
399406
>
400407
<span className="text-purple-300 text-sm font-medium mr-2">span.op</span>
401408
<code className="text-purple-400 text-sm font-mono">{spanOps.serverError}</code>
402-
</div>
409+
</button>
403410
{copiedSpan === spanOps.serverError && (
404411
<div className="absolute -top-8 left-1/2 -translate-x-1/2 bg-green-500/90 text-white text-xs px-2 py-1 rounded animate-fade-out">
405412
Copied!
@@ -414,6 +421,7 @@ function RouteComponent() {
414421

415422
<div>
416423
<button
424+
type="button"
417425
onClick={() => {
418426
setDemoStep(prev => prev + 1)
419427
handleServerTrace()
@@ -449,14 +457,15 @@ function RouteComponent() {
449457
<div className="bg-purple-900/20 border border-purple-500/50 rounded-lg p-3">
450458
<div className="flex items-center justify-between">
451459
<div className="relative">
452-
<div
460+
<button
461+
type="button"
453462
className={`inline-flex items-center bg-purple-900/40 px-3 py-1.5 rounded-lg border border-purple-500/50 cursor-pointer hover:bg-purple-900/60 transition-all ${copiedSpan === spanOps.server ? 'scale-95' : ''}`}
454463
onClick={() => handleCopy(spanOps.server)}
455464
title="Click to copy operation name"
456465
>
457466
<span className="text-purple-300 text-sm font-medium mr-2">span.op</span>
458467
<code className="text-purple-400 text-sm font-mono">{spanOps.server}</code>
459-
</div>
468+
</button>
460469
{copiedSpan === spanOps.server && (
461470
<div className="absolute -top-8 left-1/2 -translate-x-1/2 bg-green-500/90 text-white text-xs px-2 py-1 rounded animate-fade-out">
462471
Copied!
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
{
22
"dependencies": {
3-
"@sentry/node": "^9.1.0",
4-
"@sentry/profiling-node": "^9.1.0",
5-
"@sentry/react": "^9.1.0"
3+
"@sentry/tanstackstart-react": "^9.12.0"
64
}
75
}

packages/cta-engine/templates/react/add-on/start/assets/app.config.ts.ejs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { defineConfig } from '@tanstack/react-start/config'
22
import viteTsConfigPaths from 'vite-tsconfig-paths'<% if (tailwind) { %>
33
import tailwindcss from "@tailwindcss/vite"
4+
<% } %><% if (addOnEnabled['sentry']) { %>
5+
import { wrapVinxiConfigWithSentry } from "@sentry/tanstackstart-react";
46
<% } %>
5-
6-
export default defineConfig({
7+
const config = defineConfig({
78
tsr: {
89
appDirectory: 'src',
910
},
@@ -17,3 +18,15 @@ export default defineConfig({
1718
],
1819
},
1920
})
21+
22+
<% if (addOnEnabled['sentry']) { %>
23+
export default wrapVinxiConfigWithSentry(config, {
24+
org: process.env.VITE_SENTRY_ORG,
25+
project: process.env.VITE_SENTRY_PROJECT,
26+
authToken: process.env.SENTRY_AUTH_TOKEN,
27+
// Only print logs for uploading source maps in CI
28+
// Set to `true` to suppress logs
29+
silent: !process.env.CI,
30+
});<% } else { %>
31+
export default config
32+
<% } %>

packages/cta-engine/templates/react/add-on/start/assets/src/client.tsx

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { hydrateRoot } from 'react-dom/client'
2+
import { StartClient } from '@tanstack/react-start'
3+
<% if (addOnEnabled['sentry']) { %>
4+
import * as Sentry from "@sentry/tanstackstart-react";
5+
<% } %>
6+
import { createRouter } from './router'
7+
8+
const router = createRouter()
9+
10+
<% if (addOnEnabled['sentry']) { %>
11+
Sentry.init({
12+
dsn: import.meta.env.VITE_SENTRY_DSN,
13+
integrations: [
14+
Sentry.tanstackRouterBrowserTracingIntegration(router),
15+
Sentry.replayIntegration({
16+
maskAllText: false,
17+
blockAllMedia: false,
18+
}),
19+
],
20+
// Set tracesSampleRate to 1.0 to capture 100%
21+
// of transactions for tracing.
22+
// We recommend adjusting this value in production.
23+
// Learn more at https://docs.sentry.io/platforms/javascript/configuration/options/#traces-sample-rate
24+
tracesSampleRate: 1.0,
25+
// Capture Replay for 10% of all sessions,
26+
// plus for 100% of sessions with an error.
27+
// Learn more at https://docs.sentry.io/platforms/javascript/session-replay/configuration/#general-integration-configuration
28+
replaysSessionSampleRate: 0.1,
29+
replaysOnErrorSampleRate: 1.0,
30+
});
31+
<% } %>
32+
33+
hydrateRoot(document, <StartClient router={router} />)

packages/cta-engine/templates/react/add-on/start/assets/src/router.tsx.ejs

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import { createRouter as createTanstackRouter } from '@tanstack/react-router'<% if (addOnEnabled.sentry) { %>
2-
import * as Sentry from '@sentry/react'
3-
import * as SentryServer from '@sentry/node'
4-
import { createIsomorphicFn } from '@tanstack/react-start'
5-
<% } %><% if (addOnEnabled['tanstack-query']) { %>
1+
import { createRouter as createTanstackRouter } from '@tanstack/react-router'<% if (addOnEnabled['tanstack-query']) { %>
62
import { routerWithQueryClient } from '@tanstack/react-router-with-query'
73
import * as TanstackQuery from './integrations/tanstack-query/root-provider'
84
<% } %>
@@ -44,31 +40,6 @@ export const createRouter = () => {
4440
return router
4541
}
4642

47-
<% if (addOnEnabled.sentry) { %>
48-
const router = createRouter()
49-
createIsomorphicFn().server(() => {
50-
SentryServer.init({
51-
dsn: import.meta.env.VITE_SENTRY_DSN,
52-
tracesSampleRate: 1.0,
53-
profilesSampleRate: 1.0,
54-
})
55-
}).client(() => {
56-
Sentry.init({
57-
dsn: import.meta.env.VITE_SENTRY_DSN,
58-
integrations: [
59-
Sentry.replayIntegration({
60-
maskAllText: false,
61-
blockAllMedia: false,
62-
}),
63-
Sentry.tanstackRouterBrowserTracingIntegration(router),
64-
],
65-
tracesSampleRate: 1.0,
66-
replaysSessionSampleRate: 1.0,
67-
replaysOnErrorSampleRate: 1.0,
68-
})
69-
})()
70-
<% } %>
71-
7243
// Register the router instance for type safety
7344
declare module '@tanstack/react-router' {
7445
interface Register {

0 commit comments

Comments
 (0)