@nauticana/sail 1.1.14 → 1.1.16
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 +1 -1
- package/package.json +1 -1
- package/src/util/errors.ts +27 -1
package/LICENSE
CHANGED
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
same "printed page" as the copyright notice for easier
|
|
187
187
|
identification within third-party archives.
|
|
188
188
|
|
|
189
|
-
Copyright
|
|
189
|
+
Copyright 2026 Mustafa Karli
|
|
190
190
|
|
|
191
191
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
192
|
you may not use this file except in compliance with the License.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nauticana/sail",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.16",
|
|
4
4
|
"description": "Metadata-driven Angular component library for CRUD admin frontends backed by the keel Go backend. Tables, forms, navigation, OTP/2FA/social auth, billing, payout onboarding.",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"scripts": {
|
package/src/util/errors.ts
CHANGED
|
@@ -15,11 +15,36 @@ function asString(value: unknown): string | undefined {
|
|
|
15
15
|
return typeof value === 'string' && value ? value : undefined;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
function statusOf(err: unknown): number | undefined {
|
|
19
|
+
if (!err || typeof err !== 'object') return undefined;
|
|
20
|
+
const s = (err as { status?: unknown }).status;
|
|
21
|
+
return typeof s === 'number' ? s : undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* True when the browser never received a readable response — the network was
|
|
26
|
+
* down, a CORS rule blocked it, or the request was aborted. Angular collapses
|
|
27
|
+
* all three to status 0 with a ProgressEvent body, so this is the only signal
|
|
28
|
+
* available. Use it to offer a retry rather than reporting a backend rejection.
|
|
29
|
+
*/
|
|
30
|
+
export function isTransportFailure(err: unknown): boolean {
|
|
31
|
+
return statusOf(err) === 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
18
34
|
/**
|
|
19
35
|
* Human-readable message from any sail error shape — SailApiError (BackendService),
|
|
20
36
|
* raw HttpErrorResponse (direct HttpClient calls), or plain Error.
|
|
37
|
+
*
|
|
38
|
+
* keel answers every rejection with an RFC 7807 body, so an error carrying no
|
|
39
|
+
* `detail` did not come from the API: either nothing reached it (status 0) or
|
|
40
|
+
* something in front of it replied with a body we cannot read. Both used to
|
|
41
|
+
* collapse into the caller's fallback, which reads as a backend rejection and
|
|
42
|
+
* hides the real fault; they are now reported distinctly.
|
|
21
43
|
*/
|
|
22
44
|
export function errorDetail(err: unknown, fallback: string): string {
|
|
45
|
+
if (isTransportFailure(err)) {
|
|
46
|
+
return 'Cannot reach the server — the network or a CORS rule blocked the response.';
|
|
47
|
+
}
|
|
23
48
|
const problem = problemOf(err);
|
|
24
49
|
if (problem) {
|
|
25
50
|
const message = asString(problem.detail) ?? asString(problem.title) ?? asString(problem.message);
|
|
@@ -28,7 +53,8 @@ export function errorDetail(err: unknown, fallback: string): string {
|
|
|
28
53
|
if (err instanceof Error && err.message) {
|
|
29
54
|
return err.message;
|
|
30
55
|
}
|
|
31
|
-
|
|
56
|
+
const status = statusOf(err);
|
|
57
|
+
return status ? `${fallback} (HTTP ${status})` : fallback;
|
|
32
58
|
}
|
|
33
59
|
|
|
34
60
|
/** Stable machine-readable discriminator from a keel RFC 7807 response. */
|