@codenhub/error 0.0.1 → 0.1.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 +201 -201
- package/README.md +145 -52
- package/dist/bucket.js +167 -0
- package/dist/create-app-error.d.ts +33 -0
- package/dist/create-app-error.js +104 -0
- package/dist/index.d.ts +5 -53
- package/dist/index.js +4 -2
- package/dist/normalize.js +125 -0
- package/dist/registries/browser.d.ts +21 -5
- package/dist/registries/browser.js +70 -16
- package/dist/registries/index.d.ts +3 -3
- package/dist/registries/index.js +3 -3
- package/dist/registries/supabase.d.ts +22 -5
- package/dist/registries/supabase.js +118 -19
- package/dist/registry.d.ts +43 -0
- package/dist/registry.js +116 -0
- package/dist/result.d.ts +100 -0
- package/dist/result.js +90 -0
- package/dist/types.d.ts +286 -0
- package/package.json +8 -5
- package/dist/src-DrlQ39IZ.js +0 -322
- package/dist/types-D6n8W1xw.d.ts +0 -87
package/dist/index.d.ts
CHANGED
|
@@ -1,53 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
/** Error class that normalizes unknown thrown or returned values into a predictable shape. */
|
|
7
|
-
declare class AppError extends Error {
|
|
8
|
-
/** App-level registry used when no registry is passed to the constructor. */
|
|
9
|
-
static readonly registry: ErrorRegistry;
|
|
10
|
-
/** Creates an isolated registry without modifying the app-level registry. */
|
|
11
|
-
static createRegistry(): ErrorRegistry;
|
|
12
|
-
/** Classification assigned after registry lookup and fallback handling. */
|
|
13
|
-
readonly type: AppErrorType;
|
|
14
|
-
/** User-facing message resolved from registry feedback or fallback handling. */
|
|
15
|
-
readonly message: string;
|
|
16
|
-
/** Optional localization key from matched registry feedback. */
|
|
17
|
-
readonly messageKey: string | null;
|
|
18
|
-
/** Optional source label from matched registry feedback. */
|
|
19
|
-
readonly source: AppErrorSource;
|
|
20
|
-
/** Original value passed to the constructor, or the original value from a wrapped `AppError`. */
|
|
21
|
-
readonly originalError: unknown;
|
|
22
|
-
/** Whether retrying the failed operation is likely to help. */
|
|
23
|
-
readonly retryable: boolean;
|
|
24
|
-
/**
|
|
25
|
-
* Normalizes an unknown error value. Construction does not throw; unmatched values become `unknown` errors.
|
|
26
|
-
*/
|
|
27
|
-
constructor(error: unknown, options?: AppErrorOptions);
|
|
28
|
-
private static resolve;
|
|
29
|
-
}
|
|
30
|
-
//#endregion
|
|
31
|
-
//#region src/registry.d.ts
|
|
32
|
-
/** Creates an empty, isolated registry for classifying unknown errors. */
|
|
33
|
-
declare const createErrorRegistry: () => ErrorRegistry;
|
|
34
|
-
//#endregion
|
|
35
|
-
//#region src/result.d.ts
|
|
36
|
-
/** Successful result value returned by `ok()`. */
|
|
37
|
-
type Ok<T> = {
|
|
38
|
-
ok: true;
|
|
39
|
-
value: T;
|
|
40
|
-
};
|
|
41
|
-
/** Failed result value returned by `err()`. */
|
|
42
|
-
type Err = {
|
|
43
|
-
ok: false;
|
|
44
|
-
error: AppError;
|
|
45
|
-
};
|
|
46
|
-
/** Result union for APIs that return success or failure without throwing. */
|
|
47
|
-
type Result<T> = Ok<T> | Err;
|
|
48
|
-
/** Wraps a value in a successful result. */
|
|
49
|
-
declare const ok: <T>(value: T) => Ok<T>;
|
|
50
|
-
/** Normalizes an unknown error value and wraps it in a failed result. */
|
|
51
|
-
declare const err: (error: unknown, options?: AppErrorOptions) => Err;
|
|
52
|
-
//#endregion
|
|
53
|
-
export { AppError, type AppErrorOptions, type AppErrorSource, type AppErrorType, DEFAULT_APP_ERROR_MESSAGE, type Err, type ErrorFeedback, type ErrorPatternDefinition, type ErrorPatternRegistryBucket, type ErrorPrefixDefinition, type ErrorPrefixRegistryBucket, type ErrorRegistry, type ErrorRegistryBucket, type Ok, type Result, createErrorRegistry, err, ok };
|
|
1
|
+
import { AppError, AppErrorOptions, AppErrorSource, AppErrorType, ErrorFeedback, ErrorPatternDefinition, ErrorPatternRegistryBucket, ErrorPrefixDefinition, ErrorPrefixRegistryBucket, ErrorRegistry, ErrorRegistryBucket, ReadonlyErrorRegistry } from "./types.js";
|
|
2
|
+
import { DEFAULT_APP_ERROR_MESSAGE, createAppError, isAppError } from "./create-app-error.js";
|
|
3
|
+
import { createErrorRegistry, freezeRegistry, getErrorRegistry, setErrorRegistry } from "./registry.js";
|
|
4
|
+
import { Err, Ok, Result, andThen, err, map, match, ok, unwrap, unwrapOr } from "./result.js";
|
|
5
|
+
export { type AppError, type AppErrorOptions, type AppErrorSource, type AppErrorType, DEFAULT_APP_ERROR_MESSAGE, type Err, type ErrorFeedback, type ErrorPatternDefinition, type ErrorPatternRegistryBucket, type ErrorPrefixDefinition, type ErrorPrefixRegistryBucket, type ErrorRegistry, type ErrorRegistryBucket, type Ok, type ReadonlyErrorRegistry, type Result, andThen, createAppError, createErrorRegistry, err, freezeRegistry, getErrorRegistry, isAppError, map, match, ok, setErrorRegistry, unwrap, unwrapOr };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { createErrorRegistry, freezeRegistry, getErrorRegistry, setErrorRegistry } from "./registry.js";
|
|
2
|
+
import { DEFAULT_APP_ERROR_MESSAGE, createAppError, isAppError } from "./create-app-error.js";
|
|
3
|
+
import { andThen, err, map, match, ok, unwrap, unwrapOr } from "./result.js";
|
|
4
|
+
export { DEFAULT_APP_ERROR_MESSAGE, andThen, createAppError, createErrorRegistry, err, freezeRegistry, getErrorRegistry, isAppError, map, match, ok, setErrorRegistry, unwrap, unwrapOr };
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { normalizeErrorIdentifier } from "./bucket.js";
|
|
2
|
+
//#region src/normalize.ts
|
|
3
|
+
const ERROR_UNWRAP_MAX_DEPTH = 3;
|
|
4
|
+
const ERROR_WRAPPER_FIELD_NAMES = [
|
|
5
|
+
"cause",
|
|
6
|
+
"originalError",
|
|
7
|
+
"error",
|
|
8
|
+
"err",
|
|
9
|
+
"inner",
|
|
10
|
+
"innerError"
|
|
11
|
+
];
|
|
12
|
+
const isRecord = (value) => {
|
|
13
|
+
return (typeof value === "object" || typeof value === "function") && value !== null;
|
|
14
|
+
};
|
|
15
|
+
const getRecordField = (source, key) => {
|
|
16
|
+
try {
|
|
17
|
+
return source[key];
|
|
18
|
+
} catch {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const getStringField = (source, key) => {
|
|
23
|
+
const value = getRecordField(source, key);
|
|
24
|
+
return typeof value === "string" ? value : null;
|
|
25
|
+
};
|
|
26
|
+
const toKnownClassification = (feedback) => ({
|
|
27
|
+
type: "known",
|
|
28
|
+
message: feedback.message,
|
|
29
|
+
messageKey: feedback.messageKey ?? null,
|
|
30
|
+
source: feedback.source ?? null,
|
|
31
|
+
isRetryable: feedback.isRetryable ?? false
|
|
32
|
+
});
|
|
33
|
+
const toUnexpectedClassification = (feedback) => ({
|
|
34
|
+
type: "unexpected",
|
|
35
|
+
message: feedback.message,
|
|
36
|
+
messageKey: feedback.messageKey ?? null,
|
|
37
|
+
source: feedback.source ?? null,
|
|
38
|
+
isRetryable: feedback.isRetryable ?? false
|
|
39
|
+
});
|
|
40
|
+
const normalizeError = (error) => {
|
|
41
|
+
if (typeof error === "string") return {
|
|
42
|
+
code: null,
|
|
43
|
+
message: error,
|
|
44
|
+
name: null
|
|
45
|
+
};
|
|
46
|
+
if (!isRecord(error)) return {
|
|
47
|
+
code: null,
|
|
48
|
+
message: null,
|
|
49
|
+
name: null
|
|
50
|
+
};
|
|
51
|
+
const rawCode = getRecordField(error, "code");
|
|
52
|
+
return {
|
|
53
|
+
code: typeof rawCode === "string" ? rawCode : typeof rawCode === "number" ? String(rawCode) : null,
|
|
54
|
+
message: getStringField(error, "message"),
|
|
55
|
+
name: getStringField(error, "name")
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
const getWrappedErrorCandidates = (error) => {
|
|
59
|
+
if (!isRecord(error)) return [];
|
|
60
|
+
return ERROR_WRAPPER_FIELD_NAMES.map((fieldName) => getRecordField(error, fieldName)).filter((value) => value !== void 0 && value !== null);
|
|
61
|
+
};
|
|
62
|
+
const getErrorCandidates = (error, maxDepth = ERROR_UNWRAP_MAX_DEPTH) => {
|
|
63
|
+
const visitedObjects = /* @__PURE__ */ new Set();
|
|
64
|
+
if (isRecord(error)) visitedObjects.add(error);
|
|
65
|
+
const pendingCandidates = [{
|
|
66
|
+
depth: 0,
|
|
67
|
+
value: error
|
|
68
|
+
}];
|
|
69
|
+
const candidates = [];
|
|
70
|
+
for (let index = 0; index < pendingCandidates.length; index += 1) {
|
|
71
|
+
const candidate = pendingCandidates[index];
|
|
72
|
+
candidates.push(candidate.value);
|
|
73
|
+
if (candidate.depth >= maxDepth) continue;
|
|
74
|
+
for (const wrappedErrorCandidate of getWrappedErrorCandidates(candidate.value)) {
|
|
75
|
+
if (isRecord(wrappedErrorCandidate)) {
|
|
76
|
+
if (visitedObjects.has(wrappedErrorCandidate)) continue;
|
|
77
|
+
visitedObjects.add(wrappedErrorCandidate);
|
|
78
|
+
}
|
|
79
|
+
pendingCandidates.push({
|
|
80
|
+
depth: candidate.depth + 1,
|
|
81
|
+
value: wrappedErrorCandidate
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return candidates;
|
|
86
|
+
};
|
|
87
|
+
const getKnownMessageFeedback = (registry, message) => {
|
|
88
|
+
const normalizedMessage = normalizeErrorIdentifier(message);
|
|
89
|
+
const exactFeedback = registry.messages.get(normalizedMessage);
|
|
90
|
+
if (exactFeedback !== void 0) return toKnownClassification(exactFeedback);
|
|
91
|
+
const sortedPrefixes = registry.prefixes.values();
|
|
92
|
+
for (const definition of sortedPrefixes) if (normalizedMessage.startsWith(definition.prefix)) return toKnownClassification(definition);
|
|
93
|
+
return null;
|
|
94
|
+
};
|
|
95
|
+
const resolveDeterministicKnownError = (registry, { code, message, name }) => {
|
|
96
|
+
if (code !== null) {
|
|
97
|
+
const feedback = registry.codes.get(code);
|
|
98
|
+
if (feedback !== void 0) return toKnownClassification(feedback);
|
|
99
|
+
}
|
|
100
|
+
if (name !== null) {
|
|
101
|
+
const feedback = registry.names.get(name);
|
|
102
|
+
if (feedback !== void 0) return toKnownClassification(feedback);
|
|
103
|
+
}
|
|
104
|
+
if (message !== null) {
|
|
105
|
+
const feedback = getKnownMessageFeedback(registry, message);
|
|
106
|
+
if (feedback !== null) return feedback;
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
};
|
|
110
|
+
const resolveHeuristicUnexpectedError = (registry, { message }) => {
|
|
111
|
+
if (message === null) return null;
|
|
112
|
+
const matchedDefinition = registry.patterns.values().find((definition) => definition.pattern.test(message));
|
|
113
|
+
if (matchedDefinition === void 0) return null;
|
|
114
|
+
return toUnexpectedClassification(matchedDefinition);
|
|
115
|
+
};
|
|
116
|
+
const classifyErrorCandidateKnown = (registry, error) => {
|
|
117
|
+
const normalizedError = normalizeError(error);
|
|
118
|
+
return resolveDeterministicKnownError(registry, normalizedError);
|
|
119
|
+
};
|
|
120
|
+
const classifyErrorCandidateUnexpected = (registry, error) => {
|
|
121
|
+
const normalizedError = normalizeError(error);
|
|
122
|
+
return resolveHeuristicUnexpectedError(registry, normalizedError);
|
|
123
|
+
};
|
|
124
|
+
//#endregion
|
|
125
|
+
export { classifyErrorCandidateKnown, classifyErrorCandidateUnexpected, getErrorCandidates };
|
|
@@ -1,10 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ErrorFeedback, ReadonlyErrorRegistry } from "../types.js";
|
|
2
2
|
|
|
3
3
|
//#region src/registries/browser.d.ts
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* Raw name mapping definitions for common browser and Web API errors.
|
|
6
|
+
*
|
|
7
|
+
* Provides fallback messages, translation keys, and source labels for typical browser DOMExceptions.
|
|
7
8
|
*/
|
|
8
|
-
declare const
|
|
9
|
+
declare const browserErrorNames: Record<string, ErrorFeedback>;
|
|
10
|
+
/**
|
|
11
|
+
* Raw heuristic pattern mappings for common browser and Web API errors.
|
|
12
|
+
*
|
|
13
|
+
* Defines regex patterns to identify fetch failures, DNS issues, and network connection refusal.
|
|
14
|
+
*/
|
|
15
|
+
declare const browserErrorPatterns: readonly (readonly [RegExp, ErrorFeedback])[];
|
|
16
|
+
/**
|
|
17
|
+
* An opt-in, read-only error registry pre-populated with mappings for common browser and Web API errors.
|
|
18
|
+
*
|
|
19
|
+
* Includes name mappings for DOMException types (e.g., `AbortError`, `TimeoutError`, `QuotaExceededError`)
|
|
20
|
+
* and pattern mappings for network fetch failures (e.g., DNS errors, connection refusal).
|
|
21
|
+
*
|
|
22
|
+
* Importing this registry preset does not access or require browser/DOM globals.
|
|
23
|
+
*/
|
|
24
|
+
declare const browserErrorRegistry: ReadonlyErrorRegistry;
|
|
9
25
|
//#endregion
|
|
10
|
-
export { browserErrorRegistry };
|
|
26
|
+
export { browserErrorNames, browserErrorPatterns, browserErrorRegistry };
|
|
@@ -1,32 +1,86 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createErrorRegistry, freezeRegistry } from "../registry.js";
|
|
2
2
|
//#region src/registries/browser.ts
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Raw name mapping definitions for common browser and Web API errors.
|
|
5
|
+
*
|
|
6
|
+
* Provides fallback messages, translation keys, and source labels for typical browser DOMExceptions.
|
|
6
7
|
*/
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
["AbortError", {
|
|
8
|
+
const browserErrorNames = {
|
|
9
|
+
AbortError: {
|
|
10
10
|
message: "Request cancelled.",
|
|
11
11
|
messageKey: "error.browser.abort",
|
|
12
12
|
source: "browser"
|
|
13
|
-
}
|
|
14
|
-
|
|
13
|
+
},
|
|
14
|
+
QuotaExceededError: {
|
|
15
15
|
message: "Browser storage quota exceeded.",
|
|
16
16
|
messageKey: "error.browser.storageQuotaExceeded",
|
|
17
17
|
source: "browser.storage"
|
|
18
|
-
}
|
|
19
|
-
|
|
18
|
+
},
|
|
19
|
+
NotAllowedError: {
|
|
20
20
|
message: "Permission was denied.",
|
|
21
21
|
messageKey: "error.browser.permissionDenied",
|
|
22
22
|
source: "browser.permissions"
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
},
|
|
24
|
+
NotFoundError: {
|
|
25
|
+
message: "The requested resource could not be found.",
|
|
26
|
+
messageKey: "error.browser.notFound",
|
|
27
|
+
source: "browser"
|
|
28
|
+
},
|
|
29
|
+
SecurityError: {
|
|
30
|
+
message: "The operation is insecure.",
|
|
31
|
+
messageKey: "error.browser.security",
|
|
32
|
+
source: "browser"
|
|
33
|
+
},
|
|
34
|
+
TimeoutError: {
|
|
35
|
+
message: "The operation timed out.",
|
|
36
|
+
messageKey: "error.browser.timeout",
|
|
37
|
+
source: "browser",
|
|
38
|
+
isRetryable: true
|
|
39
|
+
},
|
|
40
|
+
NotSupportedError: {
|
|
41
|
+
message: "The operation is not supported.",
|
|
42
|
+
messageKey: "error.browser.notSupported",
|
|
43
|
+
source: "browser"
|
|
44
|
+
},
|
|
45
|
+
InvalidStateError: {
|
|
46
|
+
message: "The operation is invalid in the current state.",
|
|
47
|
+
messageKey: "error.browser.invalidState",
|
|
48
|
+
source: "browser"
|
|
49
|
+
},
|
|
50
|
+
NetworkError: {
|
|
51
|
+
message: "A network error occurred.",
|
|
52
|
+
messageKey: "error.browser.network",
|
|
53
|
+
source: "browser.network",
|
|
54
|
+
isRetryable: true
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Raw heuristic pattern mappings for common browser and Web API errors.
|
|
59
|
+
*
|
|
60
|
+
* Defines regex patterns to identify fetch failures, DNS issues, and network connection refusal.
|
|
61
|
+
*/
|
|
62
|
+
const browserErrorPatterns = [[/failed to fetch|networkerror|load failed/i, {
|
|
26
63
|
message: "Network request failed.",
|
|
27
64
|
messageKey: "error.browser.network",
|
|
28
65
|
source: "browser.network",
|
|
29
|
-
|
|
30
|
-
}]
|
|
66
|
+
isRetryable: true
|
|
67
|
+
}], [/connection refused|dns_probe_finished/i, {
|
|
68
|
+
message: "Could not connect to the server.",
|
|
69
|
+
messageKey: "error.browser.connectionRefused",
|
|
70
|
+
source: "browser.network",
|
|
71
|
+
isRetryable: true
|
|
72
|
+
}]];
|
|
73
|
+
const registry = createErrorRegistry();
|
|
74
|
+
registry.names.addList(Object.entries(browserErrorNames));
|
|
75
|
+
registry.patterns.addList(browserErrorPatterns);
|
|
76
|
+
/**
|
|
77
|
+
* An opt-in, read-only error registry pre-populated with mappings for common browser and Web API errors.
|
|
78
|
+
*
|
|
79
|
+
* Includes name mappings for DOMException types (e.g., `AbortError`, `TimeoutError`, `QuotaExceededError`)
|
|
80
|
+
* and pattern mappings for network fetch failures (e.g., DNS errors, connection refusal).
|
|
81
|
+
*
|
|
82
|
+
* Importing this registry preset does not access or require browser/DOM globals.
|
|
83
|
+
*/
|
|
84
|
+
const browserErrorRegistry = freezeRegistry(registry);
|
|
31
85
|
//#endregion
|
|
32
|
-
export { browserErrorRegistry };
|
|
86
|
+
export { browserErrorNames, browserErrorPatterns, browserErrorRegistry };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { browserErrorRegistry } from "./browser.js";
|
|
2
|
-
import { supabaseErrorRegistry } from "./supabase.js";
|
|
3
|
-
export { browserErrorRegistry, supabaseErrorRegistry };
|
|
1
|
+
import { browserErrorNames, browserErrorPatterns, browserErrorRegistry } from "./browser.js";
|
|
2
|
+
import { supabaseErrorCodes, supabaseErrorNames, supabaseErrorRegistry } from "./supabase.js";
|
|
3
|
+
export { browserErrorNames, browserErrorPatterns, browserErrorRegistry, supabaseErrorCodes, supabaseErrorNames, supabaseErrorRegistry };
|
package/dist/registries/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { browserErrorRegistry } from "./browser.js";
|
|
2
|
-
import { supabaseErrorRegistry } from "./supabase.js";
|
|
3
|
-
export { browserErrorRegistry, supabaseErrorRegistry };
|
|
1
|
+
import { browserErrorNames, browserErrorPatterns, browserErrorRegistry } from "./browser.js";
|
|
2
|
+
import { supabaseErrorCodes, supabaseErrorNames, supabaseErrorRegistry } from "./supabase.js";
|
|
3
|
+
export { browserErrorNames, browserErrorPatterns, browserErrorRegistry, supabaseErrorCodes, supabaseErrorNames, supabaseErrorRegistry };
|
|
@@ -1,10 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ErrorFeedback, ReadonlyErrorRegistry } from "../types.js";
|
|
2
2
|
|
|
3
3
|
//#region src/registries/supabase.d.ts
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* Raw code mapping definitions for common Supabase service errors.
|
|
6
|
+
*
|
|
7
|
+
* Includes Postgres database codes and Supabase Auth specific error codes.
|
|
7
8
|
*/
|
|
8
|
-
declare const
|
|
9
|
+
declare const supabaseErrorCodes: Record<string, ErrorFeedback>;
|
|
10
|
+
/**
|
|
11
|
+
* Raw name mapping definitions for common Supabase service errors.
|
|
12
|
+
*
|
|
13
|
+
* Includes name mappings for edge function execution issues.
|
|
14
|
+
*/
|
|
15
|
+
declare const supabaseErrorNames: Record<string, ErrorFeedback>;
|
|
16
|
+
/**
|
|
17
|
+
* An opt-in, read-only error registry pre-populated with mappings for common Supabase service errors.
|
|
18
|
+
*
|
|
19
|
+
* Includes code mappings for Supabase Auth (e.g., rate limits, invalid credentials) and PostgreSQL
|
|
20
|
+
* database errors (e.g., foreign key violations, unique constraint violations), as well as name
|
|
21
|
+
* mappings for edge function execution issues.
|
|
22
|
+
*
|
|
23
|
+
* Importing this preset does not establish any network connection to Supabase services or require client dependencies.
|
|
24
|
+
*/
|
|
25
|
+
declare const supabaseErrorRegistry: ReadonlyErrorRegistry;
|
|
9
26
|
//#endregion
|
|
10
|
-
export { supabaseErrorRegistry };
|
|
27
|
+
export { supabaseErrorCodes, supabaseErrorNames, supabaseErrorRegistry };
|
|
@@ -1,32 +1,131 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createErrorRegistry, freezeRegistry } from "../registry.js";
|
|
2
2
|
//#region src/registries/supabase.ts
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Raw code mapping definitions for common Supabase service errors.
|
|
5
|
+
*
|
|
6
|
+
* Includes Postgres database codes and Supabase Auth specific error codes.
|
|
6
7
|
*/
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
["invalid_credentials", {
|
|
8
|
+
const supabaseErrorCodes = {
|
|
9
|
+
invalid_credentials: {
|
|
10
10
|
message: "Invalid email or password.",
|
|
11
11
|
messageKey: "error.supabase.auth.invalidCredentials",
|
|
12
12
|
source: "supabase.auth"
|
|
13
|
-
}
|
|
14
|
-
|
|
13
|
+
},
|
|
14
|
+
email_not_confirmed: {
|
|
15
15
|
message: "Email address is not confirmed.",
|
|
16
16
|
messageKey: "error.supabase.auth.emailNotConfirmed",
|
|
17
17
|
source: "supabase.auth"
|
|
18
|
-
}
|
|
19
|
-
|
|
18
|
+
},
|
|
19
|
+
user_already_exists: {
|
|
20
|
+
message: "An account with this email address already exists.",
|
|
21
|
+
messageKey: "error.supabase.auth.userAlreadyExists",
|
|
22
|
+
source: "supabase.auth"
|
|
23
|
+
},
|
|
24
|
+
signup_disabled: {
|
|
25
|
+
message: "Signups are currently disabled.",
|
|
26
|
+
messageKey: "error.supabase.auth.signupDisabled",
|
|
27
|
+
source: "supabase.auth"
|
|
28
|
+
},
|
|
29
|
+
otp_expired: {
|
|
30
|
+
message: "One-time password has expired.",
|
|
31
|
+
messageKey: "error.supabase.auth.otpExpired",
|
|
32
|
+
source: "supabase.auth"
|
|
33
|
+
},
|
|
34
|
+
sms_send_failed: {
|
|
35
|
+
message: "Failed to send SMS message.",
|
|
36
|
+
messageKey: "error.supabase.auth.smsSendFailed",
|
|
37
|
+
source: "supabase.auth",
|
|
38
|
+
isRetryable: true
|
|
39
|
+
},
|
|
40
|
+
over_sms_send_rate_limit: {
|
|
41
|
+
message: "SMS send rate limit exceeded. Please try again later.",
|
|
42
|
+
messageKey: "error.supabase.auth.overSmsSendRateLimit",
|
|
43
|
+
source: "supabase.auth"
|
|
44
|
+
},
|
|
45
|
+
over_email_send_rate_limit: {
|
|
46
|
+
message: "Email send rate limit exceeded. Please try again later.",
|
|
47
|
+
messageKey: "error.supabase.auth.overEmailSendRateLimit",
|
|
48
|
+
source: "supabase.auth"
|
|
49
|
+
},
|
|
50
|
+
invalid_grant: {
|
|
51
|
+
message: "Invalid login credentials or refresh token.",
|
|
52
|
+
messageKey: "error.supabase.auth.invalidGrant",
|
|
53
|
+
source: "supabase.auth"
|
|
54
|
+
},
|
|
55
|
+
bad_oauth_state: {
|
|
56
|
+
message: "Invalid OAuth state.",
|
|
57
|
+
messageKey: "error.supabase.auth.badOAuthState",
|
|
58
|
+
source: "supabase.auth"
|
|
59
|
+
},
|
|
60
|
+
"23505": {
|
|
20
61
|
message: "A record with this value already exists.",
|
|
21
62
|
messageKey: "error.supabase.database.uniqueViolation",
|
|
22
63
|
source: "supabase.database"
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
64
|
+
},
|
|
65
|
+
"23503": {
|
|
66
|
+
message: "Referenced record could not be found.",
|
|
67
|
+
messageKey: "error.supabase.database.foreignKeyViolation",
|
|
68
|
+
source: "supabase.database"
|
|
69
|
+
},
|
|
70
|
+
"23502": {
|
|
71
|
+
message: "A required field is missing.",
|
|
72
|
+
messageKey: "error.supabase.database.notNullViolation",
|
|
73
|
+
source: "supabase.database"
|
|
74
|
+
},
|
|
75
|
+
"42P01": {
|
|
76
|
+
message: "Database table not found.",
|
|
77
|
+
messageKey: "error.supabase.database.undefinedTable",
|
|
78
|
+
source: "supabase.database"
|
|
79
|
+
},
|
|
80
|
+
"42703": {
|
|
81
|
+
message: "Database column not found.",
|
|
82
|
+
messageKey: "error.supabase.database.undefinedColumn",
|
|
83
|
+
source: "supabase.database"
|
|
84
|
+
},
|
|
85
|
+
"57014": {
|
|
86
|
+
message: "Database query timed out or was cancelled.",
|
|
87
|
+
messageKey: "error.supabase.database.timeout",
|
|
88
|
+
source: "supabase.database",
|
|
89
|
+
isRetryable: true
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Raw name mapping definitions for common Supabase service errors.
|
|
94
|
+
*
|
|
95
|
+
* Includes name mappings for edge function execution issues.
|
|
96
|
+
*/
|
|
97
|
+
const supabaseErrorNames = {
|
|
98
|
+
FunctionsHttpError: {
|
|
99
|
+
message: "Edge Function request failed.",
|
|
100
|
+
messageKey: "error.supabase.functions.http",
|
|
101
|
+
source: "supabase.functions",
|
|
102
|
+
isRetryable: true
|
|
103
|
+
},
|
|
104
|
+
FunctionsRelayError: {
|
|
105
|
+
message: "Edge Function relay failed.",
|
|
106
|
+
messageKey: "error.supabase.functions.relay",
|
|
107
|
+
source: "supabase.functions",
|
|
108
|
+
isRetryable: true
|
|
109
|
+
},
|
|
110
|
+
FunctionsFetchError: {
|
|
111
|
+
message: "Failed to fetch Edge Function.",
|
|
112
|
+
messageKey: "error.supabase.functions.fetch",
|
|
113
|
+
source: "supabase.functions",
|
|
114
|
+
isRetryable: true
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
const registry = createErrorRegistry();
|
|
118
|
+
registry.codes.addList(Object.entries(supabaseErrorCodes));
|
|
119
|
+
registry.names.addList(Object.entries(supabaseErrorNames));
|
|
120
|
+
/**
|
|
121
|
+
* An opt-in, read-only error registry pre-populated with mappings for common Supabase service errors.
|
|
122
|
+
*
|
|
123
|
+
* Includes code mappings for Supabase Auth (e.g., rate limits, invalid credentials) and PostgreSQL
|
|
124
|
+
* database errors (e.g., foreign key violations, unique constraint violations), as well as name
|
|
125
|
+
* mappings for edge function execution issues.
|
|
126
|
+
*
|
|
127
|
+
* Importing this preset does not establish any network connection to Supabase services or require client dependencies.
|
|
128
|
+
*/
|
|
129
|
+
const supabaseErrorRegistry = freezeRegistry(registry);
|
|
31
130
|
//#endregion
|
|
32
|
-
export { supabaseErrorRegistry };
|
|
131
|
+
export { supabaseErrorCodes, supabaseErrorNames, supabaseErrorRegistry };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ErrorRegistry, ReadonlyErrorRegistry } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/registry.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Creates an empty, isolated error registry.
|
|
6
|
+
*
|
|
7
|
+
* Optionally merges a list of preset registries into the newly created registry.
|
|
8
|
+
*
|
|
9
|
+
* @param presets - Optional list of existing registries to merge during creation.
|
|
10
|
+
* @returns A new, mutable ErrorRegistry instance.
|
|
11
|
+
*/
|
|
12
|
+
declare const createErrorRegistry: (presets?: readonly (ErrorRegistry | ReadonlyErrorRegistry)[]) => ErrorRegistry;
|
|
13
|
+
/**
|
|
14
|
+
* Retrieves the active global error registry.
|
|
15
|
+
*
|
|
16
|
+
* This registry is used as the default classification source for `createAppError`.
|
|
17
|
+
*
|
|
18
|
+
* @returns The current active ErrorRegistry.
|
|
19
|
+
*/
|
|
20
|
+
declare const getErrorRegistry: () => ErrorRegistry;
|
|
21
|
+
/**
|
|
22
|
+
* Sets the active global error registry.
|
|
23
|
+
*
|
|
24
|
+
* Allows consumers to replace the default registry at application initialization.
|
|
25
|
+
* Throws a TypeError if the provided value is null or not an object.
|
|
26
|
+
*
|
|
27
|
+
* @param registry - The ErrorRegistry instance to set as active.
|
|
28
|
+
* @throws TypeError - If the parameter is not a valid ErrorRegistry.
|
|
29
|
+
*/
|
|
30
|
+
declare const setErrorRegistry: (registry: ErrorRegistry) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Wraps an ErrorRegistry in a read-only Proxy to prevent any future mutations.
|
|
33
|
+
*
|
|
34
|
+
* All mutating methods (such as `add`, `addList`, `clear`, `delete`) will throw a TypeError
|
|
35
|
+
* if called on a frozen registry bucket. The returned type is `ReadonlyErrorRegistry`,
|
|
36
|
+
* which only exposes the read-facing bucket surface at the type level.
|
|
37
|
+
*
|
|
38
|
+
* @param registry - The ErrorRegistry instance to freeze.
|
|
39
|
+
* @returns A read-only `ReadonlyErrorRegistry` instance.
|
|
40
|
+
*/
|
|
41
|
+
declare const freezeRegistry: (registry: ErrorRegistry) => ReadonlyErrorRegistry;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { createErrorRegistry, freezeRegistry, getErrorRegistry, setErrorRegistry };
|