-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherrors.ts
More file actions
148 lines (132 loc) · 3.77 KB
/
errors.ts
File metadata and controls
148 lines (132 loc) · 3.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import { AbortError, ClientError, TimeoutError } from "@probitas/client";
import { HttpBody } from "./body.ts";
/**
* Format error message with status and body detail.
* JSON bodies are pretty-printed with Deno.inspect for readability.
*/
function formatErrorMessage(
status: number,
statusText: string,
body: HttpBody,
): string {
const text = body.text;
if (text === null) {
return `${status}: ${statusText}`;
}
// Try to parse as JSON for pretty-printing, otherwise use text as-is
let detail: string;
try {
const json = body.json;
detail = Deno.inspect(json, {
compact: false,
sorted: true,
trailingComma: true,
});
} catch {
detail = text;
}
const indented = detail
.split("\n")
.map((line) => ` ${line}`)
.join("\n");
return `${status}: ${statusText}\n\n${indented}`;
}
/**
* Options for creating an HttpError.
*/
export interface HttpErrorOptions extends ErrorOptions {
/** Response body as raw bytes */
readonly body?: Uint8Array | null;
/** Response headers */
readonly headers?: Headers | null;
}
/**
* HTTP error class for non-2xx responses.
*
* This error is thrown (or returned in response.error) when the server
* responds with a 4xx or 5xx status code. It includes the response body
* for inspecting error details.
*
* @example Check status code and body
* ```ts
* import { createHttpClient, HttpError } from "@probitas/client-http";
*
* const http = createHttpClient({ url: "http://localhost:3000", throwOnError: true });
* try {
* await http.get("/not-found");
* } catch (error) {
* if (error instanceof HttpError && error.status === 404) {
* console.log("Not found:", error.text);
* }
* }
* ```
*/
export class HttpError extends ClientError {
override readonly name: string = "HttpError";
override readonly kind = "http" as const;
/** HTTP status code */
readonly status: number;
/** HTTP status text */
readonly statusText: string;
/** Response headers (null if not available) */
readonly headers: Headers | null;
readonly #body: HttpBody;
constructor(
status: number,
statusText: string,
options?: HttpErrorOptions,
) {
const headers = options?.headers ?? null;
const body = new HttpBody(options?.body ?? null, headers);
const message = formatErrorMessage(status, statusText, body);
super(message, "http", options);
this.status = status;
this.statusText = statusText;
this.headers = headers;
this.#body = body;
}
/** Response body as raw bytes (null if no body) */
get body(): Uint8Array | null {
return this.#body.bytes;
}
/** Get body as ArrayBuffer (null if no body) */
get arrayBuffer(): ArrayBuffer | null {
return this.#body.arrayBuffer;
}
/** Get body as Blob (null if no body) */
get blob(): Blob | null {
return this.#body.blob;
}
/** Get body as text (null if no body) */
get text(): string | null {
return this.#body.text;
}
/**
* Get body as parsed JSON (null if no body).
* @throws SyntaxError if body is not valid JSON
*/
get json(): unknown {
return this.#body.json;
}
}
/**
* Error thrown when a network-level failure occurs.
*
* This error indicates that the request could not be processed by the server
* due to network issues (connection refused, DNS resolution failure, etc.).
*/
export class HttpNetworkError extends ClientError {
override readonly name = "HttpNetworkError";
override readonly kind = "network" as const;
constructor(message: string, options?: ErrorOptions) {
super(message, "network", options);
}
}
/**
* Error types that indicate the operation was not processed.
* These are errors that occur before the request reaches the server.
*/
export type HttpFailureError =
| HttpNetworkError
| AbortError
| TimeoutError;