effect-orpc 0.1.4 → 0.2.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/README.md +95 -0
- package/dist/index.js +806 -476
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/contract.ts +491 -0
- package/src/effect-builder.ts +349 -619
- package/src/effect-enhance-router.ts +20 -21
- package/src/effect-procedure.ts +274 -263
- package/src/effect-runtime.ts +134 -0
- package/src/eoc.ts +499 -0
- package/src/extension/compose-surfaces.ts +15 -0
- package/src/extension/create-node-proxy.ts +270 -0
- package/src/extension/state.ts +108 -0
- package/src/index.ts +20 -3
- package/src/tagged-error.ts +24 -4
- package/src/tests/contract.test.ts +346 -0
- package/src/tests/effect-builder.proxy.test.ts +253 -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 +210 -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/effect-builder-surface.ts +441 -0
- package/src/types/effect-procedure-surface.ts +243 -0
- package/src/types/index.ts +22 -26
- package/src/types/variants.ts +100 -16
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import type { OmitChainMethodDeep } from "@orpc/shared";
|
|
2
|
+
import { describe, expectTypeOf, it } from "vitest";
|
|
3
|
+
|
|
4
|
+
import type {
|
|
5
|
+
EffectContractProcedureBuilderWithInputOutput,
|
|
6
|
+
EffectContractRouterBuilder,
|
|
7
|
+
} from "../index";
|
|
8
|
+
import { eoc } from "../index";
|
|
9
|
+
import {
|
|
10
|
+
type BaseMeta,
|
|
11
|
+
baseErrorMap,
|
|
12
|
+
generalSchema,
|
|
13
|
+
inputSchema,
|
|
14
|
+
outputSchema,
|
|
15
|
+
ping,
|
|
16
|
+
pong,
|
|
17
|
+
} from "./shared";
|
|
18
|
+
|
|
19
|
+
const generalBuilder = eoc
|
|
20
|
+
.$meta({ mode: "dev" } as BaseMeta)
|
|
21
|
+
.$input(inputSchema)
|
|
22
|
+
.errors(baseErrorMap);
|
|
23
|
+
|
|
24
|
+
describe("parity: @orpc/contract builder-variants.test-d.ts", () => {
|
|
25
|
+
describe("EffectContractProcedureBuilder", () => {
|
|
26
|
+
const builder = eoc.errors(baseErrorMap).meta({ mode: "dev" } as BaseMeta);
|
|
27
|
+
|
|
28
|
+
it("backward compatibility", () => {
|
|
29
|
+
const expected = {} as OmitChainMethodDeep<
|
|
30
|
+
typeof generalBuilder,
|
|
31
|
+
"$meta" | "$route" | "$input" | "prefix" | "tag" | "router"
|
|
32
|
+
>;
|
|
33
|
+
|
|
34
|
+
expectTypeOf<keyof typeof builder>().toEqualTypeOf<
|
|
35
|
+
keyof typeof expected
|
|
36
|
+
>();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it(".errors / .meta / .route / .input / .output", () => {
|
|
40
|
+
expectTypeOf(
|
|
41
|
+
builder.errors({ INVALID: { message: "invalid" } }),
|
|
42
|
+
).toBeObject();
|
|
43
|
+
expectTypeOf(builder.meta({ log: true })).toBeObject();
|
|
44
|
+
expectTypeOf(builder.route({ method: "GET" })).toBeObject();
|
|
45
|
+
expectTypeOf(builder.input(generalSchema)).toBeObject();
|
|
46
|
+
expectTypeOf(builder.output(generalSchema)).toBeObject();
|
|
47
|
+
|
|
48
|
+
// @ts-expect-error - schema is invalid
|
|
49
|
+
builder.errors({ TOO_MANY_REQUESTS: { data: {} } });
|
|
50
|
+
// @ts-expect-error - invalid method
|
|
51
|
+
builder.route({ method: "INVALID" });
|
|
52
|
+
// @ts-expect-error - schema is invalid
|
|
53
|
+
builder.input({});
|
|
54
|
+
// @ts-expect-error - schema is invalid
|
|
55
|
+
builder.output({});
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe("EffectContractProcedureBuilderWithInput", () => {
|
|
60
|
+
const builder = eoc
|
|
61
|
+
.errors(baseErrorMap)
|
|
62
|
+
.meta({ mode: "dev" })
|
|
63
|
+
.input(inputSchema);
|
|
64
|
+
|
|
65
|
+
it("backward compatibility", () => {
|
|
66
|
+
const expected = {} as OmitChainMethodDeep<
|
|
67
|
+
typeof generalBuilder,
|
|
68
|
+
"$meta" | "$route" | "$input" | "prefix" | "tag" | "router" | "input"
|
|
69
|
+
>;
|
|
70
|
+
|
|
71
|
+
expectTypeOf<keyof typeof builder>().toEqualTypeOf<
|
|
72
|
+
keyof typeof expected
|
|
73
|
+
>();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it(".errors / .meta / .route / .output", () => {
|
|
77
|
+
expectTypeOf(
|
|
78
|
+
builder.errors({ INVALID: { message: "invalid" } }),
|
|
79
|
+
).toBeObject();
|
|
80
|
+
expectTypeOf(builder.meta({ log: true })).toBeObject();
|
|
81
|
+
expectTypeOf(builder.route({ method: "GET" })).toBeObject();
|
|
82
|
+
expectTypeOf(builder.output(generalSchema)).toExtend<
|
|
83
|
+
EffectContractProcedureBuilderWithInputOutput<
|
|
84
|
+
typeof inputSchema,
|
|
85
|
+
typeof generalSchema,
|
|
86
|
+
typeof baseErrorMap,
|
|
87
|
+
BaseMeta
|
|
88
|
+
>
|
|
89
|
+
>();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe("EffectContractProcedureBuilderWithOutput", () => {
|
|
94
|
+
const builder = eoc
|
|
95
|
+
.errors(baseErrorMap)
|
|
96
|
+
.meta({ mode: "dev" })
|
|
97
|
+
.output(outputSchema);
|
|
98
|
+
|
|
99
|
+
it("backward compatibility", () => {
|
|
100
|
+
const expected = {} as OmitChainMethodDeep<
|
|
101
|
+
typeof generalBuilder,
|
|
102
|
+
"$meta" | "$route" | "$input" | "prefix" | "tag" | "router" | "output"
|
|
103
|
+
>;
|
|
104
|
+
|
|
105
|
+
expectTypeOf<keyof typeof builder>().toEqualTypeOf<
|
|
106
|
+
keyof typeof expected
|
|
107
|
+
>();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it(".errors / .meta / .route / .input", () => {
|
|
111
|
+
expectTypeOf(
|
|
112
|
+
builder.errors({ INVALID: { message: "invalid" } }),
|
|
113
|
+
).toBeObject();
|
|
114
|
+
expectTypeOf(builder.meta({ log: true })).toBeObject();
|
|
115
|
+
expectTypeOf(builder.route({ method: "GET" })).toBeObject();
|
|
116
|
+
expectTypeOf(builder.input(generalSchema)).toExtend<
|
|
117
|
+
EffectContractProcedureBuilderWithInputOutput<
|
|
118
|
+
typeof generalSchema,
|
|
119
|
+
typeof outputSchema,
|
|
120
|
+
typeof baseErrorMap,
|
|
121
|
+
BaseMeta
|
|
122
|
+
>
|
|
123
|
+
>();
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe("EffectContractProcedureBuilderWithInputOutput", () => {
|
|
128
|
+
const builder = eoc
|
|
129
|
+
.errors(baseErrorMap)
|
|
130
|
+
.meta({ mode: "dev" })
|
|
131
|
+
.input(inputSchema)
|
|
132
|
+
.output(outputSchema);
|
|
133
|
+
|
|
134
|
+
it("backward compatibility", () => {
|
|
135
|
+
const expected = {} as OmitChainMethodDeep<
|
|
136
|
+
typeof generalBuilder,
|
|
137
|
+
| "$meta"
|
|
138
|
+
| "$route"
|
|
139
|
+
| "$input"
|
|
140
|
+
| "prefix"
|
|
141
|
+
| "tag"
|
|
142
|
+
| "router"
|
|
143
|
+
| "input"
|
|
144
|
+
| "output"
|
|
145
|
+
>;
|
|
146
|
+
|
|
147
|
+
expectTypeOf<keyof typeof builder>().toEqualTypeOf<
|
|
148
|
+
keyof typeof expected
|
|
149
|
+
>();
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it(".errors / .meta / .route", () => {
|
|
153
|
+
expectTypeOf(
|
|
154
|
+
builder.errors({ INVALID: { message: "invalid" } }),
|
|
155
|
+
).toBeObject();
|
|
156
|
+
expectTypeOf(builder.meta({ log: true })).toBeObject();
|
|
157
|
+
expectTypeOf(builder.route({ method: "GET" })).toBeObject();
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe("EffectContractRouterBuilder", () => {
|
|
162
|
+
const builder = eoc.errors(baseErrorMap).prefix("/api");
|
|
163
|
+
|
|
164
|
+
it("backward compatibility", () => {
|
|
165
|
+
expectTypeOf(builder.errors).toBeFunction();
|
|
166
|
+
expectTypeOf(builder.prefix).toBeFunction();
|
|
167
|
+
expectTypeOf(builder.tag).toBeFunction();
|
|
168
|
+
expectTypeOf(builder.router).toBeFunction();
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it(".errors / .prefix / .tag / .router", () => {
|
|
172
|
+
expectTypeOf(
|
|
173
|
+
builder.errors({ INVALID: { message: "invalid" } }),
|
|
174
|
+
).toBeObject();
|
|
175
|
+
expectTypeOf(builder.prefix("/api")).toExtend<
|
|
176
|
+
EffectContractRouterBuilder<typeof baseErrorMap, BaseMeta>
|
|
177
|
+
>();
|
|
178
|
+
expectTypeOf(builder.tag("tag1", "tag2")).toExtend<
|
|
179
|
+
EffectContractRouterBuilder<typeof baseErrorMap, BaseMeta>
|
|
180
|
+
>();
|
|
181
|
+
expectTypeOf(builder.router({ ping, pong })).toExtend<{
|
|
182
|
+
ping: typeof ping;
|
|
183
|
+
pong: typeof pong;
|
|
184
|
+
}>();
|
|
185
|
+
|
|
186
|
+
// @ts-expect-error - invalid prefix
|
|
187
|
+
builder.prefix(1);
|
|
188
|
+
// @ts-expect-error - invalid tag
|
|
189
|
+
builder.tag(1);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
});
|
|
@@ -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,210 @@
|
|
|
1
|
+
import type { ContractProcedure, Schema } from "@orpc/contract";
|
|
2
|
+
import type {
|
|
3
|
+
Builder,
|
|
4
|
+
DecoratedMiddleware,
|
|
5
|
+
Middleware,
|
|
6
|
+
MiddlewareOutputFn,
|
|
7
|
+
} from "@orpc/server";
|
|
8
|
+
import type { OmitChainMethodDeep } from "@orpc/shared";
|
|
9
|
+
import { describe, expectTypeOf, it } from "vitest";
|
|
10
|
+
import z from "zod";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
EffectBuilder,
|
|
14
|
+
EffectDecoratedProcedure,
|
|
15
|
+
makeEffectORPC,
|
|
16
|
+
} from "../index";
|
|
17
|
+
import type { CurrentContext, InitialContext } from "./parity-shared";
|
|
18
|
+
import { runtime } from "./parity-shared";
|
|
19
|
+
import type { AssertExtends } from "./shared";
|
|
20
|
+
import {
|
|
21
|
+
baseErrorMap,
|
|
22
|
+
baseMeta,
|
|
23
|
+
type BaseMeta,
|
|
24
|
+
inputSchema,
|
|
25
|
+
outputSchema,
|
|
26
|
+
} from "./shared";
|
|
27
|
+
|
|
28
|
+
const typedBuilder = {} as EffectBuilder<
|
|
29
|
+
InitialContext,
|
|
30
|
+
CurrentContext,
|
|
31
|
+
typeof inputSchema,
|
|
32
|
+
typeof outputSchema,
|
|
33
|
+
typeof baseErrorMap,
|
|
34
|
+
BaseMeta,
|
|
35
|
+
never,
|
|
36
|
+
never
|
|
37
|
+
>;
|
|
38
|
+
|
|
39
|
+
const rootBuilder = makeEffectORPC(runtime)
|
|
40
|
+
.$context<InitialContext>()
|
|
41
|
+
.$meta(baseMeta)
|
|
42
|
+
.$input(inputSchema)
|
|
43
|
+
.errors(baseErrorMap);
|
|
44
|
+
|
|
45
|
+
const withMiddlewares = rootBuilder.use(({ next }) =>
|
|
46
|
+
next({ context: { auth: true as boolean } }),
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const procedureBuilder = withMiddlewares.meta(baseMeta);
|
|
50
|
+
const withInput = procedureBuilder.input(inputSchema);
|
|
51
|
+
const withOutput = procedureBuilder.output(outputSchema);
|
|
52
|
+
const withInputOutput = withInput.output(outputSchema);
|
|
53
|
+
|
|
54
|
+
describe("parity: @orpc/server builder.test-d.ts", () => {
|
|
55
|
+
it("exposes every upstream builder key", () => {
|
|
56
|
+
type MissingEffectBuilderKeys = Exclude<
|
|
57
|
+
keyof Builder<
|
|
58
|
+
InitialContext,
|
|
59
|
+
CurrentContext,
|
|
60
|
+
typeof inputSchema,
|
|
61
|
+
typeof outputSchema,
|
|
62
|
+
typeof baseErrorMap,
|
|
63
|
+
BaseMeta
|
|
64
|
+
>,
|
|
65
|
+
keyof typeof typedBuilder
|
|
66
|
+
>;
|
|
67
|
+
|
|
68
|
+
expectTypeOf<MissingEffectBuilderKeys>().toEqualTypeOf<never>();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("is a contract procedure", () => {
|
|
72
|
+
expectTypeOf<
|
|
73
|
+
AssertExtends<
|
|
74
|
+
typeof typedBuilder,
|
|
75
|
+
ContractProcedure<
|
|
76
|
+
typeof inputSchema,
|
|
77
|
+
typeof outputSchema,
|
|
78
|
+
typeof baseErrorMap,
|
|
79
|
+
BaseMeta
|
|
80
|
+
>
|
|
81
|
+
>
|
|
82
|
+
>().toEqualTypeOf<true>();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it(".$config / .$context / .$meta / .$route / .$input", () => {
|
|
86
|
+
expectTypeOf(
|
|
87
|
+
rootBuilder.$config({
|
|
88
|
+
initialInputValidationIndex: Number.NEGATIVE_INFINITY,
|
|
89
|
+
initialOutputValidationIndex: Number.POSITIVE_INFINITY,
|
|
90
|
+
}),
|
|
91
|
+
).toBeObject();
|
|
92
|
+
|
|
93
|
+
expectTypeOf(rootBuilder.$context()).toBeObject();
|
|
94
|
+
expectTypeOf(rootBuilder.$context<{ anything: string }>()).toBeObject();
|
|
95
|
+
expectTypeOf(rootBuilder.$meta<{ auth?: boolean }>({})).toBeObject();
|
|
96
|
+
expectTypeOf(rootBuilder.$route({ method: "GET" })).toBeObject();
|
|
97
|
+
|
|
98
|
+
const schema = z.void();
|
|
99
|
+
expectTypeOf(rootBuilder.$input(schema)).toBeObject();
|
|
100
|
+
expectTypeOf(rootBuilder.$input<Schema<void, unknown>>()).toBeObject();
|
|
101
|
+
|
|
102
|
+
rootBuilder.$config({
|
|
103
|
+
// @ts-expect-error - must be number
|
|
104
|
+
initialInputValidationIndex: "INVALID",
|
|
105
|
+
});
|
|
106
|
+
// @ts-expect-error - initial meta is required
|
|
107
|
+
rootBuilder.$meta<{ auth?: boolean }>();
|
|
108
|
+
// @ts-expect-error - invalid method
|
|
109
|
+
rootBuilder.$route({ method: "INVALID" });
|
|
110
|
+
// @ts-expect-error - invalid schema
|
|
111
|
+
rootBuilder.$input<"invalid">();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it(".middleware", () => {
|
|
115
|
+
expectTypeOf(
|
|
116
|
+
rootBuilder.middleware(
|
|
117
|
+
({ next }, input: "input", output: MiddlewareOutputFn<"output">) => {
|
|
118
|
+
expectTypeOf(input).toEqualTypeOf<"input">();
|
|
119
|
+
expectTypeOf(output).toEqualTypeOf<MiddlewareOutputFn<"output">>();
|
|
120
|
+
return next({ context: { extra: true } });
|
|
121
|
+
},
|
|
122
|
+
),
|
|
123
|
+
).toExtend<
|
|
124
|
+
DecoratedMiddleware<
|
|
125
|
+
InitialContext,
|
|
126
|
+
{ extra: boolean },
|
|
127
|
+
"input",
|
|
128
|
+
"output",
|
|
129
|
+
any,
|
|
130
|
+
BaseMeta
|
|
131
|
+
>
|
|
132
|
+
>();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it(".errors / .use / .meta / .route / .input / .output", () => {
|
|
136
|
+
expectTypeOf(
|
|
137
|
+
rootBuilder.errors({ BAD_GATEWAY: { message: "BAD" } }),
|
|
138
|
+
).toBeObject();
|
|
139
|
+
expectTypeOf(withMiddlewares.use).toBeFunction();
|
|
140
|
+
expectTypeOf(withMiddlewares.meta).toBeFunction();
|
|
141
|
+
expectTypeOf(withMiddlewares.route).toBeFunction();
|
|
142
|
+
expectTypeOf(withMiddlewares.input).toBeFunction();
|
|
143
|
+
expectTypeOf(withMiddlewares.output).toBeFunction();
|
|
144
|
+
|
|
145
|
+
const mid = {} as Middleware<
|
|
146
|
+
{ cacheable?: boolean } & Record<never, never>,
|
|
147
|
+
Record<never, never>,
|
|
148
|
+
unknown,
|
|
149
|
+
unknown,
|
|
150
|
+
any,
|
|
151
|
+
BaseMeta
|
|
152
|
+
>;
|
|
153
|
+
expectTypeOf(withMiddlewares.use(mid)).toBeObject();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it(".handler / .effect / .prefix / .tag / .router / .lazy", () => {
|
|
157
|
+
expectTypeOf(withOutput.handler(() => ({ output: 456 }))).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(
|
|
171
|
+
withOutput.effect(function* () {
|
|
172
|
+
return { output: 456 };
|
|
173
|
+
}),
|
|
174
|
+
).toExtend<
|
|
175
|
+
EffectDecoratedProcedure<
|
|
176
|
+
InitialContext & Record<never, never>,
|
|
177
|
+
CurrentContext,
|
|
178
|
+
typeof inputSchema,
|
|
179
|
+
typeof outputSchema,
|
|
180
|
+
typeof baseErrorMap,
|
|
181
|
+
BaseMeta,
|
|
182
|
+
never,
|
|
183
|
+
never
|
|
184
|
+
>
|
|
185
|
+
>();
|
|
186
|
+
|
|
187
|
+
expectTypeOf(rootBuilder.prefix("/api")).toBeObject();
|
|
188
|
+
expectTypeOf(rootBuilder.tag("tag1", "tag2")).toBeObject();
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
describe("parity: @orpc/server builder-variants.test-d.ts", () => {
|
|
193
|
+
it("keeps variant method surface aligned with upstream", () => {
|
|
194
|
+
void ({} as OmitChainMethodDeep<
|
|
195
|
+
typeof typedBuilder,
|
|
196
|
+
"$config" | "$context" | "$meta" | "$route" | "$input" | "middleware"
|
|
197
|
+
>);
|
|
198
|
+
|
|
199
|
+
expectTypeOf(withMiddlewares.errors).toBeFunction();
|
|
200
|
+
expectTypeOf(withMiddlewares.use).toBeFunction();
|
|
201
|
+
expectTypeOf(withMiddlewares.handler).toBeFunction();
|
|
202
|
+
expectTypeOf(withMiddlewares.effect).toBeFunction();
|
|
203
|
+
|
|
204
|
+
expectTypeOf(withMiddlewares.handler).toBeFunction();
|
|
205
|
+
expectTypeOf(procedureBuilder.traced).toBeFunction();
|
|
206
|
+
expectTypeOf(withInput.output).toBeFunction();
|
|
207
|
+
expectTypeOf(withOutput.input).toBeFunction();
|
|
208
|
+
expectTypeOf(withInputOutput.effect).toBeFunction();
|
|
209
|
+
});
|
|
210
|
+
});
|