@grandlinex/base-con 1.0.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 +29 -0
- package/README.md +11 -0
- package/dist/cjs/AxiosCon.d.ts +3 -0
- package/dist/cjs/AxiosCon.js +41 -0
- package/dist/cjs/BaseCon.d.ts +182 -0
- package/dist/cjs/BaseCon.js +411 -0
- package/dist/cjs/ConMerger.d.ts +2 -0
- package/dist/cjs/ConMerger.js +13 -0
- package/dist/cjs/FetchCon.d.ts +3 -0
- package/dist/cjs/FetchCon.js +79 -0
- package/dist/cjs/NodeCon.d.ts +3 -0
- package/dist/cjs/NodeCon.js +158 -0
- package/dist/cjs/index.d.ts +11 -0
- package/dist/cjs/index.js +35 -0
- package/dist/cjs/package.json +3 -0
- package/dist/mjs/AxiosCon.d.ts +3 -0
- package/dist/mjs/AxiosCon.js +36 -0
- package/dist/mjs/BaseCon.d.ts +182 -0
- package/dist/mjs/BaseCon.js +404 -0
- package/dist/mjs/ConMerger.d.ts +2 -0
- package/dist/mjs/ConMerger.js +10 -0
- package/dist/mjs/FetchCon.d.ts +3 -0
- package/dist/mjs/FetchCon.js +77 -0
- package/dist/mjs/NodeCon.d.ts +3 -0
- package/dist/mjs/NodeCon.js +120 -0
- package/dist/mjs/index.d.ts +11 -0
- package/dist/mjs/index.js +11 -0
- package/dist/mjs/package.json +3 -0
- package/package.json +72 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, GrandlineX
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# @grandlinex/base-con
|
|
2
|
+
|
|
3
|
+
A foundational library that provides core api request handling for GrandLineX projects.
|
|
4
|
+
It offers a set of utilities and conventions to streamline development and integration across the GrandLineX ecosystem.
|
|
5
|
+
|
|
6
|
+
## Description
|
|
7
|
+
|
|
8
|
+
`@grandlinex/base-con` is a lightweight module designed to serve as a base for other GrandLineX packages.
|
|
9
|
+
It encapsulates common utilities and patterns, ensuring consistency and reducing boilerplate across projects.
|
|
10
|
+
|
|
11
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const axios_1 = __importDefault(require("axios"));
|
|
7
|
+
async function acTransform(r) {
|
|
8
|
+
const res = await r;
|
|
9
|
+
return {
|
|
10
|
+
code: res.status,
|
|
11
|
+
data: res.data,
|
|
12
|
+
headers: res.headers,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const AxiosCon = {
|
|
16
|
+
get: async (url, config) => {
|
|
17
|
+
return acTransform(axios_1.default.get(url, {
|
|
18
|
+
headers: config?.headers,
|
|
19
|
+
validateStatus: (status) => true,
|
|
20
|
+
}));
|
|
21
|
+
},
|
|
22
|
+
post: async (url, body, config) => {
|
|
23
|
+
return acTransform(axios_1.default.post(url, body, {
|
|
24
|
+
headers: config?.headers,
|
|
25
|
+
validateStatus: (status) => true,
|
|
26
|
+
}));
|
|
27
|
+
},
|
|
28
|
+
patch: async (url, body, config) => {
|
|
29
|
+
return acTransform(axios_1.default.patch(url, body, {
|
|
30
|
+
headers: config?.headers,
|
|
31
|
+
validateStatus: (status) => true,
|
|
32
|
+
}));
|
|
33
|
+
},
|
|
34
|
+
delete: async (url, config) => {
|
|
35
|
+
return acTransform(axios_1.default.delete(url, {
|
|
36
|
+
headers: config?.headers,
|
|
37
|
+
validateStatus: (status) => true,
|
|
38
|
+
}));
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
exports.default = AxiosCon;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THIS FILE IS AUTOMATICALLY GENERATED
|
|
3
|
+
* DO NOT EDIT THIS FILE
|
|
4
|
+
*/
|
|
5
|
+
export type ErrorType = {
|
|
6
|
+
type: string;
|
|
7
|
+
global?: string[];
|
|
8
|
+
field?: {
|
|
9
|
+
key: string;
|
|
10
|
+
message: string;
|
|
11
|
+
}[];
|
|
12
|
+
};
|
|
13
|
+
export type HeaderType = string | string[] | number | undefined;
|
|
14
|
+
export type HandleRes<T> = {
|
|
15
|
+
success: boolean;
|
|
16
|
+
data: T | null;
|
|
17
|
+
code?: number;
|
|
18
|
+
error?: ErrorType;
|
|
19
|
+
headers?: Record<string, HeaderType>;
|
|
20
|
+
};
|
|
21
|
+
export type PathParam = {
|
|
22
|
+
[key: string]: string | number | undefined;
|
|
23
|
+
};
|
|
24
|
+
export declare function isErrorType(x: any): x is ErrorType;
|
|
25
|
+
export interface ConHandleConfig {
|
|
26
|
+
headers?: Record<string, string>;
|
|
27
|
+
param?: PathParam;
|
|
28
|
+
query?: PathParam;
|
|
29
|
+
}
|
|
30
|
+
export interface ConHandleResponse<T> {
|
|
31
|
+
code: number;
|
|
32
|
+
data: T | null;
|
|
33
|
+
headers: Record<string, HeaderType>;
|
|
34
|
+
}
|
|
35
|
+
export interface ConHandle {
|
|
36
|
+
get<T>(url: string, config?: ConHandleConfig): Promise<ConHandleResponse<T>>;
|
|
37
|
+
post<T, J>(url: string, body?: J, config?: ConHandleConfig): Promise<ConHandleResponse<T>>;
|
|
38
|
+
patch<T, J>(url: string, body?: J, config?: ConHandleConfig): Promise<ConHandleResponse<T>>;
|
|
39
|
+
delete<T>(url: string, config?: ConHandleConfig): Promise<ConHandleResponse<T>>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* BaseCon provides a minimal client for interacting with an HTTP backend.
|
|
43
|
+
* It manages connection state, authentication tokens, and reconnection
|
|
44
|
+
* logic while delegating actual HTTP requests to a supplied {@link ConHandle}.
|
|
45
|
+
*
|
|
46
|
+
* @class
|
|
47
|
+
*/
|
|
48
|
+
export default class BaseCon {
|
|
49
|
+
private api;
|
|
50
|
+
private permanentHeader;
|
|
51
|
+
private authorization;
|
|
52
|
+
private noAuth;
|
|
53
|
+
private disconnected;
|
|
54
|
+
private readonly logger;
|
|
55
|
+
con: ConHandle;
|
|
56
|
+
reconnect: () => Promise<boolean>;
|
|
57
|
+
onReconnect: (con: BaseCon) => Promise<boolean>;
|
|
58
|
+
constructor(conf: {
|
|
59
|
+
con: ConHandle;
|
|
60
|
+
endpoint: string;
|
|
61
|
+
logger?: (arg: any) => void;
|
|
62
|
+
permanentHeader?: Record<string, string>;
|
|
63
|
+
});
|
|
64
|
+
/**
|
|
65
|
+
* Retrieves the API endpoint.
|
|
66
|
+
*
|
|
67
|
+
* @return {string} The API endpoint string.
|
|
68
|
+
*/
|
|
69
|
+
getApiEndpoint(): string;
|
|
70
|
+
/**
|
|
71
|
+
* Sets the API endpoint URL used by the client.
|
|
72
|
+
*
|
|
73
|
+
* @param {string} endpoint - The full URL of the API endpoint.
|
|
74
|
+
* @returns {void}
|
|
75
|
+
*/
|
|
76
|
+
setApiEndpoint(endpoint: string): void;
|
|
77
|
+
/**
|
|
78
|
+
* Indicates whether the instance is considered connected.
|
|
79
|
+
*
|
|
80
|
+
* The instance is regarded as connected when it either does not require authentication
|
|
81
|
+
* (`noAuth` is true) or it has an authorization token set (`authorization` is not null),
|
|
82
|
+
* and it is not currently marked as disconnected.
|
|
83
|
+
*
|
|
84
|
+
* @return {boolean} `true` if the instance is connected, `false` otherwise.
|
|
85
|
+
*/
|
|
86
|
+
isConnected(): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Returns the current authorization token.
|
|
89
|
+
*
|
|
90
|
+
* @return {string} The authorization token or an empty string if none is set.
|
|
91
|
+
*/
|
|
92
|
+
token(): string | null;
|
|
93
|
+
/**
|
|
94
|
+
* Returns the current authorization token.
|
|
95
|
+
*
|
|
96
|
+
* @return {string} The authorization token or an empty string if none is set.
|
|
97
|
+
*/
|
|
98
|
+
getBearer(): string | null;
|
|
99
|
+
private p;
|
|
100
|
+
/**
|
|
101
|
+
* Sends a ping request to the API to verify connectivity and version availability.
|
|
102
|
+
*
|
|
103
|
+
* @return {boolean} `true` if the API responded with a 200 status code and a valid version object; `false` otherwise.
|
|
104
|
+
*/
|
|
105
|
+
ping(): Promise<boolean>;
|
|
106
|
+
private tokenHeader;
|
|
107
|
+
setPermanentHeader(header: Record<string, string>): void;
|
|
108
|
+
/**
|
|
109
|
+
* Validates the current authentication token by performing a ping and a test request
|
|
110
|
+
* to the backend. The method first ensures connectivity via {@link ping}. If the ping
|
|
111
|
+
* succeeds, it attempts to retrieve a token from the `/test/auth` endpoint using the
|
|
112
|
+
* current token in the `Authorization` header. The operation is considered successful
|
|
113
|
+
* if the response status code is 200 or 201.
|
|
114
|
+
*
|
|
115
|
+
* If any step fails, an error is logged and the method returns {@code false}. On
|
|
116
|
+
* success, it returns {@code true}.
|
|
117
|
+
*
|
|
118
|
+
* @return {Promise<boolean>} A promise that resolves to {@code true} if the token
|
|
119
|
+
* test succeeds, otherwise {@code false}.
|
|
120
|
+
*/
|
|
121
|
+
testToken(): Promise<boolean>;
|
|
122
|
+
/**
|
|
123
|
+
* Attempts to establish a connection to the backend without authentication.
|
|
124
|
+
*
|
|
125
|
+
* This method sends a ping request. If the ping succeeds, it clears any
|
|
126
|
+
* existing authorization data, marks the instance as connected,
|
|
127
|
+
* enables the no‑authentication mode, and returns `true`. If the ping
|
|
128
|
+
* fails, it logs a warning, clears authorization, marks the instance
|
|
129
|
+
* as disconnected, and returns `false`.
|
|
130
|
+
*
|
|
131
|
+
* @return {Promise<boolean>} `true` when a connection is successfully
|
|
132
|
+
* established without authentication, otherwise `false`.
|
|
133
|
+
*/
|
|
134
|
+
connectNoAuth(): Promise<boolean>;
|
|
135
|
+
/**
|
|
136
|
+
* Forces a connection using the provided bearer token.
|
|
137
|
+
*
|
|
138
|
+
* @param {string|null} token The token to be used for authentication.
|
|
139
|
+
* @returns {void}
|
|
140
|
+
*/
|
|
141
|
+
forceConnect(token: string | null): void;
|
|
142
|
+
coppyFrom(con: BaseCon): void;
|
|
143
|
+
/**
|
|
144
|
+
* Establishes a connection to the backend using the supplied credentials.
|
|
145
|
+
* Performs a health‑check ping first; if successful, it requests an authentication
|
|
146
|
+
* token from the `/token` endpoint. When the token is obtained, the method
|
|
147
|
+
* updates internal state (authorization header, connection flags) and, unless
|
|
148
|
+
* a dry run is requested, sets up a reconnection routine. Any errors are
|
|
149
|
+
* logged and the method resolves to `false`.
|
|
150
|
+
*
|
|
151
|
+
* @param {string} email - The user's email address for authentication.
|
|
152
|
+
* @param {string} pw - The password (or token) for the specified user.
|
|
153
|
+
* @param {boolean} [dry=false] - If `true`, the method performs a dry run
|
|
154
|
+
* without persisting credentials or configuring reconnection logic.
|
|
155
|
+
*
|
|
156
|
+
* @returns Promise<boolean> `true` if the connection was successfully
|
|
157
|
+
* established, otherwise `false`.
|
|
158
|
+
*/
|
|
159
|
+
connect(email: string, pw: string, dry?: boolean): Promise<boolean>;
|
|
160
|
+
/**
|
|
161
|
+
* Performs an HTTP request using the client’s internal connection.
|
|
162
|
+
*
|
|
163
|
+
* The method verifies that the client is connected before attempting a request.
|
|
164
|
+
* It automatically injects the authorization token, permanent headers, and any
|
|
165
|
+
* headers supplied in `config`. If the request body is a `FormData` instance
|
|
166
|
+
* (or provides a `getHeaders` method), the appropriate form headers are added.
|
|
167
|
+
*
|
|
168
|
+
* Response handling:
|
|
169
|
+
* - `200` or `201`: returns `success: true` with the received data.
|
|
170
|
+
* - `498`: attempts to reconnect and retries the request once.
|
|
171
|
+
* - `401`: logs an authentication error, marks the client as disconnected.
|
|
172
|
+
* - `403` and other status codes: return `success: false` with the status code.
|
|
173
|
+
*
|
|
174
|
+
* @param {'POST'|'GET'|'PATCH'|'DELETE'} type The HTTP method to use.
|
|
175
|
+
* @param {string} path The endpoint path relative to the base URL.
|
|
176
|
+
* @param {J} [body] Optional request payload. May be `FormData` or a plain object.
|
|
177
|
+
* @param {ConHandleConfig} [config] Optional Axios-like configuration for the request.
|
|
178
|
+
* @returns {Promise<HandleRes<T>>} A promise that resolves to a `HandleRes` object
|
|
179
|
+
* containing the response data, status code, any error information, and headers.
|
|
180
|
+
*/
|
|
181
|
+
handle<T, J>(type: 'POST' | 'GET' | 'PATCH' | 'DELETE', path: string, body?: J, config?: ConHandleConfig): Promise<HandleRes<T>>;
|
|
182
|
+
}
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* THIS FILE IS AUTOMATICALLY GENERATED
|
|
4
|
+
* DO NOT EDIT THIS FILE
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.isErrorType = isErrorType;
|
|
11
|
+
const form_data_1 = __importDefault(require("form-data"));
|
|
12
|
+
function isErrorType(x) {
|
|
13
|
+
return x && typeof x === 'object' && x.type === 'error';
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* BaseCon provides a minimal client for interacting with an HTTP backend.
|
|
17
|
+
* It manages connection state, authentication tokens, and reconnection
|
|
18
|
+
* logic while delegating actual HTTP requests to a supplied {@link ConHandle}.
|
|
19
|
+
*
|
|
20
|
+
* @class
|
|
21
|
+
*/
|
|
22
|
+
class BaseCon {
|
|
23
|
+
constructor(conf) {
|
|
24
|
+
this.api = conf.endpoint;
|
|
25
|
+
this.logger = conf.logger ?? console.log;
|
|
26
|
+
this.disconnected = true;
|
|
27
|
+
this.noAuth = false;
|
|
28
|
+
this.authorization = null;
|
|
29
|
+
this.con = conf.con;
|
|
30
|
+
this.permanentHeader = conf.permanentHeader || {};
|
|
31
|
+
this.reconnect = async () => {
|
|
32
|
+
this.disconnected = true;
|
|
33
|
+
return false;
|
|
34
|
+
};
|
|
35
|
+
this.onReconnect = () => Promise.resolve(true);
|
|
36
|
+
this.handle = this.handle.bind(this);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Retrieves the API endpoint.
|
|
40
|
+
*
|
|
41
|
+
* @return {string} The API endpoint string.
|
|
42
|
+
*/
|
|
43
|
+
getApiEndpoint() {
|
|
44
|
+
return this.api;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Sets the API endpoint URL used by the client.
|
|
48
|
+
*
|
|
49
|
+
* @param {string} endpoint - The full URL of the API endpoint.
|
|
50
|
+
* @returns {void}
|
|
51
|
+
*/
|
|
52
|
+
setApiEndpoint(endpoint) {
|
|
53
|
+
this.api = endpoint;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Indicates whether the instance is considered connected.
|
|
57
|
+
*
|
|
58
|
+
* The instance is regarded as connected when it either does not require authentication
|
|
59
|
+
* (`noAuth` is true) or it has an authorization token set (`authorization` is not null),
|
|
60
|
+
* and it is not currently marked as disconnected.
|
|
61
|
+
*
|
|
62
|
+
* @return {boolean} `true` if the instance is connected, `false` otherwise.
|
|
63
|
+
*/
|
|
64
|
+
isConnected() {
|
|
65
|
+
return (this.noAuth || this.authorization !== null) && !this.disconnected;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Returns the current authorization token.
|
|
69
|
+
*
|
|
70
|
+
* @return {string} The authorization token or an empty string if none is set.
|
|
71
|
+
*/
|
|
72
|
+
token() {
|
|
73
|
+
return this.authorization;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Returns the current authorization token.
|
|
77
|
+
*
|
|
78
|
+
* @return {string} The authorization token or an empty string if none is set.
|
|
79
|
+
*/
|
|
80
|
+
getBearer() {
|
|
81
|
+
if (this.authorization) {
|
|
82
|
+
return `Bearer ${this.authorization}`;
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
p(path, config) {
|
|
87
|
+
let pp = path;
|
|
88
|
+
if (config?.param) {
|
|
89
|
+
const e = Object.keys(config.param);
|
|
90
|
+
for (const d of e) {
|
|
91
|
+
pp = pp.replace(`{${d}}`, `${config.param[d]}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (config?.query) {
|
|
95
|
+
const e = Object.keys(config.query);
|
|
96
|
+
const slices = [];
|
|
97
|
+
for (const d of e) {
|
|
98
|
+
if (config.query[d]) {
|
|
99
|
+
slices.push(`${d}=${config.query[d]}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (slices.length > 0) {
|
|
103
|
+
pp += `?${slices.join('&')}`;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return `${this.api}${pp}`;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Sends a ping request to the API to verify connectivity and version availability.
|
|
110
|
+
*
|
|
111
|
+
* @return {boolean} `true` if the API responded with a 200 status code and a valid version object; `false` otherwise.
|
|
112
|
+
*/
|
|
113
|
+
async ping() {
|
|
114
|
+
try {
|
|
115
|
+
const version = await this.con.get(this.p('/version'));
|
|
116
|
+
return version.data?.api !== undefined && version.code === 200;
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
this.logger('ping failed');
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
tokenHeader() {
|
|
124
|
+
if (this.authorization) {
|
|
125
|
+
return {
|
|
126
|
+
Authorization: this.getBearer(),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
return {};
|
|
130
|
+
}
|
|
131
|
+
setPermanentHeader(header) {
|
|
132
|
+
this.permanentHeader = header;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Validates the current authentication token by performing a ping and a test request
|
|
136
|
+
* to the backend. The method first ensures connectivity via {@link ping}. If the ping
|
|
137
|
+
* succeeds, it attempts to retrieve a token from the `/test/auth` endpoint using the
|
|
138
|
+
* current token in the `Authorization` header. The operation is considered successful
|
|
139
|
+
* if the response status code is 200 or 201.
|
|
140
|
+
*
|
|
141
|
+
* If any step fails, an error is logged and the method returns {@code false}. On
|
|
142
|
+
* success, it returns {@code true}.
|
|
143
|
+
*
|
|
144
|
+
* @return {Promise<boolean>} A promise that resolves to {@code true} if the token
|
|
145
|
+
* test succeeds, otherwise {@code false}.
|
|
146
|
+
*/
|
|
147
|
+
async testToken() {
|
|
148
|
+
const ping = await this.ping();
|
|
149
|
+
if (ping) {
|
|
150
|
+
try {
|
|
151
|
+
const con = await this.con.get(this.p('/test/auth'), {
|
|
152
|
+
headers: this.tokenHeader(),
|
|
153
|
+
});
|
|
154
|
+
return con.code === 200 || con.code === 201;
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
this.logger(e);
|
|
158
|
+
this.logger('cant connect to backend');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
this.logger('test ping failed');
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Attempts to establish a connection to the backend without authentication.
|
|
166
|
+
*
|
|
167
|
+
* This method sends a ping request. If the ping succeeds, it clears any
|
|
168
|
+
* existing authorization data, marks the instance as connected,
|
|
169
|
+
* enables the no‑authentication mode, and returns `true`. If the ping
|
|
170
|
+
* fails, it logs a warning, clears authorization, marks the instance
|
|
171
|
+
* as disconnected, and returns `false`.
|
|
172
|
+
*
|
|
173
|
+
* @return {Promise<boolean>} `true` when a connection is successfully
|
|
174
|
+
* established without authentication, otherwise `false`.
|
|
175
|
+
*/
|
|
176
|
+
async connectNoAuth() {
|
|
177
|
+
const ping = await this.ping();
|
|
178
|
+
if (ping) {
|
|
179
|
+
this.authorization = null;
|
|
180
|
+
this.disconnected = false;
|
|
181
|
+
this.noAuth = true;
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
this.logger('cant connect to backend');
|
|
185
|
+
this.authorization = null;
|
|
186
|
+
this.disconnected = true;
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Forces a connection using the provided bearer token.
|
|
191
|
+
*
|
|
192
|
+
* @param {string|null} token The token to be used for authentication.
|
|
193
|
+
* @returns {void}
|
|
194
|
+
*/
|
|
195
|
+
forceConnect(token) {
|
|
196
|
+
if (token) {
|
|
197
|
+
this.authorization = token.replace('Bearer ', '').replace('bearer ', '');
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
this.authorization = null;
|
|
201
|
+
}
|
|
202
|
+
this.disconnected = false;
|
|
203
|
+
this.noAuth = token === null;
|
|
204
|
+
}
|
|
205
|
+
coppyFrom(con) {
|
|
206
|
+
this.authorization = con.authorization;
|
|
207
|
+
this.disconnected = con.disconnected;
|
|
208
|
+
this.noAuth = con.noAuth;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Establishes a connection to the backend using the supplied credentials.
|
|
212
|
+
* Performs a health‑check ping first; if successful, it requests an authentication
|
|
213
|
+
* token from the `/token` endpoint. When the token is obtained, the method
|
|
214
|
+
* updates internal state (authorization header, connection flags) and, unless
|
|
215
|
+
* a dry run is requested, sets up a reconnection routine. Any errors are
|
|
216
|
+
* logged and the method resolves to `false`.
|
|
217
|
+
*
|
|
218
|
+
* @param {string} email - The user's email address for authentication.
|
|
219
|
+
* @param {string} pw - The password (or token) for the specified user.
|
|
220
|
+
* @param {boolean} [dry=false] - If `true`, the method performs a dry run
|
|
221
|
+
* without persisting credentials or configuring reconnection logic.
|
|
222
|
+
*
|
|
223
|
+
* @returns Promise<boolean> `true` if the connection was successfully
|
|
224
|
+
* established, otherwise `false`.
|
|
225
|
+
*/
|
|
226
|
+
async connect(email, pw, dry = false) {
|
|
227
|
+
const ping = await this.ping();
|
|
228
|
+
if (ping) {
|
|
229
|
+
try {
|
|
230
|
+
const token = await this.con.post(this.p('/token'), {
|
|
231
|
+
username: email,
|
|
232
|
+
token: pw,
|
|
233
|
+
});
|
|
234
|
+
if (token.code === 200 || token.code === 201) {
|
|
235
|
+
if (!dry) {
|
|
236
|
+
this.authorization = `Bearer ${token.data?.token}`;
|
|
237
|
+
this.disconnected = false;
|
|
238
|
+
this.noAuth = false;
|
|
239
|
+
this.reconnect = async () => {
|
|
240
|
+
return ((await this.connect(email, pw)) && (await this.testToken()));
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
catch (e) {
|
|
247
|
+
this.logger(e);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
this.logger('cant connect to backend');
|
|
251
|
+
this.authorization = null;
|
|
252
|
+
this.disconnected = true;
|
|
253
|
+
this.noAuth = false;
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Performs an HTTP request using the client’s internal connection.
|
|
258
|
+
*
|
|
259
|
+
* The method verifies that the client is connected before attempting a request.
|
|
260
|
+
* It automatically injects the authorization token, permanent headers, and any
|
|
261
|
+
* headers supplied in `config`. If the request body is a `FormData` instance
|
|
262
|
+
* (or provides a `getHeaders` method), the appropriate form headers are added.
|
|
263
|
+
*
|
|
264
|
+
* Response handling:
|
|
265
|
+
* - `200` or `201`: returns `success: true` with the received data.
|
|
266
|
+
* - `498`: attempts to reconnect and retries the request once.
|
|
267
|
+
* - `401`: logs an authentication error, marks the client as disconnected.
|
|
268
|
+
* - `403` and other status codes: return `success: false` with the status code.
|
|
269
|
+
*
|
|
270
|
+
* @param {'POST'|'GET'|'PATCH'|'DELETE'} type The HTTP method to use.
|
|
271
|
+
* @param {string} path The endpoint path relative to the base URL.
|
|
272
|
+
* @param {J} [body] Optional request payload. May be `FormData` or a plain object.
|
|
273
|
+
* @param {ConHandleConfig} [config] Optional Axios-like configuration for the request.
|
|
274
|
+
* @returns {Promise<HandleRes<T>>} A promise that resolves to a `HandleRes` object
|
|
275
|
+
* containing the response data, status code, any error information, and headers.
|
|
276
|
+
*/
|
|
277
|
+
async handle(type, path, body, config) {
|
|
278
|
+
if (!this.isConnected()) {
|
|
279
|
+
this.logger('Disconnected');
|
|
280
|
+
return {
|
|
281
|
+
success: false,
|
|
282
|
+
data: null,
|
|
283
|
+
code: -1,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
let formHeader = null;
|
|
287
|
+
const cK = body;
|
|
288
|
+
if (cK &&
|
|
289
|
+
(cK instanceof form_data_1.default || typeof cK?.getHeaders === 'function')) {
|
|
290
|
+
formHeader = cK?.getHeaders?.() || {};
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
formHeader = {};
|
|
294
|
+
}
|
|
295
|
+
let dat;
|
|
296
|
+
switch (type) {
|
|
297
|
+
case 'GET':
|
|
298
|
+
dat = await this.con.get(this.p(path, config), {
|
|
299
|
+
...config,
|
|
300
|
+
headers: {
|
|
301
|
+
...this.tokenHeader(),
|
|
302
|
+
...formHeader,
|
|
303
|
+
...config?.headers,
|
|
304
|
+
...this.permanentHeader,
|
|
305
|
+
},
|
|
306
|
+
});
|
|
307
|
+
break;
|
|
308
|
+
case 'POST':
|
|
309
|
+
dat = await this.con.post(this.p(path, config), body, {
|
|
310
|
+
...config,
|
|
311
|
+
headers: {
|
|
312
|
+
...this.tokenHeader(),
|
|
313
|
+
...formHeader,
|
|
314
|
+
...config?.headers,
|
|
315
|
+
...this.permanentHeader,
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
break;
|
|
319
|
+
case 'PATCH':
|
|
320
|
+
dat = await this.con.patch(this.p(path, config), body, {
|
|
321
|
+
...config,
|
|
322
|
+
headers: {
|
|
323
|
+
...this.tokenHeader(),
|
|
324
|
+
...formHeader,
|
|
325
|
+
...config?.headers,
|
|
326
|
+
...this.permanentHeader,
|
|
327
|
+
},
|
|
328
|
+
});
|
|
329
|
+
break;
|
|
330
|
+
case 'DELETE':
|
|
331
|
+
dat = await this.con.delete(this.p(path, config), {
|
|
332
|
+
...config,
|
|
333
|
+
headers: {
|
|
334
|
+
...this.tokenHeader(),
|
|
335
|
+
...formHeader,
|
|
336
|
+
...config?.headers,
|
|
337
|
+
...this.permanentHeader,
|
|
338
|
+
},
|
|
339
|
+
});
|
|
340
|
+
break;
|
|
341
|
+
default:
|
|
342
|
+
return {
|
|
343
|
+
success: false,
|
|
344
|
+
data: null,
|
|
345
|
+
code: -1,
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
let error;
|
|
349
|
+
if (isErrorType(dat.data)) {
|
|
350
|
+
error = dat.data;
|
|
351
|
+
}
|
|
352
|
+
let x = false;
|
|
353
|
+
switch (dat.code) {
|
|
354
|
+
case 200:
|
|
355
|
+
case 201:
|
|
356
|
+
return {
|
|
357
|
+
success: true,
|
|
358
|
+
data: dat.data,
|
|
359
|
+
code: dat.code,
|
|
360
|
+
error,
|
|
361
|
+
headers: dat.headers,
|
|
362
|
+
};
|
|
363
|
+
case 498:
|
|
364
|
+
x = await this.reconnect();
|
|
365
|
+
if (x) {
|
|
366
|
+
this.onReconnect(this).catch((dx) => {
|
|
367
|
+
this.logger(dx);
|
|
368
|
+
});
|
|
369
|
+
return this.handle(type, path, body, config);
|
|
370
|
+
}
|
|
371
|
+
this.reconnect = async () => {
|
|
372
|
+
this.disconnected = true;
|
|
373
|
+
return false;
|
|
374
|
+
};
|
|
375
|
+
this.disconnected = true;
|
|
376
|
+
return {
|
|
377
|
+
success: false,
|
|
378
|
+
data: null,
|
|
379
|
+
code: dat.code,
|
|
380
|
+
error,
|
|
381
|
+
headers: dat.headers,
|
|
382
|
+
};
|
|
383
|
+
case 401:
|
|
384
|
+
this.logger('AUTH NOT VALID');
|
|
385
|
+
return {
|
|
386
|
+
success: false,
|
|
387
|
+
data: null,
|
|
388
|
+
code: dat.code,
|
|
389
|
+
error,
|
|
390
|
+
headers: dat.headers,
|
|
391
|
+
};
|
|
392
|
+
case 403:
|
|
393
|
+
return {
|
|
394
|
+
success: false,
|
|
395
|
+
data: null,
|
|
396
|
+
error,
|
|
397
|
+
code: dat.code,
|
|
398
|
+
headers: dat.headers,
|
|
399
|
+
};
|
|
400
|
+
default:
|
|
401
|
+
return {
|
|
402
|
+
success: false,
|
|
403
|
+
data: null,
|
|
404
|
+
error,
|
|
405
|
+
code: dat.code,
|
|
406
|
+
headers: dat.headers,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
exports.default = BaseCon;
|