├── .npmrc ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ └── publish-and-deploy.yml ├── docs ├── .prettierignore ├── static │ ├── googlea3479269b2f388cf.html │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── mstile-150x150.png │ ├── trpc-sveltekit.png │ ├── apple-touch-icon.png │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── browserconfig.xml │ └── safari-pinned-tab.svg ├── src │ ├── lib │ │ ├── menuStore.ts │ │ ├── components │ │ │ ├── home │ │ │ │ ├── LogoVercel.svelte │ │ │ │ ├── SupportedAdapter.svelte │ │ │ │ ├── Mantra.svelte │ │ │ │ ├── SupportedAdapters.svelte │ │ │ │ ├── CallsToAction.svelte │ │ │ │ ├── LogoSvelte.svelte │ │ │ │ ├── LogoTrpc.svelte │ │ │ │ ├── LogoNetlify.svelte │ │ │ │ ├── LogoNode.svelte │ │ │ │ └── LogosBlend.svelte │ │ │ ├── Info.svelte │ │ │ ├── layout │ │ │ │ ├── MenuLink.svelte │ │ │ │ ├── DarkModeSwitcher.svelte │ │ │ │ ├── PageNavigation.svelte │ │ │ │ ├── Footer.svelte │ │ │ │ ├── Menu.svelte │ │ │ │ └── Header.svelte │ │ │ └── Logo.svelte │ │ ├── useMediaQuery.ts │ │ ├── icons │ │ │ ├── IconCheck.svelte │ │ │ ├── IconWebSocket.svelte │ │ │ ├── IconMenu.svelte │ │ │ ├── IconMoon.svelte │ │ │ ├── IconFolder.svelte │ │ │ ├── IconLock.svelte │ │ │ ├── IconArrowLeft.svelte │ │ │ ├── IconArrowRight.svelte │ │ │ ├── IconInfoCircle.svelte │ │ │ ├── IconClipboard.svelte │ │ │ ├── IconErrorHandling.svelte │ │ │ ├── IconHome.svelte │ │ │ ├── IconBulb.svelte │ │ │ ├── IconFileCode.svelte │ │ │ ├── IconRocket.svelte │ │ │ ├── IconFileDatabase.svelte │ │ │ ├── IconSpeakerphone.svelte │ │ │ ├── IconLifeBuoy.svelte │ │ │ ├── IconHeartHandshake.svelte │ │ │ ├── IconTools.svelte │ │ │ ├── IconGitHub.svelte │ │ │ └── IconSun.svelte │ │ ├── loadCodeBlocks.ts │ │ └── constants.ts │ ├── routes │ │ ├── +layout.server.ts │ │ ├── suggested-structure │ │ │ ├── +page.server.ts │ │ │ └── +page.svelte │ │ ├── handling-errors │ │ │ ├── +page.server.ts │ │ │ └── +page.svelte │ │ ├── page-data │ │ │ ├── +page.server.ts │ │ │ └── +page.svelte │ │ ├── page-server-data │ │ │ ├── +page.server.ts │ │ │ └── +page.svelte │ │ ├── robots.txt │ │ │ └── +server.ts │ │ ├── recipes-and-caveats │ │ │ ├── +page.server.ts │ │ │ └── +page.svelte │ │ ├── authentication │ │ │ ├── +page.server.ts │ │ │ └── +page.svelte │ │ ├── using-with-svelte-query │ │ │ └── +page.svelte │ │ ├── +page.svelte │ │ ├── getting-started │ │ │ ├── +page.server.ts │ │ │ └── +page.svelte │ │ ├── acknowledgements │ │ │ └── +page.svelte │ │ ├── experimental-websocket-support │ │ │ └── +page.svelte │ │ ├── site.webmanifest │ │ │ └── +server.ts │ │ ├── sitemap.xml │ │ │ └── +server.ts │ │ ├── hire-the-author │ │ │ └── +page.svelte │ │ └── +layout.svelte │ ├── app.scss │ ├── app.d.ts │ ├── app.html │ └── service-worker.js ├── .eslintignore ├── .gitignore ├── vite.config.ts ├── svelte.config.js ├── .eslintrc.cjs ├── tsconfig.json ├── misc │ └── suggested-structure.txt └── package.json ├── package ├── .gitignore ├── src │ ├── index.ts │ ├── websocket │ │ ├── index.ts │ │ ├── vitePlugin.ts │ │ ├── client.ts │ │ ├── svelteKitServer.ts │ │ └── server.ts │ ├── ValidRoute.ts │ └── client.ts ├── .eslintignore ├── tsconfig.json ├── .eslintrc.cjs └── package.json ├── examples ├── simple │ ├── .prettierignore │ ├── static │ │ └── favicon.png │ ├── .gitignore │ ├── vite.config.ts │ ├── .eslintignore │ ├── src │ │ ├── routes │ │ │ ├── page-data │ │ │ │ ├── +page.svelte │ │ │ │ └── +page.ts │ │ │ ├── page-server-data │ │ │ │ ├── +page.svelte │ │ │ │ └── +page.server.ts │ │ │ ├── +page.svelte │ │ │ └── +layout.svelte │ │ ├── hooks.server.ts │ │ ├── app.d.ts │ │ ├── lib │ │ │ └── trpc │ │ │ │ ├── context.ts │ │ │ │ ├── client.ts │ │ │ │ └── router.ts │ │ └── app.html │ ├── README.md │ ├── .eslintrc.cjs │ ├── tsconfig.json │ ├── svelte.config.js │ ├── LICENSE │ └── package.json ├── bookstall │ ├── .prettierignore │ ├── .env │ ├── prisma │ │ ├── bookstall.db │ │ └── schema.prisma │ ├── static │ │ └── favicon.png │ ├── src │ │ ├── lib │ │ │ ├── assets │ │ │ │ └── trpc-logo.png │ │ │ ├── prisma.ts │ │ │ ├── dayjs.ts │ │ │ ├── trpc │ │ │ │ ├── t.ts │ │ │ │ ├── middleware │ │ │ │ │ ├── auth.ts │ │ │ │ │ └── logger.ts │ │ │ │ ├── client.ts │ │ │ │ ├── router.ts │ │ │ │ ├── context.ts │ │ │ │ └── routes │ │ │ │ │ ├── stores.ts │ │ │ │ │ ├── authors.ts │ │ │ │ │ └── books.ts │ │ │ ├── components │ │ │ │ ├── inputs │ │ │ │ │ ├── LabelAsterisk.svelte │ │ │ │ │ ├── CheckboxList.svelte │ │ │ │ │ ├── Select.svelte │ │ │ │ │ ├── TextInput.svelte │ │ │ │ │ └── TextareaInput.svelte │ │ │ │ ├── BusyOverlay.svelte │ │ │ │ ├── Footer.svelte │ │ │ │ ├── AuthorizationAlert.svelte │ │ │ │ ├── HeaderNavLink.svelte │ │ │ │ ├── Header.svelte │ │ │ │ └── ModalEditor.svelte │ │ │ ├── savable.ts │ │ │ └── icons │ │ │ │ ├── IconAdd.svelte │ │ │ │ ├── IconClock.svelte │ │ │ │ ├── IconPencil.svelte │ │ │ │ ├── IconVerticalDots.svelte │ │ │ │ ├── IconEmpty.svelte │ │ │ │ └── IconTrash.svelte │ │ ├── routes │ │ │ ├── logout │ │ │ │ └── +server.ts │ │ │ ├── books │ │ │ │ └── +page.server.ts │ │ │ ├── stores │ │ │ │ ├── +page.server.ts │ │ │ │ └── +page.svelte │ │ │ ├── authors │ │ │ │ ├── +page.server.ts │ │ │ │ └── +page.svelte │ │ │ ├── +layout.server.ts │ │ │ ├── login │ │ │ │ ├── +page.server.ts │ │ │ │ └── +page.svelte │ │ │ ├── +page.svelte │ │ │ └── +layout.svelte │ │ ├── app.d.ts │ │ ├── app.html │ │ └── hooks.server.ts │ ├── vite.config.ts │ ├── .eslintignore │ ├── .gitignore │ ├── README.md │ ├── .eslintrc.cjs │ ├── tsconfig.json │ ├── svelte.config.js │ ├── LICENSE │ └── package.json └── websocket │ ├── .prettierignore │ ├── static │ └── favicon.png │ ├── wsServer.js │ ├── .gitignore │ ├── .eslintignore │ ├── src │ ├── app.d.ts │ ├── hooks.server.ts │ ├── app.html │ ├── routes │ │ ├── +layout.svelte │ │ ├── +page.svelte │ │ └── messages │ │ │ └── +page.svelte │ └── lib │ │ └── trpc │ │ ├── context.ts │ │ ├── client.ts │ │ └── router.ts │ ├── vite.config.ts │ ├── README.md │ ├── .eslintrc.cjs │ ├── tsconfig.json │ ├── svelte.config.js │ ├── LICENSE │ └── package.json ├── .gitignore ├── .vscode └── settings.json ├── CONTRIBUTING.md ├── .prettierignore ├── .prettierrc ├── turbo.json ├── LICENSE └── package.json /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: icflorescu 2 | -------------------------------------------------------------------------------- /docs/.prettierignore: -------------------------------------------------------------------------------- 1 | /.svelte-kit 2 | /package 3 | -------------------------------------------------------------------------------- /package/.gitignore: -------------------------------------------------------------------------------- 1 | README.md 2 | LICENSE 3 | dist 4 | -------------------------------------------------------------------------------- /examples/simple/.prettierignore: -------------------------------------------------------------------------------- 1 | /.svelte-kit 2 | /package 3 | -------------------------------------------------------------------------------- /examples/bookstall/.prettierignore: -------------------------------------------------------------------------------- 1 | /.svelte-kit 2 | /package 3 | -------------------------------------------------------------------------------- /examples/websocket/.prettierignore: -------------------------------------------------------------------------------- 1 | /.svelte-kit 2 | /package 3 | -------------------------------------------------------------------------------- /examples/bookstall/.env: -------------------------------------------------------------------------------- 1 | JWT_SECRET=eF4mHkWrEb15Uv3qpjg75R9hmJG2BZs5 2 | -------------------------------------------------------------------------------- /package/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './client.js'; 2 | export * from './server.js'; 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | .turbo 4 | yarn-error.log 5 | vite.config.ts.* 6 | -------------------------------------------------------------------------------- /docs/static/googlea3479269b2f388cf.html: -------------------------------------------------------------------------------- 1 | google-site-verification: googlea3479269b2f388cf.html 2 | -------------------------------------------------------------------------------- /docs/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icflorescu/trpc-sveltekit/HEAD/docs/static/favicon.ico -------------------------------------------------------------------------------- /docs/src/lib/menuStore.ts: -------------------------------------------------------------------------------- 1 | import { writable } from 'svelte/store'; 2 | 3 | export const menuVisible = writable(false); 4 | -------------------------------------------------------------------------------- /docs/static/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icflorescu/trpc-sveltekit/HEAD/docs/static/favicon-16x16.png -------------------------------------------------------------------------------- /docs/static/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icflorescu/trpc-sveltekit/HEAD/docs/static/favicon-32x32.png -------------------------------------------------------------------------------- /docs/static/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icflorescu/trpc-sveltekit/HEAD/docs/static/mstile-150x150.png -------------------------------------------------------------------------------- /docs/static/trpc-sveltekit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icflorescu/trpc-sveltekit/HEAD/docs/static/trpc-sveltekit.png -------------------------------------------------------------------------------- /docs/.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | -------------------------------------------------------------------------------- /docs/static/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icflorescu/trpc-sveltekit/HEAD/docs/static/apple-touch-icon.png -------------------------------------------------------------------------------- /examples/simple/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icflorescu/trpc-sveltekit/HEAD/examples/simple/static/favicon.png -------------------------------------------------------------------------------- /docs/static/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icflorescu/trpc-sveltekit/HEAD/docs/static/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/static/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icflorescu/trpc-sveltekit/HEAD/docs/static/android-chrome-512x512.png -------------------------------------------------------------------------------- /examples/bookstall/prisma/bookstall.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icflorescu/trpc-sveltekit/HEAD/examples/bookstall/prisma/bookstall.db -------------------------------------------------------------------------------- /examples/bookstall/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icflorescu/trpc-sveltekit/HEAD/examples/bookstall/static/favicon.png -------------------------------------------------------------------------------- /examples/websocket/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icflorescu/trpc-sveltekit/HEAD/examples/websocket/static/favicon.png -------------------------------------------------------------------------------- /examples/websocket/wsServer.js: -------------------------------------------------------------------------------- 1 | import { SvelteKitTRPCWSServer } from 'trpc-sveltekit/websocket'; 2 | 3 | SvelteKitTRPCWSServer(import.meta.url); 4 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/assets/trpc-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icflorescu/trpc-sveltekit/HEAD/examples/bookstall/src/lib/assets/trpc-logo.png -------------------------------------------------------------------------------- /examples/bookstall/src/lib/prisma.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from '@prisma/client'; 2 | 3 | const prisma = new PrismaClient(); 4 | 5 | export default prisma; 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib", 3 | "eslint.workingDirectories": ["./package", "./docs", "./examples/*"] 4 | } 5 | -------------------------------------------------------------------------------- /package/.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # Ignore files for PNPM, NPM and YARN 6 | pnpm-lock.yaml 7 | package-lock.json 8 | yarn.lock 9 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | vite.config.ts.timestamp-*.* 11 | -------------------------------------------------------------------------------- /package/src/websocket/index.ts: -------------------------------------------------------------------------------- 1 | export * from './client.js'; 2 | export * from './server.js'; 3 | export * from './svelteKitServer.js'; 4 | export * from './vitePlugin.js'; 5 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/dayjs.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | import relativeTime from 'dayjs/plugin/relativeTime'; 3 | dayjs.extend(relativeTime); 4 | 5 | export default dayjs; 6 | -------------------------------------------------------------------------------- /examples/simple/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | 7 | .env 8 | .env.* 9 | !.env.example 10 | 11 | vite.config.ts.timestamp-*.* 12 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Pull requests are welcomed. 2 | Please make sure to follow the linting rules. 3 | If you're adding a new feature, please make sure to update the documaentation where needed. 4 | -------------------------------------------------------------------------------- /examples/websocket/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | 7 | .env 8 | .env.* 9 | !.env.example 10 | 11 | vite.config.ts.timestamp-*.* 12 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | .env 5 | .env.* 6 | !.env.example 7 | 8 | # Ignore files for PNPM, NPM and YARN 9 | pnpm-lock.yaml 10 | package-lock.json 11 | yarn.lock 12 | -------------------------------------------------------------------------------- /docs/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import type { UserConfig } from 'vite'; 3 | 4 | const config: UserConfig = { 5 | plugins: [sveltekit()] 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /examples/simple/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import type { UserConfig } from 'vite'; 3 | 4 | const config: UserConfig = { 5 | plugins: [sveltekit()] 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /docs/src/lib/components/home/LogoVercel.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/bookstall/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import type { UserConfig } from 'vite'; 3 | 4 | const config: UserConfig = { 5 | plugins: [sveltekit()] 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /docs/src/routes/+layout.server.ts: -------------------------------------------------------------------------------- 1 | import { version } from '../../../package/package.json'; 2 | import type { LayoutServerLoad } from './$types'; 3 | 4 | export const prerender = true; 5 | 6 | export const load: LayoutServerLoad = () => ({ version }); 7 | -------------------------------------------------------------------------------- /examples/bookstall/.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /examples/bookstall/src/routes/logout/+server.ts: -------------------------------------------------------------------------------- 1 | import type { RequestHandler } from './$types'; 2 | 3 | export const POST: RequestHandler = ({ cookies }) => { 4 | cookies.delete('jwt', { path: '/', secure: false }); 5 | return new Response(); 6 | }; 7 | -------------------------------------------------------------------------------- /examples/simple/.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /examples/websocket/.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/trpc/t.ts: -------------------------------------------------------------------------------- 1 | import type { Context } from '$lib/trpc/context'; 2 | import { initTRPC } from '@trpc/server'; 3 | import transformer from 'trpc-transformer'; 4 | 5 | export const t = initTRPC.context().create({ transformer }); 6 | -------------------------------------------------------------------------------- /examples/simple/src/routes/page-data/+page.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
Data loaded in
+page.ts
8 |

{data.greeting}

9 | -------------------------------------------------------------------------------- /docs/src/app.scss: -------------------------------------------------------------------------------- 1 | $enable-responsive-typography: false; 2 | @import '@picocss/pico/scss/pico'; 3 | 4 | h2 { 5 | font-size: 2rem; 6 | } 7 | 8 | @media (min-width: 768px) { 9 | h2 { 10 | font-weight: normal; 11 | font-size: 3rem; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/simple/src/routes/page-server-data/+page.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
Data loaded in
+page.ts
8 |

{data.greeting}

9 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": false, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100, 6 | "plugins": ["prettier-plugin-svelte"], 7 | "pluginSearchDirs": ["."], 8 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] 9 | } 10 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/trpc/middleware/auth.ts: -------------------------------------------------------------------------------- 1 | import { t } from '$lib/trpc/t'; 2 | import { TRPCError } from '@trpc/server'; 3 | 4 | export const auth = t.middleware(async ({ next, ctx }) => { 5 | if (!ctx.userId) throw new TRPCError({ code: 'UNAUTHORIZED' }); 6 | return next(); 7 | }); 8 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/components/inputs/LabelAsterisk.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | {#if required} 6 | * 7 | {/if} 8 | 9 | 15 | -------------------------------------------------------------------------------- /docs/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | // and what to do when importing types 4 | declare namespace App { 5 | // interface Locals {} 6 | // interface PageData {} 7 | // interface Error {} 8 | // interface Platform {} 9 | } 10 | -------------------------------------------------------------------------------- /docs/static/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #2b5797 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/simple/src/hooks.server.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from '$lib/trpc/context'; 2 | import { router } from '$lib/trpc/router'; 3 | import type { Handle } from '@sveltejs/kit'; 4 | import { createTRPCHandle } from 'trpc-sveltekit'; 5 | 6 | export const handle: Handle = createTRPCHandle({ router, createContext }); 7 | -------------------------------------------------------------------------------- /examples/bookstall/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | // and what to do when importing types 4 | declare namespace App { 5 | // interface Locals {} 6 | // interface PageData {} 7 | // interface Error {} 8 | // interface Platform {} 9 | } 10 | -------------------------------------------------------------------------------- /examples/simple/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | // and what to do when importing types 4 | declare namespace App { 5 | // interface Locals {} 6 | // interface PageData {} 7 | // interface Error {} 8 | // interface Platform {} 9 | } 10 | -------------------------------------------------------------------------------- /examples/websocket/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | // and what to do when importing types 4 | declare namespace App { 5 | // interface Locals {} 6 | // interface PageData {} 7 | // interface Error {} 8 | // interface Platform {} 9 | } 10 | -------------------------------------------------------------------------------- /examples/simple/src/lib/trpc/context.ts: -------------------------------------------------------------------------------- 1 | import type { RequestEvent } from '@sveltejs/kit'; 2 | 3 | export async function createContext(event: RequestEvent) { 4 | return { 5 | event // 👈 `event` is now available in your context 6 | }; 7 | } 8 | 9 | export type Context = Awaited>; 10 | -------------------------------------------------------------------------------- /examples/bookstall/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | 7 | # You should uncomment the next lines in your appplication 8 | 9 | # .env 10 | # .env.* 11 | # !.env.example 12 | 13 | vite.config.ts.timestamp-*.* 14 | 15 | # LOCK 16 | bun.lockb 17 | 18 | # PRISMA 19 | prisma/*.db 20 | -------------------------------------------------------------------------------- /examples/simple/src/routes/page-data/+page.ts: -------------------------------------------------------------------------------- 1 | import { trpc } from '$lib/trpc/client'; 2 | import type { PageLoad } from './$types'; 3 | 4 | // 👇 this method will be invoked on BOTH the server and the client, as needed ⚠️ 5 | export const load: PageLoad = async (event) => ({ 6 | greeting: await trpc(event).greeting.query() 7 | }); 8 | -------------------------------------------------------------------------------- /examples/websocket/src/hooks.server.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from '$lib/trpc/context'; 2 | import { router } from '$lib/trpc/router'; 3 | import { createTRPCWebSocketServer } from 'trpc-sveltekit/websocket'; 4 | 5 | import { building } from '$app/environment'; 6 | 7 | if (!building) createTRPCWebSocketServer({ router, createContext }); 8 | -------------------------------------------------------------------------------- /examples/bookstall/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/simple/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/websocket/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/websocket/src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 | 7 |
8 | 9 | 18 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/trpc/middleware/logger.ts: -------------------------------------------------------------------------------- 1 | import { t } from '$lib/trpc/t'; 2 | 3 | export const logger = t.middleware(async ({ path, type, next }) => { 4 | const start = Date.now(); 5 | const result = await next(); 6 | const ms = Date.now() - start; 7 | console.log(`${result.ok ? 'OK' : 'ERR'} ${type} ${path} - ${ms}ms`); 8 | return result; 9 | }); 10 | -------------------------------------------------------------------------------- /package/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "lib": ["esnext", "DOM", "DOM.Iterable"], 5 | "moduleResolution": "Node", 6 | "declaration": true, 7 | "skipLibCheck": true, 8 | "module": "ESNext", 9 | "target": "ESNext", 10 | "outDir": "dist", 11 | "rootDirs": ["src", "node_modules/@sveltejs/kit/src/runtime/components"], 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/src/routes/suggested-structure/+page.server.ts: -------------------------------------------------------------------------------- 1 | import loadCodeBlocks from '$lib/loadCodeBlocks'; 2 | import type { PageServerLoad } from './$types'; 3 | 4 | export const prerender = true; 5 | 6 | export const load: PageServerLoad = async () => ({ 7 | codeBlocks: await loadCodeBlocks({ 8 | 'suggested-structure.txt': 'misc', 9 | 'bookstall/src/lib/trpc/t.ts': 'example' 10 | }) 11 | }); 12 | -------------------------------------------------------------------------------- /examples/bookstall/src/routes/books/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from '$lib/trpc/context'; 2 | import { createCaller } from '$lib/trpc/router'; 3 | import type { PageServerLoad } from './$types'; 4 | 5 | export const load: PageServerLoad = async (event) => ({ 6 | books: await createCaller(await createContext(event)).books.list( 7 | event.url.searchParams.get('q') || undefined 8 | ) 9 | }); 10 | -------------------------------------------------------------------------------- /examples/bookstall/src/routes/stores/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from '$lib/trpc/context'; 2 | import { createCaller } from '$lib/trpc/router'; 3 | import type { PageServerLoad } from './$types'; 4 | 5 | export const load: PageServerLoad = async (event) => ({ 6 | stores: await createCaller(await createContext(event)).stores.list( 7 | event.url.searchParams.get('q') || undefined 8 | ) 9 | }); 10 | -------------------------------------------------------------------------------- /package/src/websocket/vitePlugin.ts: -------------------------------------------------------------------------------- 1 | import type { PluginOption } from 'vite'; 2 | 3 | import { createWSSGlobalInstance, onHttpServerUpgrade } from './svelteKitServer.js'; 4 | 5 | export const vitePluginTrpcWebSocket: PluginOption = { 6 | name: 'TrpcWebSocketServer', 7 | configureServer(server) { 8 | createWSSGlobalInstance(); 9 | server.httpServer?.on('upgrade', onHttpServerUpgrade); 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /docs/src/routes/handling-errors/+page.server.ts: -------------------------------------------------------------------------------- 1 | import loadCodeBlocks from '$lib/loadCodeBlocks'; 2 | import type { PageServerLoad } from './$types'; 3 | 4 | export const prerender = true; 5 | 6 | export const load: PageServerLoad = async () => ({ 7 | codeBlocks: await loadCodeBlocks({ 8 | 'bookstall/src/routes/authors/+page.svelte': 'example', 9 | 'bookstall/src/hooks.server.ts': 'example' 10 | }) 11 | }); 12 | -------------------------------------------------------------------------------- /docs/src/routes/page-data/+page.server.ts: -------------------------------------------------------------------------------- 1 | import loadCodeBlocks from '$lib/loadCodeBlocks'; 2 | import type { PageServerLoad } from './$types'; 3 | 4 | export const prerender = true; 5 | 6 | export const load: PageServerLoad = async () => ({ 7 | codeBlocks: await loadCodeBlocks({ 8 | 'simple/src/routes/page-data/+page.ts': 'example', 9 | 'simple/src/routes/page-data/+page.svelte': 'example' 10 | }) 11 | }); 12 | -------------------------------------------------------------------------------- /examples/simple/src/routes/page-server-data/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from '$lib/trpc/context'; 2 | import { createCaller } from '$lib/trpc/router'; 3 | import type { PageServerLoad } from './$types'; 4 | 5 | // 👇 since this is only called on the server, we can bypass HTTP 💡 6 | export const load: PageServerLoad = async (event) => ({ 7 | greeting: await createCaller(await createContext(event)).greeting() 8 | }); 9 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/savable.ts: -------------------------------------------------------------------------------- 1 | export function savable>(obj: T): T { 2 | return Object.fromEntries( 3 | Object.entries(obj).map(([key, value]) => { 4 | if (typeof value === 'string') { 5 | const adjustedValue = value.trim(); 6 | return [key, adjustedValue === '' ? null : adjustedValue]; 7 | } 8 | return [key, value]; 9 | }) 10 | ) as T; 11 | } 12 | -------------------------------------------------------------------------------- /examples/bookstall/src/routes/authors/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from '$lib/trpc/context'; 2 | import { createCaller } from '$lib/trpc/router'; 3 | import type { PageServerLoad } from './$types'; 4 | 5 | export const load: PageServerLoad = async (event) => { 6 | return { 7 | authors: await createCaller(await createContext(event)).authors.list( 8 | event.url.searchParams.get('q') || undefined 9 | ) 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /docs/src/routes/page-server-data/+page.server.ts: -------------------------------------------------------------------------------- 1 | import loadCodeBlocks from '$lib/loadCodeBlocks'; 2 | import type { PageServerLoad } from './$types'; 3 | 4 | export const prerender = true; 5 | 6 | export const load: PageServerLoad = async () => ({ 7 | codeBlocks: await loadCodeBlocks({ 8 | 'simple/src/routes/page-server-data/+page.server.ts': 'example', 9 | 'simple/src/routes/page-server-data/+page.svelte': 'example' 10 | }) 11 | }); 12 | -------------------------------------------------------------------------------- /docs/src/routes/robots.txt/+server.ts: -------------------------------------------------------------------------------- 1 | import { GITHUB_PAGES_ROOT } from '$lib/constants'; 2 | import type { RequestHandler } from './$types'; 3 | 4 | export const prerender = true; 5 | 6 | export const GET: RequestHandler = () => { 7 | return new Response( 8 | [ 9 | 'User-agent: *', 10 | 'Allow: /', 11 | `Host: ${GITHUB_PAGES_ROOT}/`, 12 | `Sitemap: ${GITHUB_PAGES_ROOT}/sitemap.xml` 13 | ].join('\n') 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /examples/websocket/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import type { UserConfig } from 'vite'; 3 | 4 | import { vitePluginTrpcWebSocket } from '../../package/src/websocket'; 5 | // Replace the above in your project with: 6 | // import { vitePluginTrpcWebSocket } from 'trpc-sveltekit/websocket'; 7 | 8 | const config: UserConfig = { 9 | plugins: [sveltekit(), vitePluginTrpcWebSocket] 10 | }; 11 | 12 | export default config; 13 | -------------------------------------------------------------------------------- /examples/bookstall/src/hooks.server.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from '$lib/trpc/context'; 2 | import { router } from '$lib/trpc/router'; 3 | import type { Handle } from '@sveltejs/kit'; 4 | import { createTRPCHandle } from 'trpc-sveltekit'; 5 | 6 | export const handle: Handle = createTRPCHandle({ 7 | router, 8 | createContext, 9 | onError: ({ type, path, error }) => 10 | console.error(`Encountered error while trying to process ${type} @ ${path}:`, error) 11 | }); 12 | -------------------------------------------------------------------------------- /docs/src/routes/recipes-and-caveats/+page.server.ts: -------------------------------------------------------------------------------- 1 | import loadCodeBlocks from '$lib/loadCodeBlocks'; 2 | import type { PageServerLoad } from './$types'; 3 | 4 | export const prerender = true; 5 | 6 | export const load: PageServerLoad = async () => ({ 7 | codeBlocks: await loadCodeBlocks({ 8 | 'bookstall/src/lib/trpc/router.ts': 'example', 9 | 'bookstall/src/routes/authors/+page.svelte': 'example', 10 | 'simple/src/lib/trpc/context.ts': 'example' 11 | }) 12 | }); 13 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/icons/IconAdd.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/websocket/src/lib/trpc/context.ts: -------------------------------------------------------------------------------- 1 | import type { CreateHTTPContextOptions } from '@trpc/server/adapters/standalone'; 2 | import type { CreateWSSContextFnOptions } from '@trpc/server/adapters/ws'; 3 | 4 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 5 | export async function createContext(opts: CreateHTTPContextOptions | CreateWSSContextFnOptions) { 6 | return { 7 | // context information 8 | }; 9 | } 10 | 11 | export type Context = Awaited>; 12 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/icons/IconClock.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /examples/bookstall/src/routes/+layout.server.ts: -------------------------------------------------------------------------------- 1 | import { JWT_SECRET } from '$env/static/private'; 2 | import jwt from 'jsonwebtoken'; 3 | import type { LayoutServerLoad } from './$types'; 4 | 5 | export const load: LayoutServerLoad = async ({ cookies }) => { 6 | try { 7 | const { name: userName } = jwt.verify(cookies.get('jwt') || '', JWT_SECRET) as { name: string }; 8 | return { isAuthenticated: true, userName }; 9 | } catch { 10 | return { isAuthenticated: false, userName: '' }; 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /docs/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-static'; 2 | import preprocess from 'svelte-preprocess'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://github.com/sveltejs/svelte-preprocess 7 | // for more information about preprocessors 8 | preprocess: preprocess(), 9 | kit: { 10 | adapter: adapter(), 11 | paths: { base: '/trpc-sveltekit', relative: false }, 12 | appDir: 'internal' 13 | } 14 | }; 15 | 16 | export default config; 17 | -------------------------------------------------------------------------------- /examples/websocket/src/lib/trpc/client.ts: -------------------------------------------------------------------------------- 1 | import type { Router } from '$lib/trpc/router'; 2 | import { createTRPCWebSocketClient } from 'trpc-sveltekit/websocket'; 3 | 4 | let browserClient: ReturnType>; 5 | 6 | export function trpc() { 7 | const isBrowser = typeof window !== 'undefined'; 8 | if (isBrowser && browserClient) return browserClient; 9 | const client = createTRPCWebSocketClient(); 10 | if (isBrowser) browserClient = client; 11 | return client; 12 | } 13 | -------------------------------------------------------------------------------- /examples/simple/src/lib/trpc/client.ts: -------------------------------------------------------------------------------- 1 | import type { Router } from '$lib/trpc/router'; 2 | import { createTRPCClient, type TRPCClientInit } from 'trpc-sveltekit'; 3 | 4 | let browserClient: ReturnType>; 5 | 6 | export function trpc(init?: TRPCClientInit) { 7 | const isBrowser = typeof window !== 'undefined'; 8 | if (isBrowser && browserClient) return browserClient; 9 | const client = createTRPCClient({ init }); 10 | if (isBrowser) browserClient = client; 11 | return client; 12 | } 13 | -------------------------------------------------------------------------------- /examples/websocket/README.md: -------------------------------------------------------------------------------- 1 | # 😎 tRPC-SvelteKit example: Websocket 2 | 3 | [![License][license-image]][license-url] 4 | 5 | **STATE:** Experimental 6 | 7 | - [x] Websocket works in development, with wroken hot reload 8 | - [x] Fix hot reload 9 | - [x] Websocket works in production 10 | - [x] Document usage & implementation 11 | - [ ] Website docs 12 | 13 | ## License 14 | 15 | The [ISC License](LICENSE). 16 | 17 | [license-image]: http://img.shields.io/npm/l/trpc-sveltekit.svg?style=flat-square 18 | [license-url]: LICENSE 19 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/icons/IconPencil.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/icons/IconVerticalDots.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/src/routes/authentication/+page.server.ts: -------------------------------------------------------------------------------- 1 | import loadCodeBlocks from '$lib/loadCodeBlocks'; 2 | import type { PageServerLoad } from './$types'; 3 | 4 | export const prerender = true; 5 | 6 | export const load: PageServerLoad = async () => ({ 7 | codeBlocks: await loadCodeBlocks({ 8 | 'bookstall/src/routes/login/+page.server.ts': 'example', 9 | 'bookstall/src/lib/trpc/context.ts': 'example', 10 | 'bookstall/src/lib/trpc/middleware/auth.ts': 'example', 11 | 'bookstall/src/lib/trpc/routes/authors.ts': 'example' 12 | }) 13 | }); 14 | -------------------------------------------------------------------------------- /docs/src/routes/using-with-svelte-query/+page.svelte: -------------------------------------------------------------------------------- 1 |

Using with Svelte-Query

2 | 3 |

4 | If you want to use tRPC-SvelteKit with 5 | Svelte Query, 6 | check out the 7 | tRPC Svelte Query Adapter 12 | by @ vishalbalaji. 13 |

14 | -------------------------------------------------------------------------------- /examples/simple/src/lib/trpc/router.ts: -------------------------------------------------------------------------------- 1 | import type { Context } from '$lib/trpc/context'; 2 | import { initTRPC } from '@trpc/server'; 3 | import delay from 'delay'; 4 | 5 | export const t = initTRPC.context().create(); 6 | 7 | export const router = t.router({ 8 | greeting: t.procedure.query(async () => { 9 | await delay(500); // 👈 simulate an expensive operation 10 | return `Hello tRPC v10 @ ${new Date().toLocaleTimeString()}`; 11 | }) 12 | }); 13 | 14 | export const createCaller = t.createCallerFactory(router); 15 | 16 | export type Router = typeof router; 17 | -------------------------------------------------------------------------------- /docs/src/lib/useMediaQuery.ts: -------------------------------------------------------------------------------- 1 | import { browser } from '$app/environment'; 2 | import { readable } from 'svelte/store'; 3 | 4 | export const useMediaQuery = (mediaQueryString: string) => { 5 | const matches = readable(null, (set) => { 6 | if (!browser) return; 7 | const m = window.matchMedia(mediaQueryString); 8 | set(m.matches); 9 | const el = (e: MediaQueryListEvent) => set(e.matches); 10 | m.addEventListener('change', el); 11 | return () => { 12 | m.removeEventListener('change', el); 13 | }; 14 | }); 15 | return matches; 16 | }; 17 | -------------------------------------------------------------------------------- /examples/simple/README.md: -------------------------------------------------------------------------------- 1 | # 😎 tRPC-SvelteKit example: Simple 2 | 3 | [![License][license-image]][license-url] 4 | 5 | A sample SvelteKit application built to illustrate the usage of [trpc-sveltekit](https://icflorescu.github.io/trpc-sveltekit/). 6 | 7 | ## Screenshot 8 | 9 | ![tRPC-SvelteKit simple example](https://user-images.githubusercontent.com/581999/204538156-c69c7233-37b2-47b4-8181-6b81c898b2c6.png) 10 | 11 | ## License 12 | 13 | The [ISC License](LICENSE). 14 | 15 | [license-image]: http://img.shields.io/npm/l/trpc-sveltekit.svg?style=flat-square 16 | [license-url]: LICENSE 17 | -------------------------------------------------------------------------------- /docs/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 | 10 | 11 | 12 | 13 |
14 | 15 | 21 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/trpc/client.ts: -------------------------------------------------------------------------------- 1 | import type { Router } from '$lib/trpc/router'; 2 | import { createTRPCClient, type TRPCClientInit } from 'trpc-sveltekit'; 3 | import transformer from 'trpc-transformer'; 4 | 5 | let browserClient: ReturnType>; 6 | 7 | export function trpc(init?: TRPCClientInit) { 8 | const isBrowser = typeof window !== 'undefined'; 9 | if (isBrowser && browserClient) return browserClient; 10 | const client = createTRPCClient({ init, transformer }); 11 | if (isBrowser) browserClient = client; 12 | return client; 13 | } 14 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "pipeline": { 4 | "dev": { "cache": false }, 5 | "docs#dev": { "cache": false }, 6 | "example-simple#dev": { "cache": false }, 7 | "example-bookstall#dev": { "cache": false }, 8 | "example-websocket#dev": { "cache": false }, 9 | "trpc-sveltekit#build": { "outputs": ["dist/**"] }, 10 | "docs#build": { "dependsOn": ["trpc-sveltekit#build"], "outputs": ["build/**"] }, 11 | "preview": { "dependsOn": ["^build"] }, 12 | "lint": { "outputs": [] }, 13 | "format": { "outputs": [] } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /docs/src/routes/getting-started/+page.server.ts: -------------------------------------------------------------------------------- 1 | import loadCodeBlocks from '$lib/loadCodeBlocks'; 2 | import type { PageServerLoad } from './$types'; 3 | 4 | export const prerender = true; 5 | 6 | export const load: PageServerLoad = async () => { 7 | return { 8 | codeBlocks: await loadCodeBlocks({ 9 | 'simple/src/lib/trpc/context.ts': 'example', 10 | 'simple/src/lib/trpc/router.ts': 'example', 11 | 'simple/src/hooks.server.ts': 'example', 12 | 'simple/src/lib/trpc/client.ts': 'example', 13 | 'simple/src/routes/+page.svelte': 'example' 14 | }) 15 | }; 16 | }; 17 | -------------------------------------------------------------------------------- /examples/bookstall/README.md: -------------------------------------------------------------------------------- 1 | # 😎 tRPC-SvelteKit example: Bookstall 2 | 3 | [![License][license-image]][license-url] 4 | 5 | A sample SvelteKit application built to illustrate the usage of [trpc-sveltekit](https://icflorescu.github.io/trpc-sveltekit/). 6 | 7 | ## Screenshot 8 | 9 | ![tRPC-SvelteKit Example: Bookstall](https://user-images.githubusercontent.com/581999/204535160-5ca59227-81cb-4281-bbad-23a7869c6031.png) 10 | 11 | ## License 12 | 13 | The [ISC License](LICENSE). 14 | 15 | [license-image]: http://img.shields.io/npm/l/trpc-sveltekit.svg?style=flat-square 16 | [license-url]: LICENSE 17 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/icons/IconEmpty.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], 5 | plugins: ['svelte3', '@typescript-eslint'], 6 | ignorePatterns: ['*.cjs'], 7 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], 8 | settings: { 9 | 'svelte3/typescript': () => require('typescript') 10 | }, 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaVersion: 2020 14 | }, 15 | env: { 16 | browser: true, 17 | es2017: true, 18 | node: true 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /examples/simple/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], 5 | plugins: ['svelte3', '@typescript-eslint'], 6 | ignorePatterns: ['*.cjs'], 7 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], 8 | settings: { 9 | 'svelte3/typescript': () => require('typescript') 10 | }, 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaVersion: 2020 14 | }, 15 | env: { 16 | browser: true, 17 | es2017: true, 18 | node: true 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /examples/bookstall/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], 5 | plugins: ['svelte3', '@typescript-eslint'], 6 | ignorePatterns: ['*.cjs'], 7 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], 8 | settings: { 9 | 'svelte3/typescript': () => require('typescript') 10 | }, 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaVersion: 2020 14 | }, 15 | env: { 16 | browser: true, 17 | es2017: true, 18 | node: true 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/components/BusyOverlay.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | {#if visible} 8 |
9 | {/if} 10 | 11 | 26 | -------------------------------------------------------------------------------- /examples/websocket/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], 5 | plugins: ['svelte3', '@typescript-eslint'], 6 | ignorePatterns: ['*.cjs'], 7 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], 8 | settings: { 9 | 'svelte3/typescript': () => require('typescript') 10 | }, 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaVersion: 2020 14 | }, 15 | env: { 16 | browser: true, 17 | es2017: true, 18 | node: true 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /docs/src/routes/acknowledgements/+page.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |

Acknowledgements

6 | 7 |

8 | Huge thanks to Alex / KATT 9 | for being the first sponsor of this project 🎉, for his outstanding work at 10 | tRPC.io and for his encouragement. 11 |

12 | 13 |

14 | Thank you for your support, 15 |
16 | Ionut-Cristian Florescu 17 |

18 | -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true 12 | } 13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 14 | // 15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } 18 | -------------------------------------------------------------------------------- /examples/bookstall/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true 12 | } 13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 14 | // 15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } 18 | -------------------------------------------------------------------------------- /examples/simple/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true 12 | } 13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 14 | // 15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } 18 | -------------------------------------------------------------------------------- /examples/websocket/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true 12 | } 13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 14 | // 15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } 18 | -------------------------------------------------------------------------------- /examples/simple/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 14 | 15 |
Loading data in
+page.svelte
16 | 17 | Load 24 |

{greeting}

25 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/trpc/router.ts: -------------------------------------------------------------------------------- 1 | import { authors } from '$lib/trpc/routes/authors'; 2 | import { books } from '$lib/trpc/routes/books'; 3 | import { stores } from '$lib/trpc/routes/stores'; 4 | import { t } from '$lib/trpc/t'; 5 | import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server'; 6 | 7 | export const router = t.router({ 8 | authors, 9 | books, 10 | stores 11 | }); 12 | 13 | export const createCaller = t.createCallerFactory(router); 14 | 15 | export type Router = typeof router; 16 | 17 | // 👇 type helpers 💡 18 | export type RouterInputs = inferRouterInputs; 19 | export type RouterOutputs = inferRouterOutputs; 20 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/icons/IconTrash.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/src/lib/components/home/SupportedAdapter.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 | 7 |
@sveltejs/adapter-{name}
8 |
9 | 10 | 30 | -------------------------------------------------------------------------------- /package/src/ValidRoute.ts: -------------------------------------------------------------------------------- 1 | type HasTrailingSlash = S extends `${string}/` 2 | ? IfTrue 3 | : IfFalse; 4 | 5 | type ValidateRouteStart = HasTrailingSlash< 6 | S, 7 | IfInvalid, 8 | S extends `/${string}` ? IfValid : IfInvalid 9 | >; 10 | 11 | type ValidateRouteEnd = string & { 12 | __errorMsg: `${T} is not a valid route because ${HasTrailingSlash< 13 | T, 14 | 'it has a trailing slash', 15 | 'it does not start with a slash' 16 | >}`; 17 | }; 18 | 19 | export type ValidRoute = ValidateRouteStart> | '/trpc'; 20 | -------------------------------------------------------------------------------- /docs/src/routes/experimental-websocket-support/+page.svelte: -------------------------------------------------------------------------------- 1 |

Experimental WebSocket support

2 | 3 |

4 | SvelteKit doesn't (yet) offer WebSockets support, but if you're using @sveltejs/adapter-node, tRPC-SvelteKit can spin up 7 | an experimental WS server to process tRPC procedure calls. 8 |

9 | 10 |

11 | Please refer to the dedicated section in the README for more information. 16 |

17 | -------------------------------------------------------------------------------- /package/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], 5 | plugins: ['svelte3', '@typescript-eslint'], 6 | ignorePatterns: ['*.cjs'], 7 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], 8 | settings: { 9 | 'svelte3/typescript': () => require('typescript') 10 | }, 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaVersion: 2020 14 | }, 15 | env: { 16 | browser: true, 17 | es2017: true, 18 | node: true 19 | }, 20 | rules: { 21 | '@typescript-eslint/no-explicit-any': 'off' 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /docs/src/lib/components/Info.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |
7 | 8 |
9 |

10 | 11 |

12 |
13 | 14 | 33 | -------------------------------------------------------------------------------- /docs/src/lib/components/home/Mantra.svelte: -------------------------------------------------------------------------------- 1 |

2 | Move fast and break nothing. 3 |
4 | End-to-end typesafe APIs for your 5 |
6 | SvelteKit applications. 7 |

8 | 9 | 31 | -------------------------------------------------------------------------------- /package/src/websocket/client.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CreateTRPCClientOptions, 3 | createTRPCProxyClient, 4 | createWSClient, 5 | wsLink 6 | } from '@trpc/client'; 7 | import { AnyRouter } from '@trpc/server'; 8 | 9 | export function createTRPCWebSocketClient(): ReturnType< 10 | typeof createTRPCProxyClient 11 | > { 12 | if (typeof location === 'undefined') return; 13 | 14 | const uri = `${location.protocol === 'http:' ? 'ws:' : 'wss:'}//${location.host}/trpc`; 15 | 16 | const wsClient = createWSClient({ 17 | url: uri 18 | }); 19 | 20 | return createTRPCProxyClient({ 21 | links: [wsLink({ client: wsClient })] 22 | } as CreateTRPCClientOptions); 23 | } 24 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/trpc/context.ts: -------------------------------------------------------------------------------- 1 | import { JWT_SECRET } from '$env/static/private'; 2 | import type { RequestEvent } from '@sveltejs/kit'; 3 | import jwt from 'jsonwebtoken'; 4 | 5 | export async function createContext(event: RequestEvent) { 6 | try { 7 | const token = event.cookies.get('jwt'); 8 | // 👆 or, if we're using HTTP headers based authentication, we could do something like this: 9 | // const token = event.request.headers.get('authorization')?.replace('Bearer ', ''); 10 | 11 | const { id: userId } = jwt.verify(token || '', JWT_SECRET) as { id: string }; 12 | 13 | return { userId }; 14 | } catch { 15 | return { userId: '' }; 16 | } 17 | } 18 | 19 | export type Context = Awaited>; 20 | -------------------------------------------------------------------------------- /examples/bookstall/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-auto'; 2 | import preprocess from 'svelte-preprocess'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://github.com/sveltejs/svelte-preprocess 7 | // for more information about preprocessors 8 | preprocess: preprocess(), 9 | kit: { 10 | adapter: adapter(), 11 | // this is only needed for the example app in trpc-sveltekit monorepo 12 | // you can remove this in your own app, since you'll be installing the package from npm 13 | alias: { 14 | 'trpc-sveltekit': 15 | process.env.NODE_ENV === 'production' ? '../../package/dist' : '../../package/src' 16 | } 17 | } 18 | }; 19 | 20 | export default config; 21 | -------------------------------------------------------------------------------- /examples/simple/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-auto'; 2 | import preprocess from 'svelte-preprocess'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://github.com/sveltejs/svelte-preprocess 7 | // for more information about preprocessors 8 | preprocess: preprocess(), 9 | kit: { 10 | adapter: adapter(), 11 | // this is only needed for the example app in trpc-sveltekit monorepo 12 | // you can remove this in your own app, since you'll be installing the package from npm 13 | alias: { 14 | 'trpc-sveltekit': 15 | process.env.NODE_ENV === 'production' ? '../../package/dist' : '../../package/src' 16 | } 17 | } 18 | }; 19 | 20 | export default config; 21 | -------------------------------------------------------------------------------- /examples/websocket/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-node'; 2 | import preprocess from 'svelte-preprocess'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://github.com/sveltejs/svelte-preprocess 7 | // for more information about preprocessors 8 | preprocess: preprocess(), 9 | kit: { 10 | adapter: adapter(), 11 | // this is only needed for the example app in trpc-sveltekit monorepo 12 | // you can remove this in your own app, since you'll be installing the package from npm 13 | alias: { 14 | 'trpc-sveltekit': 15 | process.env.NODE_ENV === 'production' ? '../../package/dist' : '../../package/src' 16 | } 17 | } 18 | }; 19 | 20 | export default config; 21 | -------------------------------------------------------------------------------- /docs/src/routes/site.webmanifest/+server.ts: -------------------------------------------------------------------------------- 1 | import { GITHUB_PAGES_ROOT } from '$lib/constants'; 2 | import type { RequestHandler } from './$types'; 3 | 4 | export const prerender = true; 5 | 6 | const ICON_SIZES = [192, 512]; 7 | 8 | export const GET: RequestHandler = () => { 9 | return new Response( 10 | JSON.stringify({ 11 | name: 'tRPC-SvelteKit', 12 | short_name: 'tRPC-SvelteKit', 13 | start_url: './', 14 | scope: '.', 15 | icons: ICON_SIZES.map((size) => ({ 16 | src: `${GITHUB_PAGES_ROOT}/android-chrome-${size}x${size}.png`, 17 | sizes: `${size}x${size}`, 18 | type: 'image/png' 19 | })), 20 | theme_color: '#141e26', 21 | background_color: '#141e26', 22 | display: 'standalone' 23 | }) 24 | ); 25 | }; 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2022-2023 Ionut-Cristian Florescu 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /examples/bookstall/LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2022, Ionut-Cristian Florescu 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /examples/simple/LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2022, Ionut-Cristian Florescu 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /examples/websocket/LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2022, Ionut-Cristian Florescu 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/components/inputs/CheckboxList.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | {label} 11 |
12 | {#each options as { value, label } (value)} 13 | 17 | {/each} 18 |
19 | 20 | 30 | -------------------------------------------------------------------------------- /docs/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | %sveltekit.head% 14 | 15 | 16 |
%sveltekit.body%
17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/websocket/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |

WebSocket example

15 |

16 | Open {$page.url}messages in a new window/tab. 17 |

18 | 19 |
20 | 21 | 22 |
23 | 24 | 33 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/components/Footer.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 | 29 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/components/AuthorizationAlert.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 32 | 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "trpc-sveltekit-monorepo", 3 | "version": "0.0.0", 4 | "description": "SvelteKit adapter for trpc.io", 5 | "author": { 6 | "name": "Ionut-Cristian Florescu", 7 | "email": "ionut.florescu@gmail.com", 8 | "url": "https://github.com/icflorescu" 9 | }, 10 | "license": "ISC", 11 | "private": true, 12 | "type": "module", 13 | "workspaces": [ 14 | "package", 15 | "docs", 16 | "examples/*" 17 | ], 18 | "scripts": { 19 | "dev": "turbo dev", 20 | "build": "turbo build", 21 | "start": "turbo preview", 22 | "lint": "turbo lint", 23 | "format": "turbo format" 24 | }, 25 | "devDependencies": { 26 | "@typescript-eslint/eslint-plugin": "^7.13.0", 27 | "@typescript-eslint/parser": "^7.13.0", 28 | "eslint": "^8.57.0", 29 | "eslint-config-prettier": "^9.1.0", 30 | "eslint-plugin-svelte3": "^4.0.0", 31 | "prettier": "^3.3.2", 32 | "prettier-plugin-svelte": "^3.2.4", 33 | "turbo": "^1.12.4" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /docs/misc/suggested-structure.txt: -------------------------------------------------------------------------------- 1 | -------------- 2 | | lib/trpc | 👈 place your tRPC-related stuff here 3 | -------------- 4 | | 5 | |-- context.ts 👈 router context 6 | |-- t.ts 👈 tRPC definition helper (see below) 7 | |-- router.ts 👈 main router definition (imports files defined in routes folder) 8 | |-- middleware.ts 👈 tRPC middleware (this could be split into multiple files if necessary) 9 | |-- client.ts 👈 define a client helper function here 10 | | 11 | | ------------ 12 | |--| routes | 👈 split your routes into multiple files and place them here 13 | | ------------ 14 | | | 15 | | |-- route-1.ts 16 | | |-- route-2.ts 17 | | |-- route-3.ts 18 | | | ... 19 | | |-- route-n.ts 20 | | 21 | | ---------------- 22 | |--| middleware | 👈 split your middleware into multiple files and place them here 23 | ---------------- 24 | | 25 | |-- middleware-1.ts 26 | | ... 27 | |-- middleware-n.ts 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: icflorescu 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /docs/src/routes/sitemap.xml/+server.ts: -------------------------------------------------------------------------------- 1 | import { GITHUB_PAGES_ROOT, PAGES } from '$lib/constants'; 2 | import type { RequestHandler } from './$types'; 3 | 4 | export const prerender = true; 5 | 6 | export const GET: RequestHandler = () => { 7 | const date = new Date().toISOString(); 8 | return new Response( 9 | [ 10 | '', 11 | '', 12 | ...PAGES.map( 13 | ({ path }) => 14 | `${GITHUB_PAGES_ROOT}${ 15 | path === '/' ? '' : path 16 | }${date}weekly0.7` 17 | ), 18 | '' 19 | ].join('\n') 20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconCheck.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /docs/src/lib/components/layout/MenuLink.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | {#if typeof title === 'string'} 11 | {title} 12 | {:else} 13 | {#each title as part, index (part)} 14 | {#if index > 0} 15 |
16 | {/if} 17 | {part} 18 | {/each} 19 | {/if} 20 |
21 | 22 | 48 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconWebSocket.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /docs/src/lib/loadCodeBlocks.ts: -------------------------------------------------------------------------------- 1 | import fromPairs from 'lodash/fp/fromPairs'; 2 | import { readFile } from 'node:fs/promises'; 3 | import { join } from 'node:path'; 4 | 5 | const cwd = process.cwd(); 6 | const examplesFolder = join(cwd, '..', 'examples'); 7 | const miscFolder = join(cwd, 'misc'); 8 | 9 | export default async function loadCodeBlocks>( 10 | options: T 11 | ) { 12 | const blocks = await Promise.all( 13 | Object.entries(options).map(async ([path, type]) => [ 14 | path, 15 | { 16 | code: await readFile(join(type === 'example' ? examplesFolder : miscFolder, path), 'utf-8'), 17 | language: path.endsWith('.ts') 18 | ? 'typescript' 19 | : path.endsWith('.txt') 20 | ? 'plaintext' 21 | : undefined, 22 | title: type === 'example' ? path.split('/').slice(2).join('/') : path 23 | } 24 | ]) 25 | ); 26 | return fromPairs(blocks) as Record< 27 | keyof T, 28 | { code: string; language?: 'typescript' | 'plaintext'; title: string } 29 | >; 30 | } 31 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/components/inputs/Select.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 26 | 27 | 36 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/components/inputs/TextInput.svelte: -------------------------------------------------------------------------------- 1 | 15 | 16 | 31 | 32 | 41 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconMenu.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconMoon.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /docs/src/routes/suggested-structure/+page.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 |

Suggested structure

11 | 12 |

13 | Here's how you could structure the tRPC-related files in a non-trivial application in order to 14 | avoid cyclic dependencies: 15 |

16 | 17 |
18 | 19 |
20 | 21 |

22 | The t.ts file contains a simple helper that allows you to build routes and middleware: 23 |

24 | 25 | 26 | 27 |

28 | You'll have to import t.ts in multiple other files such as router.ts, 29 | middleware.ts, 30 | routes/route-1.ts, routes/route-2.ts, etc. 31 |

32 | 33 | 38 | -------------------------------------------------------------------------------- /examples/websocket/src/lib/trpc/router.ts: -------------------------------------------------------------------------------- 1 | import type { Context } from '$lib/trpc/context'; 2 | import { initTRPC } from '@trpc/server'; 3 | import { observable } from '@trpc/server/observable'; 4 | import { EventEmitter } from 'events'; 5 | 6 | export const t = initTRPC.context().create(); 7 | 8 | const ee = new EventEmitter(); 9 | 10 | export const router = t.router({ 11 | allMessages: t.procedure.subscription(() => { 12 | return observable((emit) => { 13 | const onAdd = (message: string) => { 14 | emit.next(`${new Date().toLocaleTimeString()}: ${message}`); 15 | }; 16 | 17 | ee.on('add', onAdd); 18 | 19 | return () => { 20 | ee.off('add', onAdd); 21 | }; 22 | }); 23 | }), 24 | addMessage: t.procedure 25 | .input((input: unknown) => { 26 | if (typeof input === 'string') return input; 27 | 28 | throw new Error('Invalid input type'); 29 | }) 30 | .mutation(async ({ input: message }) => { 31 | ee.emit('add', message); 32 | 33 | return { success: true }; 34 | }) 35 | }); 36 | 37 | export type Router = typeof router; 38 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconFolder.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconLock.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /examples/websocket/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example-websocket", 3 | "version": "0.0.0", 4 | "author": "https://github.com/SrZorro", 5 | "private": true, 6 | "scripts": { 7 | "dev": "vite --port 3003 --clearScreen false", 8 | "build": "vite build", 9 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 10 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 11 | "lint": "prettier --plugin-search-dir . --check . && eslint .", 12 | "format": "prettier --plugin-search-dir . --write .", 13 | "start": "node ./wsServer" 14 | }, 15 | "devDependencies": { 16 | "@picocss/pico": "^1.5.12", 17 | "@sveltejs/adapter-node": "^5.1.0", 18 | "@sveltejs/kit": "^2.18.0", 19 | "sass": "^1.85.1", 20 | "svelte": "^4.2.18", 21 | "svelte-check": "^3.8.0", 22 | "svelte-preprocess": "^6.0.3", 23 | "tslib": "^2.8.1", 24 | "typescript": "^5.8.2", 25 | "vite": "^4.5.2" 26 | }, 27 | "type": "module", 28 | "dependencies": { 29 | "@trpc/client": "^10.45.2", 30 | "@trpc/server": "^10.45.2", 31 | "delay": "^6.0.0", 32 | "ws": "^8.18.1" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconArrowLeft.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconArrowRight.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconInfoCircle.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /docs/src/lib/components/home/SupportedAdapters.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 |

tRPC-SvelteKit works with:

10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 | 41 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconClipboard.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/src/routes/page-server-data/+page.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |

Page server data

9 | 10 |

11 | If you want to call tRPC procedures in your SvelteKit page server load functions, you should bypass HTTP and invoke the methods directly on the 16 | tRPC caller: 17 |

18 | 19 | 20 | 21 |

You can then use the loaded data in your pages like so:

22 | 23 | 24 | 25 |

26 | Have a look at this SvelteKit documentation section to learn the difference between shared vs. server data loading. 31 |

32 | -------------------------------------------------------------------------------- /package/src/websocket/svelteKitServer.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as url from 'url'; 3 | import type { Server } from 'ws'; 4 | import { WebSocketServer } from 'ws'; 5 | 6 | export const GlobalThisWSS = Symbol.for('trpc.sveltekit.wss'); 7 | 8 | export function onHttpServerUpgrade(req, sock, head) { 9 | const pathname = url.parse(req.url).pathname; 10 | if (pathname !== '/trpc') return; 11 | 12 | const wss = globalThis[GlobalThisWSS] as Server; 13 | 14 | wss.handleUpgrade(req, sock, head, function done(ws) { 15 | wss.emit('connection', ws, req); 16 | }); 17 | } 18 | 19 | export function createWSSGlobalInstance() { 20 | const wss = new WebSocketServer({ 21 | noServer: true 22 | }); 23 | 24 | globalThis[GlobalThisWSS] = wss; 25 | 26 | return wss; 27 | } 28 | 29 | export async function SvelteKitTRPCWSServer(import_meta_url: string) { 30 | const __filename = url.fileURLToPath(import_meta_url); 31 | const __dirname = path.dirname(__filename); 32 | 33 | createWSSGlobalInstance(); 34 | 35 | const { server } = await import(/* @vite-ignore */ path.resolve(__dirname, './build/index.js')); 36 | server.server.on('upgrade', onHttpServerUpgrade); 37 | } 38 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconErrorHandling.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 33 | 34 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconHome.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconBulb.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconFileCode.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /docs/src/lib/components/home/CallsToAction.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 21 | 22 | 46 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconRocket.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /examples/bookstall/src/routes/login/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { JWT_SECRET } from '$env/static/private'; 2 | import prisma from '$lib/prisma'; 3 | import { fail } from '@sveltejs/kit'; 4 | import { md5 } from 'hash-wasm'; 5 | import jwt from 'jsonwebtoken'; 6 | import type { Actions } from './$types'; 7 | 8 | export const actions: Actions = { 9 | default: async ({ request, cookies }) => { 10 | try { 11 | const data = await request.formData(); 12 | const email = data.get('email') as string; 13 | const password = data.get('password') as string; 14 | 15 | // 👇 replace this with a non-naiive hashing algorithm 16 | const passwordHash = await md5(password); 17 | 18 | const { id, name } = await prisma.user.findFirstOrThrow({ 19 | where: { email, passwordHash }, 20 | select: { id: true, name: true } 21 | }); 22 | 23 | cookies.set('jwt', jwt.sign({ id, name }, JWT_SECRET), { path: '/', secure: false }); 24 | 25 | return { success: true }; 26 | // 👆 or, if we're using HTTP headers based auth, we could return the token, 27 | // and let the client set the header on subsequent requests 28 | } catch { 29 | return fail(401, { error: 'Authentication failed' }); 30 | } 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /examples/simple/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example-simple", 3 | "version": "0.0.0", 4 | "author": { 5 | "name": "Ionut-Cristian Florescu", 6 | "email": "ionut.florescu@gmail.com", 7 | "url": "https://github.com/icflorescu" 8 | }, 9 | "private": true, 10 | "scripts": { 11 | "dev": "vite --port 3001 --clearScreen false", 12 | "build": "vite build", 13 | "preview": "vite preview --port 3001", 14 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 15 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 16 | "lint": "prettier --plugin-search-dir . --check . && eslint .", 17 | "format": "prettier --plugin-search-dir . --write ." 18 | }, 19 | "devDependencies": { 20 | "@picocss/pico": "^1.5.12", 21 | "@sveltejs/adapter-auto": "^3.2.2", 22 | "@sveltejs/kit": "^2.18.0", 23 | "sass": "^1.85.1", 24 | "svelte": "^4.2.18", 25 | "svelte-check": "^3.8.0", 26 | "svelte-preprocess": "^6.0.3", 27 | "tslib": "^2.8.1", 28 | "typescript": "^5.8.2", 29 | "vite": "^4.5.2" 30 | }, 31 | "type": "module", 32 | "dependencies": { 33 | "@trpc/client": "^10.45.2", 34 | "@trpc/server": "^10.45.2", 35 | "delay": "^6.0.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconFileDatabase.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconSpeakerphone.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | 34 | 35 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconLifeBuoy.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /docs/src/routes/handling-errors/+page.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |

Handling errors

9 | 10 |

11 | Whenever an error occurs in a procedure, tRPC responds to the client with an object that includes 12 | an "error" property. This property contains all the information that you need to handle the error 13 | in the client. Here's an example of how you can handle the error in your SvelteKit page (look at 14 | the try/catch block in the handleSave function): 15 |

16 | 17 | 18 | 19 |

20 | Please refer to the error handling page in the tRPC documentation for more information. 23 |

24 | 25 |

26 | You can also supply an onError handler to the createTRPCHandle method in 27 | your hooks.server.ts, which could be useful, for instance, if you want to log all 28 | errors to a service like Sentry: 29 |

30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/src/routes/authentication/+page.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |

Using authentication

9 | 10 |

11 | The tRPC-SvelteKit package works with both cookie-based and JWT-based authentication. 12 |

13 | 14 |

15 | Below is an example of how you could secure your tRPC routes with cookie-based authentication. 16 |

17 | 18 |

19 | Let's assume you have a username/password-based login page that POSTs to the following action: 24 |

25 | 26 | 27 | 28 |

Your tRPC context builder could look like this:

29 | 30 | 31 | 32 |

You could define an authentication middleware like this:

33 | 34 | 35 | 36 |

And you could use the auth middleware in your tRPC procedured as needed:

37 | 38 | 39 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconHeartHandshake.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconTools.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconGitHub.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 32 | 33 | -------------------------------------------------------------------------------- /examples/websocket/src/routes/messages/+page.svelte: -------------------------------------------------------------------------------- 1 | 24 | 25 |
26 |

✨ WebSocket Messages ✨

27 |
28 | {#each messages as message, i} 29 | {#if i === messages.length - 1} 30 |

{message}

31 | {:else} 32 |

{message}

33 | {/if} 34 | {/each} 35 |
36 |
37 | 38 | 61 | -------------------------------------------------------------------------------- /docs/src/routes/page-data/+page.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |

Page data

10 | 11 |

12 | Assuming you created a trpc() helper function as described in the 13 | getting started 14 | section, you can call tRPC procedures in your SvelteKit 15 | page load functions: 17 |

18 | 19 | 20 | 21 |

You can then use the loaded data in your pages like so:

22 | 23 | 24 | 25 |

26 | A load function defined in a +page.ts file will run 27 | both on the server and in the browser. You should therefore consider using a 28 | +page.server.js instead. 29 |

30 | 31 |

32 | Have a look at this SvelteKit documentation section to learn the difference between shared vs. server data loading. 37 |

38 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/components/HeaderNavLink.svelte: -------------------------------------------------------------------------------- 1 | 17 | 18 |
  • 19 | {title} 20 |
  • 21 | 22 | 54 | -------------------------------------------------------------------------------- /docs/src/lib/components/home/LogoSvelte.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 14 | -------------------------------------------------------------------------------- /docs/src/lib/icons/IconSun.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "0.0.0", 4 | "author": { 5 | "name": "Ionut-Cristian Florescu", 6 | "email": "ionut.florescu@gmail.com", 7 | "url": "https://github.com/icflorescu" 8 | }, 9 | "private": true, 10 | "scripts": { 11 | "dev": "vite --port 3000 --clearScreen false", 12 | "build": "vite build", 13 | "preview": "vite preview --port 3000", 14 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 15 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 16 | "lint": "prettier --plugin-search-dir . --check . && eslint .", 17 | "format": "prettier --plugin-search-dir . --write ." 18 | }, 19 | "devDependencies": { 20 | "@picocss/pico": "^1.5.10", 21 | "@sveltejs/adapter-static": "^3.0.8", 22 | "@sveltejs/kit": "^2.18.0", 23 | "@types/lodash": "^4.17.16", 24 | "@typescript-eslint/eslint-plugin": "^7.13.0", 25 | "@typescript-eslint/parser": "^7.13.0", 26 | "eslint": "^8.57.0", 27 | "eslint-config-prettier": "^9.1.0", 28 | "lodash": "^4.17.21", 29 | "prettier": "^3.5.3", 30 | "sass": "^1.85.1", 31 | "svelte": "^4.2.18", 32 | "svelte-check": "^3.8.0", 33 | "svelte-highlight": "^7.8.2", 34 | "svelte-preprocess": "^6.0.3", 35 | "tslib": "^2.8.1", 36 | "typescript": "^5.8.2", 37 | "vite": "^4.5.2" 38 | }, 39 | "type": "module" 40 | } 41 | -------------------------------------------------------------------------------- /package/src/websocket/server.ts: -------------------------------------------------------------------------------- 1 | import { AnyRouter, inferRouterContext } from '@trpc/server'; 2 | import type { CreateHTTPContextOptions } from '@trpc/server/adapters/standalone'; 3 | import type { CreateWSSContextFnOptions } from '@trpc/server/adapters/ws'; 4 | import { applyWSSHandler } from '@trpc/server/adapters/ws'; 5 | import type { Server } from 'ws'; 6 | import { GlobalThisWSS } from './svelteKitServer.js'; 7 | 8 | export async function createTRPCWebSocketServer({ 9 | router, 10 | createContext 11 | }: { 12 | /** 13 | * The tRPC router to use. 14 | * @see https://trpc.io/docs/router 15 | */ 16 | router: Router; 17 | 18 | /** 19 | * An async function that returns the tRPC context. 20 | * @see https://trpc.io/docs/context 21 | */ 22 | createContext?: ( 23 | opts: CreateHTTPContextOptions | CreateWSSContextFnOptions 24 | ) => Promise>; 25 | }) { 26 | const wss = globalThis[GlobalThisWSS] as Server; 27 | if (typeof wss === 'undefined') { 28 | // Websocket server not created 29 | console.error("WebSocket server not found but 'createTRPCWebSocketServer' had been called"); 30 | // Prerendering with websockets is not implemented 31 | // TODO: Fallback to REST for non subscriptions? 32 | process.exit(1); 33 | } else { 34 | wss.removeAllListeners(); 35 | applyWSSHandler({ 36 | createContext, 37 | router, 38 | wss 39 | }); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /docs/src/lib/components/home/LogoTrpc.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 13 | 14 | -------------------------------------------------------------------------------- /docs/src/lib/components/home/LogoNetlify.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /examples/bookstall/prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | } 4 | 5 | datasource db { 6 | provider = "sqlite" 7 | url = "file:./bookstall.db" 8 | } 9 | 10 | model User { 11 | id String @id @default(cuid()) 12 | name String 13 | email String @unique 14 | passwordHash String 15 | updatedAt DateTime @updatedAt 16 | 17 | updatedAuthors Author[] 18 | updatedBooks Book[] 19 | updatedStores Store[] 20 | } 21 | 22 | model Author { 23 | id String @id @default(cuid()) 24 | firstName String 25 | lastName String 26 | bio String? 27 | updatedAt DateTime @updatedAt 28 | updatedByUserId String? 29 | 30 | books Book[] 31 | updatedBy User? @relation(fields: [updatedByUserId], references: [id]) 32 | 33 | @@unique([firstName, lastName]) 34 | } 35 | 36 | model Book { 37 | id String @id @default(cuid()) 38 | title String 39 | excerpt String? 40 | authorId String 41 | price Decimal 42 | updatedAt DateTime @updatedAt 43 | updatedByUserId String? 44 | author Author @relation(fields: [authorId], references: [id], onDelete: Cascade) 45 | 46 | stores Store[] 47 | updatedBy User? @relation(fields: [updatedByUserId], references: [id]) 48 | } 49 | 50 | model Store { 51 | id String @id @default(cuid()) 52 | name String 53 | updatedAt DateTime @updatedAt 54 | updatedByUserId String? 55 | 56 | books Book[] 57 | updatedBy User? @relation(fields: [updatedByUserId], references: [id]) 58 | } 59 | -------------------------------------------------------------------------------- /examples/bookstall/src/lib/components/inputs/TextareaInput.svelte: -------------------------------------------------------------------------------- 1 | 30 | 31 |