// Generated by scripts/generate-manifest.mjs. Do not edit by hand. import type { AddOnCompiled } from '../../../../../types.js' type TemplateRecord = Record type TemplateAddOn = TemplateRecord & { integrations?: Array routes?: Array } type TemplateRenderContext = { [key: string]: any packageManager: any projectName: any typescript: any tailwind: any blank: any js: any jsx: any fileRouter: any codeRouter: any routerOnly: any includeExamples: any addOnEnabled: Record addOnOption: Record addOns: Array integrations: Array routes: Array getPackageManagerAddScript: (...args: Array) => string getPackageManagerRunScript: (...args: Array) => string getPackageManagerExecuteScript: (...args: Array) => string relativePath: (...args: Array) => string integrationImportContent: (...args: Array) => string integrationImportCode: (...args: Array) => string | undefined renderTemplate: (content: string) => string ignoreFile: () => never } type TemplateRenderer = (context: TemplateRenderContext) => string | undefined function __escapeXML(value: unknown) { if (value === undefined || value === null) { return '' } return String(value).replace(/[&<>'"]/g, (character) => { switch (character) { case '&': return '&' case '<': return '<' case '>': return '>' case '"': return '"' case "'": return ''' default: return character } }) } export function getManifestTemplateKey(template: string) { let hash = 0x811c9dc5 for (let i = 0; i < template.length; i++) { hash ^= template.charCodeAt(i) hash = Math.imul(hash, 0x01000193) >>> 0 } return `${hash.toString(16).padStart(8, '0')}:${template.length}` } function __render_66f4457e_670(context: TemplateRenderContext) { const { packageManager, projectName, typescript, tailwind, blank, js, jsx, fileRouter, codeRouter, routerOnly, includeExamples, addOnEnabled, addOnOption, addOns, integrations, routes, getPackageManagerAddScript, getPackageManagerRunScript, getPackageManagerExecuteScript, relativePath, integrationImportContent, integrationImportCode, renderTemplate, ignoreFile, } = context let __output = '' const __append = (value: unknown) => { if (value !== undefined && value !== null) { __output += String(value) } } __append("{\n \"scripts\": {\n \"build\": \"") __append(__escapeXML(addOnEnabled.vercel ? 'vite build' : 'vite build && cp instrument.server.mjs .output/server')) __append("\",\n \"dev\": \"") __append(__escapeXML(addOnEnabled.vercel ? 'dotenv -e .env.local -- vite dev --port 3000' : 'dotenv -e .env.local -- sh -c \"NODE_OPTIONS=\'--import ./instrument.server.mjs\' vite dev --port 3000\"')) __append("\",\n \"start\": \"") __append(__escapeXML(addOnEnabled.vercel ? 'node .output/server/index.mjs' : 'node --import ./.output/server/instrument.server.mjs .output/server/index.mjs')) __append("\"\n },\n \"dependencies\": {\n \"@sentry/tanstackstart-react\": \"^10.67.0\",\n \"dotenv-cli\": \"^11.0.0\"\n },\n \"pnpm\": {\n \"onlyBuiltDependencies\": [\n \"@sentry/cli\"\n ]\n }\n}\n") return __output } const templateRenderers: Record = { "66f4457e:670": __render_66f4457e_670, } export function hasManifestTemplate(template: string) { return getManifestTemplateKey(template) in templateRenderers } export function renderManifestTemplate( template: string, context: TemplateRenderContext, ) { const key = getManifestTemplateKey(template) const renderer = templateRenderers[key] if (!renderer) { throw new Error(`Template ${key} was not precompiled into the manifest`) } return renderer(context) ?? '' } export const addOn = { "name": "Sentry", "phase": "setup", "description": "Add Sentry's TanStack Start SDK for server error monitoring and tracing.", "link": "https://sentry.com/", "modes": [ "file-router" ], "type": "add-on", "category": "monitoring", "color": "#362D59", "priority": 130, "partner": { "id": "sentry", "tier": "bronze" }, "routes": [ { "url": "/demo/sentry/testing", "name": "Sentry", "path": "src/routes/demo.sentry.testing.tsx", "jsName": "SentryDemo" } ], "id": "sentry", "version": "0.0.0", "packageAdditions": {}, "packageTemplate": "{\n \"scripts\": {\n \"build\": \"<%= addOnEnabled.vercel ? 'vite build' : 'vite build && cp instrument.server.mjs .output/server' %>\",\n \"dev\": \"<%= addOnEnabled.vercel ? 'dotenv -e .env.local -- vite dev --port 3000' : 'dotenv -e .env.local -- sh -c \\\"NODE_OPTIONS=\\'--import ./instrument.server.mjs\\' vite dev --port 3000\\\"' %>\",\n \"start\": \"<%= addOnEnabled.vercel ? 'node .output/server/index.mjs' : 'node --import ./.output/server/instrument.server.mjs .output/server/index.mjs' %>\"\n },\n \"dependencies\": {\n \"@sentry/tanstackstart-react\": \"^10.67.0\",\n \"dotenv-cli\": \"^11.0.0\"\n },\n \"pnpm\": {\n \"onlyBuiltDependencies\": [\n \"@sentry/cli\"\n ]\n }\n}\n", "readmeIsEjs": false, "files": { "_dot_cursorrules.append": "We use Sentry for watching for errors in our deployed application, as well as for instrumentation of our application.\n\n## Error collection\n\nError collection is automatic and configured in `src/router.tsx`.\n\n## Instrumentation\n\nWe 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`:\n\n```tsx\nimport * as Sentry from '@sentry/tanstackstart-react'\n```\n\nAnd then wrap the implementation of the server function with `Sentry.startSpan`, like so:\n\n```tsx\nSentry.startSpan({ name: 'Requesting all the pokemon' }, async () => {\n // Some lengthy operation here\n await fetch('https://api.pokemon.com/data/')\n})\n```\n", "_dot_env.local.append": "# Your Sentry DSN (from your Sentry account)\nVITE_SENTRY_DSN=\n\n# Your Sentry organization (from your Sentry account)\nVITE_SENTRY_ORG=\n\n# Your Sentry project (from your Sentry account)\nVITE_SENTRY_PROJECT=\n\n# Your Sentry authentication token (from your Sentry account)\nSENTRY_AUTH_TOKEN=", "instrument.server.mjs": "import * as Sentry from '@sentry/tanstackstart-react'\n\nconst sentryDsn =\n import.meta.env?.VITE_SENTRY_DSN ?? process.env.VITE_SENTRY_DSN\n\nif (!sentryDsn) {\n console.warn('VITE_SENTRY_DSN is not defined. Sentry is not running.')\n} else {\n Sentry.init({\n dsn: sentryDsn,\n dataCollection: {\n userInfo: false,\n httpBodies: [],\n },\n tracesSampleRate: 0.1,\n })\n}\n", "src/routes/demo/sentry.testing.tsx": "/**\n * FILE OVERVIEW:\n * Purpose: Interactive demo page showcasing Sentry's monitoring capabilities\n * Key Concepts: Error tracking, Performance monitoring, Session replay\n * Module Type: Route Component\n * @ai_context: Demonstrates Sentry features through interactive examples with educational context\n */\n\nimport * as fs from 'node:fs/promises'\nimport { createFileRoute } from '@tanstack/react-router'\nimport { createServerFn } from '@tanstack/react-start'\nimport * as Sentry from '@sentry/tanstackstart-react'\nimport { useState, useEffect } from 'react'\n\nexport const Route = createFileRoute('/demo/sentry/testing')({\n component: RouteComponent,\n errorComponent: ({ error }) => {\n useEffect(() => {\n Sentry.captureException(error)\n }, [error])\n return (\n
\n
\n \n

Something went wrong

\n

{error.message}

\n
\n
\n )\n },\n})\n\n// Sentry Logo Component\nfunction SentryLogo({ size = 48 }: { size?: number }) {\n return (\n \n \n \n )\n}\n\n// Server function that will error\nconst badServerFunc = createServerFn({\n method: 'GET',\n}).handler(async () => {\n return await Sentry.startSpan(\n {\n name: 'Reading non-existent file',\n op: 'file.read',\n },\n async () => {\n try {\n await fs.readFile('./doesnt-exist', 'utf-8')\n return true\n } catch (error) {\n Sentry.captureException(error)\n throw error\n }\n },\n )\n})\n\n// Server function that will succeed but be traced\nconst goodServerFunc = createServerFn({\n method: 'GET',\n}).handler(async () => {\n return await Sentry.startSpan(\n {\n name: 'Successful server operation',\n op: 'demo.success',\n },\n async () => {\n await new Promise((resolve) => setTimeout(resolve, 500))\n return { success: true }\n },\n )\n})\n\n// 3D Button Component inspired by Sentry wizard\nfunction SentryButton({\n children,\n onClick,\n variant = 'primary',\n disabled = false,\n loading = false,\n}: {\n children: React.ReactNode\n onClick: () => void\n variant?: 'primary' | 'error'\n disabled?: boolean\n loading?: boolean\n}) {\n return (\n \n {loading && (\n \n \n \n \n )}\n {children}\n \n )\n}\n\n// Feature Card Component\nfunction FeatureCard({\n icon,\n title,\n description,\n}: {\n icon: React.ReactNode\n title: string\n description: string\n}) {\n return (\n
\n
\n
\n {icon}\n
\n

{title}

\n
\n

{description}

\n
\n )\n}\n\n// Result Badge Component\nfunction ResultBadge({\n type,\n spanOp,\n onCopy,\n}: {\n type: 'success' | 'error'\n spanOp: string\n onCopy: () => void\n}) {\n const [copied, setCopied] = useState(false)\n\n const handleCopy = () => {\n navigator.clipboard.writeText(spanOp)\n setCopied(true)\n onCopy()\n setTimeout(() => setCopied(false), 2000)\n }\n\n return (\n
\n {type === 'error' && (\n
\n \n Error captured\n \n \n \n Error captured and sent to Sentry\n \n
\n )}\n\n {type === 'success' && (\n
\n \n Trace complete\n \n \n \n Trace completed successfully\n \n
\n )}\n\n \n span.op:\n {spanOp}\n \n Copy to clipboard\n \n \n {copied && (\n \n Copied!\n \n )}\n \n
\n )\n}\n\n// Progress Bar Component\nfunction ProgressBar({ loading }: { loading: boolean }) {\n return (\n
\n \n
\n \n
\n \n {loading ? 'Running...' : 'Complete'}\n \n
\n )\n}\n\nfunction RouteComponent() {\n const [isLoading, setIsLoading] = useState>({})\n const [results, setResults] = useState<\n Record\n >({})\n const [sentryConfigured, setSentryConfigured] = useState(null)\n\n useEffect(() => {\n // Check if Sentry DSN environment variable is set\n const hasDsn = !!import.meta.env.VITE_SENTRY_DSN\n setSentryConfigured(hasDsn)\n }, [])\n\n // Don't show warning until we've checked on the client\n const showWarning = sentryConfigured === false\n\n const handleClientError = async () => {\n setIsLoading((prev) => ({ ...prev, clientError: true }))\n try {\n await Sentry.startSpan(\n { name: 'Client Error Flow Demo', op: 'demo.client-error' },\n async () => {\n Sentry.setContext('demo', {\n feature: 'client-error-demo',\n triggered_at: new Date().toISOString(),\n })\n throw new Error('Client-side error demonstration')\n },\n )\n } catch (error) {\n Sentry.captureException(error)\n setResults((prev) => ({\n ...prev,\n clientError: { type: 'error', spanOp: 'demo.client-error' },\n }))\n } finally {\n setIsLoading((prev) => ({ ...prev, clientError: false }))\n }\n }\n\n const handleServerError = async () => {\n setIsLoading((prev) => ({ ...prev, serverError: true }))\n try {\n await Sentry.startSpan(\n { name: 'Server Error Flow Demo', op: 'demo.server-error' },\n async () => {\n Sentry.setContext('demo', {\n feature: 'server-error-demo',\n triggered_at: new Date().toISOString(),\n })\n await badServerFunc()\n },\n )\n } catch (error) {\n Sentry.captureException(error)\n setResults((prev) => ({\n ...prev,\n serverError: { type: 'error', spanOp: 'demo.server-error' },\n }))\n } finally {\n setIsLoading((prev) => ({ ...prev, serverError: false }))\n }\n }\n\n const handleClientTrace = async () => {\n setIsLoading((prev) => ({ ...prev, clientTrace: true }))\n await Sentry.startSpan(\n { name: 'Client Operation', op: 'demo.client-trace' },\n async () => {\n await new Promise((resolve) => setTimeout(resolve, 1000))\n },\n )\n setResults((prev) => ({\n ...prev,\n clientTrace: { type: 'success', spanOp: 'demo.client-trace' },\n }))\n setIsLoading((prev) => ({ ...prev, clientTrace: false }))\n }\n\n const handleServerTrace = async () => {\n setIsLoading((prev) => ({ ...prev, serverTrace: true }))\n try {\n await Sentry.startSpan(\n { name: 'Server Operation', op: 'demo.server-trace' },\n async () => {\n await goodServerFunc()\n },\n )\n setResults((prev) => ({\n ...prev,\n serverTrace: { type: 'success', spanOp: 'demo.server-trace' },\n }))\n } finally {\n setIsLoading((prev) => ({ ...prev, serverTrace: false }))\n }\n }\n\n return (\n
\n
\n
\n
\n
\n \n
\n
\n

Sentry Demo

\n

\n Error monitoring & performance tracing\n

\n
\n
\n

\n Click the buttons below to trigger errors and traces, then view them\n in your{' '}\n \n Sentry dashboard\n \n .\n

\n
\n\n {/* Sentry Not Initialized Warning */}\n {showWarning && (\n
\n \n Warning\n \n \n
\n

Sentry is not initialized

\n

\n Set the VITE_SENTRY_DSN environment variable to\n enable error tracking and performance monitoring.\n

\n
\n
\n )}\n\n {/* Features Grid */}\n
\n \n \n \n }\n title=\"Error Monitoring\"\n description=\"Client & server error tracking\"\n />\n \n \n \n }\n title=\"Performance\"\n description=\"Tracing and spans visualization\"\n />\n \n \n \n }\n title=\"Session Replay\"\n description=\"Real user session playback\"\n />\n \n \n \n }\n title=\"Real-time Alerts\"\n description=\"Instant issue notifications\"\n />\n
\n\n {/* Testing Panels */}\n
\n {/* Client-Side Panel */}\n
\n
\n
\n

Client-Side Testing

\n
\n\n
\n
\n \n Trigger Client Error\n \n {isLoading.clientError && (\n \n )}\n {results.clientError && !isLoading.clientError && (\n {}}\n />\n )}\n
\n\n
\n \n Test Client Trace\n \n {isLoading.clientTrace && (\n \n )}\n {results.clientTrace && !isLoading.clientTrace && (\n {}}\n />\n )}\n
\n
\n
\n\n {/* Server-Side Panel */}\n
\n
\n
\n

Server-Side Testing

\n
\n\n
\n
\n \n Trigger Server Error\n \n {isLoading.serverError && (\n \n )}\n {results.serverError && !isLoading.serverError && (\n {}}\n />\n )}\n
\n\n
\n \n Test Server Trace\n \n {isLoading.serverTrace && (\n \n )}\n {results.serverTrace && !isLoading.serverTrace && (\n {}}\n />\n )}\n
\n
\n
\n
\n\n {/* Footer Note */}\n
\n

\n This page uses @sentry/tanstackstart-react for\n full-stack error monitoring.\n
\n \n Read the documentation →\n \n

\n
\n
\n
\n )\n}\n" }, "deletedFiles": [], "smallLogo": "" } satisfies AddOnCompiled