erlc-api 3.0.0 → 3.2.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/README.md +86 -17
- package/examples/error-handling.js +159 -0
- package/package.json +1 -1
- package/src/classes/client.js +23 -20
- package/src/erlc.js +1 -0
- package/src/errors/ErlcError.js +34 -0
- package/src/errors/errorCodes.js +218 -0
- package/src/functions/global/resetGlobalKey.js +60 -0
- package/src/functions/server/getBans.js +17 -18
- package/src/functions/server/getCommandLogs.js +17 -18
- package/src/functions/server/getJoinLogs.js +17 -18
- package/src/functions/server/getKillLogs.js +17 -18
- package/src/functions/server/getModcallLogs.js +17 -18
- package/src/functions/server/getPlayers.js +17 -18
- package/src/functions/server/getQueue.js +17 -18
- package/src/functions/server/getServer.js +46 -19
- package/src/functions/server/getStaff.js +17 -18
- package/src/functions/server/getVehicles.js +17 -18
- package/src/functions/server/runCommand.js +20 -23
- package/src/types/index.d.ts +127 -98
- package/src/utils/errorHandler.js +158 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { BASEURL } = require("../../constants.js");
|
|
2
|
+
const { processError } = require("../../utils/errorHandler.js");
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Retrieves server vehicles information
|
|
@@ -8,8 +9,8 @@ const { BASEURL } = require("../../constants.js");
|
|
|
8
9
|
module.exports = (serverToken) => {
|
|
9
10
|
return new Promise(async (resolve, reject) => {
|
|
10
11
|
// Input validation
|
|
11
|
-
if (!serverToken || typeof serverToken !==
|
|
12
|
-
return reject(new Error(
|
|
12
|
+
if (!serverToken || typeof serverToken !== "string") {
|
|
13
|
+
return reject(new Error("Server token is required and must be a string"));
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
try {
|
|
@@ -18,37 +19,35 @@ module.exports = (serverToken) => {
|
|
|
18
19
|
|
|
19
20
|
// Check if global token is configured
|
|
20
21
|
if (!config?.globalToken) {
|
|
21
|
-
|
|
22
|
+
const error = await processError(
|
|
23
|
+
new Error(
|
|
24
|
+
"Global token not configured. Please initialize the client first."
|
|
25
|
+
)
|
|
26
|
+
);
|
|
27
|
+
return reject(error);
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
const res = await fetch.default(`${BASEURL}/server/vehicles`, {
|
|
25
31
|
headers: {
|
|
26
|
-
|
|
32
|
+
Authorization: config.globalToken,
|
|
27
33
|
"Server-Key": serverToken,
|
|
28
34
|
},
|
|
29
35
|
timeout: 10000, // 10 second timeout
|
|
30
36
|
});
|
|
31
37
|
|
|
32
38
|
if (!res.ok) {
|
|
33
|
-
const errorData = await res
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
error
|
|
39
|
+
const errorData = await res
|
|
40
|
+
.json()
|
|
41
|
+
.catch(() => ({ error: "Unknown API error" }));
|
|
42
|
+
const error = await processError(res, errorData);
|
|
37
43
|
return reject(error);
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
const data = await res.json();
|
|
41
47
|
resolve(Array.isArray(data) ? data : []);
|
|
42
|
-
|
|
43
48
|
} catch (error) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
reject(new Error('Network error: Unable to connect to ER:LC API'));
|
|
47
|
-
} else if (error.name === 'AbortError') {
|
|
48
|
-
reject(new Error('Request timeout: API took too long to respond'));
|
|
49
|
-
} else {
|
|
50
|
-
reject(error);
|
|
51
|
-
}
|
|
49
|
+
const processedError = await processError(error);
|
|
50
|
+
reject(processedError);
|
|
52
51
|
}
|
|
53
52
|
});
|
|
54
|
-
};
|
|
53
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { BASEURL } = require("../../constants.js");
|
|
2
|
+
const { processError } = require("../../utils/errorHandler.js");
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Executes a command on the server
|
|
@@ -9,16 +10,16 @@ const { BASEURL } = require("../../constants.js");
|
|
|
9
10
|
module.exports = (serverToken, command) => {
|
|
10
11
|
return new Promise(async (resolve, reject) => {
|
|
11
12
|
// Input validation
|
|
12
|
-
if (!serverToken || typeof serverToken !==
|
|
13
|
-
return reject(new Error(
|
|
13
|
+
if (!serverToken || typeof serverToken !== "string") {
|
|
14
|
+
return reject(new Error("Server token is required and must be a string"));
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
if (!command || typeof command !==
|
|
17
|
-
return reject(new Error(
|
|
17
|
+
if (!command || typeof command !== "string") {
|
|
18
|
+
return reject(new Error("Command is required and must be a string"));
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
if (command.trim().length === 0) {
|
|
21
|
-
return reject(new Error(
|
|
22
|
+
return reject(new Error("Command cannot be empty"));
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
try {
|
|
@@ -27,7 +28,12 @@ module.exports = (serverToken, command) => {
|
|
|
27
28
|
|
|
28
29
|
// Check if global token is configured
|
|
29
30
|
if (!config?.globalToken) {
|
|
30
|
-
|
|
31
|
+
const error = await processError(
|
|
32
|
+
new Error(
|
|
33
|
+
"Global token not configured. Please initialize the client first."
|
|
34
|
+
)
|
|
35
|
+
);
|
|
36
|
+
return reject(error);
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
const requestBody = JSON.stringify({ command: command.trim() });
|
|
@@ -35,7 +41,7 @@ module.exports = (serverToken, command) => {
|
|
|
35
41
|
const res = await fetch.default(`${BASEURL}/server/command`, {
|
|
36
42
|
method: "POST",
|
|
37
43
|
headers: {
|
|
38
|
-
|
|
44
|
+
Authorization: config.globalToken,
|
|
39
45
|
"Server-Key": serverToken,
|
|
40
46
|
"Content-Type": "application/json",
|
|
41
47
|
},
|
|
@@ -44,27 +50,18 @@ module.exports = (serverToken, command) => {
|
|
|
44
50
|
});
|
|
45
51
|
|
|
46
52
|
if (!res.ok) {
|
|
47
|
-
const errorData = await res
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
error
|
|
53
|
+
const errorData = await res
|
|
54
|
+
.json()
|
|
55
|
+
.catch(() => ({ error: "Unknown API error" }));
|
|
56
|
+
const error = await processError(res, errorData);
|
|
51
57
|
return reject(error);
|
|
52
58
|
}
|
|
53
59
|
|
|
54
60
|
// Command executed successfully
|
|
55
61
|
resolve(true);
|
|
56
|
-
|
|
57
62
|
} catch (error) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
reject(new Error('Network error: Unable to connect to ER:LC API'));
|
|
61
|
-
} else if (error.name === 'AbortError') {
|
|
62
|
-
reject(new Error('Request timeout: Command took too long to execute'));
|
|
63
|
-
} else if (error.message.includes('JSON')) {
|
|
64
|
-
reject(new Error('Invalid command format'));
|
|
65
|
-
} else {
|
|
66
|
-
reject(error);
|
|
67
|
-
}
|
|
63
|
+
const processedError = await processError(error);
|
|
64
|
+
reject(processedError);
|
|
68
65
|
}
|
|
69
66
|
});
|
|
70
|
-
};
|
|
67
|
+
};
|
package/src/types/index.d.ts
CHANGED
|
@@ -1,98 +1,127 @@
|
|
|
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
|
-
|
|
1
|
+
// Error handling types
|
|
2
|
+
export class ErlcError extends Error {
|
|
3
|
+
code: string | number;
|
|
4
|
+
status?: number;
|
|
5
|
+
category?: string;
|
|
6
|
+
severity?: string;
|
|
7
|
+
suggestions?: string[];
|
|
8
|
+
retryable?: boolean;
|
|
9
|
+
timestamp: string;
|
|
10
|
+
originalError?: Error;
|
|
11
|
+
|
|
12
|
+
constructor(
|
|
13
|
+
message: string,
|
|
14
|
+
code: string | number,
|
|
15
|
+
status?: number,
|
|
16
|
+
originalError?: Error,
|
|
17
|
+
);
|
|
18
|
+
toJSON(): object;
|
|
19
|
+
toString(): string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ErrorInfo {
|
|
23
|
+
message: string;
|
|
24
|
+
description: string;
|
|
25
|
+
category: string;
|
|
26
|
+
severity: string;
|
|
27
|
+
code?: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface ClientConfig {
|
|
31
|
+
globalToken: string; // The ER:LC global API token
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const BASEURL = "https://api.policeroleplay.community/v1";
|
|
35
|
+
|
|
36
|
+
type PlayerId = string;
|
|
37
|
+
type PlayerName = string;
|
|
38
|
+
type TextureName = string;
|
|
39
|
+
type CarName = string;
|
|
40
|
+
|
|
41
|
+
export type ErlcPlayer = `${PlayerName}:${PlayerId}`; // Playername:UserID
|
|
42
|
+
export type ErlcPlayerPermission =
|
|
43
|
+
| "Normal"
|
|
44
|
+
| "Server Administrator"
|
|
45
|
+
| "Server Owner"
|
|
46
|
+
| "Server Moderator";
|
|
47
|
+
|
|
48
|
+
export interface ServerStatus {
|
|
49
|
+
Name: string; // The server name
|
|
50
|
+
OwnerUsername: string; // The username of the server owner
|
|
51
|
+
CoOwnerUsernames: string[]; // The usernames of the server co owners
|
|
52
|
+
CurrentPlayers: number; // The amount of people currently in-game
|
|
53
|
+
MaxPlayers: number; // The amount of people who can join the server including server owner
|
|
54
|
+
JoinKey: string; // The code used to join the private server
|
|
55
|
+
AccVerifiedReq: "Disabled" | "Email" | "Phone/ID"; // The level of verification roblox accounts need to join the private server
|
|
56
|
+
TeamBalance: boolean; // If team balance is enabled or not
|
|
57
|
+
VanityURL: string; // The vanity URL to join the server
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface ServerPlayer {
|
|
61
|
+
Player: ErlcPlayer;
|
|
62
|
+
Permission: ErlcPlayerPermission;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface JoinLog {
|
|
66
|
+
Join: boolean; // True is join and False is leave
|
|
67
|
+
Timestamp: number; // Timestamp in seconds
|
|
68
|
+
Player: ErlcPlayer;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface KillLog {
|
|
72
|
+
Killed: ErlcPlayer;
|
|
73
|
+
Timestamp: number; // Timestamp in seconds
|
|
74
|
+
Killer: ErlcPlayer;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface CommandLog {
|
|
78
|
+
Player: ErlcPlayer;
|
|
79
|
+
Timestamp: number; // Timestamp in seconds
|
|
80
|
+
Command: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface ModcallLog {
|
|
84
|
+
Caller: ErlcPlayer;
|
|
85
|
+
Moderator?: ErlcPlayer; // If call is unanswered property is undefined
|
|
86
|
+
Timestamp: number; // Timestamp in seconds
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type ServerBan = Record<PlayerId, PlayerName>;
|
|
90
|
+
|
|
91
|
+
export interface VehiclesLog {
|
|
92
|
+
Texture: string | null;
|
|
93
|
+
Name: string;
|
|
94
|
+
Owner: ErlcPlayer;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface ServerStaff {
|
|
98
|
+
CoOwners: number[];
|
|
99
|
+
Admins: Record<string, string>;
|
|
100
|
+
Mods: Record<string, string>;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface VSMCommandBody {
|
|
104
|
+
command: string; // ":h Hey everyone!"
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function getBans(serverToken: string): Promise<ServerBan>;
|
|
108
|
+
export function getCommandLogs(serverToken: string): Promise<CommandLog[]>;
|
|
109
|
+
export function getJoinLogs(serverToken: string): Promise<JoinLog[]>;
|
|
110
|
+
export function getKillLogs(serverToken: string): Promise<KillLog[]>;
|
|
111
|
+
export function getModcallLogs(serverToken: string): Promise<ModcallLog[]>;
|
|
112
|
+
export function getPlayers(serverToken: string): Promise<ServerPlayer[]>;
|
|
113
|
+
export function getQueue(serverToken: string): Promise<number[]>;
|
|
114
|
+
export function getServer(serverToken: string): Promise<ServerStatus>;
|
|
115
|
+
export function getStaff(serverToken: string): Promise<ServerStaff>;
|
|
116
|
+
export function getVehicles(serverToken: string): Promise<VehiclesLog[]>;
|
|
117
|
+
export function runCommand(
|
|
118
|
+
serverToken: string,
|
|
119
|
+
command: string,
|
|
120
|
+
): Promise<boolean>;
|
|
121
|
+
|
|
122
|
+
export function resetGlobalKey(): Promise<any>;
|
|
123
|
+
|
|
124
|
+
export class Client {
|
|
125
|
+
constructor(options: ClientConfig);
|
|
126
|
+
config(): ClientConfig;
|
|
127
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
const ErlcError = require("../errors/ErlcError.js");
|
|
2
|
+
const {
|
|
3
|
+
getErrorInfo,
|
|
4
|
+
getSuggestedActions,
|
|
5
|
+
isRetryableError,
|
|
6
|
+
} = require("../errors/errorCodes.js");
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Handles API response errors and creates appropriate ErlcError instances
|
|
10
|
+
* @param {Response} response - The fetch response object
|
|
11
|
+
* @param {Object} errorData - The parsed error data from response
|
|
12
|
+
* @returns {ErlcError} Formatted ERLC error
|
|
13
|
+
*/
|
|
14
|
+
function handleApiError(response, errorData) {
|
|
15
|
+
const status = response.status;
|
|
16
|
+
|
|
17
|
+
// Check if error data contains ERLC error code
|
|
18
|
+
if (errorData && typeof errorData.code === "number") {
|
|
19
|
+
const errorInfo = getErrorInfo(errorData.code);
|
|
20
|
+
const suggestions = getSuggestedActions(errorData.code);
|
|
21
|
+
|
|
22
|
+
const message = `${errorInfo.message}: ${errorInfo.description}`;
|
|
23
|
+
const error = new ErlcError(message, errorData.code, status);
|
|
24
|
+
error.category = errorInfo.category;
|
|
25
|
+
error.severity = errorInfo.severity;
|
|
26
|
+
error.suggestions = suggestions;
|
|
27
|
+
error.retryable = isRetryableError(errorData.code);
|
|
28
|
+
|
|
29
|
+
return error;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Handle HTTP status codes when no ERLC error code is provided
|
|
33
|
+
let message, code;
|
|
34
|
+
|
|
35
|
+
switch (status) {
|
|
36
|
+
case 400:
|
|
37
|
+
message = "Bad Request: The request was invalid or malformed";
|
|
38
|
+
code = "HTTP_400";
|
|
39
|
+
break;
|
|
40
|
+
case 401:
|
|
41
|
+
message = "Unauthorized: Authentication failed or missing credentials";
|
|
42
|
+
code = "HTTP_401";
|
|
43
|
+
break;
|
|
44
|
+
case 403:
|
|
45
|
+
message = "Forbidden: Access denied or insufficient permissions";
|
|
46
|
+
code = "HTTP_403";
|
|
47
|
+
break;
|
|
48
|
+
case 404:
|
|
49
|
+
message = "Not Found: The requested resource was not found";
|
|
50
|
+
code = "HTTP_404";
|
|
51
|
+
break;
|
|
52
|
+
case 422:
|
|
53
|
+
message = "Unprocessable Entity: The server has no players";
|
|
54
|
+
code = "HTTP_422";
|
|
55
|
+
break;
|
|
56
|
+
case 429:
|
|
57
|
+
message = "Too Many Requests: Rate limit exceeded";
|
|
58
|
+
code = "HTTP_429";
|
|
59
|
+
break;
|
|
60
|
+
case 500:
|
|
61
|
+
message = "Internal Server Error: Problem communicating with Roblox";
|
|
62
|
+
code = "HTTP_500";
|
|
63
|
+
break;
|
|
64
|
+
case 502:
|
|
65
|
+
message = "Bad Gateway: Server received invalid response";
|
|
66
|
+
code = "HTTP_502";
|
|
67
|
+
break;
|
|
68
|
+
case 503:
|
|
69
|
+
message = "Service Unavailable: Server temporarily unavailable";
|
|
70
|
+
code = "HTTP_503";
|
|
71
|
+
break;
|
|
72
|
+
default:
|
|
73
|
+
message = `HTTP Error ${status}: ${
|
|
74
|
+
errorData?.error || response.statusText || "Unknown error"
|
|
75
|
+
}`;
|
|
76
|
+
code = `HTTP_${status}`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const error = new ErlcError(message, code, status);
|
|
80
|
+
error.category = "HTTP_ERROR";
|
|
81
|
+
error.severity = status >= 500 ? "HIGH" : "MEDIUM";
|
|
82
|
+
error.retryable = [429, 500, 502, 503].includes(status);
|
|
83
|
+
|
|
84
|
+
return error;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Handles network and other non-API errors
|
|
89
|
+
* @param {Error} originalError - The original error object
|
|
90
|
+
* @returns {ErlcError} Formatted ERLC error
|
|
91
|
+
*/
|
|
92
|
+
function handleNetworkError(originalError) {
|
|
93
|
+
let message, code, category;
|
|
94
|
+
|
|
95
|
+
if (originalError.code === "ENOTFOUND") {
|
|
96
|
+
message =
|
|
97
|
+
"Network Error: Unable to connect to ERLC API (DNS resolution failed)";
|
|
98
|
+
code = "NETWORK_DNS_ERROR";
|
|
99
|
+
category = "NETWORK_ERROR";
|
|
100
|
+
} else if (originalError.code === "ECONNREFUSED") {
|
|
101
|
+
message = "Network Error: Connection refused by ERLC API server";
|
|
102
|
+
code = "NETWORK_CONNECTION_REFUSED";
|
|
103
|
+
category = "NETWORK_ERROR";
|
|
104
|
+
} else if (
|
|
105
|
+
originalError.code === "ETIMEDOUT" ||
|
|
106
|
+
originalError.name === "AbortError"
|
|
107
|
+
) {
|
|
108
|
+
message = "Request Timeout: API took too long to respond";
|
|
109
|
+
code = "REQUEST_TIMEOUT";
|
|
110
|
+
category = "TIMEOUT_ERROR";
|
|
111
|
+
} else if (originalError.message?.includes("JSON")) {
|
|
112
|
+
message = "Parse Error: Invalid JSON response from API";
|
|
113
|
+
code = "JSON_PARSE_ERROR";
|
|
114
|
+
category = "PARSE_ERROR";
|
|
115
|
+
} else {
|
|
116
|
+
message = `Unexpected Error: ${originalError.message}`;
|
|
117
|
+
code = "UNEXPECTED_ERROR";
|
|
118
|
+
category = "UNKNOWN_ERROR";
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const error = new ErlcError(message, code, null, originalError);
|
|
122
|
+
error.category = category;
|
|
123
|
+
error.severity = "MEDIUM";
|
|
124
|
+
error.retryable = [
|
|
125
|
+
"NETWORK_DNS_ERROR",
|
|
126
|
+
"REQUEST_TIMEOUT",
|
|
127
|
+
"NETWORK_CONNECTION_REFUSED",
|
|
128
|
+
].includes(code);
|
|
129
|
+
|
|
130
|
+
return error;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Main error handler that processes any error and returns a standardized ErlcError
|
|
135
|
+
* @param {Error|Response} error - The error to handle
|
|
136
|
+
* @param {Object} [errorData] - Additional error data if available
|
|
137
|
+
* @returns {ErlcError} Standardized ERLC error
|
|
138
|
+
*/
|
|
139
|
+
async function processError(error, errorData = null) {
|
|
140
|
+
// If it's already an ErlcError, return as-is
|
|
141
|
+
if (error instanceof ErlcError) {
|
|
142
|
+
return error;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// If it's a Response object (from fetch), handle as API error
|
|
146
|
+
if (error && typeof error.status === "number") {
|
|
147
|
+
return handleApiError(error, errorData);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Handle as network/system error
|
|
151
|
+
return handleNetworkError(error);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
module.exports = {
|
|
155
|
+
handleApiError,
|
|
156
|
+
handleNetworkError,
|
|
157
|
+
processError,
|
|
158
|
+
};
|