1import { assert, describe, it } from "@effect/vitest"
2import { Cause, Context, Effect, Exit, Option, Schema } from "effect"
3import { Headers } from "effect/http"
4import { Rpc, RpcGroup } from "effect/rpc"
5import { RequestId } from "effect/rpc/RpcMessage"
6import * as RpcSchema from "effect/rpc/RpcSchema"
7
8const TestGroup = RpcGroup.make(
9 Rpc.make("one"),
10 Rpc.make("two", {
11 success: Schema.String
12 })
13)
14
15describe("Rpc", () => {
16 it.effect("can implement a single handler", () =>
17 Effect.gen(function*() {
18 const TwoHandler = TestGroup.toLayerHandler("two", () => Effect.succeed("two"))
19 const handler = yield* TestGroup.accessHandler("two").pipe(
20 Effect.provide(TwoHandler)
21 )
22 const result = yield* handler(void 0, {
23 client: {
24 id: 1,
25 annotations: Context.empty(),
26 annotate() {
27 return this
28 }
29 },
30 requestId: RequestId("1"),
31 headers: Headers.empty
32 })
33 assert.strictEqual(result, "two")
34 }))
35
36 it("exitSchema uses custom defect schema", () => {
37 const rpc = Rpc.make("customDefect", {
38 success: Schema.String,
39 defect: Schema.Any
40 })
41
42 const schema = Rpc.exitSchema(rpc)
43 const encode = Schema.encodeSync(schema)
44 const decode = Schema.decodeSync(schema)
45
46 const error = { message: "boom", stack: "Error: boom\n at foo.ts:1", code: 42 }
47 const exit = Exit.die(error)
48
49 const roundTripped = decode(encode(exit))
50
51 assert(Exit.isFailure(roundTripped))
52 const defect = Cause.squash(roundTripped.cause)
53 assert.deepStrictEqual(defect, error)
54 })
55
56 it("JSON-encoded interrupt exits use null for a missing fiberId", () => {
57 const codec = Schema.toCodecJson(Rpc.exitSchema(Rpc.make("probe")))
58 const encoded = Schema.encodeSync(codec)(Exit.interrupt())
59
60 assert.deepStrictEqual(encoded, {
61 _tag: "Failure",
62 cause: [{ _tag: "Interrupt", fiberId: null }]
63 })
64 assert.deepStrictEqual(Schema.decodeSync(codec)(encoded), Exit.interrupt())
65 assert.deepStrictEqual(Schema.encodeSync(codec)(Schema.decodeSync(codec)(encoded)), encoded)
66 })
67
68 it("RpcSchema.getStreamSchemas returns Option", () => {
69 const plain = Rpc.make("plainSchemas", { success: Schema.String })
70 const stream = Rpc.make("streamSchemas", {
71 success: Schema.String,
72 error: Schema.Number,
73 stream: true
74 })
75 const none = RpcSchema.getStreamSchemas(plain.successSchema)
76 assert(Option.isNone(none))
77
78 const some = RpcSchema.getStreamSchemas(stream.successSchema)
79 if (Option.isNone(some)) {
80 assert.fail("Expected stream schema")
81 }
82 assert.strictEqual(some.value.success, Schema.String)
83 assert.strictEqual(some.value.error, Schema.Number)
84 })
85})