1import { describe, expect, it } from "vite-plus/test";
2import * as Exit from "effect/Exit";
3import * as Schema from "effect/Schema";
4
5import { ORCHESTRATION_V2_WS_METHODS } from "./orchestrationV2.ts";
6import { WsRpcGroup, WsSubscribeServerConfigRpc } from "./rpc.ts";
7
8/**
9 * The client always sends `environmentThemes`, including to servers built
10 * before the field existed, whose payload schema was an empty struct. What
11 * makes that safe is that such a schema accepts the request rather than
12 * rejecting it -- an error here would take down the config subscription.
13 */
14describe("subscribeServerConfig payload compatibility", () => {
15 it("is accepted by a server whose schema predates the field", () => {
16 const oldServerPayload = Schema.Struct({});
17 const decoded = Schema.decodeExit(oldServerPayload)({ environmentThemes: true });
18 expect(Exit.isSuccess(decoded)).toBe(true);
19 });
20
21 it("is carried by a server that declares it", () => {
22 const decoded = Schema.decodeSync(WsSubscribeServerConfigRpc.payloadSchema)({
23 environmentThemes: true,
24 });
25 expect(decoded).toEqual({ environmentThemes: true });
26 });
27
28 it("stays optional, so a client that never sends it still subscribes", () => {
29 const decoded = Schema.decodeSync(WsSubscribeServerConfigRpc.payloadSchema)({});
30 expect(decoded).toEqual({});
31 });
32});
33
34describe("WebSocket RPC contracts", () => {
35 it("exposes only the V2 orchestration transport surface", () => {
36 const methods = [...WsRpcGroup.requests.keys()];
37
38 expect(methods).toEqual(expect.arrayContaining(Object.values(ORCHESTRATION_V2_WS_METHODS)));
39 expect(methods.filter((method) => method.startsWith("orchestrationV1."))).toEqual([]);
40 });
41
42 it("rejects server-internal commands sent to dispatchCommand", () => {
43 const dispatchCommand = WsRpcGroup.requests.get(ORCHESTRATION_V2_WS_METHODS.dispatchCommand);
44 if (dispatchCommand === undefined) throw new Error("dispatchCommand is not registered");
45 const decode = Schema.decodeUnknownExit(dispatchCommand.payloadSchema);
46
47 expect(
48 Exit.isFailure(
49 decode({
50 type: "checkpoint.rollback.fail",
51 commandId: "forged-rollback-failure",
52 threadId: "thread-1",
53 requestId: "rollback-1",
54 message: "Forged failure.",
55 }),
56 ),
57 ).toBe(true);
58 expect(
59 Exit.isSuccess(
60 decode({
61 type: "checkpoint.rollback",
62 commandId: "rollback-1",
63 threadId: "thread-1",
64 scopeId: "scope-1",
65 checkpointId: "checkpoint-1",
66 }),
67 ),
68 ).toBe(true);
69 });
70});