@tanstack/cta-framework-react-cra 0.37.2 → 0.38.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.
- package/add-ons/sentry/assets/instrument.server.mjs +3 -0
- package/add-ons/sentry/assets/src/routes/demo/sentry.testing.tsx +439 -434
- package/add-ons/start/assets/src/router.tsx.ejs +2 -0
- package/dist/checksum.js +1 -1
- package/dist/types/checksum.d.ts +1 -1
- package/package.json +1 -1
- package/src/checksum.ts +1 -1
|
@@ -4,4 +4,7 @@ Sentry.init({
|
|
|
4
4
|
// Adds request headers and IP for users, for more info visit:
|
|
5
5
|
// https://docs.sentry.io/platforms/javascript/guides/tanstackstart-react/configuration/options/#sendDefaultPii
|
|
6
6
|
sendDefaultPii: true,
|
|
7
|
+
tracesSampleRate: 1.0,
|
|
8
|
+
replaysSessionSampleRate: 1.0,
|
|
9
|
+
replaysOnErrorSampleRate: 1.0,
|
|
7
10
|
})
|
|
@@ -10,7 +10,7 @@ import * as fs from 'node:fs/promises'
|
|
|
10
10
|
import { createFileRoute } from '@tanstack/react-router'
|
|
11
11
|
import { createServerFn } from '@tanstack/react-start'
|
|
12
12
|
import * as Sentry from '@sentry/tanstackstart-react'
|
|
13
|
-
import { useState, useEffect
|
|
13
|
+
import { useState, useEffect } from 'react'
|
|
14
14
|
|
|
15
15
|
export const Route = createFileRoute('/demo/sentry/testing')({
|
|
16
16
|
component: RouteComponent,
|
|
@@ -18,10 +18,38 @@ export const Route = createFileRoute('/demo/sentry/testing')({
|
|
|
18
18
|
useEffect(() => {
|
|
19
19
|
Sentry.captureException(error)
|
|
20
20
|
}, [error])
|
|
21
|
-
return
|
|
21
|
+
return (
|
|
22
|
+
<div className="min-h-screen flex items-center justify-center bg-[#181423]">
|
|
23
|
+
<div className="text-center p-8">
|
|
24
|
+
<SentryLogo />
|
|
25
|
+
<h1 className="text-2xl font-bold text-white mt-4 mb-2">
|
|
26
|
+
Something went wrong
|
|
27
|
+
</h1>
|
|
28
|
+
<p className="text-[#A49FB5]">{error.message}</p>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
)
|
|
22
32
|
},
|
|
23
33
|
})
|
|
24
34
|
|
|
35
|
+
// Sentry Logo Component
|
|
36
|
+
function SentryLogo({ size = 48 }: { size?: number }) {
|
|
37
|
+
return (
|
|
38
|
+
<svg
|
|
39
|
+
height={size}
|
|
40
|
+
width={size}
|
|
41
|
+
fill="none"
|
|
42
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
43
|
+
viewBox="0 0 40 40"
|
|
44
|
+
>
|
|
45
|
+
<path
|
|
46
|
+
d="M21.85 2.995a3.698 3.698 0 0 1 1.353 1.354l16.303 28.278a3.703 3.703 0 0 1-1.354 5.053 3.694 3.694 0 0 1-1.848.496h-3.828a31.149 31.149 0 0 0 0-3.09h3.815a.61.61 0 0 0 .537-.917L20.523 5.893a.61.61 0 0 0-1.057 0l-3.739 6.494a28.948 28.948 0 0 1 9.63 10.453 28.988 28.988 0 0 1 3.499 13.78v1.542h-9.852v-1.544a19.106 19.106 0 0 0-2.182-8.85 19.08 19.08 0 0 0-6.032-6.829l-1.85 3.208a15.377 15.377 0 0 1 6.382 12.484v1.542H3.696A3.694 3.694 0 0 1 0 34.473c0-.648.17-1.286.494-1.849l2.33-4.074a8.562 8.562 0 0 1 2.689 1.536L3.158 34.17a.611.611 0 0 0 .538.917h8.448a12.481 12.481 0 0 0-6.037-9.09l-1.344-.772 4.908-8.545 1.344.77a22.16 22.16 0 0 1 7.705 7.444 22.193 22.193 0 0 1 3.316 10.193h3.699a25.892 25.892 0 0 0-3.811-12.033 25.856 25.856 0 0 0-9.046-8.796l-1.344-.772 5.269-9.136a3.698 3.698 0 0 1 3.2-1.849c.648 0 1.285.17 1.847.495Z"
|
|
47
|
+
fill="currentColor"
|
|
48
|
+
/>
|
|
49
|
+
</svg>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
25
53
|
// Server function that will error
|
|
26
54
|
const badServerFunc = createServerFn({
|
|
27
55
|
method: 'GET',
|
|
@@ -59,65 +87,224 @@ const goodServerFunc = createServerFn({
|
|
|
59
87
|
)
|
|
60
88
|
})
|
|
61
89
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
90
|
+
// 3D Button Component inspired by Sentry wizard
|
|
91
|
+
function SentryButton({
|
|
92
|
+
children,
|
|
93
|
+
onClick,
|
|
94
|
+
variant = 'primary',
|
|
95
|
+
disabled = false,
|
|
96
|
+
loading = false,
|
|
97
|
+
}: {
|
|
98
|
+
children: React.ReactNode
|
|
99
|
+
onClick: () => void
|
|
100
|
+
variant?: 'primary' | 'error'
|
|
101
|
+
disabled?: boolean
|
|
102
|
+
loading?: boolean
|
|
103
|
+
}) {
|
|
104
|
+
const baseColor = variant === 'error' ? '#E50045' : '#553DB8'
|
|
105
|
+
const topColor = variant === 'error' ? '#FF1A5C' : '#7553FF'
|
|
71
106
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
107
|
+
return (
|
|
108
|
+
<button
|
|
109
|
+
type="button"
|
|
110
|
+
onClick={onClick}
|
|
111
|
+
disabled={disabled || loading}
|
|
112
|
+
className="group w-full rounded-lg text-white cursor-pointer border-none p-0 transition-all disabled:cursor-not-allowed disabled:opacity-60"
|
|
113
|
+
style={{ backgroundColor: baseColor }}
|
|
114
|
+
>
|
|
115
|
+
<span
|
|
116
|
+
className="flex items-center justify-center gap-3 px-6 py-4 rounded-lg text-lg font-semibold transition-transform group-hover:-translate-y-1 group-active:translate-y-0 group-disabled:translate-y-0"
|
|
117
|
+
style={{
|
|
118
|
+
backgroundColor: topColor,
|
|
119
|
+
border: `1px solid ${baseColor}`,
|
|
120
|
+
}}
|
|
121
|
+
>
|
|
122
|
+
{loading && (
|
|
123
|
+
<svg
|
|
124
|
+
className="animate-spin h-5 w-5"
|
|
125
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
126
|
+
fill="none"
|
|
127
|
+
viewBox="0 0 24 24"
|
|
128
|
+
>
|
|
129
|
+
<circle
|
|
130
|
+
className="opacity-25"
|
|
131
|
+
cx="12"
|
|
132
|
+
cy="12"
|
|
133
|
+
r="10"
|
|
134
|
+
stroke="currentColor"
|
|
135
|
+
strokeWidth="4"
|
|
136
|
+
/>
|
|
137
|
+
<path
|
|
138
|
+
className="opacity-75"
|
|
139
|
+
fill="currentColor"
|
|
140
|
+
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
141
|
+
/>
|
|
142
|
+
</svg>
|
|
143
|
+
)}
|
|
144
|
+
{children}
|
|
145
|
+
</span>
|
|
146
|
+
</button>
|
|
147
|
+
)
|
|
148
|
+
}
|
|
77
149
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
150
|
+
// Feature Card Component
|
|
151
|
+
function FeatureCard({
|
|
152
|
+
icon,
|
|
153
|
+
title,
|
|
154
|
+
description,
|
|
155
|
+
}: {
|
|
156
|
+
icon: React.ReactNode
|
|
157
|
+
title: string
|
|
158
|
+
description: string
|
|
159
|
+
}) {
|
|
160
|
+
return (
|
|
161
|
+
<div className="bg-[#1C1825] rounded-xl p-4 border border-[#2D2640] hover:border-[#7553FF]/50 transition-all group">
|
|
162
|
+
<div className="flex items-center gap-3 mb-2">
|
|
163
|
+
<div className="text-[#7553FF] group-hover:scale-110 transition-transform">
|
|
164
|
+
{icon}
|
|
165
|
+
</div>
|
|
166
|
+
<h3 className="font-semibold text-white">{title}</h3>
|
|
167
|
+
</div>
|
|
168
|
+
<p className="text-sm text-[#A49FB5] pl-9">{description}</p>
|
|
169
|
+
</div>
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Result Badge Component
|
|
174
|
+
function ResultBadge({
|
|
175
|
+
type,
|
|
176
|
+
spanOp,
|
|
177
|
+
onCopy,
|
|
178
|
+
}: {
|
|
179
|
+
type: 'success' | 'error'
|
|
180
|
+
spanOp: string
|
|
181
|
+
onCopy: () => void
|
|
182
|
+
}) {
|
|
183
|
+
const [copied, setCopied] = useState(false)
|
|
89
184
|
|
|
90
|
-
const handleCopy = (
|
|
91
|
-
navigator.clipboard.writeText(
|
|
92
|
-
|
|
93
|
-
|
|
185
|
+
const handleCopy = () => {
|
|
186
|
+
navigator.clipboard.writeText(spanOp)
|
|
187
|
+
setCopied(true)
|
|
188
|
+
onCopy()
|
|
189
|
+
setTimeout(() => setCopied(false), 2000)
|
|
94
190
|
}
|
|
95
191
|
|
|
192
|
+
return (
|
|
193
|
+
<div className="mt-4 space-y-3">
|
|
194
|
+
{type === 'error' && (
|
|
195
|
+
<div className="flex items-center gap-2 bg-[#E50045]/10 border border-[#E50045]/30 rounded-lg px-4 py-3">
|
|
196
|
+
<svg
|
|
197
|
+
className="w-5 h-5 text-[#FF1A5C]"
|
|
198
|
+
fill="none"
|
|
199
|
+
strokeLinecap="round"
|
|
200
|
+
strokeLinejoin="round"
|
|
201
|
+
strokeWidth="2"
|
|
202
|
+
viewBox="0 0 24 24"
|
|
203
|
+
stroke="currentColor"
|
|
204
|
+
>
|
|
205
|
+
<title>Error captured</title>
|
|
206
|
+
<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" />
|
|
207
|
+
</svg>
|
|
208
|
+
<span className="text-[#FF1A5C] text-sm font-medium">
|
|
209
|
+
Error captured and sent to Sentry
|
|
210
|
+
</span>
|
|
211
|
+
</div>
|
|
212
|
+
)}
|
|
213
|
+
|
|
214
|
+
{type === 'success' && (
|
|
215
|
+
<div className="flex items-center gap-2 bg-[#00F261]/10 border border-[#00BF4D]/30 rounded-lg px-4 py-3">
|
|
216
|
+
<svg
|
|
217
|
+
className="w-5 h-5 text-[#00F261]"
|
|
218
|
+
fill="none"
|
|
219
|
+
strokeLinecap="round"
|
|
220
|
+
strokeLinejoin="round"
|
|
221
|
+
strokeWidth="2"
|
|
222
|
+
viewBox="0 0 24 24"
|
|
223
|
+
stroke="currentColor"
|
|
224
|
+
>
|
|
225
|
+
<title>Trace complete</title>
|
|
226
|
+
<path d="M5 13l4 4L19 7" />
|
|
227
|
+
</svg>
|
|
228
|
+
<span className="text-[#00F261] text-sm font-medium">
|
|
229
|
+
Trace completed successfully
|
|
230
|
+
</span>
|
|
231
|
+
</div>
|
|
232
|
+
)}
|
|
233
|
+
|
|
234
|
+
<button
|
|
235
|
+
type="button"
|
|
236
|
+
onClick={handleCopy}
|
|
237
|
+
className="relative flex items-center gap-2 bg-[#7553FF]/10 hover:bg-[#7553FF]/20 border border-[#7553FF]/30 rounded-lg px-4 py-2 transition-all cursor-pointer w-full"
|
|
238
|
+
>
|
|
239
|
+
<span className="text-[#B3A1FF] text-sm">span.op:</span>
|
|
240
|
+
<code className="text-[#7553FF] font-mono text-sm">{spanOp}</code>
|
|
241
|
+
<svg
|
|
242
|
+
className="w-4 h-4 text-[#B3A1FF] ml-auto"
|
|
243
|
+
fill="none"
|
|
244
|
+
strokeLinecap="round"
|
|
245
|
+
strokeLinejoin="round"
|
|
246
|
+
strokeWidth="2"
|
|
247
|
+
viewBox="0 0 24 24"
|
|
248
|
+
stroke="currentColor"
|
|
249
|
+
>
|
|
250
|
+
<title>Copy to clipboard</title>
|
|
251
|
+
<path d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
|
252
|
+
</svg>
|
|
253
|
+
{copied && (
|
|
254
|
+
<span className="absolute -top-8 left-1/2 -translate-x-1/2 bg-[#00F261] text-[#181423] text-xs font-medium px-2 py-1 rounded animate-pulse">
|
|
255
|
+
Copied!
|
|
256
|
+
</span>
|
|
257
|
+
)}
|
|
258
|
+
</button>
|
|
259
|
+
</div>
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Progress Bar Component
|
|
264
|
+
function ProgressBar({ loading }: { loading: boolean }) {
|
|
265
|
+
return (
|
|
266
|
+
<div className="mt-4 flex items-center gap-3">
|
|
267
|
+
<div
|
|
268
|
+
className={`w-3 h-3 rounded-full transition-all ${loading ? 'bg-[#7553FF] animate-pulse' : 'bg-[#00F261]'}`}
|
|
269
|
+
/>
|
|
270
|
+
<div className="flex-1 h-2 bg-[#2D2640] rounded-full overflow-hidden">
|
|
271
|
+
<div
|
|
272
|
+
className="h-full bg-gradient-to-r from-[#7553FF] to-[#B3A1FF] rounded-full transition-all duration-500"
|
|
273
|
+
style={{ width: loading ? '60%' : '100%' }}
|
|
274
|
+
/>
|
|
275
|
+
</div>
|
|
276
|
+
<span className="text-xs text-[#A49FB5] w-16 text-right">
|
|
277
|
+
{loading ? 'Running...' : 'Complete'}
|
|
278
|
+
</span>
|
|
279
|
+
</div>
|
|
280
|
+
)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function RouteComponent() {
|
|
284
|
+
const [isLoading, setIsLoading] = useState<Record<string, boolean>>({})
|
|
285
|
+
const [results, setResults] = useState<
|
|
286
|
+
Record<string, { type: 'success' | 'error'; spanOp: string }>
|
|
287
|
+
>({})
|
|
288
|
+
|
|
96
289
|
const handleClientError = async () => {
|
|
97
290
|
setIsLoading((prev) => ({ ...prev, clientError: true }))
|
|
98
|
-
setHasError((prev) => ({ ...prev, clientError: false }))
|
|
99
|
-
setShowTrace((prev) => ({ ...prev, clientError: true }))
|
|
100
|
-
|
|
101
291
|
try {
|
|
102
292
|
await Sentry.startSpan(
|
|
103
|
-
{
|
|
104
|
-
name: 'Client Error Flow Demo',
|
|
105
|
-
op: 'demo.client-error-flow',
|
|
106
|
-
},
|
|
293
|
+
{ name: 'Client Error Flow Demo', op: 'demo.client-error' },
|
|
107
294
|
async () => {
|
|
108
295
|
Sentry.setContext('demo', {
|
|
109
296
|
feature: 'client-error-demo',
|
|
110
297
|
triggered_at: new Date().toISOString(),
|
|
111
298
|
})
|
|
112
|
-
|
|
113
|
-
// Simulate a client-side error
|
|
114
299
|
throw new Error('Client-side error demonstration')
|
|
115
300
|
},
|
|
116
301
|
)
|
|
117
302
|
} catch (error) {
|
|
118
|
-
setHasError((prev) => ({ ...prev, clientError: true }))
|
|
119
|
-
setSpanOps((prev) => ({ ...prev, clientError: 'demo.client-error-flow' }))
|
|
120
303
|
Sentry.captureException(error)
|
|
304
|
+
setResults((prev) => ({
|
|
305
|
+
...prev,
|
|
306
|
+
clientError: { type: 'error', spanOp: 'demo.client-error' },
|
|
307
|
+
}))
|
|
121
308
|
} finally {
|
|
122
309
|
setIsLoading((prev) => ({ ...prev, clientError: false }))
|
|
123
310
|
}
|
|
@@ -125,447 +312,265 @@ function RouteComponent() {
|
|
|
125
312
|
|
|
126
313
|
const handleServerError = async () => {
|
|
127
314
|
setIsLoading((prev) => ({ ...prev, serverError: true }))
|
|
128
|
-
setHasError((prev) => ({ ...prev, serverError: false }))
|
|
129
|
-
setShowTrace((prev) => ({ ...prev, serverError: true }))
|
|
130
|
-
|
|
131
315
|
try {
|
|
132
316
|
await Sentry.startSpan(
|
|
133
|
-
{
|
|
134
|
-
name: 'Server Error Flow Demo',
|
|
135
|
-
op: 'demo.server-error-flow',
|
|
136
|
-
},
|
|
317
|
+
{ name: 'Server Error Flow Demo', op: 'demo.server-error' },
|
|
137
318
|
async () => {
|
|
138
319
|
Sentry.setContext('demo', {
|
|
139
320
|
feature: 'server-error-demo',
|
|
140
321
|
triggered_at: new Date().toISOString(),
|
|
141
322
|
})
|
|
142
|
-
|
|
143
323
|
await badServerFunc()
|
|
144
324
|
},
|
|
145
325
|
)
|
|
146
326
|
} catch (error) {
|
|
147
|
-
setHasError((prev) => ({ ...prev, serverError: true }))
|
|
148
|
-
setSpanOps((prev) => ({ ...prev, serverError: 'demo.server-error-flow' }))
|
|
149
327
|
Sentry.captureException(error)
|
|
328
|
+
setResults((prev) => ({
|
|
329
|
+
...prev,
|
|
330
|
+
serverError: { type: 'error', spanOp: 'demo.server-error' },
|
|
331
|
+
}))
|
|
150
332
|
} finally {
|
|
151
333
|
setIsLoading((prev) => ({ ...prev, serverError: false }))
|
|
152
334
|
}
|
|
153
335
|
}
|
|
154
336
|
|
|
155
337
|
const handleClientTrace = async () => {
|
|
156
|
-
setIsLoading((prev) => ({ ...prev,
|
|
157
|
-
setShowTrace((prev) => ({ ...prev, client: true }))
|
|
158
|
-
|
|
338
|
+
setIsLoading((prev) => ({ ...prev, clientTrace: true }))
|
|
159
339
|
await Sentry.startSpan(
|
|
160
|
-
{
|
|
161
|
-
name: 'Client Operation',
|
|
162
|
-
op: 'demo.client',
|
|
163
|
-
},
|
|
340
|
+
{ name: 'Client Operation', op: 'demo.client-trace' },
|
|
164
341
|
async () => {
|
|
165
|
-
// Simulate some client-side work
|
|
166
342
|
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
167
343
|
},
|
|
168
344
|
)
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
345
|
+
setResults((prev) => ({
|
|
346
|
+
...prev,
|
|
347
|
+
clientTrace: { type: 'success', spanOp: 'demo.client-trace' },
|
|
348
|
+
}))
|
|
349
|
+
setIsLoading((prev) => ({ ...prev, clientTrace: false }))
|
|
172
350
|
}
|
|
173
351
|
|
|
174
352
|
const handleServerTrace = async () => {
|
|
175
|
-
setIsLoading((prev) => ({ ...prev,
|
|
176
|
-
setShowTrace((prev) => ({ ...prev, server: true }))
|
|
177
|
-
|
|
353
|
+
setIsLoading((prev) => ({ ...prev, serverTrace: true }))
|
|
178
354
|
try {
|
|
179
355
|
await Sentry.startSpan(
|
|
180
|
-
{
|
|
181
|
-
name: 'Server Operation',
|
|
182
|
-
op: 'demo.server',
|
|
183
|
-
},
|
|
356
|
+
{ name: 'Server Operation', op: 'demo.server-trace' },
|
|
184
357
|
async () => {
|
|
185
358
|
await goodServerFunc()
|
|
186
359
|
},
|
|
187
360
|
)
|
|
188
|
-
|
|
361
|
+
setResults((prev) => ({
|
|
362
|
+
...prev,
|
|
363
|
+
serverTrace: { type: 'success', spanOp: 'demo.server-trace' },
|
|
364
|
+
}))
|
|
189
365
|
} finally {
|
|
190
|
-
setIsLoading((prev) => ({ ...prev,
|
|
366
|
+
setIsLoading((prev) => ({ ...prev, serverTrace: false }))
|
|
191
367
|
}
|
|
192
368
|
}
|
|
193
369
|
|
|
194
370
|
return (
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
<h1 className="text-8xl font-bold mb-4 text-white">Sentry</h1>
|
|
220
|
-
<p className="text-4xl font-semibold text-white">
|
|
221
|
-
Code <span className="inline-block -rotate-9">breaks</span>, fix
|
|
222
|
-
it faster
|
|
223
|
-
</p>
|
|
371
|
+
<div
|
|
372
|
+
className="min-h-screen text-white"
|
|
373
|
+
style={{
|
|
374
|
+
fontFamily:
|
|
375
|
+
'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif',
|
|
376
|
+
background:
|
|
377
|
+
'linear-gradient(180deg, #181423 0%, #1C1825 50%, #181423 100%)',
|
|
378
|
+
}}
|
|
379
|
+
>
|
|
380
|
+
<div className="max-w-5xl mx-auto px-6 py-16">
|
|
381
|
+
{/* Header */}
|
|
382
|
+
<div className="text-center mb-16">
|
|
383
|
+
<div className="inline-flex items-center gap-4 mb-8">
|
|
384
|
+
<div className="text-[#7553FF]">
|
|
385
|
+
<SentryLogo size={56} />
|
|
386
|
+
</div>
|
|
387
|
+
<div className="text-left">
|
|
388
|
+
<h1 className="text-3xl font-bold text-white tracking-tight">
|
|
389
|
+
Sentry Demo
|
|
390
|
+
</h1>
|
|
391
|
+
<p className="text-[#A49FB5] text-sm">
|
|
392
|
+
Error monitoring & performance tracing
|
|
393
|
+
</p>
|
|
394
|
+
</div>
|
|
224
395
|
</div>
|
|
396
|
+
<p className="text-lg text-[#A49FB5] max-w-xl mx-auto leading-relaxed">
|
|
397
|
+
Click the buttons below to trigger errors and traces, then view
|
|
398
|
+
them in your{' '}
|
|
399
|
+
<a
|
|
400
|
+
href="https://sentry.io"
|
|
401
|
+
target="_blank"
|
|
402
|
+
rel="noopener noreferrer"
|
|
403
|
+
className="text-[#7553FF] hover:text-[#B3A1FF] underline transition-colors"
|
|
404
|
+
>
|
|
405
|
+
Sentry dashboard
|
|
406
|
+
</a>
|
|
407
|
+
.
|
|
408
|
+
</p>
|
|
409
|
+
</div>
|
|
225
410
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
<
|
|
231
|
-
<
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
411
|
+
{/* Features Grid */}
|
|
412
|
+
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 mb-12">
|
|
413
|
+
<FeatureCard
|
|
414
|
+
icon={
|
|
415
|
+
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
|
|
416
|
+
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" />
|
|
417
|
+
</svg>
|
|
418
|
+
}
|
|
419
|
+
title="Error Monitoring"
|
|
420
|
+
description="Client & server error tracking"
|
|
421
|
+
/>
|
|
422
|
+
<FeatureCard
|
|
423
|
+
icon={
|
|
424
|
+
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
|
|
425
|
+
<path d="M13 3v18h-2V3h2zm6 6v12h-2V9h2zM7 14v7H5v-7h2z" />
|
|
426
|
+
</svg>
|
|
427
|
+
}
|
|
428
|
+
title="Performance"
|
|
429
|
+
description="Tracing and spans visualization"
|
|
430
|
+
/>
|
|
431
|
+
<FeatureCard
|
|
432
|
+
icon={
|
|
433
|
+
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
|
|
434
|
+
<path d="M17 10.5V7c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-3.5l4 4v-11l-4 4z" />
|
|
435
|
+
</svg>
|
|
436
|
+
}
|
|
437
|
+
title="Session Replay"
|
|
438
|
+
description="Real user session playback"
|
|
439
|
+
/>
|
|
440
|
+
<FeatureCard
|
|
441
|
+
icon={
|
|
442
|
+
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
|
|
443
|
+
<path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z" />
|
|
444
|
+
</svg>
|
|
445
|
+
}
|
|
446
|
+
title="Real-time Alerts"
|
|
447
|
+
description="Instant issue notifications"
|
|
448
|
+
/>
|
|
449
|
+
</div>
|
|
450
|
+
|
|
451
|
+
{/* Testing Panels */}
|
|
452
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
453
|
+
{/* Client-Side Panel */}
|
|
454
|
+
<div className="bg-[#1C1825] rounded-2xl p-8 border border-[#2D2640]">
|
|
455
|
+
<div className="flex items-center gap-3 mb-6">
|
|
456
|
+
<div className="w-3 h-3 rounded-full bg-[#00F261]" />
|
|
457
|
+
<h2 className="text-xl font-semibold">Client-Side Testing</h2>
|
|
264
458
|
</div>
|
|
265
459
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
backgroundSize: '250% 100%',
|
|
287
|
-
}}
|
|
288
|
-
>
|
|
289
|
-
<div className="absolute inset-0 bg-gradient-to-r from-red-500/10 to-orange-500/10 opacity-0 group-hover:opacity-100 transition-opacity" />
|
|
290
|
-
<div className="relative">
|
|
291
|
-
<div className="flex items-center mb-2">
|
|
292
|
-
<span className="font-medium">
|
|
293
|
-
Trigger Client-Side Error
|
|
294
|
-
</span>
|
|
295
|
-
</div>
|
|
296
|
-
</div>
|
|
297
|
-
</button>
|
|
298
|
-
{hasError.clientError && (
|
|
299
|
-
<div className="mt-4 space-y-2">
|
|
300
|
-
<div className="bg-red-900/20 border border-red-500/50 rounded-lg p-2">
|
|
301
|
-
<div className="flex items-center text-red-400 text-sm">
|
|
302
|
-
<svg
|
|
303
|
-
className="w-4 h-4 mr-2"
|
|
304
|
-
fill="none"
|
|
305
|
-
strokeLinecap="round"
|
|
306
|
-
strokeLinejoin="round"
|
|
307
|
-
strokeWidth="2"
|
|
308
|
-
viewBox="0 0 24 24"
|
|
309
|
-
stroke="currentColor"
|
|
310
|
-
>
|
|
311
|
-
<title>Red Warning Sign</title>
|
|
312
|
-
<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" />
|
|
313
|
-
</svg>
|
|
314
|
-
Client-side error captured and traced
|
|
315
|
-
</div>
|
|
316
|
-
</div>
|
|
317
|
-
<div className="bg-purple-900/20 border border-purple-500/50 rounded-lg p-3">
|
|
318
|
-
<div className="flex items-center justify-between">
|
|
319
|
-
<div className="relative">
|
|
320
|
-
<button
|
|
321
|
-
type="button"
|
|
322
|
-
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' : ''}`}
|
|
323
|
-
onClick={() => handleCopy(spanOps.clientError)}
|
|
324
|
-
title="Click to copy operation name"
|
|
325
|
-
>
|
|
326
|
-
<span className="text-purple-300 text-sm font-medium mr-2">
|
|
327
|
-
span.op
|
|
328
|
-
</span>
|
|
329
|
-
<code className="text-purple-400 text-sm font-mono">
|
|
330
|
-
{spanOps.clientError}
|
|
331
|
-
</code>
|
|
332
|
-
</button>
|
|
333
|
-
{copiedSpan === spanOps.clientError && (
|
|
334
|
-
<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">
|
|
335
|
-
Copied!
|
|
336
|
-
</div>
|
|
337
|
-
)}
|
|
338
|
-
</div>
|
|
339
|
-
</div>
|
|
340
|
-
</div>
|
|
341
|
-
</div>
|
|
342
|
-
)}
|
|
343
|
-
</div>
|
|
460
|
+
<div className="space-y-4">
|
|
461
|
+
<div>
|
|
462
|
+
<SentryButton
|
|
463
|
+
variant="error"
|
|
464
|
+
onClick={handleClientError}
|
|
465
|
+
loading={isLoading.clientError}
|
|
466
|
+
>
|
|
467
|
+
Trigger Client Error
|
|
468
|
+
</SentryButton>
|
|
469
|
+
{isLoading.clientError && (
|
|
470
|
+
<ProgressBar loading={isLoading.clientError} />
|
|
471
|
+
)}
|
|
472
|
+
{results.clientError && !isLoading.clientError && (
|
|
473
|
+
<ResultBadge
|
|
474
|
+
type={results.clientError.type}
|
|
475
|
+
spanOp={results.clientError.spanOp}
|
|
476
|
+
onCopy={() => {}}
|
|
477
|
+
/>
|
|
478
|
+
)}
|
|
479
|
+
</div>
|
|
344
480
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
<span className="font-medium">
|
|
364
|
-
Test Client-Side Span
|
|
365
|
-
</span>
|
|
366
|
-
</div>
|
|
367
|
-
</div>
|
|
368
|
-
</button>
|
|
369
|
-
{showTrace.client && (
|
|
370
|
-
<div className="mt-4 space-y-2">
|
|
371
|
-
<div className="flex items-center">
|
|
372
|
-
<div
|
|
373
|
-
className={`w-3 h-3 rounded-full ${isLoading.client ? 'bg-blue-500 animate-pulse' : 'bg-green-500'}`}
|
|
374
|
-
/>
|
|
375
|
-
<div className="ml-2 flex-1">
|
|
376
|
-
<div className="h-1.5 bg-[#2D3555] rounded">
|
|
377
|
-
<div
|
|
378
|
-
className="h-full bg-blue-500 rounded transition-all duration-500"
|
|
379
|
-
style={{
|
|
380
|
-
width: isLoading.client ? '60%' : '100%',
|
|
381
|
-
}}
|
|
382
|
-
/>
|
|
383
|
-
</div>
|
|
384
|
-
</div>
|
|
385
|
-
</div>
|
|
386
|
-
{!isLoading.client && spanOps.client && (
|
|
387
|
-
<div className="bg-purple-900/20 border border-purple-500/50 rounded-lg p-3">
|
|
388
|
-
<div className="flex items-center justify-between">
|
|
389
|
-
<div className="relative">
|
|
390
|
-
<button
|
|
391
|
-
type="button"
|
|
392
|
-
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' : ''}`}
|
|
393
|
-
onClick={() => handleCopy(spanOps.client)}
|
|
394
|
-
title="Click to copy operation name"
|
|
395
|
-
>
|
|
396
|
-
<span className="text-purple-300 text-sm font-medium mr-2">
|
|
397
|
-
span.op
|
|
398
|
-
</span>
|
|
399
|
-
<code className="text-purple-400 text-sm font-mono">
|
|
400
|
-
{spanOps.client}
|
|
401
|
-
</code>
|
|
402
|
-
</button>
|
|
403
|
-
{copiedSpan === spanOps.client && (
|
|
404
|
-
<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">
|
|
405
|
-
Copied!
|
|
406
|
-
</div>
|
|
407
|
-
)}
|
|
408
|
-
</div>
|
|
409
|
-
</div>
|
|
410
|
-
</div>
|
|
411
|
-
)}
|
|
412
|
-
</div>
|
|
413
|
-
)}
|
|
414
|
-
</div>
|
|
415
|
-
</div>
|
|
481
|
+
<div>
|
|
482
|
+
<SentryButton
|
|
483
|
+
variant="primary"
|
|
484
|
+
onClick={handleClientTrace}
|
|
485
|
+
loading={isLoading.clientTrace}
|
|
486
|
+
>
|
|
487
|
+
Test Client Trace
|
|
488
|
+
</SentryButton>
|
|
489
|
+
{isLoading.clientTrace && (
|
|
490
|
+
<ProgressBar loading={isLoading.clientTrace} />
|
|
491
|
+
)}
|
|
492
|
+
{results.clientTrace && !isLoading.clientTrace && (
|
|
493
|
+
<ResultBadge
|
|
494
|
+
type={results.clientTrace.type}
|
|
495
|
+
spanOp={results.clientTrace.spanOp}
|
|
496
|
+
onCopy={() => {}}
|
|
497
|
+
/>
|
|
498
|
+
)}
|
|
416
499
|
</div>
|
|
500
|
+
</div>
|
|
501
|
+
</div>
|
|
417
502
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
<div>
|
|
425
|
-
<button
|
|
426
|
-
type="button"
|
|
427
|
-
onClick={() => {
|
|
428
|
-
setDemoStep((prev) => prev + 1)
|
|
429
|
-
handleServerError()
|
|
430
|
-
}}
|
|
431
|
-
className="w-full text-white rounded-md p-4 relative overflow-hidden group"
|
|
432
|
-
style={{
|
|
433
|
-
background:
|
|
434
|
-
'linear-gradient(120deg, #c83852, #b44092 25%, #6a5fc1 50%, #452650 55%, #452650)',
|
|
435
|
-
backgroundPosition: '2% 0',
|
|
436
|
-
backgroundSize: '250% 100%',
|
|
437
|
-
}}
|
|
438
|
-
>
|
|
439
|
-
<div className="absolute inset-0 bg-gradient-to-r from-red-500/10 to-orange-500/10 opacity-0 group-hover:opacity-100 transition-opacity" />
|
|
440
|
-
<div className="relative">
|
|
441
|
-
<div className="flex items-center mb-2">
|
|
442
|
-
<span className="font-medium">
|
|
443
|
-
Trigger Server Error
|
|
444
|
-
</span>
|
|
445
|
-
</div>
|
|
446
|
-
</div>
|
|
447
|
-
</button>
|
|
448
|
-
{hasError.serverError && (
|
|
449
|
-
<div className="mt-4 space-y-2">
|
|
450
|
-
<div className="bg-red-900/20 border border-red-500/50 rounded-lg p-3">
|
|
451
|
-
<div className="flex items-center text-red-400 text-sm">
|
|
452
|
-
<svg
|
|
453
|
-
className="w-4 h-4 mr-2"
|
|
454
|
-
fill="none"
|
|
455
|
-
strokeLinecap="round"
|
|
456
|
-
strokeLinejoin="round"
|
|
457
|
-
strokeWidth="2"
|
|
458
|
-
viewBox="0 0 24 24"
|
|
459
|
-
stroke="currentColor"
|
|
460
|
-
>
|
|
461
|
-
<title>Red Warning Sign</title>
|
|
462
|
-
<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" />
|
|
463
|
-
</svg>
|
|
464
|
-
Server-side error captured and traced
|
|
465
|
-
</div>
|
|
466
|
-
</div>
|
|
467
|
-
<div className="bg-purple-900/20 border border-purple-500/50 rounded-lg p-3">
|
|
468
|
-
<div className="flex items-center justify-between">
|
|
469
|
-
<div className="relative">
|
|
470
|
-
<button
|
|
471
|
-
type="button"
|
|
472
|
-
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' : ''}`}
|
|
473
|
-
onClick={() => handleCopy(spanOps.serverError)}
|
|
474
|
-
title="Click to copy operation name"
|
|
475
|
-
>
|
|
476
|
-
<span className="text-purple-300 text-sm font-medium mr-2">
|
|
477
|
-
span.op
|
|
478
|
-
</span>
|
|
479
|
-
<code className="text-purple-400 text-sm font-mono">
|
|
480
|
-
{spanOps.serverError}
|
|
481
|
-
</code>
|
|
482
|
-
</button>
|
|
483
|
-
{copiedSpan === spanOps.serverError && (
|
|
484
|
-
<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">
|
|
485
|
-
Copied!
|
|
486
|
-
</div>
|
|
487
|
-
)}
|
|
488
|
-
</div>
|
|
489
|
-
</div>
|
|
490
|
-
</div>
|
|
491
|
-
</div>
|
|
492
|
-
)}
|
|
493
|
-
</div>
|
|
503
|
+
{/* Server-Side Panel */}
|
|
504
|
+
<div className="bg-[#1C1825] rounded-2xl p-8 border border-[#2D2640]">
|
|
505
|
+
<div className="flex items-center gap-3 mb-6">
|
|
506
|
+
<div className="w-3 h-3 rounded-full bg-[#7553FF]" />
|
|
507
|
+
<h2 className="text-xl font-semibold">Server-Side Testing</h2>
|
|
508
|
+
</div>
|
|
494
509
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
{!isLoading.server && spanOps.server && (
|
|
535
|
-
<div className="bg-purple-900/20 border border-purple-500/50 rounded-lg p-3">
|
|
536
|
-
<div className="flex items-center justify-between">
|
|
537
|
-
<div className="relative">
|
|
538
|
-
<button
|
|
539
|
-
type="button"
|
|
540
|
-
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' : ''}`}
|
|
541
|
-
onClick={() => handleCopy(spanOps.server)}
|
|
542
|
-
title="Click to copy operation name"
|
|
543
|
-
>
|
|
544
|
-
<span className="text-purple-300 text-sm font-medium mr-2">
|
|
545
|
-
span.op
|
|
546
|
-
</span>
|
|
547
|
-
<code className="text-purple-400 text-sm font-mono">
|
|
548
|
-
{spanOps.server}
|
|
549
|
-
</code>
|
|
550
|
-
</button>
|
|
551
|
-
{copiedSpan === spanOps.server && (
|
|
552
|
-
<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">
|
|
553
|
-
Copied!
|
|
554
|
-
</div>
|
|
555
|
-
)}
|
|
556
|
-
</div>
|
|
557
|
-
</div>
|
|
558
|
-
</div>
|
|
559
|
-
)}
|
|
560
|
-
</div>
|
|
561
|
-
)}
|
|
562
|
-
</div>
|
|
563
|
-
</div>
|
|
510
|
+
<div className="space-y-4">
|
|
511
|
+
<div>
|
|
512
|
+
<SentryButton
|
|
513
|
+
variant="error"
|
|
514
|
+
onClick={handleServerError}
|
|
515
|
+
loading={isLoading.serverError}
|
|
516
|
+
>
|
|
517
|
+
Trigger Server Error
|
|
518
|
+
</SentryButton>
|
|
519
|
+
{isLoading.serverError && (
|
|
520
|
+
<ProgressBar loading={isLoading.serverError} />
|
|
521
|
+
)}
|
|
522
|
+
{results.serverError && !isLoading.serverError && (
|
|
523
|
+
<ResultBadge
|
|
524
|
+
type={results.serverError.type}
|
|
525
|
+
spanOp={results.serverError.spanOp}
|
|
526
|
+
onCopy={() => {}}
|
|
527
|
+
/>
|
|
528
|
+
)}
|
|
529
|
+
</div>
|
|
530
|
+
|
|
531
|
+
<div>
|
|
532
|
+
<SentryButton
|
|
533
|
+
variant="primary"
|
|
534
|
+
onClick={handleServerTrace}
|
|
535
|
+
loading={isLoading.serverTrace}
|
|
536
|
+
>
|
|
537
|
+
Test Server Trace
|
|
538
|
+
</SentryButton>
|
|
539
|
+
{isLoading.serverTrace && (
|
|
540
|
+
<ProgressBar loading={isLoading.serverTrace} />
|
|
541
|
+
)}
|
|
542
|
+
{results.serverTrace && !isLoading.serverTrace && (
|
|
543
|
+
<ResultBadge
|
|
544
|
+
type={results.serverTrace.type}
|
|
545
|
+
spanOp={results.serverTrace.spanOp}
|
|
546
|
+
onCopy={() => {}}
|
|
547
|
+
/>
|
|
548
|
+
)}
|
|
564
549
|
</div>
|
|
565
550
|
</div>
|
|
566
551
|
</div>
|
|
567
552
|
</div>
|
|
553
|
+
|
|
554
|
+
{/* Footer Note */}
|
|
555
|
+
<div className="mt-12 text-center">
|
|
556
|
+
<p className="text-sm text-[#6E6C75]">
|
|
557
|
+
This page uses{' '}
|
|
558
|
+
<code className="bg-[#1C1825] px-2 py-1 rounded text-[#B3A1FF]">
|
|
559
|
+
@sentry/tanstackstart-react
|
|
560
|
+
</code>{' '}
|
|
561
|
+
for full-stack error monitoring.
|
|
562
|
+
<br />
|
|
563
|
+
<a
|
|
564
|
+
href="https://docs.sentry.io/platforms/javascript/guides/tanstackstart-react/"
|
|
565
|
+
target="_blank"
|
|
566
|
+
rel="noopener noreferrer"
|
|
567
|
+
className="text-[#7553FF] hover:text-[#B3A1FF] underline transition-colors"
|
|
568
|
+
>
|
|
569
|
+
Read the documentation →
|
|
570
|
+
</a>
|
|
571
|
+
</p>
|
|
572
|
+
</div>
|
|
568
573
|
</div>
|
|
569
|
-
|
|
574
|
+
</div>
|
|
570
575
|
)
|
|
571
576
|
}
|
package/dist/checksum.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// This file is auto-generated. Do not edit manually.
|
|
2
2
|
// Generated from add-ons, examples, hosts, project, and toolchains directories
|
|
3
|
-
export const contentChecksum = '
|
|
3
|
+
export const contentChecksum = 'a2932d45e0b8b23cc8ea876ec00379239a4dbacc8f01dbe99a4f6bf68bffe6b4';
|
package/dist/types/checksum.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const contentChecksum = "
|
|
1
|
+
export declare const contentChecksum = "a2932d45e0b8b23cc8ea876ec00379239a4dbacc8f01dbe99a4f6bf68bffe6b4";
|
package/package.json
CHANGED
package/src/checksum.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// This file is auto-generated. Do not edit manually.
|
|
2
2
|
// Generated from add-ons, examples, hosts, project, and toolchains directories
|
|
3
|
-
export const contentChecksum = '
|
|
3
|
+
export const contentChecksum = 'a2932d45e0b8b23cc8ea876ec00379239a4dbacc8f01dbe99a4f6bf68bffe6b4'
|