@trpc/next 10.26.0 → 10.27.1
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/dist/app-dir/client.d.ts +4 -7
- package/dist/app-dir/client.d.ts.map +1 -1
- package/dist/app-dir/client.js +144 -54
- package/dist/app-dir/client.mjs +144 -56
- package/dist/app-dir/client.test.d.ts +2 -0
- package/dist/app-dir/client.test.d.ts.map +1 -0
- package/dist/app-dir/create-action-hook.d.ts +51 -0
- package/dist/app-dir/create-action-hook.d.ts.map +1 -0
- package/dist/app-dir/formDataToObject.d.ts +2 -0
- package/dist/app-dir/formDataToObject.d.ts.map +1 -0
- package/dist/app-dir/server.d.ts +21 -2
- package/dist/app-dir/server.d.ts.map +1 -1
- package/dist/app-dir/server.js +88 -0
- package/dist/app-dir/server.mjs +89 -2
- package/dist/app-dir/shared.d.ts +21 -1
- package/dist/app-dir/shared.d.ts.map +1 -1
- package/dist/shared-2ca37369.js +15 -0
- package/dist/shared-59b269d5.mjs +13 -0
- package/dist/shared-bc6a2699.js +14 -0
- package/package.json +9 -9
- package/src/app-dir/client.test.tsx +408 -0
- package/src/app-dir/client.ts +71 -63
- package/src/app-dir/create-action-hook.tsx +218 -0
- package/src/app-dir/formDataToObject.test.ts +58 -0
- package/src/app-dir/formDataToObject.ts +36 -0
- package/src/app-dir/server.ts +110 -4
- package/src/app-dir/shared.ts +32 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CreateTRPCClientOptions,
|
|
3
|
+
TRPCClientError,
|
|
4
|
+
TRPCLink,
|
|
5
|
+
TRPCRequestOptions,
|
|
6
|
+
createTRPCUntypedClient,
|
|
7
|
+
} from '@trpc/client';
|
|
8
|
+
import { transformResult } from '@trpc/client/shared';
|
|
9
|
+
import {
|
|
10
|
+
AnyProcedure,
|
|
11
|
+
AnyRouter,
|
|
12
|
+
MaybePromise,
|
|
13
|
+
ProcedureOptions,
|
|
14
|
+
Simplify,
|
|
15
|
+
inferHandlerInput,
|
|
16
|
+
} from '@trpc/server';
|
|
17
|
+
import { observable } from '@trpc/server/observable';
|
|
18
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
19
|
+
import { TRPCActionHandler } from './server';
|
|
20
|
+
import { ActionHandlerDef, isFormData } from './shared';
|
|
21
|
+
|
|
22
|
+
interface Def {
|
|
23
|
+
input?: any;
|
|
24
|
+
output?: any;
|
|
25
|
+
errorShape: any;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
type MutationArgs<TDef extends Def> = TDef['input'] extends void
|
|
29
|
+
? [input?: undefined | void, opts?: ProcedureOptions]
|
|
30
|
+
: [input: TDef['input'] | FormData, opts?: ProcedureOptions];
|
|
31
|
+
|
|
32
|
+
interface UseTRPCActionBaseResult<TDef extends Def> {
|
|
33
|
+
mutate: (...args: MutationArgs<TDef>) => void;
|
|
34
|
+
mutateAsync: (...args: MutationArgs<TDef>) => Promise<Def['output']>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface UseTRPCActionSuccessResult<TDef extends Def>
|
|
38
|
+
extends UseTRPCActionBaseResult<TDef> {
|
|
39
|
+
data: TDef['output'];
|
|
40
|
+
error?: never;
|
|
41
|
+
status: 'success';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface UseTRPCActionErrorResult<TDef extends Def>
|
|
45
|
+
extends UseTRPCActionBaseResult<TDef> {
|
|
46
|
+
data?: never;
|
|
47
|
+
error: TRPCClientError<TDef['errorShape']>;
|
|
48
|
+
status: 'error';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface UseTRPCActionIdleResult<TDef extends Def>
|
|
52
|
+
extends UseTRPCActionBaseResult<TDef> {
|
|
53
|
+
data?: never;
|
|
54
|
+
error?: never;
|
|
55
|
+
status: 'idle';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface UseTRPCActionLoadingResult<TDef extends Def>
|
|
59
|
+
extends UseTRPCActionBaseResult<TDef> {
|
|
60
|
+
data?: never;
|
|
61
|
+
error?: never;
|
|
62
|
+
status: 'loading';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ts-prune-ignore-next
|
|
66
|
+
export type UseTRPCActionResult<TDef extends Def> =
|
|
67
|
+
| UseTRPCActionSuccessResult<TDef>
|
|
68
|
+
| UseTRPCActionErrorResult<TDef>
|
|
69
|
+
| UseTRPCActionIdleResult<TDef>
|
|
70
|
+
| UseTRPCActionLoadingResult<TDef>;
|
|
71
|
+
|
|
72
|
+
type ActionContext = {
|
|
73
|
+
_action: (...args: any[]) => Promise<any>;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// ts-prune-ignore-next
|
|
77
|
+
export function experimental_serverActionLink<
|
|
78
|
+
TRouter extends AnyRouter = AnyRouter,
|
|
79
|
+
>(): TRPCLink<TRouter> {
|
|
80
|
+
return (runtime) =>
|
|
81
|
+
({ op }) =>
|
|
82
|
+
observable((observer) => {
|
|
83
|
+
const context = op.context as ActionContext;
|
|
84
|
+
|
|
85
|
+
context
|
|
86
|
+
._action(
|
|
87
|
+
isFormData(op.input)
|
|
88
|
+
? op.input
|
|
89
|
+
: runtime.transformer.serialize(op.input),
|
|
90
|
+
)
|
|
91
|
+
.then((data) => {
|
|
92
|
+
const transformed = transformResult(data, runtime);
|
|
93
|
+
|
|
94
|
+
if (!transformed.ok) {
|
|
95
|
+
observer.error(TRPCClientError.from(transformed.error, {}));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
observer.next({
|
|
99
|
+
context: op.context,
|
|
100
|
+
result: transformed.result,
|
|
101
|
+
});
|
|
102
|
+
observer.complete();
|
|
103
|
+
})
|
|
104
|
+
.catch((cause) => observer.error(TRPCClientError.from(cause)));
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ts-prune-ignore-next
|
|
109
|
+
/**
|
|
110
|
+
* @internal
|
|
111
|
+
*/
|
|
112
|
+
export type inferActionResultProps<TProc extends AnyProcedure> = {
|
|
113
|
+
input: inferHandlerInput<TProc>[0];
|
|
114
|
+
output: TProc['_def']['_output_out'];
|
|
115
|
+
errorShape: TProc['_def']['_config']['$types']['errorShape'];
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
interface UseTRPCActionOptions<TDef extends Def> {
|
|
119
|
+
onSuccess?: (result: TDef['output']) => void | MaybePromise<void>;
|
|
120
|
+
onError?: (result: TRPCClientError<TDef['errorShape']>) => MaybePromise<void>;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ts-prune-ignore-next
|
|
124
|
+
export function experimental_createActionHook<TRouter extends AnyRouter>(
|
|
125
|
+
opts: CreateTRPCClientOptions<TRouter>,
|
|
126
|
+
) {
|
|
127
|
+
type ActionContext = {
|
|
128
|
+
_action: (...args: any[]) => Promise<any>;
|
|
129
|
+
};
|
|
130
|
+
const client = createTRPCUntypedClient(opts);
|
|
131
|
+
return function useAction<TDef extends ActionHandlerDef>(
|
|
132
|
+
handler: TRPCActionHandler<TDef>,
|
|
133
|
+
useActionOpts?: UseTRPCActionOptions<Simplify<TDef>>,
|
|
134
|
+
) {
|
|
135
|
+
const count = useRef(0);
|
|
136
|
+
|
|
137
|
+
type Result = UseTRPCActionResult<TDef>;
|
|
138
|
+
type State = Omit<Result, 'mutate' | 'mutateAsync'>;
|
|
139
|
+
const [state, setState] = useState<State>({
|
|
140
|
+
status: 'idle',
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const actionOptsRef = useRef(useActionOpts);
|
|
144
|
+
actionOptsRef.current = useActionOpts;
|
|
145
|
+
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
return () => {
|
|
148
|
+
// cleanup after unmount to prevent calling hook opts after unmount
|
|
149
|
+
count.current = -1;
|
|
150
|
+
actionOptsRef.current = undefined;
|
|
151
|
+
};
|
|
152
|
+
}, []);
|
|
153
|
+
|
|
154
|
+
const mutateAsync = useCallback(
|
|
155
|
+
(input: any, requestOptions?: TRPCRequestOptions) => {
|
|
156
|
+
const idx = ++count.current;
|
|
157
|
+
const context = {
|
|
158
|
+
...requestOptions?.context,
|
|
159
|
+
_action(innerInput) {
|
|
160
|
+
return handler(innerInput);
|
|
161
|
+
},
|
|
162
|
+
} as ActionContext;
|
|
163
|
+
|
|
164
|
+
setState({
|
|
165
|
+
status: 'loading',
|
|
166
|
+
});
|
|
167
|
+
return client
|
|
168
|
+
.mutation('serverAction', input, {
|
|
169
|
+
...requestOptions,
|
|
170
|
+
context,
|
|
171
|
+
})
|
|
172
|
+
.then(async (data) => {
|
|
173
|
+
await actionOptsRef.current?.onSuccess?.(data as any);
|
|
174
|
+
if (idx !== count.current) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
setState({
|
|
178
|
+
status: 'success',
|
|
179
|
+
data: data as any,
|
|
180
|
+
});
|
|
181
|
+
})
|
|
182
|
+
.catch(async (error) => {
|
|
183
|
+
await actionOptsRef.current?.onError?.(error);
|
|
184
|
+
throw error;
|
|
185
|
+
})
|
|
186
|
+
.catch((error) => {
|
|
187
|
+
if (idx !== count.current) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
setState({
|
|
191
|
+
status: 'error',
|
|
192
|
+
error: TRPCClientError.from(error, {}),
|
|
193
|
+
});
|
|
194
|
+
throw error;
|
|
195
|
+
});
|
|
196
|
+
},
|
|
197
|
+
[handler],
|
|
198
|
+
) as Result['mutateAsync'];
|
|
199
|
+
|
|
200
|
+
const mutate: Result['mutate'] = useCallback(
|
|
201
|
+
(...args: any[]) => {
|
|
202
|
+
void (mutateAsync as any)(...args).catch(() => {
|
|
203
|
+
// ignored
|
|
204
|
+
});
|
|
205
|
+
},
|
|
206
|
+
[mutateAsync],
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
return useMemo(
|
|
210
|
+
() => ({
|
|
211
|
+
...state,
|
|
212
|
+
mutate,
|
|
213
|
+
mutateAsync,
|
|
214
|
+
}),
|
|
215
|
+
[mutate, mutateAsync, state],
|
|
216
|
+
) as Result;
|
|
217
|
+
};
|
|
218
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { formDataToObject } from './formDataToObject';
|
|
2
|
+
|
|
3
|
+
test('basic', () => {
|
|
4
|
+
const formData = new FormData();
|
|
5
|
+
|
|
6
|
+
formData.append('foo', 'bar');
|
|
7
|
+
|
|
8
|
+
expect(formDataToObject(formData)).toEqual({
|
|
9
|
+
foo: 'bar',
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test('multiple values on the same key', () => {
|
|
14
|
+
const formData = new FormData();
|
|
15
|
+
|
|
16
|
+
formData.append('foo', 'bar');
|
|
17
|
+
formData.append('foo', 'baz');
|
|
18
|
+
|
|
19
|
+
expect(formDataToObject(formData)).toEqual({
|
|
20
|
+
foo: ['bar', 'baz'],
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('deep key', () => {
|
|
25
|
+
const formData = new FormData();
|
|
26
|
+
|
|
27
|
+
formData.append('foo.bar.baz', 'qux');
|
|
28
|
+
|
|
29
|
+
expect(formDataToObject(formData)).toEqual({
|
|
30
|
+
foo: {
|
|
31
|
+
bar: {
|
|
32
|
+
baz: 'qux',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('array', () => {
|
|
39
|
+
const formData = new FormData();
|
|
40
|
+
|
|
41
|
+
formData.append('foo[0]', 'bar');
|
|
42
|
+
formData.append('foo[1]', 'baz');
|
|
43
|
+
|
|
44
|
+
expect(formDataToObject(formData)).toEqual({
|
|
45
|
+
foo: ['bar', 'baz'],
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('array with dot notation', () => {
|
|
50
|
+
const formData = new FormData();
|
|
51
|
+
|
|
52
|
+
formData.append('foo.0', 'bar');
|
|
53
|
+
formData.append('foo.1', 'baz');
|
|
54
|
+
|
|
55
|
+
expect(formDataToObject(formData)).toEqual({
|
|
56
|
+
foo: ['bar', 'baz'],
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
+
function set(
|
|
3
|
+
obj: Record<string, any>,
|
|
4
|
+
path: string | string[],
|
|
5
|
+
value: unknown,
|
|
6
|
+
): void {
|
|
7
|
+
if (typeof path === 'string') {
|
|
8
|
+
path = path.split(/[\.\[\]]/).filter(Boolean);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (path.length > 1) {
|
|
12
|
+
const p = path.shift()!;
|
|
13
|
+
const isArrayIndex = /^\d+$/.test(path[0]!);
|
|
14
|
+
obj[p] = obj[p] || (isArrayIndex ? [] : {});
|
|
15
|
+
set(obj[p], path, value);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const p = path[0]!;
|
|
19
|
+
if (obj[p] === undefined) {
|
|
20
|
+
obj[p] = value;
|
|
21
|
+
} else if (Array.isArray(obj[p])) {
|
|
22
|
+
obj[p].push(value);
|
|
23
|
+
} else {
|
|
24
|
+
obj[p] = [obj[p], value];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function formDataToObject(formData: FormData) {
|
|
29
|
+
const obj: Record<string, unknown> = {};
|
|
30
|
+
|
|
31
|
+
for (const [key, value] of formData.entries()) {
|
|
32
|
+
set(obj, key, value);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return obj;
|
|
36
|
+
}
|
package/src/app-dir/server.ts
CHANGED
|
@@ -1,14 +1,34 @@
|
|
|
1
1
|
/// <reference types="next" />
|
|
2
|
-
|
|
3
2
|
import {
|
|
4
3
|
CreateTRPCProxyClient,
|
|
5
4
|
clientCallTypeToProcedureType,
|
|
6
5
|
createTRPCUntypedClient,
|
|
7
6
|
} from '@trpc/client';
|
|
8
|
-
import {
|
|
9
|
-
|
|
7
|
+
import {
|
|
8
|
+
AnyProcedure,
|
|
9
|
+
AnyRootConfig,
|
|
10
|
+
AnyRouter,
|
|
11
|
+
CombinedDataTransformer,
|
|
12
|
+
MaybePromise,
|
|
13
|
+
Simplify,
|
|
14
|
+
TRPCError,
|
|
15
|
+
getTRPCErrorFromUnknown,
|
|
16
|
+
inferProcedureInput,
|
|
17
|
+
} from '@trpc/server';
|
|
18
|
+
import { TRPCResponse } from '@trpc/server/rpc';
|
|
19
|
+
import {
|
|
20
|
+
createRecursiveProxy,
|
|
21
|
+
getErrorShape,
|
|
22
|
+
transformTRPCResponse,
|
|
23
|
+
} from '@trpc/server/shared';
|
|
10
24
|
import { cache } from 'react';
|
|
11
|
-
import {
|
|
25
|
+
import { formDataToObject } from './formDataToObject';
|
|
26
|
+
import {
|
|
27
|
+
ActionHandlerDef,
|
|
28
|
+
CreateTRPCNextAppRouterOptions,
|
|
29
|
+
inferActionDef,
|
|
30
|
+
isFormData,
|
|
31
|
+
} from './shared';
|
|
12
32
|
|
|
13
33
|
// ts-prune-ignore-next
|
|
14
34
|
export function experimental_createTRPCNextAppDirServer<
|
|
@@ -32,3 +52,89 @@ export function experimental_createTRPCNextAppDirServer<
|
|
|
32
52
|
return (client[procedureType] as any)(fullPath, ...callOpts.args);
|
|
33
53
|
}) as CreateTRPCProxyClient<TRouter>;
|
|
34
54
|
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @internal
|
|
58
|
+
*/
|
|
59
|
+
export type TRPCActionHandler<TDef extends ActionHandlerDef> = (
|
|
60
|
+
input: TDef['input'] | FormData,
|
|
61
|
+
) => Promise<TRPCResponse<TDef['output'], TDef['errorShape']>>;
|
|
62
|
+
|
|
63
|
+
export function experimental_createServerActionHandler<
|
|
64
|
+
TInstance extends {
|
|
65
|
+
_config: AnyRootConfig;
|
|
66
|
+
},
|
|
67
|
+
>(
|
|
68
|
+
t: TInstance,
|
|
69
|
+
opts: {
|
|
70
|
+
createContext: () => MaybePromise<TInstance['_config']['$types']['ctx']>;
|
|
71
|
+
/**
|
|
72
|
+
* Transform form data to a `Record` before passing it to the procedure
|
|
73
|
+
* @default true
|
|
74
|
+
*/
|
|
75
|
+
normalizeFormData?: boolean;
|
|
76
|
+
},
|
|
77
|
+
) {
|
|
78
|
+
const config = t._config;
|
|
79
|
+
const { normalizeFormData = true, createContext } = opts;
|
|
80
|
+
|
|
81
|
+
const transformer = config.transformer as CombinedDataTransformer;
|
|
82
|
+
|
|
83
|
+
// TODO allow this to take a `TRouter` in addition to a `AnyProcedure`
|
|
84
|
+
return function createServerAction<TProc extends AnyProcedure>(
|
|
85
|
+
proc: TProc,
|
|
86
|
+
): TRPCActionHandler<Simplify<inferActionDef<TProc>>> {
|
|
87
|
+
return async function actionHandler(
|
|
88
|
+
rawInput: inferProcedureInput<TProc> | FormData,
|
|
89
|
+
) {
|
|
90
|
+
const ctx: undefined | TInstance['_config']['$types']['ctx'] = undefined;
|
|
91
|
+
try {
|
|
92
|
+
const ctx = await createContext();
|
|
93
|
+
if (normalizeFormData && isFormData(rawInput)) {
|
|
94
|
+
// Normalizes formdata so we can use `z.object({})` etc on the server
|
|
95
|
+
try {
|
|
96
|
+
rawInput = formDataToObject(rawInput);
|
|
97
|
+
} catch {
|
|
98
|
+
throw new TRPCError({
|
|
99
|
+
code: 'INTERNAL_SERVER_ERROR',
|
|
100
|
+
message: 'Failed to convert FormData to an object',
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
} else if (rawInput && !isFormData(rawInput)) {
|
|
104
|
+
rawInput = transformer.input.deserialize(rawInput);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const data = await proc({
|
|
108
|
+
input: undefined,
|
|
109
|
+
ctx,
|
|
110
|
+
path: 'serverAction',
|
|
111
|
+
rawInput,
|
|
112
|
+
type: proc._type,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const transformedJSON = transformTRPCResponse(config, {
|
|
116
|
+
result: {
|
|
117
|
+
data,
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
return transformedJSON;
|
|
121
|
+
} catch (cause) {
|
|
122
|
+
const error = getTRPCErrorFromUnknown(cause);
|
|
123
|
+
const shape = getErrorShape({
|
|
124
|
+
config,
|
|
125
|
+
ctx,
|
|
126
|
+
error,
|
|
127
|
+
input: rawInput,
|
|
128
|
+
path: 'serverAction',
|
|
129
|
+
type: proc._type,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// TODO: send the right HTTP header?!
|
|
133
|
+
|
|
134
|
+
return transformTRPCResponse(t._config, {
|
|
135
|
+
error: shape,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
} as TRPCActionHandler<inferActionDef<TProc>>;
|
|
139
|
+
};
|
|
140
|
+
}
|
package/src/app-dir/shared.ts
CHANGED
|
@@ -4,11 +4,13 @@ import {
|
|
|
4
4
|
TRPCUntypedClient,
|
|
5
5
|
} from '@trpc/client';
|
|
6
6
|
import {
|
|
7
|
+
AnyProcedure,
|
|
7
8
|
AnyQueryProcedure,
|
|
8
9
|
AnyRouter,
|
|
9
10
|
Filter,
|
|
10
11
|
ProtectedIntersection,
|
|
11
12
|
ThenArg,
|
|
13
|
+
inferHandlerInput,
|
|
12
14
|
} from '@trpc/server';
|
|
13
15
|
import { createRecursiveProxy } from '@trpc/server/shared';
|
|
14
16
|
|
|
@@ -59,3 +61,33 @@ export type CreateTRPCNextAppRouter<TRouter extends AnyRouter> =
|
|
|
59
61
|
export interface CreateTRPCNextAppRouterOptions<TRouter extends AnyRouter> {
|
|
60
62
|
config: () => CreateTRPCClientOptions<TRouter>;
|
|
61
63
|
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @internal
|
|
67
|
+
*/
|
|
68
|
+
export function isFormData(value: unknown): value is FormData {
|
|
69
|
+
if (typeof FormData === 'undefined') {
|
|
70
|
+
// FormData is not supported
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return value instanceof FormData;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @internal
|
|
78
|
+
*/
|
|
79
|
+
export interface ActionHandlerDef {
|
|
80
|
+
input?: any;
|
|
81
|
+
output?: any;
|
|
82
|
+
errorShape: any;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ts-prune-ignore-next
|
|
86
|
+
/**
|
|
87
|
+
* @internal
|
|
88
|
+
*/
|
|
89
|
+
export type inferActionDef<TProc extends AnyProcedure> = {
|
|
90
|
+
input: inferHandlerInput<TProc>[0];
|
|
91
|
+
output: TProc['_def']['_output_out'];
|
|
92
|
+
errorShape: TProc['_def']['_config']['$types']['errorShape'];
|
|
93
|
+
};
|