@trpc/next 11.0.0-next.91 → 11.0.0-rc.329
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/app-dir/client.d.ts +3 -3
- package/dist/app-dir/client.d.ts.map +1 -1
- package/dist/app-dir/client.js +5 -105
- package/dist/app-dir/client.mjs +4 -102
- package/dist/app-dir/create-action-hook.d.ts +18 -6
- package/dist/app-dir/create-action-hook.d.ts.map +1 -1
- package/dist/app-dir/create-action-hook.js +108 -0
- package/dist/app-dir/create-action-hook.mjs +105 -0
- package/dist/app-dir/formDataToObject.js +34 -0
- package/dist/app-dir/formDataToObject.mjs +32 -0
- package/dist/app-dir/links/nextCache.d.ts +4 -3
- package/dist/app-dir/links/nextCache.d.ts.map +1 -1
- package/dist/app-dir/links/nextCache.js +9 -10
- package/dist/app-dir/links/nextCache.mjs +8 -7
- package/dist/app-dir/links/nextHttp.d.ts +11 -5
- package/dist/app-dir/links/nextHttp.d.ts.map +1 -1
- package/dist/app-dir/links/nextHttp.js +22 -23
- package/dist/app-dir/links/nextHttp.mjs +22 -21
- package/dist/app-dir/server.d.ts +19 -12
- package/dist/app-dir/server.d.ts.map +1 -1
- package/dist/app-dir/server.js +39 -55
- package/dist/app-dir/server.mjs +29 -43
- package/dist/app-dir/shared.d.ts +19 -13
- package/dist/app-dir/shared.d.ts.map +1 -1
- package/dist/{shared-e49b9cdc.js → app-dir/shared.js} +1 -1
- package/dist/{shared-f6996341.mjs → app-dir/shared.mjs} +2 -2
- package/dist/app-dir/types.d.ts +23 -11
- package/dist/app-dir/types.d.ts.map +1 -1
- package/dist/bundle-analysis.json +56 -44
- package/dist/createTRPCNext.d.ts +10 -8
- package/dist/createTRPCNext.d.ts.map +1 -1
- package/dist/createTRPCNext.js +38 -0
- package/dist/createTRPCNext.mjs +36 -0
- package/dist/index.js +4 -190
- package/dist/index.mjs +2 -185
- package/dist/ssrPrepass.d.ts +3 -0
- package/dist/ssrPrepass.d.ts.map +1 -0
- package/dist/ssrPrepass.js +139 -0
- package/dist/ssrPrepass.mjs +137 -0
- package/dist/withTRPC.d.ts +41 -13
- package/dist/withTRPC.d.ts.map +1 -1
- package/dist/withTRPC.js +86 -0
- package/dist/withTRPC.mjs +84 -0
- package/package.json +36 -25
- package/src/app-dir/client.ts +4 -4
- package/src/app-dir/create-action-hook.tsx +49 -19
- package/src/app-dir/links/nextCache.ts +20 -8
- package/src/app-dir/links/nextHttp.ts +50 -30
- package/src/app-dir/server.ts +86 -34
- package/src/app-dir/shared.ts +52 -25
- package/src/app-dir/types.ts +41 -29
- package/src/createTRPCNext.tsx +25 -16
- package/src/ssrPrepass.ts +185 -0
- package/src/withTRPC.tsx +102 -180
- package/ssrPrepass/index.d.ts +1 -0
- package/ssrPrepass/index.js +1 -0
- package/dist/shared-642894f4.js +0 -19
package/src/withTRPC.tsx
CHANGED
|
@@ -2,102 +2,103 @@
|
|
|
2
2
|
* Heavily based on urql's ssr
|
|
3
3
|
* https://github.com/FormidableLabs/urql/blob/main/packages/next-urql/src/with-urql-client.ts
|
|
4
4
|
*/
|
|
5
|
+
import type { DehydratedState, QueryClient } from '@tanstack/react-query';
|
|
6
|
+
import { HydrationBoundary, QueryClientProvider } from '@tanstack/react-query';
|
|
7
|
+
import type { CreateTRPCClientOptions, TRPCUntypedClient } from '@trpc/client';
|
|
8
|
+
import type { CoercedTransformerParameters } from '@trpc/client/unstable-internals';
|
|
5
9
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} from '@tanstack/react-query';
|
|
12
|
-
import {
|
|
13
|
-
CreateTRPCClientOptions,
|
|
14
|
-
createTRPCUntypedClient,
|
|
15
|
-
TRPCUntypedClient,
|
|
16
|
-
} from '@trpc/client';
|
|
17
|
-
import { TRPCClientError, TRPCClientErrorLike } from '@trpc/react-query';
|
|
18
|
-
import {
|
|
19
|
-
createRootHooks,
|
|
10
|
+
getTransformer,
|
|
11
|
+
type TransformerOptions,
|
|
12
|
+
} from '@trpc/client/unstable-internals';
|
|
13
|
+
import type { TRPCClientError } from '@trpc/react-query';
|
|
14
|
+
import type {
|
|
20
15
|
CreateTRPCReactOptions,
|
|
21
16
|
CreateTRPCReactQueryClientConfig,
|
|
22
|
-
getQueryClient,
|
|
23
17
|
} from '@trpc/react-query/shared';
|
|
24
|
-
import
|
|
25
|
-
import type {
|
|
26
|
-
|
|
18
|
+
import { createRootHooks, getQueryClient } from '@trpc/react-query/shared';
|
|
19
|
+
import type {
|
|
20
|
+
AnyRouter,
|
|
21
|
+
Dict,
|
|
22
|
+
inferClientTypes,
|
|
23
|
+
ResponseMeta,
|
|
24
|
+
} from '@trpc/server/unstable-core-do-not-import';
|
|
25
|
+
import type {
|
|
27
26
|
AppContextType,
|
|
28
27
|
AppPropsType,
|
|
29
28
|
NextComponentType,
|
|
30
29
|
NextPageContext,
|
|
31
30
|
} from 'next/dist/shared/lib/utils';
|
|
32
|
-
import { NextRouter } from 'next/router';
|
|
33
|
-
import React, {
|
|
34
|
-
import ssrPrepass from 'react-ssr-prepass';
|
|
31
|
+
import type { NextRouter } from 'next/router';
|
|
32
|
+
import React, { useState } from 'react';
|
|
35
33
|
|
|
36
|
-
function transformQueryOrMutationCacheErrors<
|
|
37
|
-
TState extends
|
|
38
|
-
| DehydratedState['mutations'][0]
|
|
39
|
-
| DehydratedState['queries'][0],
|
|
40
|
-
>(result: TState): TState {
|
|
41
|
-
const error = result.state.error as Maybe<TRPCClientError<any>>;
|
|
42
|
-
if (error instanceof Error && error.name === 'TRPCClientError') {
|
|
43
|
-
const newError: TRPCClientErrorLike<any> = {
|
|
44
|
-
message: error.message,
|
|
45
|
-
data: error.data,
|
|
46
|
-
shape: error.shape,
|
|
47
|
-
};
|
|
48
|
-
return {
|
|
49
|
-
...result,
|
|
50
|
-
state: {
|
|
51
|
-
...result.state,
|
|
52
|
-
error: newError,
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
return result;
|
|
57
|
-
}
|
|
58
34
|
export type WithTRPCConfig<TRouter extends AnyRouter> =
|
|
59
35
|
CreateTRPCClientOptions<TRouter> &
|
|
60
36
|
CreateTRPCReactQueryClientConfig & {
|
|
61
37
|
abortOnUnmount?: boolean;
|
|
62
38
|
};
|
|
63
39
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
40
|
+
type WithTRPCOptions<TRouter extends AnyRouter> =
|
|
41
|
+
CreateTRPCReactOptions<TRouter> & {
|
|
42
|
+
config: (info: { ctx?: NextPageContext }) => WithTRPCConfig<TRouter>;
|
|
43
|
+
} & TransformerOptions<inferClientTypes<TRouter>>;
|
|
44
|
+
|
|
45
|
+
export type TRPCPrepassHelper = (opts: {
|
|
46
|
+
parent: WithTRPCSSROptions<AnyRouter>;
|
|
47
|
+
WithTRPC: NextComponentType<any, any, any>;
|
|
48
|
+
AppOrPage: NextComponentType<any, any, any>;
|
|
49
|
+
}) => void;
|
|
50
|
+
export type WithTRPCSSROptions<TRouter extends AnyRouter> =
|
|
51
|
+
WithTRPCOptions<TRouter> & {
|
|
52
|
+
/**
|
|
53
|
+
* If you enable this, you also need to add a `ssrPrepass`-prop
|
|
54
|
+
* @link https://trpc.io/docs/client/nextjs/ssr
|
|
55
|
+
*/
|
|
56
|
+
ssr:
|
|
57
|
+
| true
|
|
58
|
+
| ((opts: { ctx: NextPageContext }) => boolean | Promise<boolean>);
|
|
59
|
+
responseMeta?: (opts: {
|
|
60
|
+
ctx: NextPageContext;
|
|
61
|
+
clientErrors: TRPCClientError<TRouter>[];
|
|
62
|
+
}) => ResponseMeta;
|
|
63
|
+
/**
|
|
64
|
+
* use `import { ssrPrepass } from '@trpc/next/ssrPrepass'`
|
|
65
|
+
* @link https://trpc.io/docs/client/nextjs/ssr
|
|
66
|
+
*/
|
|
67
|
+
ssrPrepass: TRPCPrepassHelper;
|
|
68
|
+
};
|
|
68
69
|
|
|
69
|
-
export
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
70
|
+
export type WithTRPCNoSSROptions<TRouter extends AnyRouter> =
|
|
71
|
+
WithTRPCOptions<TRouter> & {
|
|
72
|
+
ssr?: false;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export type TRPCPrepassProps<
|
|
76
|
+
TRouter extends AnyRouter,
|
|
77
|
+
TSSRContext extends NextPageContext = NextPageContext,
|
|
78
|
+
> = {
|
|
79
|
+
config: WithTRPCConfig<TRouter>;
|
|
80
|
+
queryClient: QueryClient;
|
|
81
|
+
trpcClient: TRPCUntypedClient<TRouter>;
|
|
82
|
+
ssrState: 'prepass';
|
|
83
|
+
ssrContext: TSSRContext;
|
|
84
|
+
};
|
|
81
85
|
|
|
82
86
|
export function withTRPC<
|
|
83
87
|
TRouter extends AnyRouter,
|
|
84
88
|
TSSRContext extends NextPageContext = NextPageContext,
|
|
85
89
|
>(opts: WithTRPCNoSSROptions<TRouter> | WithTRPCSSROptions<TRouter>) {
|
|
86
90
|
const { config: getClientConfig } = opts;
|
|
91
|
+
const transformer = getTransformer(
|
|
92
|
+
(opts as CoercedTransformerParameters).transformer,
|
|
93
|
+
);
|
|
87
94
|
|
|
88
|
-
type
|
|
89
|
-
config: WithTRPCConfig<TRouter>;
|
|
90
|
-
queryClient: QueryClient;
|
|
91
|
-
trpcClient: TRPCUntypedClient<TRouter>;
|
|
92
|
-
ssrState: 'prepass';
|
|
93
|
-
ssrContext: TSSRContext;
|
|
94
|
-
};
|
|
95
|
+
type $PrepassProps = TRPCPrepassProps<TRouter, TSSRContext>;
|
|
95
96
|
return (AppOrPage: NextComponentType<any, any, any>): NextComponentType => {
|
|
96
97
|
const trpc = createRootHooks<TRouter, TSSRContext>(opts);
|
|
97
98
|
|
|
98
99
|
const WithTRPC = (
|
|
99
100
|
props: AppPropsType<NextRouter, any> & {
|
|
100
|
-
trpc?:
|
|
101
|
+
trpc?: $PrepassProps;
|
|
101
102
|
},
|
|
102
103
|
) => {
|
|
103
104
|
const [prepassProps] = useState(() => {
|
|
@@ -108,6 +109,7 @@ export function withTRPC<
|
|
|
108
109
|
const config = getClientConfig({});
|
|
109
110
|
const queryClient = getQueryClient(config);
|
|
110
111
|
const trpcClient = trpc.createClient(config);
|
|
112
|
+
|
|
111
113
|
return {
|
|
112
114
|
abortOnUnmount: config.abortOnUnmount,
|
|
113
115
|
queryClient,
|
|
@@ -120,10 +122,16 @@ export function withTRPC<
|
|
|
120
122
|
const { queryClient, trpcClient, ssrState, ssrContext } = prepassProps;
|
|
121
123
|
|
|
122
124
|
// allow normal components to be wrapped, not just app/pages
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
const trpcState = props.pageProps?.trpcState;
|
|
126
|
+
|
|
127
|
+
const hydratedState: DehydratedState | undefined = React.useMemo(() => {
|
|
128
|
+
if (!trpcState) {
|
|
129
|
+
return trpcState;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return transformer.input.deserialize(trpcState);
|
|
133
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
134
|
+
}, [trpcState, trpcClient]);
|
|
127
135
|
|
|
128
136
|
return (
|
|
129
137
|
<trpc.Provider
|
|
@@ -142,123 +150,37 @@ export function withTRPC<
|
|
|
142
150
|
);
|
|
143
151
|
};
|
|
144
152
|
|
|
145
|
-
if (
|
|
146
|
-
|
|
147
|
-
|
|
153
|
+
if (opts.ssr) {
|
|
154
|
+
opts.ssrPrepass({
|
|
155
|
+
parent: opts,
|
|
156
|
+
AppOrPage,
|
|
157
|
+
WithTRPC,
|
|
158
|
+
});
|
|
159
|
+
} else if (AppOrPage.getInitialProps) {
|
|
160
|
+
// Allow combining `getServerSideProps` and `getInitialProps`
|
|
148
161
|
|
|
162
|
+
WithTRPC.getInitialProps = async (appOrPageCtx: AppContextType) => {
|
|
149
163
|
// Determine if we are wrapping an App component or a Page component.
|
|
150
164
|
const isApp = !!appOrPageCtx.Component;
|
|
151
|
-
const ctx: NextPageContext = isApp
|
|
152
|
-
? appOrPageCtx.ctx
|
|
153
|
-
: (appOrPageCtx as any as NextPageContext);
|
|
154
165
|
|
|
155
166
|
// Run the wrapped component's getInitialProps function.
|
|
156
167
|
let pageProps: Dict<unknown> = {};
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
const getAppTreeProps = (props: Record<string, unknown>) =>
|
|
171
|
-
isApp ? { pageProps: props } : props;
|
|
172
|
-
|
|
173
|
-
if (typeof window !== 'undefined' || !opts.ssr) {
|
|
174
|
-
return getAppTreeProps(pageProps);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const config = getClientConfig({ ctx });
|
|
178
|
-
const trpcClient = createTRPCUntypedClient(config);
|
|
179
|
-
const queryClient = getQueryClient(config);
|
|
180
|
-
|
|
181
|
-
const trpcProp: TRPCPrepassProps = {
|
|
182
|
-
config,
|
|
183
|
-
trpcClient,
|
|
184
|
-
queryClient,
|
|
185
|
-
ssrState: 'prepass',
|
|
186
|
-
ssrContext: ctx as TSSRContext,
|
|
168
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
169
|
+
const originalProps = await AppOrPage.getInitialProps!(
|
|
170
|
+
appOrPageCtx as any,
|
|
171
|
+
);
|
|
172
|
+
const originalPageProps = isApp
|
|
173
|
+
? originalProps.pageProps ?? {}
|
|
174
|
+
: originalProps;
|
|
175
|
+
|
|
176
|
+
pageProps = {
|
|
177
|
+
...originalPageProps,
|
|
178
|
+
...pageProps,
|
|
187
179
|
};
|
|
188
|
-
const
|
|
189
|
-
pageProps
|
|
190
|
-
trpc: trpcProp,
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
// Run the prepass step on AppTree. This will run all trpc queries on the server.
|
|
194
|
-
// multiple prepass ensures that we can do batching on the server
|
|
195
|
-
while (true) {
|
|
196
|
-
// render full tree
|
|
197
|
-
await ssrPrepass(createElement(AppTree, prepassProps as any));
|
|
198
|
-
if (!queryClient.isFetching()) {
|
|
199
|
-
// the render didn't cause the queryClient to fetch anything
|
|
200
|
-
break;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// wait until the query cache has settled it's promises
|
|
204
|
-
await new Promise<void>((resolve) => {
|
|
205
|
-
const unsub = queryClient.getQueryCache().subscribe((event) => {
|
|
206
|
-
if (event?.query.getObserversCount() === 0) {
|
|
207
|
-
resolve();
|
|
208
|
-
unsub();
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
const dehydratedCache = dehydrate(queryClient, {
|
|
214
|
-
shouldDehydrateQuery() {
|
|
215
|
-
// makes sure errors are also dehydrated
|
|
216
|
-
return true;
|
|
217
|
-
},
|
|
218
|
-
});
|
|
219
|
-
// since error instances can't be serialized, let's make them into `TRPCClientErrorLike`-objects
|
|
220
|
-
const dehydratedCacheWithErrors = {
|
|
221
|
-
...dehydratedCache,
|
|
222
|
-
queries: dehydratedCache.queries.map(
|
|
223
|
-
transformQueryOrMutationCacheErrors,
|
|
224
|
-
),
|
|
225
|
-
mutations: dehydratedCache.mutations.map(
|
|
226
|
-
transformQueryOrMutationCacheErrors,
|
|
227
|
-
),
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
// dehydrate query client's state and add it to the props
|
|
231
|
-
pageProps.trpcState =
|
|
232
|
-
trpcClient.runtime.combinedTransformer.output.serialize(
|
|
233
|
-
dehydratedCacheWithErrors,
|
|
234
|
-
);
|
|
235
|
-
|
|
236
|
-
const appTreeProps = getAppTreeProps(pageProps);
|
|
237
|
-
|
|
238
|
-
const meta =
|
|
239
|
-
opts.responseMeta?.({
|
|
240
|
-
ctx,
|
|
241
|
-
clientErrors: [
|
|
242
|
-
...dehydratedCache.queries,
|
|
243
|
-
...dehydratedCache.mutations,
|
|
244
|
-
]
|
|
245
|
-
.map((v) => v.state.error)
|
|
246
|
-
.flatMap((err) =>
|
|
247
|
-
err instanceof Error && err.name === 'TRPCClientError'
|
|
248
|
-
? [err as TRPCClientError<TRouter>]
|
|
249
|
-
: [],
|
|
250
|
-
),
|
|
251
|
-
}) ?? {};
|
|
180
|
+
const getAppTreeProps = (props: Dict<unknown>) =>
|
|
181
|
+
isApp ? { pageProps: props } : props;
|
|
252
182
|
|
|
253
|
-
|
|
254
|
-
if (typeof value === 'string') {
|
|
255
|
-
ctx.res?.setHeader(key, value);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
if (meta.status && ctx.res) {
|
|
259
|
-
ctx.res.statusCode = meta.status;
|
|
260
|
-
}
|
|
261
|
-
return appTreeProps;
|
|
183
|
+
return getAppTreeProps(pageProps);
|
|
262
184
|
};
|
|
263
185
|
}
|
|
264
186
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../dist/ssrPrepass';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('../dist/ssrPrepass');
|
package/dist/shared-642894f4.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import '@trpc/server/shared';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @internal
|
|
5
|
-
*/
|
|
6
|
-
function generateCacheTag(procedurePath, input) {
|
|
7
|
-
return input
|
|
8
|
-
? `${procedurePath}?input=${JSON.stringify(input)}`
|
|
9
|
-
: procedurePath;
|
|
10
|
-
}
|
|
11
|
-
function isFormData(value) {
|
|
12
|
-
if (typeof FormData === 'undefined') {
|
|
13
|
-
// FormData is not supported
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
return value instanceof FormData;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export { generateCacheTag as g, isFormData as i };
|