@tanstack/cta-engine 0.10.0-alpha.21 → 0.10.0-alpha.25

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 (340) hide show
  1. package/dist/add-ons.js +91 -5
  2. package/dist/add.js +125 -0
  3. package/dist/cli.js +132 -0
  4. package/dist/config-file.js +9 -14
  5. package/dist/constants.js +2 -0
  6. package/dist/create-app.js +451 -142
  7. package/dist/custom-add-on.js +254 -0
  8. package/dist/environment.js +32 -64
  9. package/dist/file-helper.js +18 -0
  10. package/dist/index.js +1 -17
  11. package/dist/mcp.js +229 -0
  12. package/dist/options.js +333 -9
  13. package/dist/package-manager.js +6 -51
  14. package/dist/templates.js +6 -0
  15. package/dist/toolchain.js +6 -0
  16. package/dist/types/add-ons.d.ts +8 -3
  17. package/dist/types/add.d.ts +3 -0
  18. package/dist/types/cli.d.ts +7 -0
  19. package/dist/types/config-file.d.ts +4 -6
  20. package/dist/types/constants.d.ts +3 -0
  21. package/dist/types/create-app.d.ts +7 -1
  22. package/dist/types/custom-add-on.d.ts +3 -0
  23. package/dist/types/environment.d.ts +1 -2
  24. package/dist/types/file-helper.d.ts +2 -0
  25. package/dist/types/index.d.ts +1 -20
  26. package/dist/types/mcp.d.ts +7 -0
  27. package/dist/types/options.d.ts +6 -2
  28. package/dist/types/package-manager.d.ts +1 -18
  29. package/dist/types/templates.d.ts +1 -0
  30. package/dist/types/toolchain.d.ts +3 -0
  31. package/dist/types/types.d.ts +85 -788
  32. package/dist/types/utils.d.ts +0 -5
  33. package/dist/types.js +1 -65
  34. package/dist/utils.js +0 -9
  35. package/package.json +12 -9
  36. package/src/add-ons.ts +123 -7
  37. package/src/add.ts +186 -0
  38. package/src/cli.ts +210 -0
  39. package/src/config-file.ts +17 -26
  40. package/src/constants.ts +5 -0
  41. package/src/create-app.ts +730 -180
  42. package/src/custom-add-on.ts +325 -0
  43. package/src/environment.ts +33 -77
  44. package/src/file-helper.ts +20 -0
  45. package/src/index.ts +1 -77
  46. package/src/mcp.ts +302 -0
  47. package/src/options.ts +409 -8
  48. package/src/package-manager.ts +9 -80
  49. package/src/templates.ts +7 -0
  50. package/src/toolchain.ts +7 -0
  51. package/src/types.ts +87 -175
  52. package/src/utils.ts +0 -17
  53. package/templates/react/add-on/clerk/README.md +3 -0
  54. package/templates/react/add-on/clerk/assets/_dot_env.local.append +2 -0
  55. package/templates/react/add-on/clerk/assets/src/integrations/clerk/header-user.tsx +19 -0
  56. package/templates/react/add-on/clerk/assets/src/integrations/clerk/provider.tsx +18 -0
  57. package/templates/react/add-on/clerk/assets/src/routes/demo.clerk.tsx +20 -0
  58. package/templates/react/add-on/clerk/info.json +13 -0
  59. package/templates/react/add-on/clerk/package.json +5 -0
  60. package/templates/react/add-on/convex/README.md +4 -0
  61. package/templates/react/add-on/convex/assets/_dot_cursorrules.append +93 -0
  62. package/templates/react/add-on/convex/assets/_dot_env.local.append +3 -0
  63. package/templates/react/add-on/convex/assets/convex/products.ts +8 -0
  64. package/templates/react/add-on/convex/assets/convex/schema.ts +10 -0
  65. package/templates/react/add-on/convex/assets/src/integrations/convex/provider.tsx +20 -0
  66. package/templates/react/add-on/convex/assets/src/routes/demo.convex.tsx +33 -0
  67. package/templates/react/add-on/convex/info.json +13 -0
  68. package/templates/react/add-on/convex/package.json +6 -0
  69. package/templates/react/add-on/form/assets/src/components/demo.FormComponents.tsx.ejs +300 -0
  70. package/templates/react/add-on/form/assets/src/hooks/demo.form-context.ts +4 -0
  71. package/templates/react/add-on/form/assets/src/hooks/demo.form.ts +22 -0
  72. package/templates/react/add-on/form/assets/src/routes/demo.form.address.tsx.ejs +213 -0
  73. package/templates/react/add-on/form/assets/src/routes/demo.form.simple.tsx.ejs +77 -0
  74. package/templates/react/add-on/form/info.json +26 -0
  75. package/templates/react/add-on/form/package.json +6 -0
  76. package/templates/react/add-on/module-federation/assets/module-federation.config.js.ejs +31 -0
  77. package/templates/react/add-on/module-federation/assets/src/demo-mf-component.tsx +3 -0
  78. package/templates/react/add-on/module-federation/assets/src/demo-mf-self-contained.tsx +11 -0
  79. package/templates/react/add-on/module-federation/info.json +7 -0
  80. package/templates/react/add-on/module-federation/package.json +5 -0
  81. package/templates/react/add-on/netlify/README.md +11 -0
  82. package/templates/react/add-on/netlify/info.json +7 -0
  83. package/templates/react/add-on/sentry/assets/_dot_cursorrules.append +22 -0
  84. package/templates/react/add-on/sentry/assets/_dot_env.local.append +11 -0
  85. package/templates/react/add-on/sentry/assets/src/app/global-middleware.ts +11 -0
  86. package/templates/react/add-on/sentry/assets/src/routes/demo.sentry.testing.tsx +489 -0
  87. package/templates/react/add-on/sentry/info.json +14 -0
  88. package/templates/react/add-on/sentry/package.json +5 -0
  89. package/templates/react/add-on/shadcn/README.md +7 -0
  90. package/templates/react/add-on/shadcn/assets/_dot_cursorrules.append +7 -0
  91. package/templates/react/add-on/shadcn/assets/components.json +21 -0
  92. package/templates/react/add-on/shadcn/assets/src/lib/utils.ts +6 -0
  93. package/templates/react/add-on/shadcn/assets/src/styles.css +138 -0
  94. package/templates/react/add-on/shadcn/info.json +7 -0
  95. package/templates/react/add-on/shadcn/package.json +9 -0
  96. package/templates/react/add-on/start/assets/_dot_gitignore.append +2 -0
  97. package/templates/react/add-on/start/assets/app.config.ts.ejs +32 -0
  98. package/templates/react/add-on/start/assets/src/api.ts +6 -0
  99. package/templates/react/add-on/start/assets/src/client.tsx.ejs +33 -0
  100. package/templates/react/add-on/start/assets/src/router.tsx.ejs +48 -0
  101. package/templates/react/add-on/start/assets/src/routes/api.demo-names.ts +11 -0
  102. package/templates/react/add-on/start/assets/src/routes/demo.start.api-request.tsx.ejs +33 -0
  103. package/templates/react/add-on/start/assets/src/routes/demo.start.server-funcs.tsx +50 -0
  104. package/templates/react/add-on/start/assets/src/ssr.tsx.ejs +30 -0
  105. package/templates/react/add-on/start/info.json +18 -0
  106. package/templates/react/add-on/start/package.json +13 -0
  107. package/templates/react/add-on/store/assets/src/lib/demo-store.ts +13 -0
  108. package/templates/react/add-on/store/assets/src/routes/demo.store.tsx.ejs +75 -0
  109. package/templates/react/add-on/store/info.json +13 -0
  110. package/templates/react/add-on/store/package.json +6 -0
  111. package/templates/react/add-on/t3env/README.md +16 -0
  112. package/templates/react/add-on/t3env/assets/src/env.ts +39 -0
  113. package/templates/react/add-on/t3env/info.json +10 -0
  114. package/templates/react/add-on/t3env/package.json +6 -0
  115. package/templates/react/add-on/tRPC/assets/src/integrations/trpc/init.ts +9 -0
  116. package/templates/react/add-on/tRPC/assets/src/integrations/trpc/react.ts +4 -0
  117. package/templates/react/add-on/tRPC/assets/src/integrations/trpc/router.ts +18 -0
  118. package/templates/react/add-on/tRPC/assets/src/routes/api.trpc.$.tsx +16 -0
  119. package/templates/react/add-on/tRPC/info.json +9 -0
  120. package/templates/react/add-on/tRPC/package.json +9 -0
  121. package/templates/react/add-on/table/assets/src/data/demo-table-data.ts +50 -0
  122. package/templates/react/add-on/table/assets/src/routes/demo.table.tsx.ejs +373 -0
  123. package/templates/react/add-on/table/info.json +13 -0
  124. package/templates/react/add-on/table/package.json +7 -0
  125. package/templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/layout.tsx +5 -0
  126. package/templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/root-provider.tsx.ejs +70 -0
  127. package/templates/react/add-on/tanstack-query/assets/src/routes/demo.tanstack-query.tsx.ejs +53 -0
  128. package/templates/react/add-on/tanstack-query/info.json +13 -0
  129. package/templates/react/add-on/tanstack-query/package.json +6 -0
  130. package/templates/react/base/README.md.ejs +558 -0
  131. package/templates/react/base/_dot_gitignore +5 -0
  132. package/templates/react/base/_dot_vscode/settings.biome.json +35 -0
  133. package/templates/react/base/_dot_vscode/settings.json +11 -0
  134. package/templates/react/base/index.html.ejs +20 -0
  135. package/templates/react/base/package.biome.json +10 -0
  136. package/templates/react/base/package.eslintprettier.json +11 -0
  137. package/templates/react/base/package.json +30 -0
  138. package/templates/react/base/package.ts.json +7 -0
  139. package/templates/react/base/package.tw.json +6 -0
  140. package/templates/react/base/public/favicon.ico +0 -0
  141. package/templates/react/base/public/logo192.png +0 -0
  142. package/templates/react/base/public/logo512.png +0 -0
  143. package/templates/react/base/public/manifest.json +25 -0
  144. package/templates/react/base/public/robots.txt +3 -0
  145. package/templates/react/base/src/App.css +38 -0
  146. package/templates/react/base/src/App.test.tsx.ejs +10 -0
  147. package/templates/react/base/src/App.tsx.ejs +74 -0
  148. package/templates/react/base/src/components/Header.tsx.ejs +27 -0
  149. package/templates/react/base/src/logo.svg +44 -0
  150. package/templates/react/base/src/reportWebVitals.ts.ejs +28 -0
  151. package/templates/react/base/src/styles.css.ejs +15 -0
  152. package/templates/react/base/toolchain/.prettierignore +3 -0
  153. package/templates/react/base/toolchain/biome.json +31 -0
  154. package/templates/react/base/toolchain/eslint.config.js +5 -0
  155. package/templates/react/base/toolchain/prettier.config.js +10 -0
  156. package/templates/react/base/tsconfig.json.ejs +29 -0
  157. package/templates/react/base/vite.config.js.ejs +23 -0
  158. package/templates/react/code-router/src/main.tsx.ejs +92 -0
  159. package/templates/react/example/tanchat/README.md +37 -0
  160. package/templates/react/example/tanchat/assets/_dot_env.local.append +2 -0
  161. package/templates/react/example/tanchat/assets/public/example-guitar-flowers.jpg +0 -0
  162. package/templates/react/example/tanchat/assets/public/example-guitar-motherboard.jpg +0 -0
  163. package/templates/react/example/tanchat/assets/public/example-guitar-racing.jpg +0 -0
  164. package/templates/react/example/tanchat/assets/public/example-guitar-steamer-trunk.jpg +0 -0
  165. package/templates/react/example/tanchat/assets/public/example-guitar-superhero.jpg +0 -0
  166. package/templates/react/example/tanchat/assets/public/example-guitar-traveling.jpg +0 -0
  167. package/templates/react/example/tanchat/assets/public/example-guitar-video-games.jpg +0 -0
  168. package/templates/react/example/tanchat/assets/src/components/example-AIAssistant.tsx +173 -0
  169. package/templates/react/example/tanchat/assets/src/components/example-GuitarRecommendation.tsx +47 -0
  170. package/templates/react/example/tanchat/assets/src/data/example-guitars.ts +83 -0
  171. package/templates/react/example/tanchat/assets/src/demo.index.css +220 -0
  172. package/templates/react/example/tanchat/assets/src/integrations/tanchat/header-user.tsx +5 -0
  173. package/templates/react/example/tanchat/assets/src/routes/api.messages.ts +24 -0
  174. package/templates/react/example/tanchat/assets/src/routes/api.sse.ts +23 -0
  175. package/templates/react/example/tanchat/assets/src/routes/example.chat.tsx +159 -0
  176. package/templates/react/example/tanchat/assets/src/routes/example.guitars/$guitarId.tsx +50 -0
  177. package/templates/react/example/tanchat/assets/src/routes/example.guitars/index.tsx +54 -0
  178. package/templates/react/example/tanchat/assets/src/store/example-assistant.ts +3 -0
  179. package/templates/react/example/tanchat/assets/src/utils/demo.ai.ts +62 -0
  180. package/templates/react/example/tanchat/assets/src/utils/demo.sse.ts +31 -0
  181. package/templates/react/example/tanchat/assets/src/utils/demo.tools.ts +47 -0
  182. package/templates/react/example/tanchat/info.json +19 -0
  183. package/templates/react/example/tanchat/package.json +16 -0
  184. package/templates/react/file-router/package.fr.json +5 -0
  185. package/templates/react/file-router/src/main.tsx.ejs +55 -0
  186. package/templates/react/file-router/src/routes/__root.tsx.ejs +82 -0
  187. package/templates/solid/add-on/form/assets/src/routes/demo.form.tsx.ejs +352 -0
  188. package/templates/solid/add-on/form/info.json +13 -0
  189. package/templates/solid/add-on/form/package.json +5 -0
  190. package/templates/solid/add-on/module-federation/assets/module-federation.config.js.ejs +27 -0
  191. package/templates/solid/add-on/module-federation/assets/src/demo-mf-component.tsx +3 -0
  192. package/templates/solid/add-on/module-federation/assets/src/demo-mf-self-contained.tsx +9 -0
  193. package/templates/solid/add-on/module-federation/info.json +7 -0
  194. package/templates/solid/add-on/module-federation/package.json +5 -0
  195. package/templates/solid/add-on/sentry/assets/_dot_cursorrules.append +22 -0
  196. package/templates/solid/add-on/sentry/assets/_dot_env.local.append +2 -0
  197. package/templates/solid/add-on/sentry/assets/src/routes/demo.sentry.bad-event-handler.tsx +20 -0
  198. package/templates/solid/add-on/sentry/info.json +13 -0
  199. package/templates/solid/add-on/sentry/package.json +5 -0
  200. package/templates/solid/add-on/solid-ui/README.md +9 -0
  201. package/templates/solid/add-on/solid-ui/assets/src/lib/utils.ts +6 -0
  202. package/templates/solid/add-on/solid-ui/assets/src/styles.css +138 -0
  203. package/templates/solid/add-on/solid-ui/assets/ui.config.json +13 -0
  204. package/templates/solid/add-on/solid-ui/info.json +11 -0
  205. package/templates/solid/add-on/solid-ui/package.json +9 -0
  206. package/templates/solid/add-on/start/assets/app.config.ts +16 -0
  207. package/templates/solid/add-on/start/assets/src/api.ts +6 -0
  208. package/templates/solid/add-on/start/assets/src/client.tsx +7 -0
  209. package/templates/solid/add-on/start/assets/src/router.tsx.ejs +24 -0
  210. package/templates/solid/add-on/start/assets/src/routes/demo.start.server-funcs.tsx +49 -0
  211. package/templates/solid/add-on/start/assets/src/ssr.tsx +12 -0
  212. package/templates/solid/add-on/start/info.json +14 -0
  213. package/templates/solid/add-on/start/package.json +12 -0
  214. package/templates/solid/add-on/store/assets/src/lib/demo-store.ts +13 -0
  215. package/templates/solid/add-on/store/assets/src/routes/demo.store.tsx.ejs +77 -0
  216. package/templates/solid/add-on/store/info.json +13 -0
  217. package/templates/solid/add-on/store/package.json +6 -0
  218. package/templates/solid/add-on/t3env/README.md +16 -0
  219. package/templates/solid/add-on/t3env/assets/src/env.ts +39 -0
  220. package/templates/solid/add-on/t3env/info.json +10 -0
  221. package/templates/solid/add-on/t3env/package.json +6 -0
  222. package/templates/solid/add-on/tanstack-query/assets/src/integrations/tanstack-query/header-user.tsx +5 -0
  223. package/templates/solid/add-on/tanstack-query/assets/src/integrations/tanstack-query/provider.tsx +15 -0
  224. package/templates/solid/add-on/tanstack-query/assets/src/routes/demo.tanstack-query.tsx +30 -0
  225. package/templates/solid/add-on/tanstack-query/info.json +13 -0
  226. package/templates/solid/add-on/tanstack-query/package.json +6 -0
  227. package/templates/solid/base/README.md.ejs +215 -0
  228. package/templates/solid/base/_dot_cursorrules.append +35 -0
  229. package/templates/solid/base/_dot_gitignore +5 -0
  230. package/templates/solid/base/_dot_vscode/settings.biome.json +35 -0
  231. package/templates/solid/base/_dot_vscode/settings.json +11 -0
  232. package/templates/solid/base/index.html.ejs +20 -0
  233. package/templates/solid/base/package.biome.json +10 -0
  234. package/templates/solid/base/package.eslintprettier.json +11 -0
  235. package/templates/solid/base/package.json +23 -0
  236. package/templates/solid/base/package.ts.json +5 -0
  237. package/templates/solid/base/package.tw.json +6 -0
  238. package/templates/solid/base/public/favicon.ico +0 -0
  239. package/templates/solid/base/public/logo192.png +0 -0
  240. package/templates/solid/base/public/logo512.png +0 -0
  241. package/templates/solid/base/public/manifest.json +25 -0
  242. package/templates/solid/base/public/robots.txt +3 -0
  243. package/templates/solid/base/src/App.css +0 -0
  244. package/templates/solid/base/src/App.tsx.ejs +47 -0
  245. package/templates/solid/base/src/components/Header.tsx.ejs +26 -0
  246. package/templates/solid/base/src/logo.svg +120 -0
  247. package/templates/solid/base/src/styles.css.ejs +15 -0
  248. package/templates/solid/base/toolchain/.prettierignore +3 -0
  249. package/templates/solid/base/toolchain/biome.json +31 -0
  250. package/templates/solid/base/toolchain/eslint.config.js +5 -0
  251. package/templates/solid/base/toolchain/prettier.config.js +10 -0
  252. package/templates/solid/base/tsconfig.json.ejs +31 -0
  253. package/templates/solid/base/vite.config.js.ejs +22 -0
  254. package/templates/solid/code-router/src/main.tsx.ejs +71 -0
  255. package/templates/solid/example/tanchat/README.md +52 -0
  256. package/templates/solid/example/tanchat/assets/ai-streaming-server/README.md +110 -0
  257. package/templates/solid/example/tanchat/assets/ai-streaming-server/_dot_env.example +1 -0
  258. package/templates/solid/example/tanchat/assets/ai-streaming-server/package.json +26 -0
  259. package/templates/solid/example/tanchat/assets/ai-streaming-server/src/index.ts +102 -0
  260. package/templates/solid/example/tanchat/assets/ai-streaming-server/tsconfig.json +15 -0
  261. package/templates/solid/example/tanchat/assets/src/components/demo.SettingsDialog.tsx +149 -0
  262. package/templates/solid/example/tanchat/assets/src/demo.index.css +227 -0
  263. package/templates/solid/example/tanchat/assets/src/lib/demo-store.ts +13 -0
  264. package/templates/solid/example/tanchat/assets/src/routes/example.chat.tsx +435 -0
  265. package/templates/solid/example/tanchat/assets/src/store/demo.hooks.ts +17 -0
  266. package/templates/solid/example/tanchat/assets/src/store/demo.store.ts +133 -0
  267. package/templates/solid/example/tanchat/info.json +14 -0
  268. package/templates/solid/example/tanchat/package.json +7 -0
  269. package/templates/solid/file-router/package.fr.json +5 -0
  270. package/templates/solid/file-router/src/main.tsx.ejs +47 -0
  271. package/templates/solid/file-router/src/routes/__root.tsx.ejs +41 -0
  272. package/templates/solid/file-router/src/routes/index.tsx +43 -0
  273. package/tests/cra.test.ts +293 -0
  274. package/tests/snapshots/cra/cr-js-npm.json +33 -0
  275. package/tests/snapshots/cra/cr-ts-npm.json +34 -0
  276. package/tests/snapshots/cra/cr-ts-start-npm.json +38 -0
  277. package/tests/snapshots/cra/fr-ts-npm.json +34 -0
  278. package/tests/snapshots/cra/fr-ts-tw-npm.json +33 -0
  279. package/tests/snapshots/cra/solid-cr-js-npm.json +31 -0
  280. package/tests/snapshots/cra/solid-cr-ts-npm.json +32 -0
  281. package/tests/snapshots/cra/solid-cr-ts-start-npm.json +36 -0
  282. package/tests/snapshots/cra/solid-fr-ts-npm.json +33 -0
  283. package/tests/snapshots/cra/solid-fr-ts-tw-npm.json +32 -0
  284. package/tests/test-utilities.ts +87 -0
  285. package/dist/add-to-app.js +0 -169
  286. package/dist/custom-add-ons/add-on.js +0 -175
  287. package/dist/custom-add-ons/shared.js +0 -117
  288. package/dist/custom-add-ons/starter.js +0 -84
  289. package/dist/file-helpers.js +0 -165
  290. package/dist/frameworks.js +0 -92
  291. package/dist/integrations/git.js +0 -4
  292. package/dist/integrations/shadcn.js +0 -33
  293. package/dist/package-json.js +0 -48
  294. package/dist/special-steps/index.js +0 -24
  295. package/dist/special-steps/rimraf-node-modules.js +0 -16
  296. package/dist/template-file.js +0 -112
  297. package/dist/types/add-to-app.d.ts +0 -17
  298. package/dist/types/custom-add-ons/add-on.d.ts +0 -69
  299. package/dist/types/custom-add-ons/shared.d.ts +0 -15
  300. package/dist/types/custom-add-ons/starter.d.ts +0 -7
  301. package/dist/types/file-helpers.d.ts +0 -15
  302. package/dist/types/frameworks.d.ts +0 -7
  303. package/dist/types/integrations/git.d.ts +0 -2
  304. package/dist/types/integrations/shadcn.d.ts +0 -2
  305. package/dist/types/package-json.d.ts +0 -7
  306. package/dist/types/special-steps/index.d.ts +0 -2
  307. package/dist/types/special-steps/rimraf-node-modules.d.ts +0 -2
  308. package/dist/types/template-file.d.ts +0 -2
  309. package/src/add-to-app.ts +0 -274
  310. package/src/custom-add-ons/add-on.ts +0 -261
  311. package/src/custom-add-ons/shared.ts +0 -161
  312. package/src/custom-add-ons/starter.ts +0 -126
  313. package/src/file-helpers.ts +0 -235
  314. package/src/frameworks.ts +0 -134
  315. package/src/integrations/git.ts +0 -7
  316. package/src/integrations/shadcn.ts +0 -54
  317. package/src/package-json.ts +0 -69
  318. package/src/special-steps/index.ts +0 -36
  319. package/src/special-steps/rimraf-node-modules.ts +0 -25
  320. package/src/template-file.ts +0 -150
  321. package/tests/add-ons.test.ts +0 -67
  322. package/tests/add-to-app.test.ts +0 -358
  323. package/tests/config-file.test.ts +0 -68
  324. package/tests/create-app.test.ts +0 -120
  325. package/tests/custom-add-ons/add-on.test.ts +0 -12
  326. package/tests/custom-add-ons/shared.test.ts +0 -257
  327. package/tests/custom-add-ons/starter.test.ts +0 -58
  328. package/tests/environment.test.ts +0 -115
  329. package/tests/file-helper.test.ts +0 -90
  330. package/tests/frameworks.test.ts +0 -95
  331. package/tests/index.test.ts +0 -9
  332. package/tests/integrations/git.test.ts +0 -20
  333. package/tests/integrations/shadcn.test.ts +0 -91
  334. package/tests/options.test.ts +0 -42
  335. package/tests/package-json.test.ts +0 -63
  336. package/tests/package-manager.test.ts +0 -154
  337. package/tests/setupVitest.ts +0 -6
  338. package/tests/template-file.test.ts +0 -178
  339. package/tests/utils.test.ts +0 -23
  340. package/vitest.config.ts +0 -21
@@ -0,0 +1,6 @@
1
+ {
2
+ "dependencies": {
3
+ "@tanstack/react-form": "^1.0.0",
4
+ "zod": "^3.24.2"
5
+ }
6
+ }
@@ -0,0 +1,31 @@
1
+ import packageJSON from './package.json'
2
+
3
+ function remoteConfig(name, url) {
4
+ return {
5
+ type: 'module',
6
+ name,
7
+ entry: url,
8
+ entryGlobalName: 'remote',
9
+ shareScope: 'default',
10
+ }
11
+ }
12
+
13
+ export default {
14
+ filename: 'remoteEntry.js',
15
+ name: '<%= projectName %>',
16
+ exposes: {
17
+ './DemoMfComponent': './src/demo-mf-component.tsx',
18
+ './DemoMfSelfContained': './src/demo-mf-self-contained.tsx',
19
+ },
20
+ remotes: {},
21
+ shared: {
22
+ react: {
23
+ singleton: true,
24
+ requiredVersion: packageJSON.dependencies.react,
25
+ },
26
+ 'react-dom': {
27
+ singleton: true,
28
+ requiredVersion: packageJSON.dependencies['react-dom'],
29
+ },
30
+ },
31
+ }
@@ -0,0 +1,3 @@
1
+ export function DemoMfComponent() {
2
+ return <div>Demo Mf Component</div>
3
+ }
@@ -0,0 +1,11 @@
1
+ import React from 'react'
2
+ import ReactDOM from 'react-dom/client'
3
+
4
+ function App() {
5
+ return <div>Hello from self-contained module federation</div>
6
+ }
7
+
8
+ export function DemoMfSelfContained(rootElement: HTMLElement) {
9
+ const root = ReactDOM.createRoot(rootElement)
10
+ root.render(<App />)
11
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "Module Federation",
3
+ "description": "Module Federation",
4
+ "phase": "add-on",
5
+ "templates": ["code-router"],
6
+ "link": "https://module-federation.io/"
7
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "dependencies": {
3
+ "@module-federation/vite": "^1.1.9"
4
+ }
5
+ }
@@ -0,0 +1,11 @@
1
+ ## Setting up Netlify
2
+
3
+ First install the Netlify CLI with:
4
+
5
+ ```bash
6
+ npm install -g netlify-cli`
7
+ ```
8
+
9
+ ```bash
10
+ netlify init
11
+ ```
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "Netlify",
3
+ "description": "Netlify deployment setup",
4
+ "link": "https://docs.netlify.com",
5
+ "phase": "add-on",
6
+ "templates": ["file-router", "code-router"]
7
+ }
@@ -0,0 +1,22 @@
1
+ We use Sentry for watching for errors in our deployed application, as well as for instrumentation of our application.
2
+
3
+ ## Error collection
4
+
5
+ Error collection is automatic and configured in `src/router.tsx`.
6
+
7
+ ## Instrumentation
8
+
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`:
10
+
11
+ ```tsx
12
+ import * as Sentry from '@sentry/tanstackstart-react'
13
+ ```
14
+
15
+ And then wrap the implementation of the server function with `Sentry.startSpan`, like so:
16
+
17
+ ```tsx
18
+ Sentry.startSpan({ name: 'Requesting all the pokemon' }, async () => {
19
+ // Some lengthy operation here
20
+ await fetch('https://api.pokemon.com/data/')
21
+ })
22
+ ```
@@ -0,0 +1,11 @@
1
+ # Your Sentry DSN (from your Sentry account)
2
+ 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=
@@ -0,0 +1,11 @@
1
+ import * as Sentry from "@sentry/tanstackstart-react";
2
+ import {
3
+ createMiddleware,
4
+ registerGlobalMiddleware,
5
+ } from "@tanstack/react-start";
6
+
7
+ registerGlobalMiddleware({
8
+ middleware: [
9
+ createMiddleware().server(Sentry.sentryGlobalServerMiddlewareHandler()),
10
+ ],
11
+ });
@@ -0,0 +1,489 @@
1
+ /**
2
+ * FILE OVERVIEW:
3
+ * Purpose: Interactive demo page showcasing Sentry's monitoring capabilities
4
+ * Key Concepts: Error tracking, Performance monitoring, Session replay
5
+ * Module Type: Route Component
6
+ * @ai_context: Demonstrates Sentry features through interactive examples with educational context
7
+ */
8
+
9
+ import * as fs from 'node:fs/promises'
10
+ import { createFileRoute } from '@tanstack/react-router'
11
+ import { createServerFn } from '@tanstack/react-start'
12
+ import * as Sentry from "@sentry/tanstackstart-react";
13
+ import { useState, useEffect, useRef } from 'react'
14
+
15
+ export const Route = createFileRoute('/demo/sentry/testing')({
16
+ component: RouteComponent,
17
+ })
18
+
19
+ // Server function that will error
20
+ const badServerFunc = createServerFn({
21
+ method: 'GET',
22
+ }).handler(async () => {
23
+ return await Sentry.startSpan(
24
+ {
25
+ name: 'Reading non-existent file',
26
+ op: 'file.read'
27
+ },
28
+ async () => {
29
+ try {
30
+ await fs.readFile('./doesnt-exist', 'utf-8')
31
+ return true
32
+ } catch (error) {
33
+ Sentry.captureException(error)
34
+ throw error
35
+ }
36
+ }
37
+ )
38
+ })
39
+
40
+ // Server function that will succeed but be traced
41
+ const goodServerFunc = createServerFn({
42
+ method: 'GET',
43
+ }).handler(async () => {
44
+ return await Sentry.startSpan(
45
+ {
46
+ name: 'Successful server operation',
47
+ op: 'demo.success'
48
+ },
49
+ async () => {
50
+ await new Promise(resolve => setTimeout(resolve, 500))
51
+ return { success: true }
52
+ }
53
+ )
54
+ })
55
+
56
+ function RouteComponent() {
57
+ const [isLoading, setIsLoading] = useState<Record<string, boolean>>({})
58
+ const [hasError, setHasError] = useState<Record<string, boolean>>({})
59
+ const [showTrace, setShowTrace] = useState<Record<string, boolean>>({})
60
+ const [spanOps, setSpanOps] = useState<Record<string, string>>({})
61
+ const [demoStep, setDemoStep] = useState(0)
62
+ const [replayEvents, setReplayEvents] = useState<string[]>([])
63
+ const [copiedSpan, setCopiedSpan] = useState<string | null>(null)
64
+ const startTimeRef = useRef<string>('')
65
+
66
+ useEffect(() => {
67
+ // Set initial timestamp only once on client
68
+ if (!startTimeRef.current) {
69
+ startTimeRef.current = new Date().toISOString()
70
+ }
71
+
72
+ if (demoStep > 0) {
73
+ const secondsElapsed = ((new Date().getTime() - new Date(startTimeRef.current).getTime()) / 1000).toFixed(1)
74
+ setReplayEvents(prev => [...prev, `Step ${demoStep}: +${secondsElapsed}s`])
75
+ }
76
+ }, [demoStep])
77
+
78
+ const handleCopy = (operation: string) => {
79
+ navigator.clipboard.writeText(operation);
80
+ setCopiedSpan(operation);
81
+ setTimeout(() => setCopiedSpan(null), 2000);
82
+ }
83
+
84
+ const handleClientError = async () => {
85
+ setIsLoading(prev => ({ ...prev, clientError: true }))
86
+ setHasError(prev => ({ ...prev, clientError: false }))
87
+ setShowTrace(prev => ({ ...prev, clientError: true }))
88
+
89
+ try {
90
+ await Sentry.startSpan(
91
+ {
92
+ name: 'Client Error Flow Demo',
93
+ op: 'demo.client-error-flow',
94
+ },
95
+ async () => {
96
+ Sentry.setContext("demo", {
97
+ feature: "client-error-demo",
98
+ triggered_at: new Date().toISOString()
99
+ });
100
+
101
+ // Simulate a client-side error
102
+ throw new Error('Client-side error demonstration')
103
+ }
104
+ )
105
+ } catch (error) {
106
+ setHasError(prev => ({ ...prev, clientError: true }))
107
+ setSpanOps(prev => ({ ...prev, clientError: 'demo.client-error-flow' }))
108
+ Sentry.captureException(error)
109
+ } finally {
110
+ setIsLoading(prev => ({ ...prev, clientError: false }))
111
+ }
112
+ }
113
+
114
+ const handleServerError = async () => {
115
+ setIsLoading(prev => ({ ...prev, serverError: true }))
116
+ setHasError(prev => ({ ...prev, serverError: false }))
117
+ setShowTrace(prev => ({ ...prev, serverError: true }))
118
+
119
+ try {
120
+ await Sentry.startSpan(
121
+ {
122
+ name: 'Server Error Flow Demo',
123
+ op: 'demo.server-error-flow',
124
+ },
125
+ async () => {
126
+ Sentry.setContext("demo", {
127
+ feature: "server-error-demo",
128
+ triggered_at: new Date().toISOString()
129
+ });
130
+
131
+ await badServerFunc()
132
+ }
133
+ )
134
+ } catch (error) {
135
+ setHasError(prev => ({ ...prev, serverError: true }))
136
+ setSpanOps(prev => ({ ...prev, serverError: 'demo.server-error-flow' }))
137
+ Sentry.captureException(error)
138
+ } finally {
139
+ setIsLoading(prev => ({ ...prev, serverError: false }))
140
+ }
141
+ }
142
+
143
+ const handleClientTrace = async () => {
144
+ setIsLoading(prev => ({ ...prev, client: true }))
145
+ setShowTrace(prev => ({ ...prev, client: true }))
146
+
147
+ await Sentry.startSpan(
148
+ {
149
+ name: 'Client Operation',
150
+ op: 'demo.client',
151
+ },
152
+ async () => {
153
+ // Simulate some client-side work
154
+ await new Promise(resolve => setTimeout(resolve, 1000))
155
+ }
156
+ )
157
+
158
+ setSpanOps(prev => ({ ...prev, client: 'demo.client' }))
159
+ setIsLoading(prev => ({ ...prev, client: false }))
160
+ }
161
+
162
+ const handleServerTrace = async () => {
163
+ setIsLoading(prev => ({ ...prev, server: true }))
164
+ setShowTrace(prev => ({ ...prev, server: true }))
165
+
166
+ try {
167
+ await Sentry.startSpan(
168
+ {
169
+ name: 'Server Operation',
170
+ op: 'demo.server',
171
+ },
172
+ async () => {
173
+ await goodServerFunc()
174
+ }
175
+ )
176
+ setSpanOps(prev => ({ ...prev, server: 'demo.server' }))
177
+ } finally {
178
+ setIsLoading(prev => ({ ...prev, server: false }))
179
+ }
180
+ }
181
+
182
+ return (
183
+ <>
184
+ <style dangerouslySetInnerHTML={{
185
+ __html: `
186
+ @keyframes fadeOut {
187
+ from { opacity: 1; transform: translateY(0); }
188
+ to { opacity: 0; transform: translateY(-10px); }
189
+ }
190
+ .animate-fade-out {
191
+ animation: fadeOut 2s ease-out forwards;
192
+ }
193
+ `
194
+ }} />
195
+ <div className="min-h-[calc(100vh-32px)] text-white p-8" style={{
196
+ backgroundImage: 'radial-gradient(41.11% 49.93% at 50% 49.93%, #8d5494 0%, #563275 52.26%, #1f1633 100%)'
197
+ }}>
198
+ <div className="max-w-7xl mx-auto">
199
+ {/* Header */}
200
+ <div className="text-center mb-12">
201
+ <h1 className="text-8xl font-bold mb-4 text-white">
202
+ Sentry
203
+ </h1>
204
+ <p className="text-4xl font-semibold text-white">
205
+ Code <span className="inline-block -rotate-9">breaks</span>, fix it faster
206
+ </p>
207
+ </div>
208
+
209
+ {/* Content Grid */}
210
+ <div className="space-y-8">
211
+ {/* Information Section - Top */}
212
+ <div className="bg-[#1C2333] rounded-lg border border-gray-800 p-6">
213
+ <div className="space-y-4 text-gray-300">
214
+ <p>
215
+ The Sentry integration monitors this application across all routes; not just this one (we care about all tabs) using our <code>@sentry/react</code> and <code>@sentry/node</code> packages.
216
+ </p>
217
+ <div className="grid grid-cols-4 gap-4">
218
+ <div className="bg-[#2D3555] rounded-lg p-4 border border-gray-700 hover:border-purple-500/50 transition-colors">
219
+ <div className="font-bold mb-1">Error Monitoring</div>
220
+ <div className="text-sm text-gray-400">across client side and server functions</div>
221
+ </div>
222
+ <div className="bg-[#2D3555] rounded-lg p-4 border border-gray-700 hover:border-purple-500/50 transition-colors">
223
+ <div className="font-bold mb-1">Tracing and Spans</div>
224
+ <div className="text-sm text-gray-400">for client and server side performance</div>
225
+ </div>
226
+ <div className="bg-[#2D3555] rounded-lg p-4 border border-gray-700 hover:border-purple-500/50 transition-colors">
227
+ <div className="font-bold mb-1">Session replay</div>
228
+ <div className="text-sm text-gray-400">real user session playback</div>
229
+ </div>
230
+ <div className="bg-[#2D3555] rounded-lg p-4 border border-gray-700 hover:border-purple-500/50 transition-colors">
231
+ <div className="font-bold mb-1">Real-time alerts</div>
232
+ <div className="text-sm text-gray-400">because sleep is overrated anyway</div>
233
+ </div>
234
+ </div>
235
+ </div>
236
+ </div>
237
+
238
+ {/* Testing Sections - Bottom Grid */}
239
+ <div className="grid grid-cols-2 gap-8">
240
+ {/* Client Side Testing */}
241
+ <div className="bg-[#1C2333] rounded-lg p-6 border border-gray-800">
242
+ <h2 className="text-xl font-semibold text-white mb-6">Client-Side Testing</h2>
243
+ <div className="space-y-6">
244
+ <div>
245
+ <button
246
+ type="button"
247
+ onClick={() => {
248
+ setDemoStep(prev => prev + 1)
249
+ handleClientError()
250
+ }}
251
+ className="w-full text-white rounded-md p-4 relative overflow-hidden group"
252
+ style={{
253
+ background: 'linear-gradient(120deg, #c83852, #b44092 25%, #6a5fc1 50%, #452650 55%, #452650)',
254
+ backgroundPosition: '2% 0',
255
+ backgroundSize: '250% 100%'
256
+ }}
257
+ >
258
+ <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" />
259
+ <div className="relative">
260
+ <div className="flex items-center mb-2">
261
+ <span className="font-medium">Trigger Client-Side Error</span>
262
+ </div>
263
+ </div>
264
+ </button>
265
+ {hasError.clientError && (
266
+ <div className="mt-4 space-y-2">
267
+ <div className="bg-red-900/20 border border-red-500/50 rounded-lg p-2">
268
+ <div className="flex items-center text-red-400 text-sm">
269
+ <svg className="w-4 h-4 mr-2" fill="none" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" viewBox="0 0 24 24" stroke="currentColor">
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" />
272
+ </svg>
273
+ Client-side error captured and traced
274
+ </div>
275
+ </div>
276
+ <div className="bg-purple-900/20 border border-purple-500/50 rounded-lg p-3">
277
+ <div className="flex items-center justify-between">
278
+ <div className="relative">
279
+ <button
280
+ type="button"
281
+ 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' : ''}`}
282
+ onClick={() => handleCopy(spanOps.clientError)}
283
+ title="Click to copy operation name"
284
+ >
285
+ <span className="text-purple-300 text-sm font-medium mr-2">span.op</span>
286
+ <code className="text-purple-400 text-sm font-mono">{spanOps.clientError}</code>
287
+ </button>
288
+ {copiedSpan === spanOps.clientError && (
289
+ <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">
290
+ Copied!
291
+ </div>
292
+ )}
293
+ </div>
294
+ </div>
295
+ </div>
296
+ </div>
297
+ )}
298
+ </div>
299
+
300
+ <div>
301
+ <button
302
+ type="button"
303
+ onClick={() => {
304
+ setDemoStep(prev => prev + 1)
305
+ handleClientTrace()
306
+ }}
307
+ className="w-full text-white rounded-md p-4 relative overflow-hidden group"
308
+ style={{
309
+ background: 'linear-gradient(120deg, #c83852, #b44092 25%, #6a5fc1 50%, #452650 55%, #452650)',
310
+ backgroundPosition: '2% 0',
311
+ backgroundSize: '250% 100%'
312
+ }}
313
+ >
314
+ <div className="absolute inset-0 bg-gradient-to-r from-blue-500/10 to-purple-500/10 opacity-0 group-hover:opacity-100 transition-opacity" />
315
+ <div className="relative">
316
+ <div className="flex items-center mb-2">
317
+ <span className="font-medium">Test Client-Side Span</span>
318
+ </div>
319
+ </div>
320
+ </button>
321
+ {showTrace.client && (
322
+ <div className="mt-4 space-y-2">
323
+ <div className="flex items-center">
324
+ <div className={`w-3 h-3 rounded-full ${isLoading.client ? 'bg-blue-500 animate-pulse' : 'bg-green-500'}`} />
325
+ <div className="ml-2 flex-1">
326
+ <div className="h-1.5 bg-[#2D3555] rounded">
327
+ <div
328
+ className="h-full bg-blue-500 rounded transition-all duration-500"
329
+ style={{ width: isLoading.client ? '60%' : '100%' }}
330
+ />
331
+ </div>
332
+ </div>
333
+ </div>
334
+ {!isLoading.client && spanOps.client && (
335
+ <div className="bg-purple-900/20 border border-purple-500/50 rounded-lg p-3">
336
+ <div className="flex items-center justify-between">
337
+ <div className="relative">
338
+ <button
339
+ type="button"
340
+ 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' : ''}`}
341
+ onClick={() => handleCopy(spanOps.client)}
342
+ title="Click to copy operation name"
343
+ >
344
+ <span className="text-purple-300 text-sm font-medium mr-2">span.op</span>
345
+ <code className="text-purple-400 text-sm font-mono">{spanOps.client}</code>
346
+ </button>
347
+ {copiedSpan === spanOps.client && (
348
+ <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">
349
+ Copied!
350
+ </div>
351
+ )}
352
+ </div>
353
+ </div>
354
+ </div>
355
+ )}
356
+ </div>
357
+ )}
358
+ </div>
359
+ </div>
360
+ </div>
361
+
362
+ {/* Server Side Testing */}
363
+ <div className="bg-[#1C2333] rounded-lg p-6 border border-gray-800">
364
+ <h2 className="text-xl font-semibold text-white mb-6">Server-Side Testing</h2>
365
+ <div className="space-y-6">
366
+ <div>
367
+ <button
368
+ type="button"
369
+ onClick={() => {
370
+ setDemoStep(prev => prev + 1)
371
+ handleServerError()
372
+ }}
373
+ className="w-full text-white rounded-md p-4 relative overflow-hidden group"
374
+ style={{
375
+ background: 'linear-gradient(120deg, #c83852, #b44092 25%, #6a5fc1 50%, #452650 55%, #452650)',
376
+ backgroundPosition: '2% 0',
377
+ backgroundSize: '250% 100%'
378
+ }}
379
+ >
380
+ <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" />
381
+ <div className="relative">
382
+ <div className="flex items-center mb-2">
383
+ <span className="font-medium">Trigger Server Error</span>
384
+ </div>
385
+ </div>
386
+ </button>
387
+ {hasError.serverError && (
388
+ <div className="mt-4 space-y-2">
389
+ <div className="bg-red-900/20 border border-red-500/50 rounded-lg p-3">
390
+ <div className="flex items-center text-red-400 text-sm">
391
+ <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>
393
+ <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" />
394
+ </svg>
395
+ Server-side error captured and traced
396
+ </div>
397
+ </div>
398
+ <div className="bg-purple-900/20 border border-purple-500/50 rounded-lg p-3">
399
+ <div className="flex items-center justify-between">
400
+ <div className="relative">
401
+ <button
402
+ type="button"
403
+ 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' : ''}`}
404
+ onClick={() => handleCopy(spanOps.serverError)}
405
+ title="Click to copy operation name"
406
+ >
407
+ <span className="text-purple-300 text-sm font-medium mr-2">span.op</span>
408
+ <code className="text-purple-400 text-sm font-mono">{spanOps.serverError}</code>
409
+ </button>
410
+ {copiedSpan === spanOps.serverError && (
411
+ <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">
412
+ Copied!
413
+ </div>
414
+ )}
415
+ </div>
416
+ </div>
417
+ </div>
418
+ </div>
419
+ )}
420
+ </div>
421
+
422
+ <div>
423
+ <button
424
+ type="button"
425
+ onClick={() => {
426
+ setDemoStep(prev => prev + 1)
427
+ handleServerTrace()
428
+ }}
429
+ className="w-full text-white rounded-md p-4 relative overflow-hidden group"
430
+ style={{
431
+ background: 'linear-gradient(120deg, #c83852, #b44092 25%, #6a5fc1 50%, #452650 55%, #452650)',
432
+ backgroundPosition: '2% 0',
433
+ backgroundSize: '250% 100%'
434
+ }}
435
+ >
436
+ <div className="absolute inset-0 bg-gradient-to-r from-blue-500/10 to-purple-500/10 opacity-0 group-hover:opacity-100 transition-opacity" />
437
+ <div className="relative">
438
+ <div className="flex items-center mb-2">
439
+ <span className="font-medium">Test server Trace</span>
440
+ </div>
441
+ </div>
442
+ </button>
443
+ {showTrace.server && (
444
+ <div className="mt-4 space-y-2">
445
+ <div className="flex items-center">
446
+ <div className={`w-3 h-3 rounded-full ${isLoading.server ? 'bg-purple-500 animate-pulse' : 'bg-green-500'}`} />
447
+ <div className="ml-2 flex-1">
448
+ <div className="h-1.5 bg-[#2D3555] rounded">
449
+ <div
450
+ className="h-full bg-purple-500 rounded transition-all duration-500"
451
+ style={{ width: isLoading.server ? '60%' : '100%' }}
452
+ />
453
+ </div>
454
+ </div>
455
+ </div>
456
+ {!isLoading.server && spanOps.server && (
457
+ <div className="bg-purple-900/20 border border-purple-500/50 rounded-lg p-3">
458
+ <div className="flex items-center justify-between">
459
+ <div className="relative">
460
+ <button
461
+ type="button"
462
+ 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' : ''}`}
463
+ onClick={() => handleCopy(spanOps.server)}
464
+ title="Click to copy operation name"
465
+ >
466
+ <span className="text-purple-300 text-sm font-medium mr-2">span.op</span>
467
+ <code className="text-purple-400 text-sm font-mono">{spanOps.server}</code>
468
+ </button>
469
+ {copiedSpan === spanOps.server && (
470
+ <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">
471
+ Copied!
472
+ </div>
473
+ )}
474
+ </div>
475
+ </div>
476
+ </div>
477
+ )}
478
+ </div>
479
+ )}
480
+ </div>
481
+ </div>
482
+ </div>
483
+ </div>
484
+ </div>
485
+ </div>
486
+ </div>
487
+ </>
488
+ )
489
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "Sentry",
3
+ "phase": "setup",
4
+ "description": "Add Sentry for error monitoring, tracing, and session replays (requires Start).",
5
+ "link": "https://sentry.com/",
6
+ "templates": ["file-router", "code-router"],
7
+ "routes": [
8
+ {
9
+ "url": "/demo/sentry/testing",
10
+ "name": "Sentry"
11
+ }
12
+ ],
13
+ "dependsOn": ["start"]
14
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "dependencies": {
3
+ "@sentry/tanstackstart-react": "^9.12.0"
4
+ }
5
+ }
@@ -0,0 +1,7 @@
1
+ ## Shadcn
2
+
3
+ Add components using the latest version of [Shadcn](https://ui.shadcn.com/).
4
+
5
+ ```bash
6
+ pnpx shadcn@latest add button
7
+ ```