@trpc/tanstack-react-query 0.0.0-alpha.0

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.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +39 -0
  3. package/dist/index.d.ts +9 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +11 -0
  6. package/dist/index.mjs +3 -0
  7. package/dist/internals/Context.d.ts +14 -0
  8. package/dist/internals/Context.d.ts.map +1 -0
  9. package/dist/internals/Context.js +52 -0
  10. package/dist/internals/Context.mjs +31 -0
  11. package/dist/internals/createOptionsProxy.d.ts +107 -0
  12. package/dist/internals/createOptionsProxy.d.ts.map +1 -0
  13. package/dist/internals/createOptionsProxy.js +99 -0
  14. package/dist/internals/createOptionsProxy.mjs +97 -0
  15. package/dist/internals/infiniteQueryOptions.d.ts +49 -0
  16. package/dist/internals/infiniteQueryOptions.d.ts.map +1 -0
  17. package/dist/internals/infiniteQueryOptions.js +39 -0
  18. package/dist/internals/infiniteQueryOptions.mjs +37 -0
  19. package/dist/internals/mutationOptions.d.ts +38 -0
  20. package/dist/internals/mutationOptions.d.ts.map +1 -0
  21. package/dist/internals/mutationOptions.js +38 -0
  22. package/dist/internals/mutationOptions.mjs +36 -0
  23. package/dist/internals/queryOptions.d.ts +61 -0
  24. package/dist/internals/queryOptions.d.ts.map +1 -0
  25. package/dist/internals/queryOptions.js +40 -0
  26. package/dist/internals/queryOptions.mjs +38 -0
  27. package/dist/internals/subscriptionOptions.d.ts +77 -0
  28. package/dist/internals/subscriptionOptions.d.ts.map +1 -0
  29. package/dist/internals/subscriptionOptions.js +173 -0
  30. package/dist/internals/subscriptionOptions.mjs +151 -0
  31. package/dist/internals/types.d.ts +41 -0
  32. package/dist/internals/types.d.ts.map +1 -0
  33. package/dist/internals/utils.d.ts +28 -0
  34. package/dist/internals/utils.d.ts.map +1 -0
  35. package/dist/internals/utils.js +112 -0
  36. package/dist/internals/utils.mjs +105 -0
  37. package/package.json +81 -0
  38. package/src/index.ts +25 -0
  39. package/src/internals/Context.tsx +46 -0
  40. package/src/internals/createOptionsProxy.ts +309 -0
  41. package/src/internals/infiniteQueryOptions.ts +233 -0
  42. package/src/internals/mutationOptions.ts +113 -0
  43. package/src/internals/queryOptions.ts +199 -0
  44. package/src/internals/subscriptionOptions.ts +286 -0
  45. package/src/internals/types.ts +47 -0
  46. package/src/internals/utils.ts +140 -0
@@ -0,0 +1,151 @@
1
+ import { hashKey, skipToken } from '@tanstack/react-query';
2
+ import * as React from 'react';
3
+ import { createTRPCOptionsResult } from './utils.mjs';
4
+
5
+ const trpcSubscriptionOptions = (args)=>{
6
+ const { subscribe, path, queryKey, opts } = args;
7
+ const input = queryKey[1]?.input;
8
+ const enabled = opts?.enabled ?? input !== skipToken;
9
+ const _subscribe = (innerOpts)=>{
10
+ return subscribe(path.join('.'), input ?? undefined, innerOpts);
11
+ };
12
+ return {
13
+ ...opts,
14
+ enabled,
15
+ subscribe: _subscribe,
16
+ queryKey,
17
+ trpc: createTRPCOptionsResult({
18
+ path
19
+ })
20
+ };
21
+ };
22
+ function useSubscription(opts) {
23
+ const optsRef = React.useRef(opts);
24
+ optsRef.current = opts;
25
+ const trackedProps = React.useRef(new Set([]));
26
+ const addTrackedProp = React.useCallback((key)=>{
27
+ trackedProps.current.add(key);
28
+ }, []);
29
+ const currentSubscriptionRef = React.useRef();
30
+ const reset = React.useCallback(()=>{
31
+ // unsubscribe from the previous subscription
32
+ currentSubscriptionRef.current?.();
33
+ updateState(getInitialState);
34
+ if (!opts.enabled) {
35
+ return;
36
+ }
37
+ let isStopped = false;
38
+ const subscription = opts.subscribe({
39
+ onStarted: ()=>{
40
+ if (!isStopped) {
41
+ optsRef.current.onStarted?.();
42
+ updateState((prev)=>({
43
+ ...prev,
44
+ status: 'pending',
45
+ error: null
46
+ }));
47
+ }
48
+ },
49
+ onData: (data)=>{
50
+ if (!isStopped) {
51
+ optsRef.current.onData?.(data);
52
+ updateState((prev)=>({
53
+ ...prev,
54
+ status: 'pending',
55
+ data,
56
+ error: null
57
+ }));
58
+ }
59
+ },
60
+ onError: (error)=>{
61
+ if (!isStopped) {
62
+ optsRef.current.onError?.(error);
63
+ updateState((prev)=>({
64
+ ...prev,
65
+ status: 'error',
66
+ error
67
+ }));
68
+ }
69
+ },
70
+ onConnectionStateChange: (result)=>{
71
+ const delta = {
72
+ status: result.state,
73
+ error: result.error
74
+ };
75
+ updateState((prev)=>{
76
+ return {
77
+ ...prev,
78
+ ...delta
79
+ };
80
+ });
81
+ }
82
+ });
83
+ currentSubscriptionRef.current = ()=>{
84
+ isStopped = true;
85
+ subscription.unsubscribe();
86
+ };
87
+ // eslint-disable-next-line react-hooks/exhaustive-deps
88
+ }, [
89
+ hashKey(opts.queryKey),
90
+ opts.enabled
91
+ ]);
92
+ const getInitialState = React.useCallback(()=>{
93
+ return opts.enabled ? {
94
+ data: undefined,
95
+ error: null,
96
+ status: 'connecting',
97
+ reset
98
+ } : {
99
+ data: undefined,
100
+ error: null,
101
+ status: 'idle',
102
+ reset
103
+ };
104
+ }, [
105
+ opts.enabled,
106
+ reset
107
+ ]);
108
+ const resultRef = React.useRef(getInitialState());
109
+ const [state, setState] = React.useState(trackResult(resultRef.current, addTrackedProp));
110
+ state.reset = reset;
111
+ const updateState = React.useCallback((callback)=>{
112
+ const prev = resultRef.current;
113
+ const next = resultRef.current = callback(prev);
114
+ let shouldUpdate = false;
115
+ for (const key of trackedProps.current){
116
+ if (prev[key] !== next[key]) {
117
+ shouldUpdate = true;
118
+ break;
119
+ }
120
+ }
121
+ if (shouldUpdate) {
122
+ setState(trackResult(next, addTrackedProp));
123
+ }
124
+ }, [
125
+ addTrackedProp
126
+ ]);
127
+ React.useEffect(()=>{
128
+ if (!opts.enabled) {
129
+ return;
130
+ }
131
+ reset();
132
+ return ()=>{
133
+ currentSubscriptionRef.current?.();
134
+ };
135
+ }, [
136
+ reset,
137
+ opts.enabled
138
+ ]);
139
+ return state;
140
+ }
141
+ function trackResult(result, onTrackResult) {
142
+ const trackedResult = new Proxy(result, {
143
+ get (target, prop) {
144
+ onTrackResult(prop);
145
+ return target[prop];
146
+ }
147
+ });
148
+ return trackedResult;
149
+ }
150
+
151
+ export { trpcSubscriptionOptions, useSubscription };
@@ -0,0 +1,41 @@
1
+ import type { TRPCRequestOptions } from '@trpc/client';
2
+ export type ResolverDef = {
3
+ input: any;
4
+ output: any;
5
+ transformer: boolean;
6
+ errorShape: any;
7
+ };
8
+ export type ExtractCursorType<TInput> = TInput extends {
9
+ cursor?: any;
10
+ } ? TInput['cursor'] : unknown;
11
+ export interface TRPCReactRequestOptions extends Omit<TRPCRequestOptions, 'signal'> {
12
+ /**
13
+ * Opt out of SSR for this query by passing `ssr: false`
14
+ */
15
+ ssr?: boolean;
16
+ /**
17
+ * Opt out or into aborting request on unmount
18
+ */
19
+ abortOnUnmount?: boolean;
20
+ }
21
+ export interface TRPCQueryBaseOptions {
22
+ /**
23
+ * tRPC-related options
24
+ */
25
+ trpc?: TRPCReactRequestOptions;
26
+ }
27
+ export interface TRPCQueryOptionsResult {
28
+ trpc: {
29
+ path: string;
30
+ };
31
+ }
32
+ export type QueryType = 'any' | 'infinite' | 'query';
33
+ export type TRPCQueryKey = [
34
+ readonly string[],
35
+ {
36
+ input?: unknown;
37
+ type?: Exclude<QueryType, 'any'>;
38
+ }?
39
+ ];
40
+ export type TRPCMutationKey = [readonly string[]];
41
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/internals/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,GAAG,CAAC;IACX,MAAM,EAAE,GAAG,CAAC;IACZ,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,GAAG,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,CAAC,MAAM,IAAI,MAAM,SAAS;IAAE,MAAM,CAAC,EAAE,GAAG,CAAA;CAAE,GACnE,MAAM,CAAC,QAAQ,CAAC,GAChB,OAAO,CAAC;AAEZ,MAAM,WAAW,uBAEf,SAAQ,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAC;IAC1C;;OAEG;IACH,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,IAAI,CAAC,EAAE,uBAAuB,CAAC;CAChC;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,UAAU,GAAG,OAAO,CAAC;AAErD,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,MAAM,EAAE;IACjB;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;KAAE,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { type QueryClient } from '@tanstack/react-query';
2
+ import type { QueryType, TRPCMutationKey, TRPCQueryKey, TRPCQueryOptionsResult } from './types';
3
+ /**
4
+ * @internal
5
+ */
6
+ export declare function createTRPCOptionsResult(value: {
7
+ path: readonly string[];
8
+ }): TRPCQueryOptionsResult['trpc'];
9
+ /**
10
+ * @internal
11
+ */
12
+ export declare function getClientArgs<TOptions>(queryKey: TRPCQueryKey, opts: TOptions, infiniteParams?: {
13
+ pageParam: any;
14
+ direction: 'forward' | 'backward';
15
+ }): readonly [string, unknown, any];
16
+ /**
17
+ * @internal
18
+ */
19
+ export declare function buildQueryFromAsyncIterable(asyncIterable: AsyncIterable<unknown>, queryClient: QueryClient, queryKey: TRPCQueryKey): Promise<unknown[]>;
20
+ /**
21
+ * To allow easy interactions with groups of related queries, such as
22
+ * invalidating all queries of a router, we use an array as the path when
23
+ * storing in tanstack query.
24
+ **/
25
+ export declare function getQueryKeyInternal(path: readonly string[], input: unknown, type: QueryType): TRPCQueryKey;
26
+ export declare function getMutationKeyInternal(path: readonly string[]): TRPCMutationKey;
27
+ export declare function unwrapLazyArg<T>(valueOrLazy: T | (() => T)): T;
28
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/internals/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpE,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EACf,YAAY,EACZ,sBAAsB,EACvB,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE;IAC7C,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CACzB,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAMjC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EACpC,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,QAAQ,EACd,cAAc,CAAC,EAAE;IACf,SAAS,EAAE,GAAG,CAAC;IACf,SAAS,EAAE,SAAS,GAAG,UAAU,CAAC;CACnC,mCAYF;AAED;;GAEG;AACH,wBAAsB,2BAA2B,CAC/C,aAAa,EAAE,aAAa,CAAC,OAAO,CAAC,EACrC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,YAAY,sBAsBvB;AAED;;;;IAII;AACJ,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,SAAS,GACd,YAAY,CA0Cd;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,eAAe,CAKjB;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAE9D"}
@@ -0,0 +1,112 @@
1
+ 'use strict';
2
+
3
+ var reactQuery = require('@tanstack/react-query');
4
+ var unstableCoreDoNotImport = require('@trpc/server/unstable-core-do-not-import');
5
+
6
+ /**
7
+ * @internal
8
+ */ function createTRPCOptionsResult(value) {
9
+ const path = value.path.join('.');
10
+ return {
11
+ path
12
+ };
13
+ }
14
+ /**
15
+ * @internal
16
+ */ function getClientArgs(queryKey, opts, infiniteParams) {
17
+ const path = queryKey[0];
18
+ let input = queryKey[1]?.input;
19
+ if (infiniteParams) {
20
+ input = {
21
+ ...input ?? {},
22
+ ...infiniteParams.pageParam ? {
23
+ cursor: infiniteParams.pageParam
24
+ } : {},
25
+ direction: infiniteParams.direction
26
+ };
27
+ }
28
+ return [
29
+ path.join('.'),
30
+ input,
31
+ opts?.trpc
32
+ ];
33
+ }
34
+ /**
35
+ * @internal
36
+ */ async function buildQueryFromAsyncIterable(asyncIterable, queryClient, queryKey) {
37
+ const queryCache = queryClient.getQueryCache();
38
+ const query = queryCache.build(queryClient, {
39
+ queryKey
40
+ });
41
+ query.setState({
42
+ data: [],
43
+ status: 'success'
44
+ });
45
+ const aggregate = [];
46
+ for await (const value of asyncIterable){
47
+ aggregate.push(value);
48
+ query.setState({
49
+ data: [
50
+ ...aggregate
51
+ ]
52
+ });
53
+ }
54
+ return aggregate;
55
+ }
56
+ /**
57
+ * To allow easy interactions with groups of related queries, such as
58
+ * invalidating all queries of a router, we use an array as the path when
59
+ * storing in tanstack query.
60
+ **/ function getQueryKeyInternal(path, input, type) {
61
+ // Construct a query key that is easy to destructure and flexible for
62
+ // partial selecting etc.
63
+ // https://github.com/trpc/trpc/issues/3128
64
+ // some parts of the path may be dot-separated, split them up
65
+ const splitPath = path.flatMap((part)=>part.split('.'));
66
+ if (!input && (!type || type === 'any')) {
67
+ // this matches also all mutations (see `getMutationKeyInternal`)
68
+ // for `utils.invalidate()` to match all queries (including vanilla react-query)
69
+ // we don't want nested array if path is empty, i.e. `[]` instead of `[[]]`
70
+ return splitPath.length ? [
71
+ splitPath
72
+ ] : [];
73
+ }
74
+ if (type === 'infinite' && unstableCoreDoNotImport.isObject(input) && ('direction' in input || 'cursor' in input)) {
75
+ const { cursor: _, direction: __, ...inputWithoutCursorAndDirection } = input;
76
+ return [
77
+ splitPath,
78
+ {
79
+ input: inputWithoutCursorAndDirection,
80
+ type: 'infinite'
81
+ }
82
+ ];
83
+ }
84
+ return [
85
+ splitPath,
86
+ {
87
+ ...typeof input !== 'undefined' && input !== reactQuery.skipToken && {
88
+ input: input
89
+ },
90
+ ...type && type !== 'any' && {
91
+ type: type
92
+ }
93
+ }
94
+ ];
95
+ }
96
+ function getMutationKeyInternal(path) {
97
+ // some parts of the path may be dot-separated, split them up
98
+ const splitPath = path.flatMap((part)=>part.split('.'));
99
+ return splitPath.length ? [
100
+ splitPath
101
+ ] : [];
102
+ }
103
+ function unwrapLazyArg(valueOrLazy) {
104
+ return unstableCoreDoNotImport.isFunction(valueOrLazy) ? valueOrLazy() : valueOrLazy;
105
+ }
106
+
107
+ exports.buildQueryFromAsyncIterable = buildQueryFromAsyncIterable;
108
+ exports.createTRPCOptionsResult = createTRPCOptionsResult;
109
+ exports.getClientArgs = getClientArgs;
110
+ exports.getMutationKeyInternal = getMutationKeyInternal;
111
+ exports.getQueryKeyInternal = getQueryKeyInternal;
112
+ exports.unwrapLazyArg = unwrapLazyArg;
@@ -0,0 +1,105 @@
1
+ import { skipToken } from '@tanstack/react-query';
2
+ import { isObject, isFunction } from '@trpc/server/unstable-core-do-not-import';
3
+
4
+ /**
5
+ * @internal
6
+ */ function createTRPCOptionsResult(value) {
7
+ const path = value.path.join('.');
8
+ return {
9
+ path
10
+ };
11
+ }
12
+ /**
13
+ * @internal
14
+ */ function getClientArgs(queryKey, opts, infiniteParams) {
15
+ const path = queryKey[0];
16
+ let input = queryKey[1]?.input;
17
+ if (infiniteParams) {
18
+ input = {
19
+ ...input ?? {},
20
+ ...infiniteParams.pageParam ? {
21
+ cursor: infiniteParams.pageParam
22
+ } : {},
23
+ direction: infiniteParams.direction
24
+ };
25
+ }
26
+ return [
27
+ path.join('.'),
28
+ input,
29
+ opts?.trpc
30
+ ];
31
+ }
32
+ /**
33
+ * @internal
34
+ */ async function buildQueryFromAsyncIterable(asyncIterable, queryClient, queryKey) {
35
+ const queryCache = queryClient.getQueryCache();
36
+ const query = queryCache.build(queryClient, {
37
+ queryKey
38
+ });
39
+ query.setState({
40
+ data: [],
41
+ status: 'success'
42
+ });
43
+ const aggregate = [];
44
+ for await (const value of asyncIterable){
45
+ aggregate.push(value);
46
+ query.setState({
47
+ data: [
48
+ ...aggregate
49
+ ]
50
+ });
51
+ }
52
+ return aggregate;
53
+ }
54
+ /**
55
+ * To allow easy interactions with groups of related queries, such as
56
+ * invalidating all queries of a router, we use an array as the path when
57
+ * storing in tanstack query.
58
+ **/ function getQueryKeyInternal(path, input, type) {
59
+ // Construct a query key that is easy to destructure and flexible for
60
+ // partial selecting etc.
61
+ // https://github.com/trpc/trpc/issues/3128
62
+ // some parts of the path may be dot-separated, split them up
63
+ const splitPath = path.flatMap((part)=>part.split('.'));
64
+ if (!input && (!type || type === 'any')) {
65
+ // this matches also all mutations (see `getMutationKeyInternal`)
66
+ // for `utils.invalidate()` to match all queries (including vanilla react-query)
67
+ // we don't want nested array if path is empty, i.e. `[]` instead of `[[]]`
68
+ return splitPath.length ? [
69
+ splitPath
70
+ ] : [];
71
+ }
72
+ if (type === 'infinite' && isObject(input) && ('direction' in input || 'cursor' in input)) {
73
+ const { cursor: _, direction: __, ...inputWithoutCursorAndDirection } = input;
74
+ return [
75
+ splitPath,
76
+ {
77
+ input: inputWithoutCursorAndDirection,
78
+ type: 'infinite'
79
+ }
80
+ ];
81
+ }
82
+ return [
83
+ splitPath,
84
+ {
85
+ ...typeof input !== 'undefined' && input !== skipToken && {
86
+ input: input
87
+ },
88
+ ...type && type !== 'any' && {
89
+ type: type
90
+ }
91
+ }
92
+ ];
93
+ }
94
+ function getMutationKeyInternal(path) {
95
+ // some parts of the path may be dot-separated, split them up
96
+ const splitPath = path.flatMap((part)=>part.split('.'));
97
+ return splitPath.length ? [
98
+ splitPath
99
+ ] : [];
100
+ }
101
+ function unwrapLazyArg(valueOrLazy) {
102
+ return isFunction(valueOrLazy) ? valueOrLazy() : valueOrLazy;
103
+ }
104
+
105
+ export { buildQueryFromAsyncIterable, createTRPCOptionsResult, getClientArgs, getMutationKeyInternal, getQueryKeyInternal, unwrapLazyArg };
package/package.json ADDED
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "@trpc/tanstack-react-query",
3
+ "version": "0.0.0-alpha.0",
4
+ "description": "Tanstack React Query Integration for tRPC",
5
+ "author": "juliusmarminge",
6
+ "license": "MIT",
7
+ "main": "dist/index.js",
8
+ "module": "dist/index.mjs",
9
+ "typings": "dist/index.d.ts",
10
+ "homepage": "https://trpc.io",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/trpc/trpc.git",
14
+ "directory": "packages/tanstack-react-query"
15
+ },
16
+ "exports": {
17
+ "./package.json": "./package.json",
18
+ ".": {
19
+ "import": "./dist/index.mjs",
20
+ "require": "./dist/index.js",
21
+ "default": "./dist/index.js"
22
+ }
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "src",
27
+ "README.md",
28
+ "package.json",
29
+ "!**/*.test.*",
30
+ "!**/__tests__"
31
+ ],
32
+ "eslintConfig": {
33
+ "rules": {
34
+ "react-hooks/exhaustive-deps": "error",
35
+ "no-restricted-imports": [
36
+ "error",
37
+ "@trpc/tanstack-react-query"
38
+ ],
39
+ "@typescript-eslint/prefer-function-type": "off"
40
+ }
41
+ },
42
+ "dependencies": {},
43
+ "peerDependencies": {
44
+ "@tanstack/react-query": "^5.59.15",
45
+ "@trpc/client": "10.45.1",
46
+ "@trpc/server": "^10.45.1",
47
+ "react": ">=18.2.0",
48
+ "react-dom": ">=18.2.0",
49
+ "typescript": ">=5.6.2"
50
+ },
51
+ "devDependencies": {
52
+ "@tanstack/react-query": "^5.59.15",
53
+ "@trpc/client": "10.45.1",
54
+ "@trpc/server": "^10.45.1",
55
+ "@types/node": "^20.10.0",
56
+ "@types/react": "^18.3.1",
57
+ "eslint": "^8.57.0",
58
+ "konn": "^0.7.0",
59
+ "react": "^18.3.1",
60
+ "react-dom": "^18.3.1",
61
+ "rollup": "^4.9.5",
62
+ "tsx": "^4.0.0",
63
+ "typescript": "^5.6.2",
64
+ "vitest": "^2.0.4",
65
+ "zod": "^3.0.0"
66
+ },
67
+ "publishConfig": {
68
+ "access": "public"
69
+ },
70
+ "funding": [
71
+ "https://trpc.io/sponsor"
72
+ ],
73
+ "scripts": {
74
+ "build": "rollup --config rollup.config.ts --configPlugin rollup-plugin-swc3",
75
+ "dev": "pnpm build --watch",
76
+ "codegen-entrypoints": "tsx entrypoints.script.ts",
77
+ "lint": "eslint --cache src",
78
+ "test-run:tsc": "tsc --noEmit --pretty",
79
+ "ts-watch": "tsc --watch"
80
+ }
81
+ }
package/src/index.ts ADDED
@@ -0,0 +1,25 @@
1
+ export { createTRPCContext } from './internals/Context';
2
+ export type {
3
+ TRPCOptionsProxy,
4
+ InferInput,
5
+ InferOutput,
6
+ DecorateMutationProcedure,
7
+ DecorateProcedure,
8
+ DecorateQueryKeyable,
9
+ DecorateQueryProcedure,
10
+ DecorateSubscriptionProcedure,
11
+ } from './internals/createOptionsProxy';
12
+ export type { TRPCQueryOptions } from './internals/queryOptions';
13
+ export type { TRPCInfiniteQueryOptions } from './internals/infiniteQueryOptions';
14
+ export type { TRPCMutationOptions } from './internals/mutationOptions';
15
+ export type {
16
+ TRPCSubscriptionOptions,
17
+ TRPCSubscriptionStatus,
18
+ TRPCSubscriptionConnectingResult,
19
+ TRPCSubscriptionErrorResult,
20
+ TRPCSubscriptionIdleResult,
21
+ TRPCSubscriptionPendingResult,
22
+ TRPCSubscriptionResult,
23
+ } from './internals/subscriptionOptions';
24
+ export { createTRPCOptionsProxy } from './internals/createOptionsProxy';
25
+ export { useSubscription } from './internals/subscriptionOptions';
@@ -0,0 +1,46 @@
1
+ import { type QueryClient } from '@tanstack/react-query';
2
+ import { type CreateTRPCClient } from '@trpc/client';
3
+ import type { AnyRouter } from '@trpc/server/unstable-core-do-not-import';
4
+ import * as React from 'react';
5
+ import {
6
+ createTRPCOptionsProxy,
7
+ type TRPCOptionsProxy,
8
+ } from './createOptionsProxy';
9
+
10
+ export function createTRPCContext<TRouter extends AnyRouter>() {
11
+ const TRPCContext = React.createContext<TRPCOptionsProxy<TRouter> | null>(
12
+ null,
13
+ );
14
+
15
+ function TRPCProvider(
16
+ props: Readonly<{
17
+ children: React.ReactNode;
18
+ queryClient: QueryClient;
19
+ trpcClient: CreateTRPCClient<TRouter>;
20
+ }>,
21
+ ) {
22
+ const value = React.useMemo(
23
+ () =>
24
+ createTRPCOptionsProxy({
25
+ client: props.trpcClient,
26
+ queryClient: props.queryClient,
27
+ }),
28
+ [props.trpcClient, props.queryClient],
29
+ );
30
+ return (
31
+ <TRPCContext.Provider value={value}>
32
+ {props.children}
33
+ </TRPCContext.Provider>
34
+ );
35
+ }
36
+
37
+ function useTRPC() {
38
+ const utils = React.useContext(TRPCContext);
39
+ if (!utils) {
40
+ throw new Error('useTRPC() can only be used inside of a <TRPCProvider>');
41
+ }
42
+ return utils;
43
+ }
44
+
45
+ return { TRPCProvider, useTRPC };
46
+ }