basic route-specific trpc file example

master
Avraham Sakal 4 months ago
parent 602ba72f75
commit 5ef118e9bc

@ -15,12 +15,6 @@
"indentStyle": "space" "indentStyle": "space"
}, },
"files": { "files": {
"ignore": [ "ignore": ["dist/**", "*.js", "*.cjs", "*.mjs", "*.spec.ts"]
"dist/**",
"*.js",
"*.cjs",
"*.mjs",
"*.spec.ts"
]
} }
} }

@ -39,6 +39,7 @@ export default function LayoutDefault({
<Link href="/" label="Welcome" /> <Link href="/" label="Welcome" />
<Link href="/todo" label="Todo" /> <Link href="/todo" label="Todo" />
<Link href="/star-wars" label="Data Fetching" /> <Link href="/star-wars" label="Data Fetching" />
<Link href="/chat" label="Chat" />
</AppShell.Navbar> </AppShell.Navbar>
<AppShell.Main> {children} </AppShell.Main> <AppShell.Main> {children} </AppShell.Main>
</AppShell> </AppShell>

@ -10,38 +10,42 @@
"deploy": "run-s build deploy:wrangler" "deploy": "run-s build deploy:wrangler"
}, },
"dependencies": { "dependencies": {
"vike": "^0.4.235", "@ai-sdk/openai": "2.0.0-beta.2",
"@ai-sdk/react": "2.0.0-beta.3",
"@auth/core": "^0.40.0", "@auth/core": "^0.40.0",
"@universal-middleware/core": "^0.4.8",
"@compiled/react": "^0.18.6", "@compiled/react": "^0.18.6",
"@hono/node-server": "^1.14.4", "@hono/node-server": "^1.14.4",
"@mantine/core": "^8.1.1",
"@mantine/hooks": "^8.1.1",
"@sinclair/typebox": "^0.34.37",
"@trpc/client": "^11.4.2",
"@trpc/server": "^11.4.2",
"@universal-middleware/core": "^0.4.8",
"@universal-middleware/hono": "^0.4.14", "@universal-middleware/hono": "^0.4.14",
"hono": "^4.8.2",
"@vitejs/plugin-react": "^4.6.0", "@vitejs/plugin-react": "^4.6.0",
"ai": "5.0.0-beta.3",
"hono": "^4.8.2",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"vike-react": "^0.6.4", "vike": "^0.4.235",
"@trpc/server": "^11.4.2",
"@trpc/client": "^11.4.2",
"vike-cloudflare": "^0.1.7", "vike-cloudflare": "^0.1.7",
"@mantine/core": "^8.1.1", "vike-react": "^0.6.4"
"@mantine/hooks": "^8.1.1"
}, },
"devDependencies": { "devDependencies": {
"typescript": "^5.8.3",
"vite": "^6.3.5",
"@biomejs/biome": "1.9.4", "@biomejs/biome": "1.9.4",
"vite-plugin-compiled-react": "^1.3.1", "@cloudflare/workers-types": "^4.20250620.0",
"@hono/vite-dev-server": "^0.19.1", "@hono/vite-dev-server": "^0.19.1",
"@types/node": "^20.19.0", "@types/node": "^20.19.0",
"@types/react": "^19.1.8", "@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6", "@types/react-dom": "^19.1.6",
"@cloudflare/workers-types": "^4.20250620.0",
"wrangler": "^4.20.5",
"npm-run-all2": "^8.0.4", "npm-run-all2": "^8.0.4",
"postcss": "^8.5.6", "postcss": "^8.5.6",
"postcss-preset-mantine": "^1.17.0", "postcss-preset-mantine": "^1.17.0",
"postcss-simple-vars": "^7.0.1" "postcss-simple-vars": "^7.0.1",
"typescript": "^5.8.3",
"vite": "^6.3.5",
"vite-plugin-compiled-react": "^1.3.1",
"wrangler": "^4.20.5"
}, },
"type": "module" "type": "module"
} }

@ -0,0 +1,55 @@
import { JsonInput, Tabs, Textarea } from "@mantine/core";
import { useState } from "react";
const defaultSystemPrompt = `You are a helpful assistant that answers questions based on the provided context. If you don't know the answer, just say that you don't know, don't try to make up an answer.`;
const defaultParameters = {
temperature: 0.5,
max_tokens: 100,
};
export default function ChatPage() {
const [prompt, setPrompt] = useState("");
const [systemPrompt, setSystemPrompt] = useState(defaultSystemPrompt);
const [parameters, setParameters] = useState(defaultParameters);
return (
<Tabs defaultValue="prompt">
<Tabs.List>
<Tabs.Tab value="prompt">Prompt</Tabs.Tab>
<Tabs.Tab value="system-prompt">System Prompt</Tabs.Tab>
<Tabs.Tab value="parameters">Parameters</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="prompt">
<Textarea
resize="vertical"
placeholder="Type your message here..."
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
console.log("Sending message...");
}
}}
/>
</Tabs.Panel>
<Tabs.Panel value="system-prompt">
<Textarea
resize="vertical"
placeholder={defaultSystemPrompt}
value={systemPrompt}
onChange={(e) => setSystemPrompt(e.target.value)}
/>
</Tabs.Panel>
<Tabs.Panel value="parameters">
<JsonInput
resize="vertical"
formatOnBlur
placeholder={JSON.stringify(defaultParameters)}
value={JSON.stringify(parameters)}
onChange={(value) => setParameters(JSON.parse(value))}
/>
</Tabs.Panel>
</Tabs>
);
}

@ -0,0 +1,22 @@
import { router, publicProcedure, Validator } from "../../trpc/server";
import { Type as T } from "@sinclair/typebox";
export const chat = router({
sendMessage: publicProcedure
.input(
Validator(
T.Object({
prompt: T.String(),
systemPrompt: T.String(),
parameters: T.Object({
temperature: T.Number(),
max_tokens: T.Number(),
}),
}),
),
)
.mutation(async ({ input: { prompt, systemPrompt, parameters } }) => {
console.log("Received new todo", { prompt, systemPrompt, parameters });
return { prompt, systemPrompt, parameters };
}),
});

@ -8,6 +8,12 @@ importers:
.: .:
dependencies: dependencies:
'@ai-sdk/openai':
specifier: 2.0.0-beta.2
version: 2.0.0-beta.2(zod@3.22.3)
'@ai-sdk/react':
specifier: 2.0.0-beta.3
version: 2.0.0-beta.3(react@19.1.0)(zod@3.22.3)
'@auth/core': '@auth/core':
specifier: ^0.40.0 specifier: ^0.40.0
version: 0.40.0 version: 0.40.0
@ -23,6 +29,9 @@ importers:
'@mantine/hooks': '@mantine/hooks':
specifier: ^8.1.1 specifier: ^8.1.1
version: 8.1.2(react@19.1.0) version: 8.1.2(react@19.1.0)
'@sinclair/typebox':
specifier: ^0.34.37
version: 0.34.37
'@trpc/client': '@trpc/client':
specifier: ^11.4.2 specifier: ^11.4.2
version: 11.4.2(@trpc/server@11.4.2(typescript@5.8.3))(typescript@5.8.3) version: 11.4.2(@trpc/server@11.4.2(typescript@5.8.3))(typescript@5.8.3)
@ -38,6 +47,9 @@ importers:
'@vitejs/plugin-react': '@vitejs/plugin-react':
specifier: ^4.6.0 specifier: ^4.6.0
version: 4.6.0(vite@6.3.5(@types/node@20.19.1)(sugarss@4.0.1(postcss@8.5.6))) version: 4.6.0(vite@6.3.5(@types/node@20.19.1)(sugarss@4.0.1(postcss@8.5.6)))
ai:
specifier: 5.0.0-beta.3
version: 5.0.0-beta.3(zod@3.22.3)
hono: hono:
specifier: ^4.8.2 specifier: ^4.8.2
version: 4.8.3 version: 4.8.3
@ -102,6 +114,38 @@ importers:
packages: packages:
'@ai-sdk/gateway@1.0.0-beta.3':
resolution: {integrity: sha512-g49gMSkXy94lYvl5LRh438OR/0JCG6ol0jV+iLot7cy5HLltZlGocEuauETBu4b10mDXOd7XIjTEZoQpYFMYLQ==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.25.49
'@ai-sdk/openai@2.0.0-beta.2':
resolution: {integrity: sha512-TQ6Bp3KLrZgofk155+jBvhHMmi+/0B7XAlNTn3OByKGfUk7CQB0mTldCcQEqj8Z9CyKYEvmmztcya30bIysCtw==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.25.49
'@ai-sdk/provider-utils@3.0.0-beta.2':
resolution: {integrity: sha512-H4K+4weOVgWqrDDeAbQWoA4U5mN4WrQPHQFdH7ynQYcnhj/pzctU9Q6mGlR5ESMWxaXxazxlOblSITlXo9bahA==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.25.49
'@ai-sdk/provider@2.0.0-beta.1':
resolution: {integrity: sha512-Z8SPncMtS3RsoXITmT7NVwrAq6M44dmw0DoUOYJqNNtCu8iMWuxB8Nxsoqpa0uEEy9R1V1ZThJAXTYgjTUxl3w==}
engines: {node: '>=18'}
'@ai-sdk/react@2.0.0-beta.3':
resolution: {integrity: sha512-Ea2hjDAS3eyoihG9LM0hEcb0XX/ACqKwV0hEI0vytRymczlTu/nmso8TrnuQ/QFCBf3RBjpnzwyz7sAECOREiw==}
engines: {node: '>=18'}
peerDependencies:
react: ^18 || ^19 || ^19.0.0-rc
zod: ^3.25.49
peerDependenciesMeta:
zod:
optional: true
'@ampproject/remapping@2.3.0': '@ampproject/remapping@2.3.0':
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
@ -869,6 +913,10 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
'@opentelemetry/api@1.9.0':
resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
engines: {node: '>=8.0.0'}
'@panva/hkdf@1.2.1': '@panva/hkdf@1.2.1':
resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==} resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==}
@ -978,6 +1026,12 @@ packages:
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
'@sinclair/typebox@0.34.37':
resolution: {integrity: sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==}
'@standard-schema/spec@1.0.0':
resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==}
'@trpc/client@11.4.2': '@trpc/client@11.4.2':
resolution: {integrity: sha512-Eep1rorAsATs9bxgaXf+BV34CRs4lAKQmwumUL4CNdNDkJItyfuWUr3xWx0np1w3EzUDVA0YDMK93iKDBBA0KQ==} resolution: {integrity: sha512-Eep1rorAsATs9bxgaXf+BV34CRs4lAKQmwumUL4CNdNDkJItyfuWUr3xWx0np1w3EzUDVA0YDMK93iKDBBA0KQ==}
peerDependencies: peerDependencies:
@ -1068,6 +1122,12 @@ packages:
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
hasBin: true hasBin: true
ai@5.0.0-beta.3:
resolution: {integrity: sha512-D0Dr+AapfMG4uszw+tBj7FdnEfM5JzffWpmJoFXHbUW+MPQwNG+rWFD6UyruY/veyqz9Xzr1U7JMwnXwctXeMg==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.25.49
ansi-styles@6.2.1: ansi-styles@6.2.1:
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -1215,6 +1275,10 @@ packages:
defu@6.1.4: defu@6.1.4:
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
dequal@2.0.3:
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
engines: {node: '>=6'}
detect-libc@2.0.4: detect-libc@2.0.4:
resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -1258,6 +1322,10 @@ packages:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'} engines: {node: '>=6'}
eventsource-parser@3.0.3:
resolution: {integrity: sha512-nVpZkTMM9rF6AQ9gPJpFsNAMt48wIzB5TQgiTLdHiuO8XEDhUgZEhqKlZWXbIzo9VmJ/HvysHqEaVeD5v9TPvA==}
engines: {node: '>=20.0.0'}
exit-hook@2.2.1: exit-hook@2.2.1:
resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -1388,6 +1456,9 @@ packages:
resolution: {integrity: sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==} resolution: {integrity: sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==}
engines: {node: ^18.17.0 || >=20.5.0} engines: {node: ^18.17.0 || >=20.5.0}
json-schema@0.4.0:
resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
json5@2.2.3: json5@2.2.3:
resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -1958,9 +2029,18 @@ packages:
engines: {node: '>=10.13.0'} engines: {node: '>=10.13.0'}
hasBin: true hasBin: true
swr@2.3.3:
resolution: {integrity: sha512-dshNvs3ExOqtZ6kJBaAsabhPdHyeY4P2cKwRCniDVifBMoG/SVI7tfLWqPXriVspf2Rg4tPzXJTnwaihIeFw2A==}
peerDependencies:
react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
tabbable@6.2.0: tabbable@6.2.0:
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
throttleit@2.1.0:
resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==}
engines: {node: '>=18'}
tinyglobby@0.2.14: tinyglobby@0.2.14:
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
engines: {node: '>=12.0.0'} engines: {node: '>=12.0.0'}
@ -2062,6 +2142,11 @@ packages:
'@types/react': '@types/react':
optional: true optional: true
use-sync-external-store@1.5.0:
resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
util-deprecate@1.0.2: util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
@ -2181,11 +2266,50 @@ packages:
youch@3.3.4: youch@3.3.4:
resolution: {integrity: sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==} resolution: {integrity: sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==}
zod-to-json-schema@3.24.6:
resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==}
peerDependencies:
zod: ^3.24.1
zod@3.22.3: zod@3.22.3:
resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==} resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==}
snapshots: snapshots:
'@ai-sdk/gateway@1.0.0-beta.3(zod@3.22.3)':
dependencies:
'@ai-sdk/provider': 2.0.0-beta.1
'@ai-sdk/provider-utils': 3.0.0-beta.2(zod@3.22.3)
zod: 3.22.3
'@ai-sdk/openai@2.0.0-beta.2(zod@3.22.3)':
dependencies:
'@ai-sdk/provider': 2.0.0-beta.1
'@ai-sdk/provider-utils': 3.0.0-beta.2(zod@3.22.3)
zod: 3.22.3
'@ai-sdk/provider-utils@3.0.0-beta.2(zod@3.22.3)':
dependencies:
'@ai-sdk/provider': 2.0.0-beta.1
'@standard-schema/spec': 1.0.0
eventsource-parser: 3.0.3
zod: 3.22.3
zod-to-json-schema: 3.24.6(zod@3.22.3)
'@ai-sdk/provider@2.0.0-beta.1':
dependencies:
json-schema: 0.4.0
'@ai-sdk/react@2.0.0-beta.3(react@19.1.0)(zod@3.22.3)':
dependencies:
'@ai-sdk/provider-utils': 3.0.0-beta.2(zod@3.22.3)
ai: 5.0.0-beta.3(zod@3.22.3)
react: 19.1.0
swr: 2.3.3(react@19.1.0)
throttleit: 2.1.0
optionalDependencies:
zod: 3.22.3
'@ampproject/remapping@2.3.0': '@ampproject/remapping@2.3.0':
dependencies: dependencies:
'@jridgewell/gen-mapping': 0.3.8 '@jridgewell/gen-mapping': 0.3.8
@ -2801,6 +2925,8 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5 '@nodelib/fs.scandir': 2.1.5
fastq: 1.19.1 fastq: 1.19.1
'@opentelemetry/api@1.9.0': {}
'@panva/hkdf@1.2.1': {} '@panva/hkdf@1.2.1': {}
'@polka/url@1.0.0-next.29': {} '@polka/url@1.0.0-next.29': {}
@ -2867,6 +2993,10 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.44.1': '@rollup/rollup-win32-x64-msvc@4.44.1':
optional: true optional: true
'@sinclair/typebox@0.34.37': {}
'@standard-schema/spec@1.0.0': {}
'@trpc/client@11.4.2(@trpc/server@11.4.2(typescript@5.8.3))(typescript@5.8.3)': '@trpc/client@11.4.2(@trpc/server@11.4.2(typescript@5.8.3))(typescript@5.8.3)':
dependencies: dependencies:
'@trpc/server': 11.4.2(typescript@5.8.3) '@trpc/server': 11.4.2(typescript@5.8.3)
@ -2952,6 +3082,14 @@ snapshots:
acorn@8.15.0: {} acorn@8.15.0: {}
ai@5.0.0-beta.3(zod@3.22.3):
dependencies:
'@ai-sdk/gateway': 1.0.0-beta.3(zod@3.22.3)
'@ai-sdk/provider': 2.0.0-beta.1
'@ai-sdk/provider-utils': 3.0.0-beta.2(zod@3.22.3)
'@opentelemetry/api': 1.9.0
zod: 3.22.3
ansi-styles@6.2.1: {} ansi-styles@6.2.1: {}
as-table@1.0.55: as-table@1.0.55:
@ -3116,6 +3254,8 @@ snapshots:
defu@6.1.4: {} defu@6.1.4: {}
dequal@2.0.3: {}
detect-libc@2.0.4: {} detect-libc@2.0.4: {}
detect-node-es@1.1.0: {} detect-node-es@1.1.0: {}
@ -3202,6 +3342,8 @@ snapshots:
escalade@3.2.0: {} escalade@3.2.0: {}
eventsource-parser@3.0.3: {}
exit-hook@2.2.1: {} exit-hook@2.2.1: {}
exsolve@1.0.7: {} exsolve@1.0.7: {}
@ -3303,6 +3445,8 @@ snapshots:
json-parse-even-better-errors@4.0.0: {} json-parse-even-better-errors@4.0.0: {}
json-schema@0.4.0: {}
json5@2.2.3: {} json5@2.2.3: {}
locate-path@3.0.0: locate-path@3.0.0:
@ -3854,8 +3998,16 @@ snapshots:
picocolors: 1.1.1 picocolors: 1.1.1
stable: 0.1.8 stable: 0.1.8
swr@2.3.3(react@19.1.0):
dependencies:
dequal: 2.0.3
react: 19.1.0
use-sync-external-store: 1.5.0(react@19.1.0)
tabbable@6.2.0: {} tabbable@6.2.0: {}
throttleit@2.1.0: {}
tinyglobby@0.2.14: tinyglobby@0.2.14:
dependencies: dependencies:
fdir: 6.4.6(picomatch@4.0.2) fdir: 6.4.6(picomatch@4.0.2)
@ -3939,6 +4091,10 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/react': 19.1.8 '@types/react': 19.1.8
use-sync-external-store@1.5.0(react@19.1.0):
dependencies:
react: 19.1.0
util-deprecate@1.0.2: {} util-deprecate@1.0.2: {}
vike-cloudflare@0.1.7(vike@0.4.235(react-streaming@0.4.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@6.3.5(@types/node@20.19.1)(sugarss@4.0.1(postcss@8.5.6))))(vite@6.3.5(@types/node@20.19.1)(sugarss@4.0.1(postcss@8.5.6))): vike-cloudflare@0.1.7(vike@0.4.235(react-streaming@0.4.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@6.3.5(@types/node@20.19.1)(sugarss@4.0.1(postcss@8.5.6))))(vite@6.3.5(@types/node@20.19.1)(sugarss@4.0.1(postcss@8.5.6))):
@ -4045,4 +4201,8 @@ snapshots:
mustache: 4.2.0 mustache: 4.2.0
stacktracey: 2.1.8 stacktracey: 2.1.8
zod-to-json-schema@3.24.6(zod@3.22.3):
dependencies:
zod: 3.22.3
zod@3.22.3: {} zod@3.22.3: {}

@ -1,4 +1,4 @@
import { appRouter } from "../trpc/server"; import { appRouter } from "../trpc/router";
// TODO: stop using universal-middleware and directly integrate server middlewares instead and/or use vike-server https://vike.dev/server. (Bati generates boilerplates that use universal-middleware https://github.com/magne4000/universal-middleware to make Bati's internal logic easier. This is temporary and will be removed soon.) // TODO: stop using universal-middleware and directly integrate server middlewares instead and/or use vike-server https://vike.dev/server. (Bati generates boilerplates that use universal-middleware https://github.com/magne4000/universal-middleware to make Bati's internal logic easier. This is temporary and will be removed soon.)
import type { Get, UniversalHandler } from "@universal-middleware/core"; import type { Get, UniversalHandler } from "@universal-middleware/core";
import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; import { fetchRequestHandler } from "@trpc/server/adapters/fetch";

@ -1,5 +1,5 @@
import { createTRPCProxyClient, httpBatchLink } from "@trpc/client"; import { createTRPCProxyClient, httpBatchLink } from "@trpc/client";
import type { AppRouter } from "./server.js"; import type { AppRouter } from "./router.js";
export const trpc = createTRPCProxyClient<AppRouter>({ export const trpc = createTRPCProxyClient<AppRouter>({
links: [ links: [

@ -0,0 +1,23 @@
import { router, publicProcedure } from "../trpc/server";
import { todos } from "../database/todoItems";
import { chat } from "../pages/chat/trpc";
export const appRouter = router({
demo: publicProcedure.query(async () => {
return { demo: true };
}),
onNewTodo: publicProcedure
.input((value): string => {
if (typeof value === "string") {
return value;
}
throw new Error("Input is not a string");
})
.mutation(async (opts) => {
console.log("Received new todo", { text: opts.input });
todos.push({ text: opts.input });
}),
chat,
});
export type AppRouter = typeof appRouter;

@ -1,5 +1,6 @@
import { initTRPC } from "@trpc/server"; import type { TSchema } from "@sinclair/typebox";
import { todos } from "../database/todoItems"; import { TypeCompiler } from "@sinclair/typebox/compiler";
import { initTRPC, TRPCError } from "@trpc/server";
/** /**
* Initialization of tRPC backend * Initialization of tRPC backend
@ -14,21 +15,20 @@ const t = initTRPC.context<object>().create();
export const router = t.router; export const router = t.router;
export const publicProcedure = t.procedure; export const publicProcedure = t.procedure;
export const appRouter = router({ /**
demo: publicProcedure.query(async () => { * Generate a TRPC-compatible validator function given a Typebox schema.
return { demo: true }; * This was copied from [https://github.com/sinclairzx81/typebox/blob/6cfcdc02cc813af2f1be57407c771fc4fadfc34a/example/trpc/readme.md].
}), * @param schema A Typebox schema
onNewTodo: publicProcedure * @returns A TRPC-compatible validator function
.input((value): string => { */
if (typeof value === "string") { export function Validator<T extends TSchema>(schema: T) {
return value; const check = TypeCompiler.Compile(schema);
} return (value: unknown) => {
throw new Error("Input is not a string"); if (check.Check(value)) return value;
}) const err = check.Errors(value).First();
.mutation(async (opts) => { throw new TRPCError({
console.log("Received new todo", { text: opts.input }); message: `${err?.message} for ${err?.path}`,
todos.push({ text: opts.input }); code: "BAD_REQUEST",
}),
}); });
};
export type AppRouter = typeof appRouter; }

Loading…
Cancel
Save