@trpc/next 10.0.0-alpha.8 → 10.0.0-proxy-alpha.53
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 +84 -1
- package/dist/index.js +163 -219
- package/dist/index.mjs +164 -215
- package/dist/setupNext.d.ts +98 -45
- package/dist/setupNext.d.ts.map +1 -1
- package/dist/withTRPC.d.ts +5 -5
- package/dist/withTRPC.d.ts.map +1 -1
- package/package.json +21 -21
- package/src/setupNext.tsx +14 -6
- package/src/withTRPC.tsx +32 -24
- package/dist/index.ts.js +0 -1
package/README.md
CHANGED
|
@@ -1,3 +1,86 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://trpc.io/"><img src="../../www/static/img/logo-text.svg" alt="tRPC" height="130"/></a>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>End-to-end typesafe APIs made easy</strong>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<!-- TODO: replace with new version GIF -->
|
|
11
|
+
<img src="https://storage.googleapis.com/trpc/trpcgif.gif" alt="Demo" />
|
|
12
|
+
</p>
|
|
13
|
+
|
|
1
14
|
# `@trpc/next`
|
|
2
15
|
|
|
3
|
-
|
|
16
|
+
> Connect a tRPC router to Next.js.
|
|
17
|
+
|
|
18
|
+
## Documentation
|
|
19
|
+
|
|
20
|
+
Full documentation for `@trpc/next` can be found [here](https://trpc.io/docs/nextjs)
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# npm
|
|
26
|
+
npm install @trpc/next @trpc/react react-query
|
|
27
|
+
|
|
28
|
+
# Yarn
|
|
29
|
+
yarn add @trpc/next @trpc/react react-query
|
|
30
|
+
|
|
31
|
+
# pnpm
|
|
32
|
+
pnpm add @trpc/next @trpc/react react-query
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Basic Example
|
|
36
|
+
|
|
37
|
+
Setup tRPC in `utils/trpc.ts`.
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { setupTRPC } from '@trpc/next';
|
|
41
|
+
// Import the router type from your server file
|
|
42
|
+
import type { AppRouter } from '../pages/api/[trpc].ts';
|
|
43
|
+
|
|
44
|
+
export const trpc = setupTRPC<AppRouter>({
|
|
45
|
+
config() {
|
|
46
|
+
return {
|
|
47
|
+
url: 'http://localhost:3000/api/trpc',
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
ssr: true,
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Hook up tRPC inside `_app.tsx`.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { trpc } from '~/utils/trpc';
|
|
58
|
+
|
|
59
|
+
const App = ({ Component, pageProps }) => {
|
|
60
|
+
return <Component {...pageProps} />;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export default trpc.withTRPC(App);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Now you can query your API in any component.
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { trpc } from '~/utils/trpc';
|
|
70
|
+
|
|
71
|
+
export function Hello() {
|
|
72
|
+
const { data, error, status } = trpc.proxy.greeting.useQuery({
|
|
73
|
+
name: 'tRPC',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (error) {
|
|
77
|
+
return <p>{error.message}</p>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (status !== 'success') {
|
|
81
|
+
return <p>Loading...</p>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return <div>{data && <p>{data.greeting}</p>}</div>;
|
|
85
|
+
}
|
|
86
|
+
```
|
package/dist/index.js
CHANGED
|
@@ -2,255 +2,199 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var
|
|
6
|
-
var _asyncToGenerator = require('@babel/runtime/helpers/asyncToGenerator');
|
|
7
|
-
var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
|
|
8
|
-
var _defineProperty = require('@babel/runtime/helpers/defineProperty');
|
|
9
|
-
var _regeneratorRuntime = require('@babel/runtime/regenerator');
|
|
5
|
+
var reactQuery = require('@tanstack/react-query');
|
|
10
6
|
var react = require('@trpc/react');
|
|
11
7
|
var React = require('react');
|
|
12
|
-
var reactQuery = require('react-query');
|
|
13
8
|
var ssrPrepass = require('react-ssr-prepass');
|
|
14
9
|
|
|
15
10
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
16
11
|
|
|
17
|
-
var _toConsumableArray__default = /*#__PURE__*/_interopDefaultLegacy(_toConsumableArray);
|
|
18
|
-
var _asyncToGenerator__default = /*#__PURE__*/_interopDefaultLegacy(_asyncToGenerator);
|
|
19
|
-
var _slicedToArray__default = /*#__PURE__*/_interopDefaultLegacy(_slicedToArray);
|
|
20
|
-
var _defineProperty__default = /*#__PURE__*/_interopDefaultLegacy(_defineProperty);
|
|
21
|
-
var _regeneratorRuntime__default = /*#__PURE__*/_interopDefaultLegacy(_regeneratorRuntime);
|
|
22
12
|
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
23
13
|
var ssrPrepass__default = /*#__PURE__*/_interopDefaultLegacy(ssrPrepass);
|
|
24
14
|
|
|
25
|
-
function
|
|
15
|
+
function extends_() {
|
|
16
|
+
extends_ = Object.assign || function (target) {
|
|
17
|
+
for (var i = 1; i < arguments.length; i++) {
|
|
18
|
+
var source = arguments[i];
|
|
26
19
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
for (var key in source) {
|
|
21
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
22
|
+
target[key] = source[key];
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
31
26
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
message: error.message,
|
|
35
|
-
data: error.data,
|
|
36
|
-
shape: error.shape
|
|
37
|
-
};
|
|
38
|
-
return _objectSpread(_objectSpread({}, result), {}, {
|
|
39
|
-
state: _objectSpread(_objectSpread({}, result.state), {}, {
|
|
40
|
-
error: newError
|
|
41
|
-
})
|
|
42
|
-
});
|
|
43
|
-
}
|
|
27
|
+
return target;
|
|
28
|
+
};
|
|
44
29
|
|
|
45
|
-
return
|
|
30
|
+
return extends_.apply(this, arguments);
|
|
46
31
|
}
|
|
47
32
|
|
|
48
|
-
function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
var trpc = react.createReactQueryHooks(opts);
|
|
52
|
-
|
|
53
|
-
var WithTRPC = function WithTRPC(props) {
|
|
54
|
-
var _props$pageProps;
|
|
55
|
-
|
|
56
|
-
var _useState = React.useState(function () {
|
|
57
|
-
if (props.trpc) {
|
|
58
|
-
return props.trpc;
|
|
59
|
-
}
|
|
33
|
+
function _extends() {
|
|
34
|
+
return extends_.apply(this, arguments);
|
|
35
|
+
}
|
|
60
36
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
37
|
+
function transformQueryOrMutationCacheErrors(result) {
|
|
38
|
+
const error = result.state.error;
|
|
39
|
+
if (error instanceof Error && error.name === 'TRPCClientError') {
|
|
40
|
+
const newError = {
|
|
41
|
+
message: error.message,
|
|
42
|
+
data: error.data,
|
|
43
|
+
shape: error.shape
|
|
44
|
+
};
|
|
64
45
|
return {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
46
|
+
...result,
|
|
47
|
+
state: {
|
|
48
|
+
...result.state,
|
|
49
|
+
error: newError
|
|
50
|
+
}
|
|
69
51
|
};
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
case 10:
|
|
123
|
-
getAppTreeProps = function getAppTreeProps(props) {
|
|
124
|
-
return isApp ? {
|
|
125
|
-
pageProps: props
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
function withTRPC(opts) {
|
|
56
|
+
const { config: getClientConfig } = opts;
|
|
57
|
+
return (AppOrPage)=>{
|
|
58
|
+
const trpc = react.createReactQueryHooks();
|
|
59
|
+
const WithTRPC = (props)=>{
|
|
60
|
+
const [{ queryClient , trpcClient , ssrState , ssrContext }] = React.useState(()=>{
|
|
61
|
+
if (props.trpc) {
|
|
62
|
+
return props.trpc;
|
|
63
|
+
}
|
|
64
|
+
const config = getClientConfig({});
|
|
65
|
+
const queryClient = new reactQuery.QueryClient(config.queryClientConfig);
|
|
66
|
+
const trpcClient = trpc.createClient(config);
|
|
67
|
+
return {
|
|
68
|
+
queryClient,
|
|
69
|
+
trpcClient,
|
|
70
|
+
ssrState: opts.ssr ? 'mounting' : false,
|
|
71
|
+
ssrContext: null
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
const hydratedState = trpc.useDehydratedState(trpcClient, props.pageProps?.trpcState);
|
|
75
|
+
return /*#__PURE__*/ React__default["default"].createElement(trpc.Provider, {
|
|
76
|
+
client: trpcClient,
|
|
77
|
+
queryClient: queryClient,
|
|
78
|
+
ssrState: ssrState,
|
|
79
|
+
ssrContext: ssrContext
|
|
80
|
+
}, /*#__PURE__*/ React__default["default"].createElement(reactQuery.QueryClientProvider, {
|
|
81
|
+
client: queryClient
|
|
82
|
+
}, /*#__PURE__*/ React__default["default"].createElement(reactQuery.Hydrate, {
|
|
83
|
+
state: hydratedState
|
|
84
|
+
}, /*#__PURE__*/ React__default["default"].createElement(AppOrPage, _extends({}, props)))));
|
|
85
|
+
};
|
|
86
|
+
if (AppOrPage.getInitialProps || opts.ssr) {
|
|
87
|
+
WithTRPC.getInitialProps = async (appOrPageCtx)=>{
|
|
88
|
+
const AppTree = appOrPageCtx.AppTree;
|
|
89
|
+
// Determine if we are wrapping an App component or a Page component.
|
|
90
|
+
const isApp = !!appOrPageCtx.Component;
|
|
91
|
+
const ctx = isApp ? appOrPageCtx.ctx : appOrPageCtx;
|
|
92
|
+
// Run the wrapped component's getInitialProps function.
|
|
93
|
+
let pageProps = {};
|
|
94
|
+
if (AppOrPage.getInitialProps) {
|
|
95
|
+
const originalProps = await AppOrPage.getInitialProps(appOrPageCtx);
|
|
96
|
+
const originalPageProps = isApp ? originalProps.pageProps ?? {} : originalProps;
|
|
97
|
+
pageProps = {
|
|
98
|
+
...originalPageProps,
|
|
99
|
+
...pageProps
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const getAppTreeProps = (props)=>isApp ? {
|
|
103
|
+
pageProps: props
|
|
126
104
|
} : props;
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
trpcClient = react.createTRPCClient(config);
|
|
141
|
-
queryClient = new reactQuery.QueryClient(config.queryClientConfig);
|
|
142
|
-
trpcProp = {
|
|
143
|
-
config: config,
|
|
144
|
-
trpcClient: trpcClient,
|
|
145
|
-
queryClient: queryClient,
|
|
146
|
-
isPrepass: true,
|
|
105
|
+
if (typeof window !== 'undefined' || !opts.ssr) {
|
|
106
|
+
return getAppTreeProps(pageProps);
|
|
107
|
+
}
|
|
108
|
+
const config = getClientConfig({
|
|
109
|
+
ctx
|
|
110
|
+
});
|
|
111
|
+
const trpcClient = react.createTRPCClient(config);
|
|
112
|
+
const queryClient = new reactQuery.QueryClient(config.queryClientConfig);
|
|
113
|
+
const trpcProp = {
|
|
114
|
+
config,
|
|
115
|
+
trpcClient,
|
|
116
|
+
queryClient,
|
|
117
|
+
ssrState: 'prepass',
|
|
147
118
|
ssrContext: ctx
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
pageProps
|
|
119
|
+
};
|
|
120
|
+
const prepassProps = {
|
|
121
|
+
pageProps,
|
|
151
122
|
trpc: trpcProp
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
_context.next = 25;
|
|
170
|
-
return new Promise(function (resolve) {
|
|
171
|
-
var unsub = queryClient.getQueryCache().subscribe(function (event) {
|
|
172
|
-
if ((event === null || event === void 0 ? void 0 : event.query.getObserversCount()) === 0) {
|
|
173
|
-
resolve();
|
|
174
|
-
unsub();
|
|
175
|
-
}
|
|
123
|
+
};
|
|
124
|
+
// Run the prepass step on AppTree. This will run all trpc queries on the server.
|
|
125
|
+
// multiple prepass ensures that we can do batching on the server
|
|
126
|
+
while(true){
|
|
127
|
+
// render full tree
|
|
128
|
+
await ssrPrepass__default["default"](/*#__PURE__*/ React.createElement(AppTree, prepassProps));
|
|
129
|
+
if (!queryClient.isFetching()) {
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
// wait until the query cache has settled it's promises
|
|
133
|
+
await new Promise((resolve)=>{
|
|
134
|
+
const unsub = queryClient.getQueryCache().subscribe((event)=>{
|
|
135
|
+
if (event?.query.getObserversCount() === 0) {
|
|
136
|
+
resolve();
|
|
137
|
+
unsub();
|
|
138
|
+
}
|
|
139
|
+
});
|
|
176
140
|
});
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
case 27:
|
|
184
|
-
dehydratedCache = reactQuery.dehydrate(queryClient, {
|
|
185
|
-
shouldDehydrateQuery: function shouldDehydrateQuery() {
|
|
186
|
-
// makes sure errors are also dehydrated
|
|
187
|
-
return true;
|
|
141
|
+
}
|
|
142
|
+
const dehydratedCache = reactQuery.dehydrate(queryClient, {
|
|
143
|
+
shouldDehydrateQuery () {
|
|
144
|
+
// makes sure errors are also dehydrated
|
|
145
|
+
return true;
|
|
188
146
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
147
|
+
});
|
|
148
|
+
// since error instances can't be serialized, let's make them into `TRPCClientErrorLike`-objects
|
|
149
|
+
const dehydratedCacheWithErrors = {
|
|
150
|
+
...dehydratedCache,
|
|
192
151
|
queries: dehydratedCache.queries.map(transformQueryOrMutationCacheErrors),
|
|
193
152
|
mutations: dehydratedCache.mutations.map(transformQueryOrMutationCacheErrors)
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
ctx
|
|
200
|
-
clientErrors: [
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
_Object$entries$_i = _slicedToArray__default["default"](_Object$entries[_i], 2), key = _Object$entries$_i[0], value = _Object$entries$_i[1];
|
|
209
|
-
|
|
153
|
+
};
|
|
154
|
+
// dehydrate query client's state and add it to the props
|
|
155
|
+
pageProps.trpcState = trpcClient.runtime.transformer.serialize(dehydratedCacheWithErrors);
|
|
156
|
+
const appTreeProps = getAppTreeProps(pageProps);
|
|
157
|
+
const meta = opts.responseMeta?.({
|
|
158
|
+
ctx,
|
|
159
|
+
clientErrors: [
|
|
160
|
+
...dehydratedCache.queries,
|
|
161
|
+
...dehydratedCache.mutations,
|
|
162
|
+
].map((v)=>v.state.error).flatMap((err)=>err instanceof Error && err.name === 'TRPCClientError' ? [
|
|
163
|
+
err
|
|
164
|
+
] : [])
|
|
165
|
+
}) || {};
|
|
166
|
+
for (const [key, value] of Object.entries(meta.headers || {})){
|
|
210
167
|
if (typeof value === 'string') {
|
|
211
|
-
|
|
168
|
+
ctx.res?.setHeader(key, value);
|
|
212
169
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if (meta.status && ctx.res) {
|
|
170
|
+
}
|
|
171
|
+
if (meta.status && ctx.res) {
|
|
216
172
|
ctx.res.statusCode = meta.status;
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}
|
|
226
|
-
}, _callee);
|
|
227
|
-
}));
|
|
228
|
-
|
|
229
|
-
return function (_x) {
|
|
230
|
-
return _ref.apply(this, arguments);
|
|
231
|
-
};
|
|
232
|
-
}();
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
var displayName = AppOrPage.displayName || AppOrPage.name || 'Component';
|
|
236
|
-
WithTRPC.displayName = "withTRPC(".concat(displayName, ")");
|
|
237
|
-
return WithTRPC;
|
|
238
|
-
};
|
|
173
|
+
}
|
|
174
|
+
return appTreeProps;
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
const displayName = AppOrPage.displayName || AppOrPage.name || 'Component';
|
|
178
|
+
WithTRPC.displayName = `withTRPC(${displayName})`;
|
|
179
|
+
return WithTRPC;
|
|
180
|
+
};
|
|
239
181
|
}
|
|
240
182
|
|
|
241
183
|
function setupTRPC(opts) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
184
|
+
const hooks = react.createReactQueryHooks();
|
|
185
|
+
const proxy = react.createReactQueryHooksProxy(hooks);
|
|
186
|
+
// TODO: maybe set TSSRContext to `never` when using `WithTRPCNoSSROptions`
|
|
187
|
+
const _withTRPC = withTRPC(opts);
|
|
188
|
+
return {
|
|
189
|
+
proxy,
|
|
190
|
+
useContext: hooks.useContext,
|
|
191
|
+
useInfiniteQuery: hooks.useInfiniteQuery,
|
|
192
|
+
useMutation: hooks.useMutation,
|
|
193
|
+
useQuery: hooks.useQuery,
|
|
194
|
+
useSubscription: hooks.useSubscription,
|
|
195
|
+
withTRPC: _withTRPC,
|
|
196
|
+
queries: hooks.queries
|
|
197
|
+
};
|
|
254
198
|
}
|
|
255
199
|
|
|
256
200
|
exports.setupTRPC = setupTRPC;
|