1import { RelayAuthInvalidError } from "@t3tools/contracts/relay";
2import { describe, expect, it } from "@effect/vitest";
3
4import {
5 DPOP_CLOCK_HINT,
6 DPOP_RETRY_HINT,
7 DPOP_UNKNOWN_HINT,
8 relayProtectedErrorMessage,
9} from "./errorPresentation.ts";
10
11describe("relayProtectedErrorMessage", () => {
12 it("presents clock skew as one possible cause when the relay omits the reason", () => {
13 const error = new RelayAuthInvalidError({
14 code: "auth_invalid",
15 reason: "invalid_dpop",
16 traceId: "trace-1",
17 });
18
19 expect(relayProtectedErrorMessage(error)).toBe(
20 `Relay rejected the DPoP proof. ${DPOP_UNKNOWN_HINT}`,
21 );
22 });
23
24 it("keeps the clock hint for a relay that confirms a time-window failure", () => {
25 const error = new RelayAuthInvalidError({
26 code: "auth_invalid",
27 reason: "invalid_dpop",
28 dpopFailureReason: "time_window",
29 traceId: "trace-1",
30 });
31
32 expect(relayProtectedErrorMessage(error)).toContain(DPOP_CLOCK_HINT);
33 });
34
35 it("does not blame the clock when the relay identifies another proof failure", () => {
36 const error = new RelayAuthInvalidError({
37 code: "auth_invalid",
38 reason: "invalid_dpop",
39 dpopFailureReason: "key_mismatch",
40 traceId: "trace-1",
41 });
42
43 expect(relayProtectedErrorMessage(error)).toBe(
44 `Relay rejected the DPoP proof. ${DPOP_RETRY_HINT}`,
45 );
46 });
47
48 it("preserves the existing message for other authentication failures", () => {
49 const error = new RelayAuthInvalidError({
50 code: "auth_invalid",
51 reason: "invalid_bearer",
52 traceId: "trace-1",
53 });
54
55 expect(relayProtectedErrorMessage(error)).toBe("Relay rejected the cloud session token.");
56 });
57});