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 |
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 |
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 |
11 |
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 |
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 |
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 |
15 | Welcome to Bookstall, a sample SvelteKit application built to illustrate the usage of ✨
16 | trpc-sveltekit.
19 |
20 | No REST API routes are being used white you're managing books, authors and stores — all data is transferred
21 | through:
22 |
23 |
24 |
25 |
26 | tRPC
27 |
28 |
29 |
30 | You are {data.isAuthenticated ? '' : 'not'} authenticated{data.userName
31 | ? ` as ${data.userName}`
32 | : ''}.
33 |
34 | {#if data.isAuthenticated}
35 | You will be able to browse and edit the books, authors and stores.
36 | {:else}
37 | You will be able to browse the books, authors and stores,
38 |
39 | but you'll need to authenticate in order to edit them.
40 | {/if}
41 |
14 | I'm Ionut-Cristian Florescu, a full-stack developer from Bucharest, Romania, EU, with more than 20
15 | years of experience in building commercial web applications and open-source projects.
16 |
17 | tRPC-SvelteKit is one of my dearest open-source projects.
18 |
19 |
20 |
21 | You can learn more about what I do by visiting my profiles on GitHub
26 |
33 |
40 | or LinkedIn,
41 | but since you are on this page, you probably have a pretty good idea of how my skills could help
42 | you.
43 |
44 |
45 |
46 | So, if you want to hire my services, don't hesitate to drop me a line at the email address listed
47 | in my GitHub profile. I'm currently getting a constant flow of approaches from recruiters, some of
48 | them relevant, others not so relevant. Mentioning "tRPC-SvelteKit" in your text would help me
49 | prioritize your message.
50 |
39 | 4
40 | Add this handle to your SvelteKit app
41 | hooks:
42 |
43 |
44 |
45 |
46 |
47 | If you have your own logic to place in the server hook, have a look at the sequence helper function in the SvelteKit docs.
52 |
53 |
54 |
55 | 5
56 | Define a helper function to easily use the tRPC client in your pages:
57 |
58 |
59 |
60 |
61 |
62 | 6
63 | Call the tRPC procedures in your pages:
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | Remember
73 |
74 |
75 |
76 | The trpc-sveltekit package exports two functions: createTRPCHandle and
77 | createTRPCClient.
78 |
79 | The former is used in your SvelteKit app hooks, the latter is used in your pages.
80 |
46 |
47 |
136 |
--------------------------------------------------------------------------------
/docs/src/lib/constants.ts:
--------------------------------------------------------------------------------
1 | import IconFileCode from '$lib/icons/IconFileCode.svelte';
2 | import IconFileDatabase from '$lib/icons/IconFileDatabase.svelte';
3 | import IconFolder from '$lib/icons/IconFolder.svelte';
4 | import IconHome from '$lib/icons/IconHome.svelte';
5 | import IconLock from '$lib/icons/IconLock.svelte';
6 | import IconRocket from '$lib/icons/IconRocket.svelte';
7 | import IconTools from '$lib/icons/IconTools.svelte';
8 | import IconBulb from './icons/IconBulb.svelte';
9 | import IconErrorHandling from './icons/IconErrorHandling.svelte';
10 | import IconHeartHandshake from './icons/IconHeartHandshake.svelte';
11 | import IconLifeBuoy from './icons/IconLifeBuoy.svelte';
12 | import IconSpeakerphone from './icons/IconSpeakerphone.svelte';
13 | import IconWebSocket from './icons/IconWebSocket.svelte';
14 |
15 | export const GITHUB_PAGES_ROOT = 'https://icflorescu.github.io/trpc-sveltekit';
16 | export const AUTHOR_URL = 'https://github.com/icflorescu';
17 | export const REPO_URL = `${AUTHOR_URL}/trpc-sveltekit`;
18 | export const BADGE_COLOR_CODE = '1095c1';
19 |
20 | export const PAGES: {
21 | title: string | string[];
22 | path: string;
23 | icon: typeof IconHome;
24 | customPageTitle?: string;
25 | pageDescription: string;
26 | }[] = [
27 | {
28 | title: 'Home',
29 | path: '/',
30 | icon: IconHome,
31 | customPageTitle: 'tRPC-SvelteKit: end-to-end typesafe APIs for SvelteKit',
32 | pageDescription:
33 | 'tRPC-SvelteKit is a tRPC adapter that makes it easy to build end-to-end typesafe APIs for your SvelteKit applications.'
34 | },
35 | {
36 | title: 'Getting started',
37 | path: '/getting-started',
38 | icon: IconRocket,
39 | pageDescription: 'Get started with tRPC-SvelteKit'
40 | },
41 | {
42 | title: 'Page data',
43 | path: '/page-data',
44 | icon: IconFileCode,
45 | pageDescription: 'How to load SvelteKit page data with tRPC'
46 | },
47 | {
48 | title: 'Page server data',
49 | path: '/page-server-data',
50 | icon: IconFileDatabase,
51 | pageDescription: 'How to load SvelteKit server data with tRPC'
52 | },
53 | {
54 | title: 'Suggested structure',
55 | path: '/suggested-structure',
56 | icon: IconFolder,
57 | pageDescription: 'Suggested structure for a tRPC-SvelteKit application'
58 | },
59 | {
60 | title: 'Authentication',
61 | path: '/authentication',
62 | icon: IconLock,
63 | pageDescription: 'How to add authentication to a tRPC-SvelteKit application'
64 | },
65 | {
66 | title: 'Handling errors',
67 | path: '/handling-errors',
68 | icon: IconErrorHandling,
69 | pageDescription: 'How to handle errors in a tRPC-SvelteKit application'
70 | },
71 | {
72 | title: 'Recipes and caveats',
73 | path: '/recipes-and-caveats',
74 | icon: IconTools,
75 | pageDescription: 'Recipes and caveats for tRPC-SvelteKit'
76 | },
77 | {
78 | title: 'Using with Svelte Query',
79 | path: '/using-with-svelte-query',
80 | icon: IconBulb,
81 | pageDescription: 'How to use tRPC-SvelteKit with Svelte Query'
82 | },
83 | {
84 | title: ['WebSocket support', '(experimental)'],
85 | path: '/experimental-websocket-support',
86 | icon: IconWebSocket,
87 | pageDescription: 'Experimental WebSocket support in tRPC-SvelteKit'
88 | },
89 | {
90 | title: 'Contribute and support',
91 | path: '/contribute-and-support',
92 | icon: IconLifeBuoy,
93 | pageDescription: 'Contribute to tRPC-SvelteKit and support the project'
94 | },
95 | {
96 | title: 'Acknowledgements',
97 | path: '/acknowledgements',
98 | icon: IconSpeakerphone,
99 | pageDescription: 'Huge thanks to tRPC-SvelteKit sponsors'
100 | },
101 | {
102 | title: 'Hire the author',
103 | path: '/hire-the-author',
104 | icon: IconHeartHandshake,
105 | pageDescription: 'Hire the author of tRPC-SvleteKit'
106 | }
107 | ];
108 |
--------------------------------------------------------------------------------
/docs/src/routes/recipes-and-caveats/+page.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
Recipes and caveats
9 |
10 |
Custom HTTP headers
11 |
12 |
13 | The createTRPCClient method optionally accepts a headers option, which
14 | can be useful, for example, to set an Authorization header.
15 |
16 |
17 |
Setting response headers and cookies
18 |
19 |
20 | To change the headers of the response, you want to use the event provided in
21 | getContext. You may also pass the event into the context, so that it can
22 | be accessed in your procedures.
23 |
24 |
25 |
26 | You can then use event.setHeaders and event.cookies to edit the headers.
27 |
28 |
29 |
30 |
31 |
Using custom data transformers
32 |
33 |
34 | The createTRPCClient method optionally accepts a transformer option.
35 | Please refer to
36 | this section in the tRPC.io documentation
39 | for more information, and keep in mind that you'll have to use the same transformer when
40 | you're defining the router and when you're creating the client.
41 |
42 |
43 | If you're looking for a convenient transformer based on superjson
48 | with
49 | Decimal.js
50 | support, consider using the
51 | trpc-transformer
54 | package. Keep in mind that you'll have to install the superjson and
55 | decimal.js peer dependencies as well.
56 |
71 | The createHTTPHandle method conveniently allows you to specify a
72 | responseMeta function.
73 |
74 |
75 |
Inferring types
76 |
77 |
78 | It is often useful to wrap functionality of your tRPC client API within other functions. For this
79 | purpose, it's necessary to be able to infer input types and output types generated by your tRPC
80 | router. The@trpc/server package exports two helper types to assist with inferring
81 | these types from your router, namely inferRouterInputs and
82 | inferRouterOutputs. Please refer to
83 | this section of the tRPC.io documentation
86 | for more information.
87 |
88 |
89 |
90 | To make your code faster to type and easier to read, you could further refine these helper types
91 | when defining your router:
92 |
93 |
94 |
95 |
96 |
Then, you could use the helper types in your pages code like so:
97 |
98 |
99 |
100 |
Reserved path prefix
101 |
102 |
103 | Invoking the createHTTPHandle method reserves the /trpc path prefix for
104 | the tRPC API. This means that you cannot use this prefix for any other purpose. If you need to use
105 | this prefix for other purposes, you can use the url option to change the reserved prefix.
106 |