@mycroblog/mykit 0.0.0-placeholder.0
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/LICENSE +21 -0
- package/README.md +129 -0
- package/dist/client.d.ts +36 -0
- package/dist/client.js +68 -0
- package/dist/idempotency.d.ts +13 -0
- package/dist/idempotency.js +14 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +13 -0
- package/dist/oauth.d.ts +39 -0
- package/dist/oauth.js +119 -0
- package/dist/paging.d.ts +25 -0
- package/dist/paging.js +27 -0
- package/dist/problem.d.ts +47 -0
- package/dist/problem.js +98 -0
- package/dist/schema.gen.d.ts +17640 -0
- package/dist/schema.gen.js +6 -0
- package/dist/sse.d.ts +13 -0
- package/dist/sse.js +76 -0
- package/dist/stream.d.ts +86 -0
- package/dist/stream.js +252 -0
- package/dist/token.d.ts +56 -0
- package/dist/token.js +83 -0
- package/dist/transport.d.ts +38 -0
- package/dist/transport.js +115 -0
- package/dist/upload.d.ts +30 -0
- package/dist/upload.js +30 -0
- package/package.json +43 -0
package/dist/problem.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/** The type of a problem that means no more than its HTTP status (RFC 9457 §4.2.1). */
|
|
2
|
+
export const problemTypeAboutBlank = "about:blank";
|
|
3
|
+
/**
|
|
4
|
+
* The error of an answer with a status of 400 or more: its RFC 9457 problem document.
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* try { await api.POST("/statuses", { body }); }
|
|
8
|
+
* catch (e) { if (e instanceof ProblemError && e.type === "/api/v1/problems/blocking") { ... } }
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* Branch on `type` and `status`, never on `title` or `detail`, which the server localizes from Accept-Language. The
|
|
12
|
+
* members beyond the standard ones (such as `reason`) are in `problem`.
|
|
13
|
+
*/
|
|
14
|
+
export class ProblemError extends Error {
|
|
15
|
+
name = "ProblemError";
|
|
16
|
+
/** The whole problem document, extension members included. */
|
|
17
|
+
problem;
|
|
18
|
+
/** The headers of the answer, such as Retry-After and WWW-Authenticate. */
|
|
19
|
+
headers;
|
|
20
|
+
constructor(problem, headers) {
|
|
21
|
+
super(problemMessage(problem));
|
|
22
|
+
this.problem = problem;
|
|
23
|
+
this.headers = headers;
|
|
24
|
+
}
|
|
25
|
+
/** The URI that identifies the problem type, `about:blank` when the problem means no more than its status. */
|
|
26
|
+
get type() {
|
|
27
|
+
return this.problem.type;
|
|
28
|
+
}
|
|
29
|
+
/** The HTTP status of the answer. */
|
|
30
|
+
get status() {
|
|
31
|
+
return this.problem.status;
|
|
32
|
+
}
|
|
33
|
+
/** The localized summary of the problem type. */
|
|
34
|
+
get title() {
|
|
35
|
+
return this.problem.title;
|
|
36
|
+
}
|
|
37
|
+
/** The localized explanation of this occurrence. */
|
|
38
|
+
get detail() {
|
|
39
|
+
return this.problem.detail;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function problemMessage(p) {
|
|
43
|
+
let s = `mykit: ${String(p.status)} ${p.type}`;
|
|
44
|
+
if (p.title !== "")
|
|
45
|
+
s += `: ${p.title}`;
|
|
46
|
+
if (p.detail !== undefined && p.detail !== "")
|
|
47
|
+
s += `: ${p.detail}`;
|
|
48
|
+
return s;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Reads the problem of an error answer. An answer that is no problem document (from a proxy, say) becomes a problem
|
|
52
|
+
* of type about:blank with the answer's status.
|
|
53
|
+
*/
|
|
54
|
+
export async function problemFromResponse(response) {
|
|
55
|
+
let doc = {};
|
|
56
|
+
if (isJSON(response.headers.get("Content-Type"))) {
|
|
57
|
+
try {
|
|
58
|
+
const parsed = JSON.parse(await response.text());
|
|
59
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed))
|
|
60
|
+
doc = parsed;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// Not JSON after all: the fallback below.
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
await response.body?.cancel();
|
|
68
|
+
}
|
|
69
|
+
const problem = {
|
|
70
|
+
...doc,
|
|
71
|
+
type: typeof doc["type"] === "string" && doc["type"] !== "" ? doc["type"] : problemTypeAboutBlank,
|
|
72
|
+
title: typeof doc["title"] === "string" && doc["title"] !== "" ? doc["title"] : response.statusText,
|
|
73
|
+
// The status of the answer is the one that happened, whatever the document says.
|
|
74
|
+
status: response.status,
|
|
75
|
+
};
|
|
76
|
+
if (typeof doc["detail"] !== "string")
|
|
77
|
+
delete problem.detail;
|
|
78
|
+
return new ProblemError(problem, response.headers);
|
|
79
|
+
}
|
|
80
|
+
/** Whether a Content-Type is JSON, application/problem+json among them. */
|
|
81
|
+
function isJSON(contentType) {
|
|
82
|
+
const mt = contentType?.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
83
|
+
return mt === "application/json" || mt.endsWith("+json");
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The failure to get an answer from the server: the connection, TLS, or the fetch implementation. Its `cause` is the
|
|
87
|
+
* error of `fetch`. An aborted request is not one: it rejects with the reason of its signal (an AbortError).
|
|
88
|
+
*/
|
|
89
|
+
export class NetworkError extends Error {
|
|
90
|
+
name = "NetworkError";
|
|
91
|
+
method;
|
|
92
|
+
url;
|
|
93
|
+
constructor(method, url, cause) {
|
|
94
|
+
super(`mykit: ${method} ${url}: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
|
|
95
|
+
this.method = method;
|
|
96
|
+
this.url = url;
|
|
97
|
+
}
|
|
98
|
+
}
|