@tanstack/create 0.49.1 → 0.49.3

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 (223) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE +21 -0
  3. package/dist/file-helpers.js +3 -1
  4. package/dist/frameworks/react/add-ons/ai/assets/src/data/demo-guitars.ts +93 -0
  5. package/dist/frameworks/react/add-ons/ai/assets/src/hooks/demo-useAudioRecorder.ts +85 -0
  6. package/dist/frameworks/react/add-ons/ai/assets/src/hooks/demo-useTTS.ts +78 -0
  7. package/dist/frameworks/react/add-ons/ai/assets/src/lib/demo-ai-hook.ts +22 -0
  8. package/dist/frameworks/react/add-ons/ai/assets/src/lib/demo-guitar-tools.ts +40 -0
  9. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.chat.ts +99 -0
  10. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.image.ts +72 -0
  11. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.structured.ts +136 -0
  12. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.transcription.ts +89 -0
  13. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.tts.ts +81 -0
  14. package/dist/frameworks/react/add-ons/better-auth/assets/src/lib/auth-client.ts +3 -0
  15. package/dist/frameworks/react/add-ons/better-auth/assets/src/lib/auth.ts +9 -0
  16. package/dist/frameworks/react/add-ons/better-auth/assets/src/routes/api/auth/$.ts +11 -0
  17. package/dist/frameworks/react/add-ons/convex/assets/convex/schema.ts +14 -0
  18. package/dist/frameworks/react/add-ons/convex/assets/convex/todos.ts +43 -0
  19. package/dist/frameworks/react/add-ons/db/assets/src/db-collections/index.ts +20 -0
  20. package/dist/frameworks/react/add-ons/db/assets/src/hooks/demo.useChat.ts +62 -0
  21. package/dist/frameworks/react/add-ons/db/assets/src/routes/demo/db-chat-api.ts +83 -0
  22. package/dist/frameworks/react/add-ons/form/assets/src/hooks/demo.form-context.ts +4 -0
  23. package/dist/frameworks/react/add-ons/form/assets/src/hooks/demo.form.ts +22 -0
  24. package/dist/frameworks/react/add-ons/mcp/assets/src/mcp-todos.ts +51 -0
  25. package/dist/frameworks/react/add-ons/mcp/assets/src/routes/demo/api.mcp-todos.ts +37 -0
  26. package/dist/frameworks/react/add-ons/mcp/assets/src/routes/{mcp.js → mcp.ts} +27 -17
  27. package/dist/frameworks/react/add-ons/mcp/assets/src/utils/mcp-handler.ts +61 -0
  28. package/dist/frameworks/react/add-ons/neon/assets/neon-vite-plugin.ts +10 -0
  29. package/dist/frameworks/react/add-ons/neon/assets/src/db.ts +13 -0
  30. package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/client.ts +29 -0
  31. package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/router/index.ts +6 -0
  32. package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/router/todos.ts +20 -0
  33. package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/schema.ts +6 -0
  34. package/dist/frameworks/react/add-ons/oRPC/assets/src/{polyfill.js → polyfill.ts} +4 -1
  35. package/dist/frameworks/react/add-ons/oRPC/assets/src/routes/api.$.ts +77 -0
  36. package/dist/frameworks/react/add-ons/oRPC/assets/src/routes/api.rpc.$.ts +29 -0
  37. package/dist/frameworks/react/add-ons/shadcn/assets/src/lib/utils.ts +6 -0
  38. package/dist/frameworks/react/add-ons/start/assets/src/data/demo.punk-songs.ts +13 -0
  39. package/dist/frameworks/react/add-ons/start/assets/src/routes/demo/api.names.ts +10 -0
  40. package/dist/frameworks/react/add-ons/store/assets/src/lib/demo-store.ts +13 -0
  41. package/dist/frameworks/react/add-ons/storybook/assets/_dot_storybook/main.ts +17 -0
  42. package/dist/frameworks/react/add-ons/storybook/assets/_dot_storybook/preview.ts +15 -0
  43. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/button.stories.ts +67 -0
  44. package/dist/{types/frameworks/react/add-ons/storybook/assets/src/components/storybook/index.d.ts → frameworks/react/add-ons/storybook/assets/src/components/storybook/index.ts} +4 -0
  45. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/input.stories.ts +43 -0
  46. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/radio-group.stories.ts +53 -0
  47. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/slider.stories.ts +55 -0
  48. package/dist/frameworks/{solid/add-ons/strapi/assets/src/lib/strapiClient.js → react/add-ons/strapi/assets/src/lib/strapiClient.ts} +3 -1
  49. package/dist/frameworks/react/add-ons/t3env/assets/src/env.ts +39 -0
  50. package/dist/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/{init.js → init.ts} +3 -1
  51. package/dist/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/react.ts +4 -0
  52. package/dist/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/router.ts +27 -0
  53. package/dist/frameworks/react/add-ons/table/assets/src/data/demo-table-data.ts +50 -0
  54. package/dist/frameworks/react/examples/events/assets/content-collections.ts +56 -0
  55. package/dist/frameworks/react/examples/events/assets/src/lib/conference-ai-hook.ts +26 -0
  56. package/dist/frameworks/react/examples/events/assets/src/lib/conference-tools.ts +210 -0
  57. package/dist/frameworks/react/examples/events/assets/src/lib/utils.ts +6 -0
  58. package/dist/frameworks/react/examples/events/assets/src/routes/api.remy-chat.ts +121 -0
  59. package/dist/frameworks/react/examples/resume/assets/content-collections.ts +36 -0
  60. package/dist/frameworks/react/examples/resume/assets/src/lib/resume-ai-hook.ts +21 -0
  61. package/dist/frameworks/react/examples/resume/assets/src/lib/resume-tools.ts +165 -0
  62. package/dist/frameworks/react/examples/resume/assets/src/lib/utils.ts +6 -0
  63. package/dist/frameworks/react/examples/resume/assets/src/routes/api.resume-chat.ts +110 -0
  64. package/dist/frameworks/solid/add-ons/better-auth/assets/src/lib/auth-client.ts +3 -0
  65. package/dist/frameworks/solid/add-ons/better-auth/assets/src/lib/auth.ts +9 -0
  66. package/dist/frameworks/solid/add-ons/better-auth/assets/src/routes/api/auth/$.ts +11 -0
  67. package/dist/frameworks/solid/add-ons/convex/assets/convex/schema.ts +14 -0
  68. package/dist/frameworks/solid/add-ons/convex/assets/convex/todos.ts +43 -0
  69. package/dist/frameworks/solid/add-ons/solid-ui/assets/src/lib/utils.ts +6 -0
  70. package/dist/frameworks/solid/add-ons/store/assets/src/lib/demo-store.ts +13 -0
  71. package/dist/frameworks/{react/add-ons/strapi/assets/src/lib/strapiClient.js → solid/add-ons/strapi/assets/src/lib/strapiClient.ts} +3 -1
  72. package/dist/frameworks/solid/add-ons/t3env/assets/src/env.ts +39 -0
  73. package/dist/frameworks/solid/examples/tanchat/assets/ai-streaming-server/src/index.ts +102 -0
  74. package/dist/frameworks/solid/examples/tanchat/assets/src/lib/demo-store.ts +13 -0
  75. package/dist/frameworks/solid/examples/tanchat/assets/src/store/demo.hooks.ts +17 -0
  76. package/dist/frameworks/solid/examples/tanchat/assets/src/store/demo.store.ts +133 -0
  77. package/dist/special-steps/post-init-script.js +6 -6
  78. package/package.json +11 -12
  79. package/src/file-helpers.ts +4 -1
  80. package/src/special-steps/post-init-script.ts +6 -6
  81. package/tests/copy-assets.test.ts +53 -0
  82. package/tests/file-helper.test.ts +19 -0
  83. package/tests/special-steps.test.ts +12 -12
  84. package/dist/frameworks/react/add-ons/ai/assets/src/data/demo-guitars.js +0 -67
  85. package/dist/frameworks/react/add-ons/ai/assets/src/hooks/demo-useAudioRecorder.js +0 -70
  86. package/dist/frameworks/react/add-ons/ai/assets/src/hooks/demo-useTTS.js +0 -66
  87. package/dist/frameworks/react/add-ons/ai/assets/src/lib/demo-ai-hook.js +0 -11
  88. package/dist/frameworks/react/add-ons/ai/assets/src/lib/demo-guitar-tools.js +0 -32
  89. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.chat.js +0 -87
  90. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.image.js +0 -55
  91. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.structured.js +0 -116
  92. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.transcription.js +0 -73
  93. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.tts.js +0 -58
  94. package/dist/frameworks/react/add-ons/better-auth/assets/src/lib/auth-client.js +0 -2
  95. package/dist/frameworks/react/add-ons/better-auth/assets/src/lib/auth.js +0 -8
  96. package/dist/frameworks/react/add-ons/better-auth/assets/src/routes/api/auth/$.js +0 -10
  97. package/dist/frameworks/react/add-ons/convex/assets/convex/schema.js +0 -13
  98. package/dist/frameworks/react/add-ons/convex/assets/convex/todos.js +0 -39
  99. package/dist/frameworks/react/add-ons/db/assets/src/db-collections/index.js +0 -11
  100. package/dist/frameworks/react/add-ons/db/assets/src/hooks/demo.useChat.js +0 -47
  101. package/dist/frameworks/react/add-ons/db/assets/src/routes/demo/db-chat-api.js +0 -68
  102. package/dist/frameworks/react/add-ons/form/assets/src/hooks/demo.form-context.js +0 -2
  103. package/dist/frameworks/react/add-ons/form/assets/src/hooks/demo.form.js +0 -15
  104. package/dist/frameworks/react/add-ons/mcp/assets/src/mcp-todos.js +0 -40
  105. package/dist/frameworks/react/add-ons/mcp/assets/src/routes/demo/api.mcp-todos.js +0 -36
  106. package/dist/frameworks/react/add-ons/mcp/assets/src/utils/mcp-handler.js +0 -41
  107. package/dist/frameworks/react/add-ons/neon/assets/neon-vite-plugin.js +0 -9
  108. package/dist/frameworks/react/add-ons/neon/assets/src/db.js +0 -11
  109. package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/client.js +0 -21
  110. package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/router/index.js +0 -5
  111. package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/router/todos.js +0 -17
  112. package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/schema.js +0 -5
  113. package/dist/frameworks/react/add-ons/oRPC/assets/src/routes/api.$.js +0 -71
  114. package/dist/frameworks/react/add-ons/oRPC/assets/src/routes/api.rpc.$.js +0 -24
  115. package/dist/frameworks/react/add-ons/shadcn/assets/src/lib/utils.js +0 -5
  116. package/dist/frameworks/react/add-ons/start/assets/src/data/demo.punk-songs.js +0 -12
  117. package/dist/frameworks/react/add-ons/start/assets/src/routes/demo/api.names.js +0 -9
  118. package/dist/frameworks/react/add-ons/store/assets/src/lib/demo-store.js +0 -10
  119. package/dist/frameworks/react/add-ons/storybook/assets/_dot_storybook/main.js +0 -15
  120. package/dist/frameworks/react/add-ons/storybook/assets/_dot_storybook/preview.js +0 -12
  121. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/button.stories.js +0 -55
  122. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/index.js +0 -5
  123. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/input.stories.js +0 -35
  124. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/radio-group.stories.js +0 -45
  125. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/slider.stories.js +0 -46
  126. package/dist/frameworks/react/add-ons/t3env/assets/src/env.js +0 -34
  127. package/dist/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/react.js +0 -2
  128. package/dist/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/router.js +0 -20
  129. package/dist/frameworks/react/add-ons/table/assets/src/data/demo-table-data.js +0 -35
  130. package/dist/frameworks/react/examples/events/assets/content-collections.js +0 -53
  131. package/dist/frameworks/react/examples/events/assets/src/lib/conference-ai-hook.js +0 -16
  132. package/dist/frameworks/react/examples/events/assets/src/lib/conference-tools.js +0 -177
  133. package/dist/frameworks/react/examples/events/assets/src/lib/utils.js +0 -5
  134. package/dist/frameworks/react/examples/events/assets/src/routes/api.remy-chat.js +0 -103
  135. package/dist/frameworks/react/examples/resume/assets/content-collections.js +0 -33
  136. package/dist/frameworks/react/examples/resume/assets/src/lib/resume-ai-hook.js +0 -11
  137. package/dist/frameworks/react/examples/resume/assets/src/lib/resume-tools.js +0 -135
  138. package/dist/frameworks/react/examples/resume/assets/src/lib/utils.js +0 -5
  139. package/dist/frameworks/react/examples/resume/assets/src/routes/api.resume-chat.js +0 -92
  140. package/dist/frameworks/solid/add-ons/better-auth/assets/src/lib/auth-client.js +0 -2
  141. package/dist/frameworks/solid/add-ons/better-auth/assets/src/lib/auth.js +0 -8
  142. package/dist/frameworks/solid/add-ons/better-auth/assets/src/routes/api/auth/$.js +0 -10
  143. package/dist/frameworks/solid/add-ons/convex/assets/convex/schema.js +0 -13
  144. package/dist/frameworks/solid/add-ons/convex/assets/convex/todos.js +0 -39
  145. package/dist/frameworks/solid/add-ons/solid-ui/assets/src/lib/utils.js +0 -5
  146. package/dist/frameworks/solid/add-ons/store/assets/src/lib/demo-store.js +0 -10
  147. package/dist/frameworks/solid/add-ons/t3env/assets/src/env.js +0 -34
  148. package/dist/frameworks/solid/examples/tanchat/assets/ai-streaming-server/src/index.js +0 -73
  149. package/dist/frameworks/solid/examples/tanchat/assets/src/lib/demo-store.js +0 -10
  150. package/dist/frameworks/solid/examples/tanchat/assets/src/store/demo.hooks.js +0 -12
  151. package/dist/frameworks/solid/examples/tanchat/assets/src/store/demo.store.js +0 -92
  152. package/dist/types/frameworks/react/add-ons/ai/assets/src/data/demo-guitars.d.ts +0 -10
  153. package/dist/types/frameworks/react/add-ons/ai/assets/src/hooks/demo-useAudioRecorder.d.ts +0 -9
  154. package/dist/types/frameworks/react/add-ons/ai/assets/src/hooks/demo-useTTS.d.ts +0 -8
  155. package/dist/types/frameworks/react/add-ons/ai/assets/src/lib/demo-ai-hook.d.ts +0 -5
  156. package/dist/types/frameworks/react/add-ons/ai/assets/src/lib/demo-guitar-tools.d.ts +0 -3
  157. package/dist/types/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.chat.d.ts +0 -1
  158. package/dist/types/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.image.d.ts +0 -1
  159. package/dist/types/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.structured.d.ts +0 -83
  160. package/dist/types/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.transcription.d.ts +0 -1
  161. package/dist/types/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.tts.d.ts +0 -1
  162. package/dist/types/frameworks/react/add-ons/better-auth/assets/src/lib/auth-client.d.ts +0 -1
  163. package/dist/types/frameworks/react/add-ons/better-auth/assets/src/lib/auth.d.ts +0 -1
  164. package/dist/types/frameworks/react/add-ons/better-auth/assets/src/routes/api/auth/$.d.ts +0 -1
  165. package/dist/types/frameworks/react/add-ons/convex/assets/convex/schema.d.ts +0 -2
  166. package/dist/types/frameworks/react/add-ons/convex/assets/convex/todos.d.ts +0 -4
  167. package/dist/types/frameworks/react/add-ons/db/assets/src/db-collections/index.d.ts +0 -17
  168. package/dist/types/frameworks/react/add-ons/db/assets/src/hooks/demo.useChat.d.ts +0 -5
  169. package/dist/types/frameworks/react/add-ons/db/assets/src/routes/demo/db-chat-api.d.ts +0 -19
  170. package/dist/types/frameworks/react/add-ons/form/assets/src/hooks/demo.form-context.d.ts +0 -1
  171. package/dist/types/frameworks/react/add-ons/form/assets/src/hooks/demo.form.d.ts +0 -1
  172. package/dist/types/frameworks/react/add-ons/mcp/assets/src/mcp-todos.d.ts +0 -7
  173. package/dist/types/frameworks/react/add-ons/mcp/assets/src/routes/demo/api.mcp-todos.d.ts +0 -1
  174. package/dist/types/frameworks/react/add-ons/mcp/assets/src/routes/mcp.d.ts +0 -1
  175. package/dist/types/frameworks/react/add-ons/mcp/assets/src/utils/mcp-handler.d.ts +0 -2
  176. package/dist/types/frameworks/react/add-ons/neon/assets/neon-vite-plugin.d.ts +0 -2
  177. package/dist/types/frameworks/react/add-ons/neon/assets/src/db.d.ts +0 -1
  178. package/dist/types/frameworks/react/add-ons/oRPC/assets/src/orpc/client.d.ts +0 -4
  179. package/dist/types/frameworks/react/add-ons/oRPC/assets/src/orpc/router/index.d.ts +0 -5
  180. package/dist/types/frameworks/react/add-ons/oRPC/assets/src/orpc/router/todos.d.ts +0 -2
  181. package/dist/types/frameworks/react/add-ons/oRPC/assets/src/orpc/schema.d.ts +0 -11
  182. package/dist/types/frameworks/react/add-ons/oRPC/assets/src/polyfill.d.ts +0 -1
  183. package/dist/types/frameworks/react/add-ons/oRPC/assets/src/routes/api.$.d.ts +0 -2
  184. package/dist/types/frameworks/react/add-ons/oRPC/assets/src/routes/api.rpc.$.d.ts +0 -2
  185. package/dist/types/frameworks/react/add-ons/shadcn/assets/src/lib/utils.d.ts +0 -2
  186. package/dist/types/frameworks/react/add-ons/start/assets/src/data/demo.punk-songs.d.ts +0 -1
  187. package/dist/types/frameworks/react/add-ons/start/assets/src/routes/demo/api.names.d.ts +0 -1
  188. package/dist/types/frameworks/react/add-ons/store/assets/src/lib/demo-store.d.ts +0 -2
  189. package/dist/types/frameworks/react/add-ons/storybook/assets/_dot_storybook/main.d.ts +0 -3
  190. package/dist/types/frameworks/react/add-ons/storybook/assets/_dot_storybook/preview.d.ts +0 -4
  191. package/dist/types/frameworks/react/add-ons/storybook/assets/src/components/storybook/button.stories.d.ts +0 -11
  192. package/dist/types/frameworks/react/add-ons/storybook/assets/src/components/storybook/input.stories.d.ts +0 -7
  193. package/dist/types/frameworks/react/add-ons/storybook/assets/src/components/storybook/radio-group.stories.d.ts +0 -7
  194. package/dist/types/frameworks/react/add-ons/storybook/assets/src/components/storybook/slider.stories.d.ts +0 -8
  195. package/dist/types/frameworks/react/add-ons/strapi/assets/src/lib/strapiClient.d.ts +0 -2
  196. package/dist/types/frameworks/react/add-ons/t3env/assets/src/env.d.ts +0 -1
  197. package/dist/types/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/init.d.ts +0 -2
  198. package/dist/types/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/react.d.ts +0 -1
  199. package/dist/types/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/router.d.ts +0 -2
  200. package/dist/types/frameworks/react/add-ons/table/assets/src/data/demo-table-data.d.ts +0 -11
  201. package/dist/types/frameworks/react/examples/events/assets/content-collections.d.ts +0 -2
  202. package/dist/types/frameworks/react/examples/events/assets/src/lib/conference-ai-hook.d.ts +0 -5
  203. package/dist/types/frameworks/react/examples/events/assets/src/lib/conference-tools.d.ts +0 -10
  204. package/dist/types/frameworks/react/examples/events/assets/src/lib/utils.d.ts +0 -2
  205. package/dist/types/frameworks/react/examples/events/assets/src/routes/api.remy-chat.d.ts +0 -1
  206. package/dist/types/frameworks/react/examples/resume/assets/content-collections.d.ts +0 -2
  207. package/dist/types/frameworks/react/examples/resume/assets/src/lib/resume-ai-hook.d.ts +0 -5
  208. package/dist/types/frameworks/react/examples/resume/assets/src/lib/resume-tools.d.ts +0 -8
  209. package/dist/types/frameworks/react/examples/resume/assets/src/lib/utils.d.ts +0 -2
  210. package/dist/types/frameworks/react/examples/resume/assets/src/routes/api.resume-chat.d.ts +0 -1
  211. package/dist/types/frameworks/solid/add-ons/better-auth/assets/src/lib/auth-client.d.ts +0 -1
  212. package/dist/types/frameworks/solid/add-ons/better-auth/assets/src/lib/auth.d.ts +0 -1
  213. package/dist/types/frameworks/solid/add-ons/better-auth/assets/src/routes/api/auth/$.d.ts +0 -1
  214. package/dist/types/frameworks/solid/add-ons/convex/assets/convex/schema.d.ts +0 -2
  215. package/dist/types/frameworks/solid/add-ons/convex/assets/convex/todos.d.ts +0 -4
  216. package/dist/types/frameworks/solid/add-ons/solid-ui/assets/src/lib/utils.d.ts +0 -2
  217. package/dist/types/frameworks/solid/add-ons/store/assets/src/lib/demo-store.d.ts +0 -2
  218. package/dist/types/frameworks/solid/add-ons/strapi/assets/src/lib/strapiClient.d.ts +0 -2
  219. package/dist/types/frameworks/solid/add-ons/t3env/assets/src/env.d.ts +0 -1
  220. package/dist/types/frameworks/solid/examples/tanchat/assets/ai-streaming-server/src/index.d.ts +0 -1
  221. package/dist/types/frameworks/solid/examples/tanchat/assets/src/lib/demo-store.d.ts +0 -2
  222. package/dist/types/frameworks/solid/examples/tanchat/assets/src/store/demo.hooks.d.ts +0 -23
  223. package/dist/types/frameworks/solid/examples/tanchat/assets/src/store/demo.store.d.ts +0 -40
package/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # @tanstack/create
2
+
3
+ ## 0.49.3
4
+
5
+ ### Patch Changes
6
+
7
+ - fix: do not exclude .ts files in asset transfer ([`30edd20`](https://github.com/TanStack/cli/commit/30edd208fd81b5c501fa42cd476232273ff108d1))
8
+
9
+ ## 0.49.2
10
+
11
+ ### Patch Changes
12
+
13
+ - Fixed windows \\ delimiter stripping ([`7940300`](https://github.com/TanStack/cli/commit/79403004689817339ec6f6e03c20fb25e841ddb0))
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021-present Tanner Linsley
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -34,8 +34,10 @@ export function getBinaryFile(content) {
34
34
  */
35
35
  export function toCleanPath(absolutePath, baseDir) {
36
36
  let cleanPath = absolutePath.replace(baseDir, '');
37
- if (cleanPath.startsWith('/'))
37
+ // Handle both Unix (/) and Windows (\) path separators
38
+ if (cleanPath.startsWith('/') || cleanPath.startsWith('\\')) {
38
39
  cleanPath = cleanPath.slice(1);
40
+ }
39
41
  return cleanPath;
40
42
  }
41
43
  export function relativePath(from, to, stripExtension = false) {
@@ -0,0 +1,93 @@
1
+ export interface Guitar {
2
+ id: number
3
+ name: string
4
+ image: string
5
+ description: string
6
+ shortDescription: string
7
+ price: number
8
+ }
9
+
10
+ const guitars: Array<Guitar> = [
11
+ {
12
+ id: 1,
13
+ name: 'TanStack Ukelele',
14
+ image: '/example-ukelele-tanstack.jpg',
15
+ description:
16
+ "Introducing the TanStack Signature Ukulele—a beautifully handcrafted concert ukulele that combines exceptional sound quality with distinctive style. Featuring a warm, resonant koa-wood body with natural grain patterns, this instrument delivers the rich, mellow tones Hawaii is famous for. The exclusive TanStack palm tree inlay on the soundhole adds a unique touch of island flair, while the matching branded headstock makes this a true collector's piece for developers and musicians alike. Whether you're a beginner looking for a quality starter instrument or an experienced player wanting something special, the TanStack Ukulele brings together craftsmanship, character, and that unmistakable tropical spirit.",
17
+ shortDescription:
18
+ 'Premium koa-wood ukulele featuring exclusive TanStack branding, perfect for beach vibes and island-inspired melodies.',
19
+ price: 299,
20
+ },
21
+ {
22
+ id: 2,
23
+ name: 'Video Game Guitar',
24
+ image: '/example-guitar-video-games.jpg',
25
+ description:
26
+ "The Video Game Guitar is a unique acoustic guitar that features a design inspired by video games. It has a sleek, high-gloss finish and a comfortable playability. The guitar's ergonomic body and fast neck profile ensure comfortable playability for hours on end.",
27
+ shortDescription:
28
+ 'A unique electric guitar with a video game design, high-gloss finish, and comfortable playability.',
29
+ price: 699,
30
+ },
31
+ {
32
+ id: 3,
33
+ name: 'Superhero Guitar',
34
+ image: '/example-guitar-superhero.jpg',
35
+ description:
36
+ "The Superhero Guitar is a bold black electric guitar that stands out with its unique superhero logo design. Its sleek, high-gloss finish and powerful pickups make it perfect for high-energy performances. The guitar's ergonomic body and fast neck profile ensure comfortable playability for hours on end.",
37
+ shortDescription:
38
+ 'A bold black electric guitar with a unique superhero logo, high-gloss finish, and powerful pickups.',
39
+ price: 699,
40
+ },
41
+ {
42
+ id: 4,
43
+ name: 'Motherboard Guitar',
44
+ image: '/example-guitar-motherboard.jpg',
45
+ description:
46
+ "This guitar is a tribute to the motherboard of a computer. It's a unique and stylish instrument that will make you feel like a hacker. The intricate circuit-inspired design features actual LED lights that pulse with your playing intensity, while the neck is inlaid with binary code patterns that glow under stage lights. Each pickup has been custom-wound to produce tones ranging from clean digital precision to glitched-out distortion, perfect for electronic music fusion. The Motherboard Guitar seamlessly bridges the gap between traditional craftsmanship and cutting-edge technology, making it the ultimate instrument for the digital age musician.",
47
+ shortDescription:
48
+ 'A tech-inspired electric guitar featuring LED lights and binary code inlays that glow under stage lights.',
49
+ price: 649,
50
+ },
51
+ {
52
+ id: 5,
53
+ name: 'Racing Guitar',
54
+ image: '/example-guitar-racing.jpg',
55
+ description:
56
+ "Engineered for speed and precision, the Racing Guitar embodies the spirit of motorsport in every curve and contour. Its aerodynamic body, painted in classic racing stripes and high-gloss finish, is crafted from lightweight materials that allow for effortless play during extended performances. The custom low-action setup and streamlined neck profile enable lightning-fast fretwork, while specially designed pickups deliver a high-octane tone that cuts through any mix. Built with performance-grade hardware including racing-inspired control knobs and checkered flag inlays, this guitar isn't just played—it's driven to the limits of musical possibility.",
57
+ shortDescription:
58
+ 'A lightweight, aerodynamic guitar with racing stripes and a low-action setup designed for speed and precision.',
59
+ price: 679,
60
+ },
61
+ {
62
+ id: 6,
63
+ name: 'Steamer Trunk Guitar',
64
+ image: '/example-guitar-steamer-trunk.jpg',
65
+ description:
66
+ 'The Steamer Trunk Guitar is a semi-hollow body instrument that exudes vintage charm and character. Crafted from reclaimed antique luggage wood, it features brass hardware that adds a touch of elegance and durability. The fretboard is adorned with a world map inlay, making it a unique piece that tells a story of travel and adventure.',
67
+ shortDescription:
68
+ 'A semi-hollow body guitar with brass hardware and a world map inlay, crafted from reclaimed antique luggage wood.',
69
+ price: 629,
70
+ },
71
+ {
72
+ id: 7,
73
+ name: "Travelin' Man Guitar",
74
+ image: '/example-guitar-traveling.jpg',
75
+ description:
76
+ "The Travelin' Man Guitar is an acoustic masterpiece adorned with vintage postcards from around the world. Each postcard tells a story of adventure and wanderlust, making this guitar a unique piece of art. Its rich, resonant tones and comfortable playability make it perfect for musicians who love to travel and perform.",
77
+ shortDescription:
78
+ 'An acoustic guitar with vintage postcards, rich tones, and comfortable playability.',
79
+ price: 499,
80
+ },
81
+ {
82
+ id: 8,
83
+ name: 'Flowerly Love Guitar',
84
+ image: '/example-guitar-flowers.jpg',
85
+ description:
86
+ "The Flowerly Love Guitar is an acoustic masterpiece adorned with intricate floral designs on its body. Each flower is hand-painted, adding a touch of nature's beauty to the instrument. Its warm, resonant tones make it perfect for both intimate performances and larger gatherings.",
87
+ shortDescription:
88
+ 'An acoustic guitar with hand-painted floral designs and warm, resonant tones.',
89
+ price: 599,
90
+ },
91
+ ]
92
+
93
+ export default guitars
@@ -0,0 +1,85 @@
1
+ import { useCallback, useRef, useState } from 'react'
2
+
3
+ /**
4
+ * Hook for recording audio and transcribing it via the transcription API.
5
+ */
6
+ export function useAudioRecorder() {
7
+ const [isRecording, setIsRecording] = useState(false)
8
+ const [isTranscribing, setIsTranscribing] = useState(false)
9
+ const mediaRecorderRef = useRef<MediaRecorder | null>(null)
10
+ const chunksRef = useRef<Blob[]>([])
11
+
12
+ const startRecording = useCallback(async () => {
13
+ try {
14
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
15
+ const mediaRecorder = new MediaRecorder(stream, {
16
+ mimeType: 'audio/webm;codecs=opus',
17
+ })
18
+ mediaRecorderRef.current = mediaRecorder
19
+ chunksRef.current = []
20
+
21
+ mediaRecorder.ondataavailable = (e) => {
22
+ if (e.data.size > 0) {
23
+ chunksRef.current.push(e.data)
24
+ }
25
+ }
26
+
27
+ mediaRecorder.start()
28
+ setIsRecording(true)
29
+ } catch (error) {
30
+ console.error('Failed to start recording:', error)
31
+ alert('Could not access microphone. Please check permissions.')
32
+ }
33
+ }, [])
34
+
35
+ const stopRecording = useCallback(async (): Promise<string | null> => {
36
+ return new Promise((resolve) => {
37
+ const mediaRecorder = mediaRecorderRef.current
38
+ if (!mediaRecorder) {
39
+ resolve(null)
40
+ return
41
+ }
42
+
43
+ mediaRecorder.onstop = async () => {
44
+ setIsRecording(false)
45
+ setIsTranscribing(true)
46
+
47
+ const audioBlob = new Blob(chunksRef.current, { type: 'audio/webm' })
48
+
49
+ // Stop all tracks
50
+ mediaRecorder.stream.getTracks().forEach((track) => track.stop())
51
+
52
+ try {
53
+ const formData = new FormData()
54
+ formData.append(
55
+ 'audio',
56
+ new File([audioBlob], 'recording.webm', { type: 'audio/webm' }),
57
+ )
58
+ formData.append('model', 'whisper-1')
59
+
60
+ const response = await fetch('/demo/api/transcription', {
61
+ method: 'POST',
62
+ body: formData,
63
+ })
64
+
65
+ if (!response.ok) {
66
+ const errorData = await response.json()
67
+ throw new Error(errorData.error || 'Transcription failed')
68
+ }
69
+
70
+ const result = await response.json()
71
+ setIsTranscribing(false)
72
+ resolve(result.text || null)
73
+ } catch (error) {
74
+ console.error('Transcription error:', error)
75
+ setIsTranscribing(false)
76
+ resolve(null)
77
+ }
78
+ }
79
+
80
+ mediaRecorder.stop()
81
+ })
82
+ }, [])
83
+
84
+ return { isRecording, isTranscribing, startRecording, stopRecording }
85
+ }
@@ -0,0 +1,78 @@
1
+ import { useCallback, useRef, useState } from 'react'
2
+
3
+ /**
4
+ * Hook for text-to-speech playback via the TTS API.
5
+ */
6
+ export function useTTS() {
7
+ const [playingId, setPlayingId] = useState<string | null>(null)
8
+ const audioRef = useRef<HTMLAudioElement | null>(null)
9
+
10
+ const speak = useCallback(async (text: string, id: string) => {
11
+ // Stop any currently playing audio
12
+ if (audioRef.current) {
13
+ audioRef.current.pause()
14
+ audioRef.current = null
15
+ }
16
+
17
+ setPlayingId(id)
18
+
19
+ try {
20
+ const response = await fetch('/demo/api/tts', {
21
+ method: 'POST',
22
+ headers: { 'Content-Type': 'application/json' },
23
+ body: JSON.stringify({
24
+ text,
25
+ voice: 'nova',
26
+ model: 'tts-1',
27
+ format: 'mp3',
28
+ }),
29
+ })
30
+
31
+ if (!response.ok) {
32
+ const errorData = await response.json()
33
+ throw new Error(errorData.error || 'TTS failed')
34
+ }
35
+
36
+ const result = await response.json()
37
+
38
+ // Convert base64 to audio and play
39
+ const audioData = atob(result.audio)
40
+ const bytes = new Uint8Array(audioData.length)
41
+ for (let i = 0; i < audioData.length; i++) {
42
+ bytes[i] = audioData.charCodeAt(i)
43
+ }
44
+ const blob = new Blob([bytes], { type: result.contentType })
45
+ const url = URL.createObjectURL(blob)
46
+
47
+ const audio = new Audio(url)
48
+ audioRef.current = audio
49
+
50
+ audio.onended = () => {
51
+ URL.revokeObjectURL(url)
52
+ setPlayingId(null)
53
+ audioRef.current = null
54
+ }
55
+
56
+ audio.onerror = () => {
57
+ URL.revokeObjectURL(url)
58
+ setPlayingId(null)
59
+ audioRef.current = null
60
+ }
61
+
62
+ await audio.play()
63
+ } catch (error) {
64
+ console.error('TTS error:', error)
65
+ setPlayingId(null)
66
+ }
67
+ }, [])
68
+
69
+ const stop = useCallback(() => {
70
+ if (audioRef.current) {
71
+ audioRef.current.pause()
72
+ audioRef.current = null
73
+ }
74
+ setPlayingId(null)
75
+ }, [])
76
+
77
+ return { playingId, speak, stop }
78
+ }
@@ -0,0 +1,22 @@
1
+ import {
2
+ fetchServerSentEvents,
3
+ useChat,
4
+ createChatClientOptions,
5
+ } from '@tanstack/ai-react'
6
+ import type { InferChatMessages } from '@tanstack/ai-react'
7
+ import { clientTools } from '@tanstack/ai-client'
8
+
9
+ import { recommendGuitarToolDef } from '@/lib/demo-guitar-tools'
10
+
11
+ const recommendGuitarToolClient = recommendGuitarToolDef.client(({ id }) => ({
12
+ id: +id,
13
+ }))
14
+
15
+ const chatOptions = createChatClientOptions({
16
+ connection: fetchServerSentEvents('/demo/api/ai/chat'),
17
+ tools: clientTools(recommendGuitarToolClient),
18
+ })
19
+
20
+ export type ChatMessages = InferChatMessages<typeof chatOptions>
21
+
22
+ export const useGuitarRecommendationChat = () => useChat(chatOptions)
@@ -0,0 +1,40 @@
1
+ import { toolDefinition } from '@tanstack/ai'
2
+ import { z } from 'zod'
3
+ import guitars from '@/data/demo-guitars'
4
+
5
+ // Tool definition for getting guitars
6
+ export const getGuitarsToolDef = toolDefinition({
7
+ name: 'getGuitars',
8
+ description: 'Get all products from the database',
9
+ inputSchema: z.object({}),
10
+ outputSchema: z.array(
11
+ z.object({
12
+ id: z.number(),
13
+ name: z.string(),
14
+ image: z.string(),
15
+ description: z.string(),
16
+ shortDescription: z.string(),
17
+ price: z.number(),
18
+ }),
19
+ ),
20
+ })
21
+
22
+ // Server implementation
23
+ export const getGuitars = getGuitarsToolDef.server(() => guitars)
24
+
25
+ // Tool definition for guitar recommendation
26
+ export const recommendGuitarToolDef = toolDefinition({
27
+ name: 'recommendGuitar',
28
+ description:
29
+ 'REQUIRED tool to display a guitar recommendation to the user. This tool MUST be used whenever recommending a guitar - do NOT write recommendations yourself. This displays the guitar in a special appealing format with a buy button.',
30
+ inputSchema: z.object({
31
+ id: z
32
+ .union([z.string(), z.number()])
33
+ .describe(
34
+ 'The ID of the guitar to recommend (from the getGuitars results)',
35
+ ),
36
+ }),
37
+ outputSchema: z.object({
38
+ id: z.number(),
39
+ }),
40
+ })
@@ -0,0 +1,99 @@
1
+ import { createFileRoute } from '@tanstack/react-router'
2
+ import { chat, maxIterations, toServerSentEventsResponse } from '@tanstack/ai'
3
+ import { anthropicText } from '@tanstack/ai-anthropic'
4
+ import { openaiText } from '@tanstack/ai-openai'
5
+ import { geminiText } from '@tanstack/ai-gemini'
6
+ import { ollamaText } from '@tanstack/ai-ollama'
7
+
8
+ import { getGuitars, recommendGuitarToolDef } from '@/lib/demo-guitar-tools'
9
+
10
+ const SYSTEM_PROMPT = `You are a helpful assistant for a store that sells guitars.
11
+
12
+ CRITICAL INSTRUCTIONS - YOU MUST FOLLOW THIS EXACT WORKFLOW:
13
+
14
+ When a user asks for a guitar recommendation:
15
+ 1. FIRST: Use the getGuitars tool (no parameters needed)
16
+ 2. SECOND: Use the recommendGuitar tool with the ID of the guitar you want to recommend
17
+ 3. NEVER write a recommendation directly - ALWAYS use the recommendGuitar tool
18
+
19
+ IMPORTANT:
20
+ - The recommendGuitar tool will display the guitar in a special, appealing format
21
+ - You MUST use recommendGuitar for ANY guitar recommendation
22
+ - ONLY recommend guitars from our inventory (use getGuitars first)
23
+ - The recommendGuitar tool has a buy button - this is how customers purchase
24
+ - Do NOT describe the guitar yourself - let the recommendGuitar tool do it
25
+ `
26
+
27
+ export const Route = createFileRoute('/demo/api/ai/chat')({
28
+ server: {
29
+ handlers: {
30
+ POST: async ({ request }) => {
31
+ // Capture request signal before reading body (it may be aborted after body is consumed)
32
+ const requestSignal = request.signal
33
+
34
+ // If request is already aborted, return early
35
+ if (requestSignal.aborted) {
36
+ return new Response(null, { status: 499 }) // 499 = Client Closed Request
37
+ }
38
+
39
+ const abortController = new AbortController()
40
+
41
+ try {
42
+ const body = await request.json()
43
+ const { messages } = body
44
+
45
+ // Determine the best available provider
46
+ let provider: string = 'ollama'
47
+ let model: string = 'mistral:7b'
48
+ if (process.env.ANTHROPIC_API_KEY) {
49
+ provider = 'anthropic'
50
+ model = 'claude-haiku-4-5'
51
+ } else if (process.env.OPENAI_API_KEY) {
52
+ provider = 'openai'
53
+ model = 'gpt-4o'
54
+ } else if (process.env.GEMINI_API_KEY) {
55
+ provider = 'gemini'
56
+ model = 'gemini-2.0-flash-exp'
57
+ }
58
+
59
+ // Adapter factory pattern for multi-vendor support
60
+ const adapterConfig = {
61
+ anthropic: () =>
62
+ anthropicText((model || 'claude-haiku-4-5') as any),
63
+ openai: () => openaiText((model || 'gpt-4o') as any),
64
+ gemini: () => geminiText((model || 'gemini-2.0-flash-exp') as any),
65
+ ollama: () => ollamaText((model || 'mistral:7b') as any),
66
+ }
67
+
68
+ const adapter = adapterConfig[provider]()
69
+
70
+ const stream = chat({
71
+ adapter,
72
+ tools: [
73
+ getGuitars, // Server tool
74
+ recommendGuitarToolDef, // No server execute - client will handle
75
+ ],
76
+ systemPrompts: [SYSTEM_PROMPT],
77
+ agentLoopStrategy: maxIterations(5),
78
+ messages,
79
+ abortController,
80
+ })
81
+
82
+ return toServerSentEventsResponse(stream, { abortController })
83
+ } catch (error: any) {
84
+ // If request was aborted, return early (don't send error response)
85
+ if (error.name === 'AbortError' || abortController.signal.aborted) {
86
+ return new Response(null, { status: 499 }) // 499 = Client Closed Request
87
+ }
88
+ return new Response(
89
+ JSON.stringify({ error: 'Failed to process chat request' }),
90
+ {
91
+ status: 500,
92
+ headers: { 'Content-Type': 'application/json' },
93
+ },
94
+ )
95
+ }
96
+ },
97
+ },
98
+ },
99
+ })
@@ -0,0 +1,72 @@
1
+ import { createFileRoute } from '@tanstack/react-router'
2
+ import { generateImage, createImageOptions } from '@tanstack/ai'
3
+ import { openaiImage } from '@tanstack/ai-openai'
4
+
5
+ export const Route = createFileRoute('/demo/api/ai/image')({
6
+ server: {
7
+ handlers: {
8
+ POST: async ({ request }) => {
9
+ const body = await request.json()
10
+ const { prompt, numberOfImages = 1, size = '1024x1024' } = body
11
+
12
+ if (!prompt || prompt.trim().length === 0) {
13
+ return new Response(
14
+ JSON.stringify({
15
+ error: 'Prompt is required',
16
+ }),
17
+ {
18
+ status: 400,
19
+ headers: { 'Content-Type': 'application/json' },
20
+ },
21
+ )
22
+ }
23
+
24
+ if (!process.env.OPENAI_API_KEY) {
25
+ return new Response(
26
+ JSON.stringify({
27
+ error: 'OPENAI_API_KEY is not configured',
28
+ }),
29
+ {
30
+ status: 500,
31
+ headers: { 'Content-Type': 'application/json' },
32
+ },
33
+ )
34
+ }
35
+
36
+ try {
37
+ const options = createImageOptions({
38
+ adapter: openaiImage('gpt-image-1'),
39
+ })
40
+
41
+ const result = await generateImage({
42
+ ...options,
43
+ prompt,
44
+ numberOfImages,
45
+ size,
46
+ })
47
+
48
+ return new Response(
49
+ JSON.stringify({
50
+ images: result.images,
51
+ model: 'gpt-image-1',
52
+ }),
53
+ {
54
+ status: 200,
55
+ headers: { 'Content-Type': 'application/json' },
56
+ },
57
+ )
58
+ } catch (error: any) {
59
+ return new Response(
60
+ JSON.stringify({
61
+ error: error.message || 'An error occurred',
62
+ }),
63
+ {
64
+ status: 500,
65
+ headers: { 'Content-Type': 'application/json' },
66
+ },
67
+ )
68
+ }
69
+ },
70
+ },
71
+ },
72
+ })
@@ -0,0 +1,136 @@
1
+ import { createFileRoute } from '@tanstack/react-router'
2
+ import { chat } from '@tanstack/ai'
3
+ import { openaiText } from '@tanstack/ai-openai'
4
+ import { z } from 'zod'
5
+
6
+ // Schema for structured recipe output
7
+ const RecipeSchema = z.object({
8
+ name: z.string().describe('The name of the recipe'),
9
+ description: z.string().describe('A brief description of the dish'),
10
+ prepTime: z.string().describe('Preparation time (e.g., "15 minutes")'),
11
+ cookTime: z.string().describe('Cooking time (e.g., "30 minutes")'),
12
+ servings: z.number().describe('Number of servings'),
13
+ difficulty: z.enum(['easy', 'medium', 'hard']).describe('Difficulty level'),
14
+ ingredients: z
15
+ .array(
16
+ z.object({
17
+ item: z.string().describe('Ingredient name'),
18
+ amount: z.string().describe('Amount needed (e.g., "2 cups")'),
19
+ notes: z.string().optional().describe('Optional preparation notes'),
20
+ }),
21
+ )
22
+ .describe('List of ingredients'),
23
+ instructions: z
24
+ .array(z.string())
25
+ .describe('Step-by-step cooking instructions'),
26
+ tips: z.array(z.string()).optional().describe('Optional cooking tips'),
27
+ nutritionPerServing: z
28
+ .object({
29
+ calories: z.number().optional(),
30
+ protein: z.string().optional(),
31
+ carbs: z.string().optional(),
32
+ fat: z.string().optional(),
33
+ })
34
+ .optional()
35
+ .describe('Nutritional information per serving'),
36
+ })
37
+
38
+ export type Recipe = z.infer<typeof RecipeSchema>
39
+
40
+ export const Route = createFileRoute('/demo/api/ai/structured')({
41
+ server: {
42
+ handlers: {
43
+ POST: async ({ request }) => {
44
+ const body = await request.json()
45
+ const { recipeName, mode = 'structured' } = body
46
+
47
+ if (!recipeName || recipeName.trim().length === 0) {
48
+ return new Response(
49
+ JSON.stringify({
50
+ error: 'Recipe name is required',
51
+ }),
52
+ {
53
+ status: 400,
54
+ headers: { 'Content-Type': 'application/json' },
55
+ },
56
+ )
57
+ }
58
+
59
+ try {
60
+ if (mode === 'structured') {
61
+ // Structured output mode - returns validated object
62
+ const result = await chat({
63
+ adapter: openaiText('gpt-4o'),
64
+ messages: [
65
+ {
66
+ role: 'user',
67
+ content: `Generate a complete recipe for: ${recipeName}. Include all ingredients with amounts, step-by-step instructions, prep/cook times, and difficulty level.`,
68
+ },
69
+ ],
70
+ outputSchema: RecipeSchema,
71
+ } as any)
72
+
73
+ return new Response(
74
+ JSON.stringify({
75
+ mode: 'structured',
76
+ recipe: result,
77
+ provider: 'openai',
78
+ model: 'gpt-4o',
79
+ }),
80
+ {
81
+ status: 200,
82
+ headers: { 'Content-Type': 'application/json' },
83
+ },
84
+ )
85
+ } else {
86
+ // One-shot markdown mode - returns text
87
+ const markdown = await chat({
88
+ adapter: openaiText('gpt-4o'),
89
+ stream: false,
90
+ messages: [
91
+ {
92
+ role: 'user',
93
+ content: `Generate a complete recipe for: ${recipeName}.
94
+
95
+ Format the recipe in beautiful markdown with:
96
+ - A title with the recipe name
97
+ - A brief description
98
+ - Prep time, cook time, and servings
99
+ - Ingredients list with amounts
100
+ - Numbered step-by-step instructions
101
+ - Optional tips section
102
+ - Nutritional info if applicable
103
+
104
+ Make it detailed and easy to follow.`,
105
+ },
106
+ ],
107
+ } as any)
108
+
109
+ return new Response(
110
+ JSON.stringify({
111
+ mode: 'oneshot',
112
+ markdown,
113
+ provider: 'openai',
114
+ model: 'gpt-4o',
115
+ }),
116
+ {
117
+ status: 200,
118
+ headers: { 'Content-Type': 'application/json' },
119
+ },
120
+ )
121
+ }
122
+ } catch (error: any) {
123
+ return new Response(
124
+ JSON.stringify({
125
+ error: error.message || 'An error occurred',
126
+ }),
127
+ {
128
+ status: 500,
129
+ headers: { 'Content-Type': 'application/json' },
130
+ },
131
+ )
132
+ }
133
+ },
134
+ },
135
+ },
136
+ })