effect-orpc 0.1.3 → 0.2.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.
- package/README.md +486 -0
- package/dist/index.js +352 -72
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/contract.ts +491 -0
- package/src/effect-builder.ts +40 -88
- package/src/effect-runtime.ts +134 -0
- package/src/eoc.ts +499 -0
- package/src/index.ts +18 -3
- package/src/tagged-error.ts +24 -4
- package/src/tests/contract.test.ts +346 -0
- package/src/tests/effect-error-map.test.ts +22 -3
- package/src/tests/parity-shared.ts +32 -0
- package/src/tests/parity.contract-builder-variants.test.ts +192 -0
- package/src/tests/parity.contract-builder.test.ts +222 -0
- package/src/tests/parity.effect-builder.test.ts +193 -0
- package/src/tests/parity.effect-procedure.test.ts +124 -0
- package/src/tests/parity.implementer-variants.test.ts +249 -0
- package/src/tests/parity.implementer.test.ts +280 -0
- package/src/tests/shared.ts +2 -0
- package/src/types/index.ts +0 -16
- package/src/types/variants.ts +25 -16
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { ContractBuilder, isContractProcedure } from "@orpc/contract";
|
|
2
|
+
import { describe, expect, expectTypeOf, it } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { effectErrorMapToErrorMap, eoc } from "../index";
|
|
5
|
+
import {
|
|
6
|
+
baseErrorMap,
|
|
7
|
+
baseMeta,
|
|
8
|
+
baseRoute,
|
|
9
|
+
generalSchema,
|
|
10
|
+
inputSchema,
|
|
11
|
+
outputSchema,
|
|
12
|
+
ping,
|
|
13
|
+
pong,
|
|
14
|
+
} from "./shared";
|
|
15
|
+
|
|
16
|
+
const builder = eoc
|
|
17
|
+
.$meta(baseMeta)
|
|
18
|
+
.$route(baseRoute)
|
|
19
|
+
.$input(inputSchema)
|
|
20
|
+
.errors(baseErrorMap);
|
|
21
|
+
|
|
22
|
+
describe("parity: @orpc/contract builder.test.ts", () => {
|
|
23
|
+
it("is a contract procedure", () => {
|
|
24
|
+
expect(eoc).toSatisfy(isContractProcedure);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it(".$meta", () => {
|
|
28
|
+
const meta = { dev: true, log: true };
|
|
29
|
+
const applied = builder.$meta(meta);
|
|
30
|
+
|
|
31
|
+
expect(applied).toBeInstanceOf(ContractBuilder);
|
|
32
|
+
expect(applied).not.toBe(builder);
|
|
33
|
+
expect(applied["~orpc"]).toEqual({
|
|
34
|
+
...builder["~orpc"],
|
|
35
|
+
meta,
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it(".$route", () => {
|
|
40
|
+
const route = { method: "GET", path: "/api" } as const;
|
|
41
|
+
const applied = builder.$route(route);
|
|
42
|
+
|
|
43
|
+
expect(applied).toBeInstanceOf(ContractBuilder);
|
|
44
|
+
expect(applied).not.toBe(builder);
|
|
45
|
+
expect(applied["~orpc"]).toEqual({
|
|
46
|
+
...builder["~orpc"],
|
|
47
|
+
route,
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it(".$input", () => {
|
|
52
|
+
const applied = builder.$input(generalSchema);
|
|
53
|
+
|
|
54
|
+
expect(applied).toBeInstanceOf(ContractBuilder);
|
|
55
|
+
expect(applied).not.toBe(builder);
|
|
56
|
+
expect(applied["~orpc"]).toEqual({
|
|
57
|
+
...builder["~orpc"],
|
|
58
|
+
inputSchema: generalSchema,
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it(".errors", () => {
|
|
63
|
+
const errors = {
|
|
64
|
+
BAD_GATEWAY: { data: outputSchema },
|
|
65
|
+
OVERRIDE: { message: "override" },
|
|
66
|
+
} as const;
|
|
67
|
+
const applied = builder.errors(errors);
|
|
68
|
+
|
|
69
|
+
expect(applied).toBeInstanceOf(ContractBuilder);
|
|
70
|
+
expect(applied).not.toBe(builder);
|
|
71
|
+
expect(applied["~orpc"]).toEqual({
|
|
72
|
+
...builder["~orpc"],
|
|
73
|
+
errorMap: effectErrorMapToErrorMap({
|
|
74
|
+
...baseErrorMap,
|
|
75
|
+
...errors,
|
|
76
|
+
}),
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it(".meta", () => {
|
|
81
|
+
const meta = { dev: true, log: true };
|
|
82
|
+
const applied = builder.meta(meta);
|
|
83
|
+
|
|
84
|
+
expect(applied).toBeInstanceOf(ContractBuilder);
|
|
85
|
+
expect(applied).not.toBe(builder);
|
|
86
|
+
expect(applied["~orpc"]).toEqual({
|
|
87
|
+
...builder["~orpc"],
|
|
88
|
+
meta: { ...builder["~orpc"].meta, ...meta },
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it(".route", () => {
|
|
93
|
+
const route = { method: "GET", path: "/path" } as const;
|
|
94
|
+
const applied = builder.route(route);
|
|
95
|
+
|
|
96
|
+
expect(applied).toBeInstanceOf(ContractBuilder);
|
|
97
|
+
expect(applied).not.toBe(builder);
|
|
98
|
+
expect(applied["~orpc"]).toEqual({
|
|
99
|
+
...builder["~orpc"],
|
|
100
|
+
route: { ...builder["~orpc"].route, ...route },
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it(".input", () => {
|
|
105
|
+
const applied = builder.input(generalSchema);
|
|
106
|
+
|
|
107
|
+
expect(applied).toBeInstanceOf(ContractBuilder);
|
|
108
|
+
expect(applied).not.toBe(builder);
|
|
109
|
+
expect(applied["~orpc"]).toEqual({
|
|
110
|
+
...builder["~orpc"],
|
|
111
|
+
inputSchema: generalSchema,
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it(".output", () => {
|
|
116
|
+
const applied = builder.output(generalSchema);
|
|
117
|
+
|
|
118
|
+
expect(applied).toBeInstanceOf(ContractBuilder);
|
|
119
|
+
expect(applied).not.toBe(builder);
|
|
120
|
+
expect(applied["~orpc"]).toEqual({
|
|
121
|
+
...builder["~orpc"],
|
|
122
|
+
outputSchema: generalSchema,
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it(".prefix", () => {
|
|
127
|
+
const applied = builder.prefix("/api") as any;
|
|
128
|
+
|
|
129
|
+
expect(applied).toBeInstanceOf(ContractBuilder);
|
|
130
|
+
expect(applied).not.toBe(builder);
|
|
131
|
+
expect(applied["~orpc"]).toEqual({
|
|
132
|
+
...builder["~orpc"],
|
|
133
|
+
prefix: "/api",
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it(".tag", () => {
|
|
138
|
+
const applied = builder.tag("tag1", "tag2") as any;
|
|
139
|
+
|
|
140
|
+
expect(applied).toBeInstanceOf(ContractBuilder);
|
|
141
|
+
expect(applied).not.toBe(builder);
|
|
142
|
+
expect(applied["~orpc"]).toEqual({
|
|
143
|
+
...builder["~orpc"],
|
|
144
|
+
tags: ["tag1", "tag2"],
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it(".router", () => {
|
|
149
|
+
const router = builder.router({ ping, pong });
|
|
150
|
+
|
|
151
|
+
expect(router.ping["~orpc"].route.path).toBe("/base");
|
|
152
|
+
expect(router.ping["~orpc"].meta).toEqual(baseMeta);
|
|
153
|
+
expect(router.ping["~orpc"].errorMap).toEqual(baseErrorMap);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe("parity: @orpc/contract builder.test-d.ts", () => {
|
|
158
|
+
const typedBuilder = builder;
|
|
159
|
+
|
|
160
|
+
it("is a contract procedure", () => {
|
|
161
|
+
expectTypeOf(typedBuilder["~orpc"]).toBeObject();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("preserves ContractBuilder typing for root methods", () => {
|
|
165
|
+
expectTypeOf(typedBuilder.$meta<{ auth?: boolean }>({})).toBeObject();
|
|
166
|
+
|
|
167
|
+
expectTypeOf(typedBuilder.$route({ method: "GET", path: "/api" })).toExtend<
|
|
168
|
+
typeof typedBuilder
|
|
169
|
+
>();
|
|
170
|
+
|
|
171
|
+
expectTypeOf(typedBuilder.$input(generalSchema)).toBeObject();
|
|
172
|
+
|
|
173
|
+
expectTypeOf(
|
|
174
|
+
typedBuilder.errors({
|
|
175
|
+
INVALID: { message: "invalid" },
|
|
176
|
+
OVERRIDE: { message: "override" },
|
|
177
|
+
}),
|
|
178
|
+
).toBeObject();
|
|
179
|
+
|
|
180
|
+
expectTypeOf(typedBuilder.meta({ log: true })).toBeObject();
|
|
181
|
+
expectTypeOf(typedBuilder.route({ method: "GET" })).toBeObject();
|
|
182
|
+
expectTypeOf(typedBuilder.input(generalSchema)).toBeObject();
|
|
183
|
+
expectTypeOf(typedBuilder.output(generalSchema)).toBeObject();
|
|
184
|
+
expectTypeOf(typedBuilder.prefix("/api")).toBeObject();
|
|
185
|
+
expectTypeOf(typedBuilder.tag("tag1", "tag2")).toBeObject();
|
|
186
|
+
expectTypeOf(typedBuilder.router({ ping, pong })).toExtend<{
|
|
187
|
+
ping: typeof ping;
|
|
188
|
+
pong: typeof pong;
|
|
189
|
+
}>();
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("preserves ContractBuilder constraints", () => {
|
|
193
|
+
// @ts-expect-error - initial meta is required
|
|
194
|
+
typedBuilder.$meta<{ auth?: boolean }>();
|
|
195
|
+
// @ts-expect-error - auth is missing in initial meta
|
|
196
|
+
typedBuilder.$meta<{ auth: boolean }>({});
|
|
197
|
+
// @ts-expect-error - invalid method
|
|
198
|
+
typedBuilder.$route({ method: "INVALID" });
|
|
199
|
+
// @ts-expect-error - invalid schema
|
|
200
|
+
typedBuilder.$input({});
|
|
201
|
+
// @ts-expect-error - schema is invalid
|
|
202
|
+
typedBuilder.errors({ TOO_MANY_REQUESTS: { data: {} } });
|
|
203
|
+
// @ts-expect-error - invalid meta
|
|
204
|
+
typedBuilder.meta({ meta: "INVALID" });
|
|
205
|
+
// @ts-expect-error - invalid method
|
|
206
|
+
typedBuilder.route({ method: "INVALID" });
|
|
207
|
+
// @ts-expect-error - invalid schema
|
|
208
|
+
typedBuilder.input({});
|
|
209
|
+
// @ts-expect-error - invalid schema
|
|
210
|
+
typedBuilder.output({});
|
|
211
|
+
// @ts-expect-error - invalid prefix
|
|
212
|
+
typedBuilder.prefix(1);
|
|
213
|
+
// @ts-expect-error - invalid tag
|
|
214
|
+
typedBuilder.tag(1);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it("keeps eoc-specific tagged error normalization separate", () => {
|
|
218
|
+
const applied = eoc.errors(baseErrorMap);
|
|
219
|
+
|
|
220
|
+
expectTypeOf(applied["~orpc"].errorMap).toBeObject();
|
|
221
|
+
});
|
|
222
|
+
});
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import type { ContractProcedure, Schema } from "@orpc/contract";
|
|
2
|
+
import type {
|
|
3
|
+
DecoratedMiddleware,
|
|
4
|
+
Middleware,
|
|
5
|
+
MiddlewareOutputFn,
|
|
6
|
+
} from "@orpc/server";
|
|
7
|
+
import type { OmitChainMethodDeep } from "@orpc/shared";
|
|
8
|
+
import { describe, expectTypeOf, it } from "vitest";
|
|
9
|
+
import z from "zod";
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
EffectBuilder,
|
|
13
|
+
EffectDecoratedProcedure,
|
|
14
|
+
makeEffectORPC,
|
|
15
|
+
} from "../index";
|
|
16
|
+
import type { CurrentContext, InitialContext } from "./parity-shared";
|
|
17
|
+
import { runtime } from "./parity-shared";
|
|
18
|
+
import type { AssertExtends } from "./shared";
|
|
19
|
+
import {
|
|
20
|
+
baseErrorMap,
|
|
21
|
+
baseMeta,
|
|
22
|
+
type BaseMeta,
|
|
23
|
+
inputSchema,
|
|
24
|
+
outputSchema,
|
|
25
|
+
} from "./shared";
|
|
26
|
+
|
|
27
|
+
const typedBuilder = {} as EffectBuilder<
|
|
28
|
+
InitialContext,
|
|
29
|
+
CurrentContext,
|
|
30
|
+
typeof inputSchema,
|
|
31
|
+
typeof outputSchema,
|
|
32
|
+
typeof baseErrorMap,
|
|
33
|
+
BaseMeta,
|
|
34
|
+
never,
|
|
35
|
+
never
|
|
36
|
+
>;
|
|
37
|
+
|
|
38
|
+
const rootBuilder = makeEffectORPC(runtime)
|
|
39
|
+
.$context<InitialContext>()
|
|
40
|
+
.$meta(baseMeta)
|
|
41
|
+
.$input(inputSchema)
|
|
42
|
+
.errors(baseErrorMap);
|
|
43
|
+
|
|
44
|
+
const withMiddlewares = rootBuilder.use(({ next }) =>
|
|
45
|
+
next({ context: { auth: true as boolean } }),
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const procedureBuilder = withMiddlewares.meta(baseMeta);
|
|
49
|
+
const withInput = procedureBuilder.input(inputSchema);
|
|
50
|
+
const withOutput = procedureBuilder.output(outputSchema);
|
|
51
|
+
const withInputOutput = withInput.output(outputSchema);
|
|
52
|
+
|
|
53
|
+
describe("parity: @orpc/server builder.test-d.ts", () => {
|
|
54
|
+
it("is a contract procedure", () => {
|
|
55
|
+
expectTypeOf<
|
|
56
|
+
AssertExtends<
|
|
57
|
+
typeof typedBuilder,
|
|
58
|
+
ContractProcedure<
|
|
59
|
+
typeof inputSchema,
|
|
60
|
+
typeof outputSchema,
|
|
61
|
+
typeof baseErrorMap,
|
|
62
|
+
BaseMeta
|
|
63
|
+
>
|
|
64
|
+
>
|
|
65
|
+
>().toEqualTypeOf<true>();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it(".$config / .$context / .$meta / .$route / .$input", () => {
|
|
69
|
+
expectTypeOf(
|
|
70
|
+
rootBuilder.$config({
|
|
71
|
+
initialInputValidationIndex: Number.NEGATIVE_INFINITY,
|
|
72
|
+
initialOutputValidationIndex: Number.POSITIVE_INFINITY,
|
|
73
|
+
}),
|
|
74
|
+
).toBeObject();
|
|
75
|
+
|
|
76
|
+
expectTypeOf(rootBuilder.$context()).toBeObject();
|
|
77
|
+
expectTypeOf(rootBuilder.$context<{ anything: string }>()).toBeObject();
|
|
78
|
+
expectTypeOf(rootBuilder.$meta<{ auth?: boolean }>({})).toBeObject();
|
|
79
|
+
expectTypeOf(rootBuilder.$route({ method: "GET" })).toBeObject();
|
|
80
|
+
|
|
81
|
+
const schema = z.void();
|
|
82
|
+
expectTypeOf(rootBuilder.$input(schema)).toBeObject();
|
|
83
|
+
expectTypeOf(rootBuilder.$input<Schema<void, unknown>>()).toBeObject();
|
|
84
|
+
|
|
85
|
+
rootBuilder.$config({
|
|
86
|
+
// @ts-expect-error - must be number
|
|
87
|
+
initialInputValidationIndex: "INVALID",
|
|
88
|
+
});
|
|
89
|
+
// @ts-expect-error - initial meta is required
|
|
90
|
+
rootBuilder.$meta<{ auth?: boolean }>();
|
|
91
|
+
// @ts-expect-error - invalid method
|
|
92
|
+
rootBuilder.$route({ method: "INVALID" });
|
|
93
|
+
// @ts-expect-error - invalid schema
|
|
94
|
+
rootBuilder.$input<"invalid">();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it(".middleware", () => {
|
|
98
|
+
expectTypeOf(
|
|
99
|
+
rootBuilder.middleware(
|
|
100
|
+
({ next }, input: "input", output: MiddlewareOutputFn<"output">) => {
|
|
101
|
+
expectTypeOf(input).toEqualTypeOf<"input">();
|
|
102
|
+
expectTypeOf(output).toEqualTypeOf<MiddlewareOutputFn<"output">>();
|
|
103
|
+
return next({ context: { extra: true } });
|
|
104
|
+
},
|
|
105
|
+
),
|
|
106
|
+
).toExtend<
|
|
107
|
+
DecoratedMiddleware<
|
|
108
|
+
InitialContext,
|
|
109
|
+
{ extra: boolean },
|
|
110
|
+
"input",
|
|
111
|
+
"output",
|
|
112
|
+
any,
|
|
113
|
+
BaseMeta
|
|
114
|
+
>
|
|
115
|
+
>();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it(".errors / .use / .meta / .route / .input / .output", () => {
|
|
119
|
+
expectTypeOf(
|
|
120
|
+
rootBuilder.errors({ BAD_GATEWAY: { message: "BAD" } }),
|
|
121
|
+
).toBeObject();
|
|
122
|
+
expectTypeOf(withMiddlewares.use).toBeFunction();
|
|
123
|
+
expectTypeOf(withMiddlewares.meta).toBeFunction();
|
|
124
|
+
expectTypeOf(withMiddlewares.route).toBeFunction();
|
|
125
|
+
expectTypeOf(withMiddlewares.input).toBeFunction();
|
|
126
|
+
expectTypeOf(withMiddlewares.output).toBeFunction();
|
|
127
|
+
|
|
128
|
+
const mid = {} as Middleware<
|
|
129
|
+
{ cacheable?: boolean } & Record<never, never>,
|
|
130
|
+
Record<never, never>,
|
|
131
|
+
unknown,
|
|
132
|
+
unknown,
|
|
133
|
+
any,
|
|
134
|
+
BaseMeta
|
|
135
|
+
>;
|
|
136
|
+
expectTypeOf(withMiddlewares.use(mid)).toBeObject();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it(".handler / .effect / .prefix / .tag / .router / .lazy", () => {
|
|
140
|
+
expectTypeOf(withOutput.handler(() => ({ output: 456 }))).toExtend<
|
|
141
|
+
EffectDecoratedProcedure<
|
|
142
|
+
InitialContext & Record<never, never>,
|
|
143
|
+
CurrentContext,
|
|
144
|
+
typeof inputSchema,
|
|
145
|
+
typeof outputSchema,
|
|
146
|
+
typeof baseErrorMap,
|
|
147
|
+
BaseMeta,
|
|
148
|
+
never,
|
|
149
|
+
never
|
|
150
|
+
>
|
|
151
|
+
>();
|
|
152
|
+
|
|
153
|
+
expectTypeOf(
|
|
154
|
+
withOutput.effect(function* () {
|
|
155
|
+
return { output: 456 };
|
|
156
|
+
}),
|
|
157
|
+
).toExtend<
|
|
158
|
+
EffectDecoratedProcedure<
|
|
159
|
+
InitialContext & Record<never, never>,
|
|
160
|
+
CurrentContext,
|
|
161
|
+
typeof inputSchema,
|
|
162
|
+
typeof outputSchema,
|
|
163
|
+
typeof baseErrorMap,
|
|
164
|
+
BaseMeta,
|
|
165
|
+
never,
|
|
166
|
+
never
|
|
167
|
+
>
|
|
168
|
+
>();
|
|
169
|
+
|
|
170
|
+
expectTypeOf(rootBuilder.prefix("/api")).toBeObject();
|
|
171
|
+
expectTypeOf(rootBuilder.tag("tag1", "tag2")).toBeObject();
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
describe("parity: @orpc/server builder-variants.test-d.ts", () => {
|
|
176
|
+
it("keeps variant method surface aligned with upstream", () => {
|
|
177
|
+
void ({} as OmitChainMethodDeep<
|
|
178
|
+
typeof typedBuilder,
|
|
179
|
+
"$config" | "$context" | "$meta" | "$route" | "$input" | "middleware"
|
|
180
|
+
>);
|
|
181
|
+
|
|
182
|
+
expectTypeOf(withMiddlewares.errors).toBeFunction();
|
|
183
|
+
expectTypeOf(withMiddlewares.use).toBeFunction();
|
|
184
|
+
expectTypeOf(withMiddlewares.handler).toBeFunction();
|
|
185
|
+
expectTypeOf(withMiddlewares.effect).toBeFunction();
|
|
186
|
+
|
|
187
|
+
expectTypeOf(withMiddlewares.handler).toBeFunction();
|
|
188
|
+
expectTypeOf(procedureBuilder.traced).toBeFunction();
|
|
189
|
+
expectTypeOf(withInput.output).toBeFunction();
|
|
190
|
+
expectTypeOf(withOutput.input).toBeFunction();
|
|
191
|
+
expectTypeOf(withInputOutput.effect).toBeFunction();
|
|
192
|
+
});
|
|
193
|
+
});
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { Middleware, MiddlewareOutputFn, Procedure } from "@orpc/server";
|
|
2
|
+
import { describe, expectTypeOf, it } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { makeEffectORPC } from "../index";
|
|
5
|
+
import type { CurrentContext, InitialContext } from "./parity-shared";
|
|
6
|
+
import { runtime } from "./parity-shared";
|
|
7
|
+
import {
|
|
8
|
+
type AssertExtends,
|
|
9
|
+
baseErrorMap,
|
|
10
|
+
type BaseMeta,
|
|
11
|
+
inputSchema,
|
|
12
|
+
outputSchema,
|
|
13
|
+
} from "./shared";
|
|
14
|
+
|
|
15
|
+
const procedure = makeEffectORPC(runtime)
|
|
16
|
+
.$context<InitialContext>()
|
|
17
|
+
.$meta({ mode: "dev" } as BaseMeta)
|
|
18
|
+
.$input(inputSchema)
|
|
19
|
+
.errors(baseErrorMap)
|
|
20
|
+
.use(({ next }) => next({ context: { auth: true as boolean } }))
|
|
21
|
+
.output(outputSchema)
|
|
22
|
+
.effect(function* () {
|
|
23
|
+
return { output: 456 };
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe("parity: @orpc/server procedure-decorated.test-d.ts", () => {
|
|
27
|
+
it("is a procedure", () => {
|
|
28
|
+
expectTypeOf<
|
|
29
|
+
AssertExtends<
|
|
30
|
+
typeof procedure,
|
|
31
|
+
Procedure<
|
|
32
|
+
InitialContext & Record<never, never>,
|
|
33
|
+
CurrentContext,
|
|
34
|
+
typeof inputSchema,
|
|
35
|
+
typeof outputSchema,
|
|
36
|
+
typeof baseErrorMap,
|
|
37
|
+
BaseMeta
|
|
38
|
+
>
|
|
39
|
+
>
|
|
40
|
+
>().toEqualTypeOf<true>();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it(".errors / .meta / .route", () => {
|
|
44
|
+
expectTypeOf(
|
|
45
|
+
procedure.errors({
|
|
46
|
+
BAD_GATEWAY: { message: "BAD_GATEWAY" },
|
|
47
|
+
OVERRIDE: { message: "OVERRIDE" },
|
|
48
|
+
}),
|
|
49
|
+
).toBeObject();
|
|
50
|
+
|
|
51
|
+
expectTypeOf(procedure.meta({ mode: "dev", log: true })).toBeObject();
|
|
52
|
+
expectTypeOf(
|
|
53
|
+
procedure.route({ method: "POST", path: "/v2/users", tags: ["tag"] }),
|
|
54
|
+
).toBeObject();
|
|
55
|
+
|
|
56
|
+
// @ts-expect-error - invalid meta
|
|
57
|
+
procedure.meta({ log: "INVALID" });
|
|
58
|
+
// @ts-expect-error - invalid method
|
|
59
|
+
procedure.route({ method: "INVALID" });
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe(".use", () => {
|
|
63
|
+
it("without map input", () => {
|
|
64
|
+
expectTypeOf(
|
|
65
|
+
procedure.use(({ next }, input, output) => {
|
|
66
|
+
expectTypeOf(input).toEqualTypeOf<{ input: string }>();
|
|
67
|
+
expectTypeOf(output).toBeFunction();
|
|
68
|
+
return next({ context: { extra: true } });
|
|
69
|
+
}),
|
|
70
|
+
).toBeObject();
|
|
71
|
+
|
|
72
|
+
procedure.use(
|
|
73
|
+
// @ts-expect-error - invalid TInContext
|
|
74
|
+
{} as Middleware<{ auth: "invalid" }, any, any, any, any, any>,
|
|
75
|
+
);
|
|
76
|
+
// @ts-expect-error - input is not match
|
|
77
|
+
procedure.use(({ next }, _input: "invalid") => next({}));
|
|
78
|
+
procedure.use(
|
|
79
|
+
// @ts-expect-error - output is not match
|
|
80
|
+
({ next }, _input, _output: MiddlewareOutputFn<"invalid">) => next({}),
|
|
81
|
+
);
|
|
82
|
+
// @ts-expect-error - conflict context
|
|
83
|
+
procedure.use(({ next }) => next({ context: { db: undefined } }));
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("with map input", () => {
|
|
87
|
+
expectTypeOf(
|
|
88
|
+
procedure.use(
|
|
89
|
+
({ next }, input: { mapped: string }, output) => {
|
|
90
|
+
expectTypeOf(input).toEqualTypeOf<{ mapped: string }>();
|
|
91
|
+
expectTypeOf(output).toBeFunction();
|
|
92
|
+
return next({ context: { extra: true } });
|
|
93
|
+
},
|
|
94
|
+
(input) => ({ mapped: input.input }),
|
|
95
|
+
),
|
|
96
|
+
).toBeObject();
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it(".callable / .actionable", () => {
|
|
101
|
+
expectTypeOf(
|
|
102
|
+
procedure.callable({
|
|
103
|
+
context: async (_clientContext: { batch?: boolean }) => ({
|
|
104
|
+
db: "postgres",
|
|
105
|
+
}),
|
|
106
|
+
}),
|
|
107
|
+
).toBeFunction();
|
|
108
|
+
|
|
109
|
+
expectTypeOf(
|
|
110
|
+
procedure.actionable({
|
|
111
|
+
context: async (_clientContext: { batch?: boolean }) => ({
|
|
112
|
+
db: "postgres",
|
|
113
|
+
}),
|
|
114
|
+
}),
|
|
115
|
+
).toBeFunction();
|
|
116
|
+
|
|
117
|
+
procedure.actionable({
|
|
118
|
+
// @ts-expect-error - all clientContext must be optional
|
|
119
|
+
context: async (_clientContext: { batch: boolean }) => ({
|
|
120
|
+
db: "postgres",
|
|
121
|
+
}),
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
});
|