@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.
- package/CHANGELOG.md +13 -0
- package/LICENSE +21 -0
- package/dist/file-helpers.js +3 -1
- package/dist/frameworks/react/add-ons/ai/assets/src/data/demo-guitars.ts +93 -0
- package/dist/frameworks/react/add-ons/ai/assets/src/hooks/demo-useAudioRecorder.ts +85 -0
- package/dist/frameworks/react/add-ons/ai/assets/src/hooks/demo-useTTS.ts +78 -0
- package/dist/frameworks/react/add-ons/ai/assets/src/lib/demo-ai-hook.ts +22 -0
- package/dist/frameworks/react/add-ons/ai/assets/src/lib/demo-guitar-tools.ts +40 -0
- package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.chat.ts +99 -0
- package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.image.ts +72 -0
- package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.structured.ts +136 -0
- package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.transcription.ts +89 -0
- package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.tts.ts +81 -0
- package/dist/frameworks/react/add-ons/better-auth/assets/src/lib/auth-client.ts +3 -0
- package/dist/frameworks/react/add-ons/better-auth/assets/src/lib/auth.ts +9 -0
- package/dist/frameworks/react/add-ons/better-auth/assets/src/routes/api/auth/$.ts +11 -0
- package/dist/frameworks/react/add-ons/convex/assets/convex/schema.ts +14 -0
- package/dist/frameworks/react/add-ons/convex/assets/convex/todos.ts +43 -0
- package/dist/frameworks/react/add-ons/db/assets/src/db-collections/index.ts +20 -0
- package/dist/frameworks/react/add-ons/db/assets/src/hooks/demo.useChat.ts +62 -0
- package/dist/frameworks/react/add-ons/db/assets/src/routes/demo/db-chat-api.ts +83 -0
- package/dist/frameworks/react/add-ons/form/assets/src/hooks/demo.form-context.ts +4 -0
- package/dist/frameworks/react/add-ons/form/assets/src/hooks/demo.form.ts +22 -0
- package/dist/frameworks/react/add-ons/mcp/assets/src/mcp-todos.ts +51 -0
- package/dist/frameworks/react/add-ons/mcp/assets/src/routes/demo/api.mcp-todos.ts +37 -0
- package/dist/frameworks/react/add-ons/mcp/assets/src/routes/{mcp.js → mcp.ts} +27 -17
- package/dist/frameworks/react/add-ons/mcp/assets/src/utils/mcp-handler.ts +61 -0
- package/dist/frameworks/react/add-ons/neon/assets/neon-vite-plugin.ts +10 -0
- package/dist/frameworks/react/add-ons/neon/assets/src/db.ts +13 -0
- package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/client.ts +29 -0
- package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/router/index.ts +6 -0
- package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/router/todos.ts +20 -0
- package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/schema.ts +6 -0
- package/dist/frameworks/react/add-ons/oRPC/assets/src/{polyfill.js → polyfill.ts} +4 -1
- package/dist/frameworks/react/add-ons/oRPC/assets/src/routes/api.$.ts +77 -0
- package/dist/frameworks/react/add-ons/oRPC/assets/src/routes/api.rpc.$.ts +29 -0
- package/dist/frameworks/react/add-ons/shadcn/assets/src/lib/utils.ts +6 -0
- package/dist/frameworks/react/add-ons/start/assets/src/data/demo.punk-songs.ts +13 -0
- package/dist/frameworks/react/add-ons/start/assets/src/routes/demo/api.names.ts +10 -0
- package/dist/frameworks/react/add-ons/store/assets/src/lib/demo-store.ts +13 -0
- package/dist/frameworks/react/add-ons/storybook/assets/_dot_storybook/main.ts +17 -0
- package/dist/frameworks/react/add-ons/storybook/assets/_dot_storybook/preview.ts +15 -0
- package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/button.stories.ts +67 -0
- 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
- package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/input.stories.ts +43 -0
- package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/radio-group.stories.ts +53 -0
- package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/slider.stories.ts +55 -0
- package/dist/frameworks/{solid/add-ons/strapi/assets/src/lib/strapiClient.js → react/add-ons/strapi/assets/src/lib/strapiClient.ts} +3 -1
- package/dist/frameworks/react/add-ons/t3env/assets/src/env.ts +39 -0
- package/dist/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/{init.js → init.ts} +3 -1
- package/dist/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/react.ts +4 -0
- package/dist/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/router.ts +27 -0
- package/dist/frameworks/react/add-ons/table/assets/src/data/demo-table-data.ts +50 -0
- package/dist/frameworks/react/examples/events/assets/content-collections.ts +56 -0
- package/dist/frameworks/react/examples/events/assets/src/lib/conference-ai-hook.ts +26 -0
- package/dist/frameworks/react/examples/events/assets/src/lib/conference-tools.ts +210 -0
- package/dist/frameworks/react/examples/events/assets/src/lib/utils.ts +6 -0
- package/dist/frameworks/react/examples/events/assets/src/routes/api.remy-chat.ts +121 -0
- package/dist/frameworks/react/examples/resume/assets/content-collections.ts +36 -0
- package/dist/frameworks/react/examples/resume/assets/src/lib/resume-ai-hook.ts +21 -0
- package/dist/frameworks/react/examples/resume/assets/src/lib/resume-tools.ts +165 -0
- package/dist/frameworks/react/examples/resume/assets/src/lib/utils.ts +6 -0
- package/dist/frameworks/react/examples/resume/assets/src/routes/api.resume-chat.ts +110 -0
- package/dist/frameworks/solid/add-ons/better-auth/assets/src/lib/auth-client.ts +3 -0
- package/dist/frameworks/solid/add-ons/better-auth/assets/src/lib/auth.ts +9 -0
- package/dist/frameworks/solid/add-ons/better-auth/assets/src/routes/api/auth/$.ts +11 -0
- package/dist/frameworks/solid/add-ons/convex/assets/convex/schema.ts +14 -0
- package/dist/frameworks/solid/add-ons/convex/assets/convex/todos.ts +43 -0
- package/dist/frameworks/solid/add-ons/solid-ui/assets/src/lib/utils.ts +6 -0
- package/dist/frameworks/solid/add-ons/store/assets/src/lib/demo-store.ts +13 -0
- package/dist/frameworks/{react/add-ons/strapi/assets/src/lib/strapiClient.js → solid/add-ons/strapi/assets/src/lib/strapiClient.ts} +3 -1
- package/dist/frameworks/solid/add-ons/t3env/assets/src/env.ts +39 -0
- package/dist/frameworks/solid/examples/tanchat/assets/ai-streaming-server/src/index.ts +102 -0
- package/dist/frameworks/solid/examples/tanchat/assets/src/lib/demo-store.ts +13 -0
- package/dist/frameworks/solid/examples/tanchat/assets/src/store/demo.hooks.ts +17 -0
- package/dist/frameworks/solid/examples/tanchat/assets/src/store/demo.store.ts +133 -0
- package/dist/special-steps/post-init-script.js +6 -6
- package/package.json +11 -12
- package/src/file-helpers.ts +4 -1
- package/src/special-steps/post-init-script.ts +6 -6
- package/tests/copy-assets.test.ts +53 -0
- package/tests/file-helper.test.ts +19 -0
- package/tests/special-steps.test.ts +12 -12
- package/dist/frameworks/react/add-ons/ai/assets/src/data/demo-guitars.js +0 -67
- package/dist/frameworks/react/add-ons/ai/assets/src/hooks/demo-useAudioRecorder.js +0 -70
- package/dist/frameworks/react/add-ons/ai/assets/src/hooks/demo-useTTS.js +0 -66
- package/dist/frameworks/react/add-ons/ai/assets/src/lib/demo-ai-hook.js +0 -11
- package/dist/frameworks/react/add-ons/ai/assets/src/lib/demo-guitar-tools.js +0 -32
- package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.chat.js +0 -87
- package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.image.js +0 -55
- package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.structured.js +0 -116
- package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.transcription.js +0 -73
- package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.tts.js +0 -58
- package/dist/frameworks/react/add-ons/better-auth/assets/src/lib/auth-client.js +0 -2
- package/dist/frameworks/react/add-ons/better-auth/assets/src/lib/auth.js +0 -8
- package/dist/frameworks/react/add-ons/better-auth/assets/src/routes/api/auth/$.js +0 -10
- package/dist/frameworks/react/add-ons/convex/assets/convex/schema.js +0 -13
- package/dist/frameworks/react/add-ons/convex/assets/convex/todos.js +0 -39
- package/dist/frameworks/react/add-ons/db/assets/src/db-collections/index.js +0 -11
- package/dist/frameworks/react/add-ons/db/assets/src/hooks/demo.useChat.js +0 -47
- package/dist/frameworks/react/add-ons/db/assets/src/routes/demo/db-chat-api.js +0 -68
- package/dist/frameworks/react/add-ons/form/assets/src/hooks/demo.form-context.js +0 -2
- package/dist/frameworks/react/add-ons/form/assets/src/hooks/demo.form.js +0 -15
- package/dist/frameworks/react/add-ons/mcp/assets/src/mcp-todos.js +0 -40
- package/dist/frameworks/react/add-ons/mcp/assets/src/routes/demo/api.mcp-todos.js +0 -36
- package/dist/frameworks/react/add-ons/mcp/assets/src/utils/mcp-handler.js +0 -41
- package/dist/frameworks/react/add-ons/neon/assets/neon-vite-plugin.js +0 -9
- package/dist/frameworks/react/add-ons/neon/assets/src/db.js +0 -11
- package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/client.js +0 -21
- package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/router/index.js +0 -5
- package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/router/todos.js +0 -17
- package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/schema.js +0 -5
- package/dist/frameworks/react/add-ons/oRPC/assets/src/routes/api.$.js +0 -71
- package/dist/frameworks/react/add-ons/oRPC/assets/src/routes/api.rpc.$.js +0 -24
- package/dist/frameworks/react/add-ons/shadcn/assets/src/lib/utils.js +0 -5
- package/dist/frameworks/react/add-ons/start/assets/src/data/demo.punk-songs.js +0 -12
- package/dist/frameworks/react/add-ons/start/assets/src/routes/demo/api.names.js +0 -9
- package/dist/frameworks/react/add-ons/store/assets/src/lib/demo-store.js +0 -10
- package/dist/frameworks/react/add-ons/storybook/assets/_dot_storybook/main.js +0 -15
- package/dist/frameworks/react/add-ons/storybook/assets/_dot_storybook/preview.js +0 -12
- package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/button.stories.js +0 -55
- package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/index.js +0 -5
- package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/input.stories.js +0 -35
- package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/radio-group.stories.js +0 -45
- package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/slider.stories.js +0 -46
- package/dist/frameworks/react/add-ons/t3env/assets/src/env.js +0 -34
- package/dist/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/react.js +0 -2
- package/dist/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/router.js +0 -20
- package/dist/frameworks/react/add-ons/table/assets/src/data/demo-table-data.js +0 -35
- package/dist/frameworks/react/examples/events/assets/content-collections.js +0 -53
- package/dist/frameworks/react/examples/events/assets/src/lib/conference-ai-hook.js +0 -16
- package/dist/frameworks/react/examples/events/assets/src/lib/conference-tools.js +0 -177
- package/dist/frameworks/react/examples/events/assets/src/lib/utils.js +0 -5
- package/dist/frameworks/react/examples/events/assets/src/routes/api.remy-chat.js +0 -103
- package/dist/frameworks/react/examples/resume/assets/content-collections.js +0 -33
- package/dist/frameworks/react/examples/resume/assets/src/lib/resume-ai-hook.js +0 -11
- package/dist/frameworks/react/examples/resume/assets/src/lib/resume-tools.js +0 -135
- package/dist/frameworks/react/examples/resume/assets/src/lib/utils.js +0 -5
- package/dist/frameworks/react/examples/resume/assets/src/routes/api.resume-chat.js +0 -92
- package/dist/frameworks/solid/add-ons/better-auth/assets/src/lib/auth-client.js +0 -2
- package/dist/frameworks/solid/add-ons/better-auth/assets/src/lib/auth.js +0 -8
- package/dist/frameworks/solid/add-ons/better-auth/assets/src/routes/api/auth/$.js +0 -10
- package/dist/frameworks/solid/add-ons/convex/assets/convex/schema.js +0 -13
- package/dist/frameworks/solid/add-ons/convex/assets/convex/todos.js +0 -39
- package/dist/frameworks/solid/add-ons/solid-ui/assets/src/lib/utils.js +0 -5
- package/dist/frameworks/solid/add-ons/store/assets/src/lib/demo-store.js +0 -10
- package/dist/frameworks/solid/add-ons/t3env/assets/src/env.js +0 -34
- package/dist/frameworks/solid/examples/tanchat/assets/ai-streaming-server/src/index.js +0 -73
- package/dist/frameworks/solid/examples/tanchat/assets/src/lib/demo-store.js +0 -10
- package/dist/frameworks/solid/examples/tanchat/assets/src/store/demo.hooks.js +0 -12
- package/dist/frameworks/solid/examples/tanchat/assets/src/store/demo.store.js +0 -92
- package/dist/types/frameworks/react/add-ons/ai/assets/src/data/demo-guitars.d.ts +0 -10
- package/dist/types/frameworks/react/add-ons/ai/assets/src/hooks/demo-useAudioRecorder.d.ts +0 -9
- package/dist/types/frameworks/react/add-ons/ai/assets/src/hooks/demo-useTTS.d.ts +0 -8
- package/dist/types/frameworks/react/add-ons/ai/assets/src/lib/demo-ai-hook.d.ts +0 -5
- package/dist/types/frameworks/react/add-ons/ai/assets/src/lib/demo-guitar-tools.d.ts +0 -3
- package/dist/types/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.chat.d.ts +0 -1
- package/dist/types/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.image.d.ts +0 -1
- package/dist/types/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.structured.d.ts +0 -83
- package/dist/types/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.transcription.d.ts +0 -1
- package/dist/types/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.tts.d.ts +0 -1
- package/dist/types/frameworks/react/add-ons/better-auth/assets/src/lib/auth-client.d.ts +0 -1
- package/dist/types/frameworks/react/add-ons/better-auth/assets/src/lib/auth.d.ts +0 -1
- package/dist/types/frameworks/react/add-ons/better-auth/assets/src/routes/api/auth/$.d.ts +0 -1
- package/dist/types/frameworks/react/add-ons/convex/assets/convex/schema.d.ts +0 -2
- package/dist/types/frameworks/react/add-ons/convex/assets/convex/todos.d.ts +0 -4
- package/dist/types/frameworks/react/add-ons/db/assets/src/db-collections/index.d.ts +0 -17
- package/dist/types/frameworks/react/add-ons/db/assets/src/hooks/demo.useChat.d.ts +0 -5
- package/dist/types/frameworks/react/add-ons/db/assets/src/routes/demo/db-chat-api.d.ts +0 -19
- package/dist/types/frameworks/react/add-ons/form/assets/src/hooks/demo.form-context.d.ts +0 -1
- package/dist/types/frameworks/react/add-ons/form/assets/src/hooks/demo.form.d.ts +0 -1
- package/dist/types/frameworks/react/add-ons/mcp/assets/src/mcp-todos.d.ts +0 -7
- package/dist/types/frameworks/react/add-ons/mcp/assets/src/routes/demo/api.mcp-todos.d.ts +0 -1
- package/dist/types/frameworks/react/add-ons/mcp/assets/src/routes/mcp.d.ts +0 -1
- package/dist/types/frameworks/react/add-ons/mcp/assets/src/utils/mcp-handler.d.ts +0 -2
- package/dist/types/frameworks/react/add-ons/neon/assets/neon-vite-plugin.d.ts +0 -2
- package/dist/types/frameworks/react/add-ons/neon/assets/src/db.d.ts +0 -1
- package/dist/types/frameworks/react/add-ons/oRPC/assets/src/orpc/client.d.ts +0 -4
- package/dist/types/frameworks/react/add-ons/oRPC/assets/src/orpc/router/index.d.ts +0 -5
- package/dist/types/frameworks/react/add-ons/oRPC/assets/src/orpc/router/todos.d.ts +0 -2
- package/dist/types/frameworks/react/add-ons/oRPC/assets/src/orpc/schema.d.ts +0 -11
- package/dist/types/frameworks/react/add-ons/oRPC/assets/src/polyfill.d.ts +0 -1
- package/dist/types/frameworks/react/add-ons/oRPC/assets/src/routes/api.$.d.ts +0 -2
- package/dist/types/frameworks/react/add-ons/oRPC/assets/src/routes/api.rpc.$.d.ts +0 -2
- package/dist/types/frameworks/react/add-ons/shadcn/assets/src/lib/utils.d.ts +0 -2
- package/dist/types/frameworks/react/add-ons/start/assets/src/data/demo.punk-songs.d.ts +0 -1
- package/dist/types/frameworks/react/add-ons/start/assets/src/routes/demo/api.names.d.ts +0 -1
- package/dist/types/frameworks/react/add-ons/store/assets/src/lib/demo-store.d.ts +0 -2
- package/dist/types/frameworks/react/add-ons/storybook/assets/_dot_storybook/main.d.ts +0 -3
- package/dist/types/frameworks/react/add-ons/storybook/assets/_dot_storybook/preview.d.ts +0 -4
- package/dist/types/frameworks/react/add-ons/storybook/assets/src/components/storybook/button.stories.d.ts +0 -11
- package/dist/types/frameworks/react/add-ons/storybook/assets/src/components/storybook/input.stories.d.ts +0 -7
- package/dist/types/frameworks/react/add-ons/storybook/assets/src/components/storybook/radio-group.stories.d.ts +0 -7
- package/dist/types/frameworks/react/add-ons/storybook/assets/src/components/storybook/slider.stories.d.ts +0 -8
- package/dist/types/frameworks/react/add-ons/strapi/assets/src/lib/strapiClient.d.ts +0 -2
- package/dist/types/frameworks/react/add-ons/t3env/assets/src/env.d.ts +0 -1
- package/dist/types/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/init.d.ts +0 -2
- package/dist/types/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/react.d.ts +0 -1
- package/dist/types/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/router.d.ts +0 -2
- package/dist/types/frameworks/react/add-ons/table/assets/src/data/demo-table-data.d.ts +0 -11
- package/dist/types/frameworks/react/examples/events/assets/content-collections.d.ts +0 -2
- package/dist/types/frameworks/react/examples/events/assets/src/lib/conference-ai-hook.d.ts +0 -5
- package/dist/types/frameworks/react/examples/events/assets/src/lib/conference-tools.d.ts +0 -10
- package/dist/types/frameworks/react/examples/events/assets/src/lib/utils.d.ts +0 -2
- package/dist/types/frameworks/react/examples/events/assets/src/routes/api.remy-chat.d.ts +0 -1
- package/dist/types/frameworks/react/examples/resume/assets/content-collections.d.ts +0 -2
- package/dist/types/frameworks/react/examples/resume/assets/src/lib/resume-ai-hook.d.ts +0 -5
- package/dist/types/frameworks/react/examples/resume/assets/src/lib/resume-tools.d.ts +0 -8
- package/dist/types/frameworks/react/examples/resume/assets/src/lib/utils.d.ts +0 -2
- package/dist/types/frameworks/react/examples/resume/assets/src/routes/api.resume-chat.d.ts +0 -1
- package/dist/types/frameworks/solid/add-ons/better-auth/assets/src/lib/auth-client.d.ts +0 -1
- package/dist/types/frameworks/solid/add-ons/better-auth/assets/src/lib/auth.d.ts +0 -1
- package/dist/types/frameworks/solid/add-ons/better-auth/assets/src/routes/api/auth/$.d.ts +0 -1
- package/dist/types/frameworks/solid/add-ons/convex/assets/convex/schema.d.ts +0 -2
- package/dist/types/frameworks/solid/add-ons/convex/assets/convex/todos.d.ts +0 -4
- package/dist/types/frameworks/solid/add-ons/solid-ui/assets/src/lib/utils.d.ts +0 -2
- package/dist/types/frameworks/solid/add-ons/store/assets/src/lib/demo-store.d.ts +0 -2
- package/dist/types/frameworks/solid/add-ons/strapi/assets/src/lib/strapiClient.d.ts +0 -2
- package/dist/types/frameworks/solid/add-ons/t3env/assets/src/env.d.ts +0 -1
- package/dist/types/frameworks/solid/examples/tanchat/assets/ai-streaming-server/src/index.d.ts +0 -1
- package/dist/types/frameworks/solid/examples/tanchat/assets/src/lib/demo-store.d.ts +0 -2
- package/dist/types/frameworks/solid/examples/tanchat/assets/src/store/demo.hooks.d.ts +0 -23
- package/dist/types/frameworks/solid/examples/tanchat/assets/src/store/demo.store.d.ts +0 -40
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { createFileRoute } from '@tanstack/react-router'
|
|
2
|
+
import { generateTranscription } from '@tanstack/ai'
|
|
3
|
+
import { openaiTranscription } from '@tanstack/ai-openai'
|
|
4
|
+
|
|
5
|
+
export const Route = createFileRoute('/demo/api/ai/transcription')({
|
|
6
|
+
server: {
|
|
7
|
+
handlers: {
|
|
8
|
+
POST: async ({ request }) => {
|
|
9
|
+
const formData = await request.formData()
|
|
10
|
+
const audioFile = formData.get('audio') as File | null
|
|
11
|
+
const audioBase64 = formData.get('audioBase64') as string | null
|
|
12
|
+
const model = (formData.get('model') as string) || 'whisper-1'
|
|
13
|
+
const language = formData.get('language') as string | null
|
|
14
|
+
const responseFormat = formData.get('responseFormat') as string | null
|
|
15
|
+
|
|
16
|
+
if (!audioFile && !audioBase64) {
|
|
17
|
+
return new Response(
|
|
18
|
+
JSON.stringify({
|
|
19
|
+
error: 'Audio file or base64 data is required',
|
|
20
|
+
}),
|
|
21
|
+
{
|
|
22
|
+
status: 400,
|
|
23
|
+
headers: { 'Content-Type': 'application/json' },
|
|
24
|
+
},
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!process.env.OPENAI_API_KEY) {
|
|
29
|
+
return new Response(
|
|
30
|
+
JSON.stringify({
|
|
31
|
+
error: 'OPENAI_API_KEY is not configured',
|
|
32
|
+
}),
|
|
33
|
+
{
|
|
34
|
+
status: 500,
|
|
35
|
+
headers: { 'Content-Type': 'application/json' },
|
|
36
|
+
},
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const adapter = openaiTranscription(model as any)
|
|
42
|
+
|
|
43
|
+
// Prepare audio data
|
|
44
|
+
let audioData: string | File
|
|
45
|
+
if (audioFile) {
|
|
46
|
+
audioData = audioFile
|
|
47
|
+
} else if (audioBase64) {
|
|
48
|
+
audioData = audioBase64
|
|
49
|
+
} else {
|
|
50
|
+
throw new Error('No audio data provided')
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const result = await generateTranscription({
|
|
54
|
+
adapter,
|
|
55
|
+
audio: audioData,
|
|
56
|
+
language: language || undefined,
|
|
57
|
+
responseFormat: (responseFormat as any) || 'verbose_json',
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
return new Response(
|
|
61
|
+
JSON.stringify({
|
|
62
|
+
id: result.id,
|
|
63
|
+
model: result.model,
|
|
64
|
+
text: result.text,
|
|
65
|
+
language: result.language,
|
|
66
|
+
duration: result.duration,
|
|
67
|
+
segments: result.segments,
|
|
68
|
+
words: result.words,
|
|
69
|
+
}),
|
|
70
|
+
{
|
|
71
|
+
status: 200,
|
|
72
|
+
headers: { 'Content-Type': 'application/json' },
|
|
73
|
+
},
|
|
74
|
+
)
|
|
75
|
+
} catch (error: any) {
|
|
76
|
+
return new Response(
|
|
77
|
+
JSON.stringify({
|
|
78
|
+
error: error.message || 'An error occurred',
|
|
79
|
+
}),
|
|
80
|
+
{
|
|
81
|
+
status: 500,
|
|
82
|
+
headers: { 'Content-Type': 'application/json' },
|
|
83
|
+
},
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
})
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createFileRoute } from '@tanstack/react-router'
|
|
2
|
+
import { generateSpeech } from '@tanstack/ai'
|
|
3
|
+
import { openaiSpeech } from '@tanstack/ai-openai'
|
|
4
|
+
|
|
5
|
+
export const Route = createFileRoute('/demo/api/ai/tts')({
|
|
6
|
+
server: {
|
|
7
|
+
handlers: {
|
|
8
|
+
POST: async ({ request }) => {
|
|
9
|
+
const body = await request.json()
|
|
10
|
+
const {
|
|
11
|
+
text,
|
|
12
|
+
voice = 'alloy',
|
|
13
|
+
model = 'tts-1',
|
|
14
|
+
format = 'mp3',
|
|
15
|
+
speed = 1.0,
|
|
16
|
+
} = body
|
|
17
|
+
|
|
18
|
+
if (!text || text.trim().length === 0) {
|
|
19
|
+
return new Response(
|
|
20
|
+
JSON.stringify({
|
|
21
|
+
error: 'Text is required',
|
|
22
|
+
}),
|
|
23
|
+
{
|
|
24
|
+
status: 400,
|
|
25
|
+
headers: { 'Content-Type': 'application/json' },
|
|
26
|
+
},
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!process.env.OPENAI_API_KEY) {
|
|
31
|
+
return new Response(
|
|
32
|
+
JSON.stringify({
|
|
33
|
+
error: 'OPENAI_API_KEY is not configured',
|
|
34
|
+
}),
|
|
35
|
+
{
|
|
36
|
+
status: 500,
|
|
37
|
+
headers: { 'Content-Type': 'application/json' },
|
|
38
|
+
},
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const adapter = openaiSpeech(model)
|
|
44
|
+
|
|
45
|
+
const result = await generateSpeech({
|
|
46
|
+
adapter,
|
|
47
|
+
text,
|
|
48
|
+
voice,
|
|
49
|
+
format,
|
|
50
|
+
speed,
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
return new Response(
|
|
54
|
+
JSON.stringify({
|
|
55
|
+
id: result.id,
|
|
56
|
+
model: result.model,
|
|
57
|
+
audio: result.audio,
|
|
58
|
+
format: result.format,
|
|
59
|
+
contentType: result.contentType,
|
|
60
|
+
duration: result.duration,
|
|
61
|
+
}),
|
|
62
|
+
{
|
|
63
|
+
status: 200,
|
|
64
|
+
headers: { 'Content-Type': 'application/json' },
|
|
65
|
+
},
|
|
66
|
+
)
|
|
67
|
+
} catch (error: any) {
|
|
68
|
+
return new Response(
|
|
69
|
+
JSON.stringify({
|
|
70
|
+
error: error.message || 'An error occurred',
|
|
71
|
+
}),
|
|
72
|
+
{
|
|
73
|
+
status: 500,
|
|
74
|
+
headers: { 'Content-Type': 'application/json' },
|
|
75
|
+
},
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createFileRoute } from '@tanstack/react-router'
|
|
2
|
+
import { auth } from '@/lib/auth'
|
|
3
|
+
|
|
4
|
+
export const Route = createFileRoute('/api/auth/$')({
|
|
5
|
+
server: {
|
|
6
|
+
handlers: {
|
|
7
|
+
GET: ({ request }) => auth.handler(request),
|
|
8
|
+
POST: ({ request }) => auth.handler(request),
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineSchema, defineTable } from 'convex/server'
|
|
2
|
+
import { v } from 'convex/values'
|
|
3
|
+
|
|
4
|
+
export default defineSchema({
|
|
5
|
+
products: defineTable({
|
|
6
|
+
title: v.string(),
|
|
7
|
+
imageId: v.string(),
|
|
8
|
+
price: v.number(),
|
|
9
|
+
}),
|
|
10
|
+
todos: defineTable({
|
|
11
|
+
text: v.string(),
|
|
12
|
+
completed: v.boolean(),
|
|
13
|
+
}),
|
|
14
|
+
})
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { mutation, query } from './_generated/server'
|
|
2
|
+
import { v } from 'convex/values'
|
|
3
|
+
|
|
4
|
+
export const list = query({
|
|
5
|
+
args: {},
|
|
6
|
+
handler: async (ctx) => {
|
|
7
|
+
return await ctx.db
|
|
8
|
+
.query('todos')
|
|
9
|
+
.withIndex('by_creation_time')
|
|
10
|
+
.order('desc')
|
|
11
|
+
.collect()
|
|
12
|
+
},
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
export const add = mutation({
|
|
16
|
+
args: { text: v.string() },
|
|
17
|
+
handler: async (ctx, args) => {
|
|
18
|
+
return await ctx.db.insert('todos', {
|
|
19
|
+
text: args.text,
|
|
20
|
+
completed: false,
|
|
21
|
+
})
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
export const toggle = mutation({
|
|
26
|
+
args: { id: v.id('todos') },
|
|
27
|
+
handler: async (ctx, args) => {
|
|
28
|
+
const todo = await ctx.db.get(args.id)
|
|
29
|
+
if (!todo) {
|
|
30
|
+
throw new Error('Todo not found')
|
|
31
|
+
}
|
|
32
|
+
return await ctx.db.patch(args.id, {
|
|
33
|
+
completed: !todo.completed,
|
|
34
|
+
})
|
|
35
|
+
},
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
export const remove = mutation({
|
|
39
|
+
args: { id: v.id('todos') },
|
|
40
|
+
handler: async (ctx, args) => {
|
|
41
|
+
return await ctx.db.delete(args.id)
|
|
42
|
+
},
|
|
43
|
+
})
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createCollection,
|
|
3
|
+
localOnlyCollectionOptions,
|
|
4
|
+
} from "@tanstack/react-db";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
const MessageSchema = z.object({
|
|
8
|
+
id: z.number(),
|
|
9
|
+
text: z.string(),
|
|
10
|
+
user: z.string(),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export type Message = z.infer<typeof MessageSchema>;
|
|
14
|
+
|
|
15
|
+
export const messagesCollection = createCollection(
|
|
16
|
+
localOnlyCollectionOptions({
|
|
17
|
+
getKey: (message) => message.id,
|
|
18
|
+
schema: MessageSchema,
|
|
19
|
+
})
|
|
20
|
+
);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react'
|
|
2
|
+
import { useLiveQuery } from '@tanstack/react-db'
|
|
3
|
+
|
|
4
|
+
import { messagesCollection, type Message } from '@/db-collections'
|
|
5
|
+
|
|
6
|
+
import type { Collection } from '@tanstack/react-db'
|
|
7
|
+
|
|
8
|
+
function useStreamConnection(
|
|
9
|
+
url: string,
|
|
10
|
+
collection: Collection<any, any, any>,
|
|
11
|
+
) {
|
|
12
|
+
const loadedRef = useRef(false)
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
const fetchData = async () => {
|
|
16
|
+
if (loadedRef.current) return
|
|
17
|
+
loadedRef.current = true
|
|
18
|
+
|
|
19
|
+
const response = await fetch(url)
|
|
20
|
+
const reader = response.body?.getReader()
|
|
21
|
+
if (!reader) {
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const decoder = new TextDecoder()
|
|
26
|
+
while (true) {
|
|
27
|
+
const { done, value } = await reader.read()
|
|
28
|
+
if (done) break
|
|
29
|
+
for (const chunk of decoder
|
|
30
|
+
.decode(value, { stream: true })
|
|
31
|
+
.split('\n')
|
|
32
|
+
.filter((chunk) => chunk.length > 0)) {
|
|
33
|
+
collection.insert(JSON.parse(chunk))
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
fetchData()
|
|
38
|
+
}, [])
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function useChat() {
|
|
42
|
+
useStreamConnection('/demo/db-chat-api', messagesCollection)
|
|
43
|
+
|
|
44
|
+
const sendMessage = (message: string, user: string) => {
|
|
45
|
+
fetch('/demo/db-chat-api', {
|
|
46
|
+
method: 'POST',
|
|
47
|
+
body: JSON.stringify({ text: message.trim(), user: user.trim() }),
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return { sendMessage }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function useMessages() {
|
|
55
|
+
const { data: messages } = useLiveQuery((q) =>
|
|
56
|
+
q.from({ message: messagesCollection }).select(({ message }) => ({
|
|
57
|
+
...message,
|
|
58
|
+
})),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
return messages as Message[]
|
|
62
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { createFileRoute } from '@tanstack/react-router'
|
|
2
|
+
import { json } from '@tanstack/react-start'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
createCollection,
|
|
6
|
+
localOnlyCollectionOptions,
|
|
7
|
+
} from '@tanstack/react-db'
|
|
8
|
+
import { z } from 'zod'
|
|
9
|
+
|
|
10
|
+
const IncomingMessageSchema = z.object({
|
|
11
|
+
user: z.string(),
|
|
12
|
+
text: z.string(),
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const MessageSchema = IncomingMessageSchema.extend({
|
|
16
|
+
id: z.number(),
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
export type Message = z.infer<typeof MessageSchema>
|
|
20
|
+
|
|
21
|
+
export const serverMessagesCollection = createCollection(
|
|
22
|
+
localOnlyCollectionOptions({
|
|
23
|
+
getKey: (message) => message.id,
|
|
24
|
+
schema: MessageSchema,
|
|
25
|
+
}),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
let id = 0
|
|
29
|
+
serverMessagesCollection.insert({
|
|
30
|
+
id: id++,
|
|
31
|
+
user: 'Alice',
|
|
32
|
+
text: 'Hello, how are you?',
|
|
33
|
+
})
|
|
34
|
+
serverMessagesCollection.insert({
|
|
35
|
+
id: id++,
|
|
36
|
+
user: 'Bob',
|
|
37
|
+
text: "I'm fine, thank you!",
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
const sendMessage = (message: { user: string; text: string }) => {
|
|
41
|
+
serverMessagesCollection.insert({
|
|
42
|
+
id: id++,
|
|
43
|
+
user: message.user,
|
|
44
|
+
text: message.text,
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const Route = createFileRoute('/demo/db-chat-api')({
|
|
49
|
+
server: {
|
|
50
|
+
handlers: {
|
|
51
|
+
GET: () => {
|
|
52
|
+
const stream = new ReadableStream({
|
|
53
|
+
start(controller) {
|
|
54
|
+
for (const [_id, message] of serverMessagesCollection.state) {
|
|
55
|
+
controller.enqueue(JSON.stringify(message) + '\n')
|
|
56
|
+
}
|
|
57
|
+
serverMessagesCollection.subscribeChanges((changes) => {
|
|
58
|
+
for (const change of changes) {
|
|
59
|
+
if (change.type === 'insert') {
|
|
60
|
+
controller.enqueue(JSON.stringify(change.value) + '\n')
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
},
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
return new Response(stream, {
|
|
68
|
+
headers: {
|
|
69
|
+
'Content-Type': 'application/x-ndjson',
|
|
70
|
+
},
|
|
71
|
+
})
|
|
72
|
+
},
|
|
73
|
+
POST: async ({ request }) => {
|
|
74
|
+
const message = IncomingMessageSchema.safeParse(await request.json())
|
|
75
|
+
if (!message.success) {
|
|
76
|
+
return new Response(message.error.message, { status: 400 })
|
|
77
|
+
}
|
|
78
|
+
sendMessage(message.data)
|
|
79
|
+
return json(message.data)
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
})
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createFormHook } from '@tanstack/react-form'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Select,
|
|
5
|
+
SubscribeButton,
|
|
6
|
+
TextArea,
|
|
7
|
+
TextField,
|
|
8
|
+
} from '../components/demo.FormComponents'
|
|
9
|
+
import { fieldContext, formContext } from './demo.form-context'
|
|
10
|
+
|
|
11
|
+
export const { useAppForm } = createFormHook({
|
|
12
|
+
fieldComponents: {
|
|
13
|
+
TextField,
|
|
14
|
+
Select,
|
|
15
|
+
TextArea,
|
|
16
|
+
},
|
|
17
|
+
formComponents: {
|
|
18
|
+
SubscribeButton,
|
|
19
|
+
},
|
|
20
|
+
fieldContext,
|
|
21
|
+
formContext,
|
|
22
|
+
})
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
|
|
3
|
+
const todosPath = './mcp-todos.json'
|
|
4
|
+
|
|
5
|
+
// In-memory todos storage
|
|
6
|
+
const todos = fs.existsSync(todosPath)
|
|
7
|
+
? JSON.parse(fs.readFileSync(todosPath, 'utf8'))
|
|
8
|
+
: [
|
|
9
|
+
{
|
|
10
|
+
id: 1,
|
|
11
|
+
title: 'Buy groceries',
|
|
12
|
+
},
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
// Subscription callbacks per userID
|
|
16
|
+
let subscribers: ((todos: Todo[]) => void)[] = []
|
|
17
|
+
|
|
18
|
+
export type Todo = {
|
|
19
|
+
id: number
|
|
20
|
+
title: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Get the todos for a user
|
|
24
|
+
export function getTodos(): Todo[] {
|
|
25
|
+
return todos
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Add an item to the todos
|
|
29
|
+
export function addTodo(title: string) {
|
|
30
|
+
todos.push({ id: todos.length + 1, title })
|
|
31
|
+
fs.writeFileSync(todosPath, JSON.stringify(todos, null, 2))
|
|
32
|
+
notifySubscribers()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Subscribe to cart changes for a user
|
|
36
|
+
export function subscribeToTodos(callback: (todos: Todo[]) => void) {
|
|
37
|
+
subscribers.push(callback)
|
|
38
|
+
callback(todos)
|
|
39
|
+
return () => {
|
|
40
|
+
subscribers = subscribers.filter((cb) => cb !== callback)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Notify all subscribers of a user's cart
|
|
45
|
+
function notifySubscribers() {
|
|
46
|
+
for (const cb of subscribers) {
|
|
47
|
+
try {
|
|
48
|
+
cb(todos)
|
|
49
|
+
} catch {}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { createFileRoute } from '@tanstack/react-router'
|
|
2
|
+
|
|
3
|
+
import { addTodo, getTodos, subscribeToTodos } from '@/mcp-todos'
|
|
4
|
+
|
|
5
|
+
export const Route = createFileRoute('/api/mcp-todos')({
|
|
6
|
+
server: {
|
|
7
|
+
handlers: {
|
|
8
|
+
GET: () => {
|
|
9
|
+
const stream = new ReadableStream({
|
|
10
|
+
start(controller) {
|
|
11
|
+
function ping() {
|
|
12
|
+
try {
|
|
13
|
+
controller.enqueue(`event: ping\n\n`)
|
|
14
|
+
setTimeout(ping, 1000)
|
|
15
|
+
} catch {}
|
|
16
|
+
}
|
|
17
|
+
ping()
|
|
18
|
+
const unsubscribe = subscribeToTodos((todos) => {
|
|
19
|
+
controller.enqueue(`data: ${JSON.stringify(todos)}\n\n`)
|
|
20
|
+
})
|
|
21
|
+
const todos = getTodos()
|
|
22
|
+
controller.enqueue(`data: ${JSON.stringify(todos)}\n\n`)
|
|
23
|
+
return () => unsubscribe()
|
|
24
|
+
},
|
|
25
|
+
})
|
|
26
|
+
return new Response(stream, {
|
|
27
|
+
headers: { 'Content-Type': 'text/event-stream' },
|
|
28
|
+
})
|
|
29
|
+
},
|
|
30
|
+
POST: async ({ request }) => {
|
|
31
|
+
const { title } = await request.json()
|
|
32
|
+
addTodo(title)
|
|
33
|
+
return Response.json(getTodos())
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
})
|
|
@@ -1,21 +1,30 @@
|
|
|
1
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
2
|
-
import { createFileRoute } from '@tanstack/react-router'
|
|
3
|
-
import z from 'zod'
|
|
4
|
-
|
|
5
|
-
import {
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
2
|
+
import { createFileRoute } from '@tanstack/react-router'
|
|
3
|
+
import z from 'zod'
|
|
4
|
+
|
|
5
|
+
import { handleMcpRequest } from '@/utils/mcp-handler'
|
|
6
|
+
|
|
7
|
+
import { addTodo } from '@/mcp-todos'
|
|
8
|
+
|
|
6
9
|
const server = new McpServer({
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
})
|
|
10
|
-
|
|
10
|
+
name: 'start-server',
|
|
11
|
+
version: '1.0.0',
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
server.registerTool(
|
|
15
|
+
'addTodo',
|
|
16
|
+
{
|
|
11
17
|
title: 'Tool to add a todo to a list of todos',
|
|
12
18
|
description: 'Add a todo to a list of todos',
|
|
13
19
|
inputSchema: {
|
|
14
|
-
|
|
20
|
+
title: z.string().describe('The title of the todo'),
|
|
15
21
|
},
|
|
16
|
-
},
|
|
22
|
+
},
|
|
23
|
+
({ title }) => ({
|
|
17
24
|
content: [{ type: 'text', text: String(addTodo(title)) }],
|
|
18
|
-
})
|
|
25
|
+
}),
|
|
26
|
+
)
|
|
27
|
+
|
|
19
28
|
// server.registerResource(
|
|
20
29
|
// "counter-value",
|
|
21
30
|
// "count://",
|
|
@@ -34,10 +43,11 @@ server.registerTool('addTodo', {
|
|
|
34
43
|
// };
|
|
35
44
|
// }
|
|
36
45
|
// );
|
|
46
|
+
|
|
37
47
|
export const Route = createFileRoute('/mcp')({
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
},
|
|
48
|
+
server: {
|
|
49
|
+
handlers: {
|
|
50
|
+
POST: async ({ request }) => handleMcpRequest(request, server),
|
|
42
51
|
},
|
|
43
|
-
}
|
|
52
|
+
},
|
|
53
|
+
})
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js'
|
|
2
|
+
|
|
3
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
4
|
+
import type { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js'
|
|
5
|
+
|
|
6
|
+
export async function handleMcpRequest(
|
|
7
|
+
request: Request,
|
|
8
|
+
server: McpServer,
|
|
9
|
+
): Promise<Response> {
|
|
10
|
+
try {
|
|
11
|
+
const jsonRpcRequest = (await request.json()) as JSONRPCMessage
|
|
12
|
+
|
|
13
|
+
const [clientTransport, serverTransport] =
|
|
14
|
+
InMemoryTransport.createLinkedPair()
|
|
15
|
+
|
|
16
|
+
let responseData: JSONRPCMessage | null = null
|
|
17
|
+
|
|
18
|
+
clientTransport.onmessage = (message: JSONRPCMessage) => {
|
|
19
|
+
responseData = message
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
await server.connect(serverTransport)
|
|
23
|
+
|
|
24
|
+
await clientTransport.start()
|
|
25
|
+
await serverTransport.start()
|
|
26
|
+
|
|
27
|
+
await clientTransport.send(jsonRpcRequest)
|
|
28
|
+
|
|
29
|
+
await new Promise((resolve) => setTimeout(resolve, 10))
|
|
30
|
+
|
|
31
|
+
await clientTransport.close()
|
|
32
|
+
await serverTransport.close()
|
|
33
|
+
|
|
34
|
+
return Response.json(responseData, {
|
|
35
|
+
headers: {
|
|
36
|
+
'Content-Type': 'application/json',
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error('MCP handler error:', error)
|
|
41
|
+
|
|
42
|
+
// Return a JSON-RPC error response
|
|
43
|
+
return Response.json(
|
|
44
|
+
{
|
|
45
|
+
jsonrpc: '2.0',
|
|
46
|
+
error: {
|
|
47
|
+
code: -32603,
|
|
48
|
+
message: 'Internal server error',
|
|
49
|
+
data: error instanceof Error ? error.message : String(error),
|
|
50
|
+
},
|
|
51
|
+
id: null,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
status: 500,
|
|
55
|
+
headers: {
|
|
56
|
+
'Content-Type': 'application/json',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { neon } from '@neondatabase/serverless'
|
|
2
|
+
|
|
3
|
+
let client: ReturnType<typeof neon>
|
|
4
|
+
|
|
5
|
+
export async function getClient() {
|
|
6
|
+
if (!process.env.VITE_DATABASE_URL) {
|
|
7
|
+
return undefined
|
|
8
|
+
}
|
|
9
|
+
if (!client) {
|
|
10
|
+
client = await neon(process.env.VITE_DATABASE_URL!)
|
|
11
|
+
}
|
|
12
|
+
return client
|
|
13
|
+
}
|