@gandalan/weblibs 2.0.12 → 2.0.14
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/api/dtos/produktion.js +1 -0
- package/api/fluentRestClient.js +68 -5
- package/index.d.ts +2 -1
- package/package.json +1 -1
- package/scripts/generate-dts.mjs +1 -1
package/api/dtos/produktion.js
CHANGED
package/api/fluentRestClient.js
CHANGED
|
@@ -18,20 +18,83 @@
|
|
|
18
18
|
* Error thrown for non-ok HTTP responses. Carries the status code so callers
|
|
19
19
|
* can react to specific statuses (e.g. the automatic 401 retry in fluentApi)
|
|
20
20
|
* without parsing the message.
|
|
21
|
+
*
|
|
22
|
+
* `body` holds the raw response body (if it could be read) and `detail` the
|
|
23
|
+
* best-effort human-readable reason extracted from it: for a JSON body the
|
|
24
|
+
* first of `ExceptionMessage` / `Message` / `error` / `title` / `detail`
|
|
25
|
+
* (IDAS WebApi and ASP.NET Core ProblemDetails conventions), for a plain-text
|
|
26
|
+
* body the text itself, for HTML or an unreadable body `null`. UI code should
|
|
27
|
+
* show `detail` to the user and log `message` (method, url, status).
|
|
28
|
+
*
|
|
29
|
+
* Use {@link RestError.fromResponse} to build one from a fetch response; the
|
|
30
|
+
* constructor alone cannot read the body (it is asynchronous).
|
|
21
31
|
*/
|
|
22
32
|
export class RestError extends Error {
|
|
23
33
|
/**
|
|
24
34
|
* @param {string} method - HTTP method of the failed request.
|
|
25
35
|
* @param {string} url - Full URL of the failed request.
|
|
26
36
|
* @param {Response} res - The non-ok fetch response.
|
|
37
|
+
* @param {string|null} [body=null] - Raw response body, if read.
|
|
27
38
|
*/
|
|
28
|
-
constructor(method, url, res) {
|
|
39
|
+
constructor(method, url, res, body = null) {
|
|
29
40
|
super(`${method} ${url} failed: ${res.status} ${res.statusText}`);
|
|
30
41
|
this.name = "RestError";
|
|
31
42
|
this.method = method;
|
|
32
43
|
this.url = url;
|
|
33
44
|
this.status = res.status;
|
|
34
45
|
this.statusText = res.statusText;
|
|
46
|
+
/** @type {string|null} */
|
|
47
|
+
this.body = body;
|
|
48
|
+
/** @type {string|null} */
|
|
49
|
+
this.detail = RestError.extractDetail(body, res.headers.get("content-type"));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Builds a RestError with the response body read (never throws: an
|
|
54
|
+
* unreadable body just leaves `body`/`detail` at `null`).
|
|
55
|
+
* @param {string} method
|
|
56
|
+
* @param {string} url
|
|
57
|
+
* @param {Response} res
|
|
58
|
+
* @returns {Promise<RestError>}
|
|
59
|
+
*/
|
|
60
|
+
static async fromResponse(method, url, res) {
|
|
61
|
+
let body = null;
|
|
62
|
+
try {
|
|
63
|
+
body = await res.text();
|
|
64
|
+
} catch {
|
|
65
|
+
// body already consumed or stream failed – keep null
|
|
66
|
+
}
|
|
67
|
+
return new RestError(method, url, res, body);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Extracts a human-readable reason from an error body.
|
|
72
|
+
* @param {string|null} body
|
|
73
|
+
* @param {string|null} contentType
|
|
74
|
+
* @returns {string|null}
|
|
75
|
+
*/
|
|
76
|
+
static extractDetail(body, contentType) {
|
|
77
|
+
if (!body) return null;
|
|
78
|
+
const text = body.trim();
|
|
79
|
+
if (!text) return null;
|
|
80
|
+
const looksHtml = /^<!doctype html|^<html/i.test(text) || (contentType ?? "").includes("text/html");
|
|
81
|
+
if (looksHtml) return null;
|
|
82
|
+
if (text.startsWith("{") || text.startsWith("[")) {
|
|
83
|
+
try {
|
|
84
|
+
const json = JSON.parse(text);
|
|
85
|
+
if (typeof json === "string") return json;
|
|
86
|
+
if (json && typeof json === "object" && !Array.isArray(json)) {
|
|
87
|
+
for (const key of ["ExceptionMessage", "exceptionMessage", "Message", "message", "error", "Error", "detail", "title"]) {
|
|
88
|
+
const value = json[key];
|
|
89
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
} catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return text.length <= 500 ? text : null;
|
|
35
98
|
}
|
|
36
99
|
}
|
|
37
100
|
|
|
@@ -92,7 +155,7 @@ export function restClient() {
|
|
|
92
155
|
return skipResponseParsing ? res : await this._parseReponse(res);
|
|
93
156
|
}
|
|
94
157
|
|
|
95
|
-
throw
|
|
158
|
+
throw await RestError.fromResponse("GET", finalUrl, res);
|
|
96
159
|
},
|
|
97
160
|
|
|
98
161
|
/**
|
|
@@ -112,7 +175,7 @@ export function restClient() {
|
|
|
112
175
|
return skipResponseParsing ? res : await this._parseReponse(res);
|
|
113
176
|
}
|
|
114
177
|
|
|
115
|
-
throw
|
|
178
|
+
throw await RestError.fromResponse("PUT", finalUrl, res);
|
|
116
179
|
},
|
|
117
180
|
|
|
118
181
|
/**
|
|
@@ -143,7 +206,7 @@ export function restClient() {
|
|
|
143
206
|
return skipResponseParsing ? res : await this._parseReponse(res);
|
|
144
207
|
}
|
|
145
208
|
|
|
146
|
-
throw
|
|
209
|
+
throw await RestError.fromResponse("POST", finalUrl, res);
|
|
147
210
|
},
|
|
148
211
|
|
|
149
212
|
/**
|
|
@@ -166,7 +229,7 @@ export function restClient() {
|
|
|
166
229
|
return skipResponseParsing ? res : await this._parseReponse(res);
|
|
167
230
|
}
|
|
168
231
|
|
|
169
|
-
throw
|
|
232
|
+
throw await RestError.fromResponse("DELETE", finalUrl, res);
|
|
170
233
|
},
|
|
171
234
|
|
|
172
235
|
_createHeaders(contentType) {
|
package/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export function createAuthManager(): FluentAuthManager;
|
|
|
7
7
|
export function fluentIdasAuthManager(appToken: string, authBaseUrl: string): FluentAuthManager;
|
|
8
8
|
export function fetchEnvConfig(envConfig?: string): Promise<EnvironmentConfig>;
|
|
9
9
|
export function restClient(): FluentRESTClient;
|
|
10
|
-
export class RestError extends Error { method: string; url: string; status: number; statusText: string; constructor(method: string, url: string, res: Response); }
|
|
10
|
+
export class RestError extends Error { method: string; url: string; status: number; statusText: string; body: string | null; detail: string | null; constructor(method: string, url: string, res: Response, body?: string | null); static fromResponse(method: string, url: string, res: Response): Promise<RestError>; static extractDetail(body: string | null, contentType: string | null): string | null; }
|
|
11
11
|
|
|
12
12
|
export type AblageApi = {
|
|
13
13
|
get: (guid: string) => Promise<AblageDTO>;
|
|
@@ -834,6 +834,7 @@ export type BerechnungResultDTO = {
|
|
|
834
834
|
BelegPositionGuid: string;
|
|
835
835
|
RawDataFileContent: string;
|
|
836
836
|
ProduktionsDaten: ProduktionsDatenDTO;
|
|
837
|
+
Meldung: string;
|
|
837
838
|
};
|
|
838
839
|
|
|
839
840
|
export type BerechtigungDTO = {
|
package/package.json
CHANGED
package/scripts/generate-dts.mjs
CHANGED
|
@@ -32,7 +32,7 @@ const rootFunctionDeclarationStatements = [
|
|
|
32
32
|
"export function fluentIdasAuthManager(appToken: string, authBaseUrl: string): FluentAuthManager;",
|
|
33
33
|
"export function fetchEnvConfig(envConfig?: string): Promise<EnvironmentConfig>;",
|
|
34
34
|
"export function restClient(): FluentRESTClient;",
|
|
35
|
-
"export class RestError extends Error { method: string; url: string; status: number; statusText: string; constructor(method: string, url: string, res: Response); }"
|
|
35
|
+
"export class RestError extends Error { method: string; url: string; status: number; statusText: string; body: string | null; detail: string | null; constructor(method: string, url: string, res: Response, body?: string | null); static fromResponse(method: string, url: string, res: Response): Promise<RestError>; static extractDetail(body: string | null, contentType: string | null): string | null; }"
|
|
36
36
|
];
|
|
37
37
|
|
|
38
38
|
const simpleImportTypePattern = /^import\((?:"|').+(?:"|')\)\.[A-Za-z0-9_$]+$/;
|