@aicore/cocodb-ws-client 1.0.23 → 1.0.26
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/package.json +9 -9
- package/src/index.js +4 -1
- package/src/utils/api.js +48 -0
- package/src/utils/client.js +52 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aicore/cocodb-ws-client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.26",
|
|
4
4
|
"description": "Websocket client for cocoDb",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
],
|
|
39
39
|
"repository": {
|
|
40
40
|
"type": "git",
|
|
41
|
-
"url": "git+https://github.com/aicore/
|
|
41
|
+
"url": "git+https://github.com/aicore/cocoDbWsClient.git"
|
|
42
42
|
},
|
|
43
43
|
"author": "Charly, core.ai",
|
|
44
44
|
"license": "AGPL-3.0-or-later",
|
|
@@ -47,20 +47,20 @@
|
|
|
47
47
|
},
|
|
48
48
|
"homepage": "https://github.com/aicore/cocoDbWsClient#readme",
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@commitlint/cli": "19.8.
|
|
51
|
-
"@commitlint/config-conventional": "19.8.
|
|
50
|
+
"@commitlint/cli": "19.8.1",
|
|
51
|
+
"@commitlint/config-conventional": "19.8.1",
|
|
52
52
|
"c8": "10.1.3",
|
|
53
|
-
"chai": "5.
|
|
53
|
+
"chai": "5.3.3",
|
|
54
54
|
"cli-color": "2.0.4",
|
|
55
55
|
"documentation": "14.0.3",
|
|
56
|
-
"eslint": "9.
|
|
57
|
-
"glob": "11.0
|
|
56
|
+
"eslint": "9.39.2",
|
|
57
|
+
"glob": "11.1.0",
|
|
58
58
|
"husky": "9.1.7",
|
|
59
|
-
"mocha": "11.
|
|
59
|
+
"mocha": "11.7.5"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
62
|
"@aicore/libcommonutils": "1.0.20",
|
|
63
|
-
"ws": "8.18.
|
|
63
|
+
"ws": "8.18.3"
|
|
64
64
|
},
|
|
65
65
|
"optionalDependencies": {
|
|
66
66
|
"bufferutil": "4.0.9",
|
package/src/index.js
CHANGED
package/src/utils/api.js
CHANGED
|
@@ -392,3 +392,51 @@ export function query(tableName, queryString, useIndexForFields = null, options=
|
|
|
392
392
|
});
|
|
393
393
|
}
|
|
394
394
|
|
|
395
|
+
/**
|
|
396
|
+
* Lists all databases on the MySQL server.
|
|
397
|
+
* @example <caption>Sample usage</caption>
|
|
398
|
+
* const response = await listDatabases();
|
|
399
|
+
* console.log(response.databases); // ['mysql', 'information_schema', 'mydb']
|
|
400
|
+
* @returns {Promise<Object>} A promise resolving to {isSuccess: boolean, databases: string[]}
|
|
401
|
+
*/
|
|
402
|
+
export function listDatabases() {
|
|
403
|
+
return sendMessage({
|
|
404
|
+
fn: 'listDatabases',
|
|
405
|
+
request: {}
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Lists all tables in a database.
|
|
411
|
+
* @param {string} databaseName - The name of the database
|
|
412
|
+
* @returns {Promise<Object>} A promise resolving to {isSuccess: boolean, tables: string[]}
|
|
413
|
+
*/
|
|
414
|
+
export function listTables(databaseName) {
|
|
415
|
+
if (isStringEmpty(databaseName)) {
|
|
416
|
+
throw new Error('Please provide valid databaseName');
|
|
417
|
+
}
|
|
418
|
+
return sendMessage({
|
|
419
|
+
fn: 'listTables',
|
|
420
|
+
request: {
|
|
421
|
+
databaseName: databaseName
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Gets index information for a table.
|
|
428
|
+
* @param {string} tableName - The table name in database.tableName format
|
|
429
|
+
* @returns {Promise<Object>} A promise resolving to {isSuccess: boolean, indexes: IndexInfo[]}
|
|
430
|
+
*/
|
|
431
|
+
export function getTableIndexes(tableName) {
|
|
432
|
+
if (isStringEmpty(tableName)) {
|
|
433
|
+
throw new Error('Please provide valid tableName');
|
|
434
|
+
}
|
|
435
|
+
return sendMessage({
|
|
436
|
+
fn: 'getTableIndexes',
|
|
437
|
+
request: {
|
|
438
|
+
tableName: tableName
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
|
package/src/utils/client.js
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import {WS} from "./WebSocket.js";
|
|
2
2
|
import {isString, isObject, isStringEmpty, COCO_DB_FUNCTIONS} from "@aicore/libcommonutils";
|
|
3
3
|
|
|
4
|
+
// Additional functions not yet in COCO_DB_FUNCTIONS from libcommonutils
|
|
5
|
+
const ADDITIONAL_FUNCTIONS = {
|
|
6
|
+
listDatabases: 'listDatabases',
|
|
7
|
+
listTables: 'listTables',
|
|
8
|
+
getTableIndexes: 'getTableIndexes'
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Checks if a function name is a valid cocodb function
|
|
13
|
+
* @param {string} fn - The function name to check
|
|
14
|
+
* @returns {boolean} True if the function is valid
|
|
15
|
+
*/
|
|
16
|
+
function isValidFunction(fn) {
|
|
17
|
+
return (fn in COCO_DB_FUNCTIONS) || (fn in ADDITIONAL_FUNCTIONS);
|
|
18
|
+
}
|
|
19
|
+
|
|
4
20
|
let client = null,
|
|
5
21
|
cocoDBEndPointURL = null,
|
|
6
22
|
cocoAuthKey = null,
|
|
@@ -34,6 +50,7 @@ function _checkActivityForHibernation() {
|
|
|
34
50
|
return;
|
|
35
51
|
}
|
|
36
52
|
if(!client || client.hibernating
|
|
53
|
+
|| client.userClosedConnection
|
|
37
54
|
|| !client.connectionEstablished // cant hibernate if connection isnt already established/ is being establised
|
|
38
55
|
|| ID_TO_RESOLVE_REJECT_MAP.size > 0){ // if there are any pending responses, we cant hibernate
|
|
39
56
|
return;
|
|
@@ -91,8 +108,18 @@ function _setupClientAndWaitForClose(connectedCb) {
|
|
|
91
108
|
__receiveMessage(data);
|
|
92
109
|
});
|
|
93
110
|
|
|
111
|
+
let terminated = false;
|
|
94
112
|
function _connectionTerminated(reason) {
|
|
113
|
+
if (terminated) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
terminated = true;
|
|
117
|
+
|
|
95
118
|
console.log(reason);
|
|
119
|
+
// not set bufferRequests = true for unexpected failures.
|
|
120
|
+
// Real connection failures → reject immediately, don't buffer
|
|
121
|
+
// Hibernation → buffer and reconnect transparently
|
|
122
|
+
|
|
96
123
|
client.connectionEstablished = false;
|
|
97
124
|
for (let [sequenceNumber, handler] of ID_TO_RESOLVE_REJECT_MAP) {
|
|
98
125
|
handler.reject(reason);
|
|
@@ -100,11 +127,20 @@ function _setupClientAndWaitForClose(connectedCb) {
|
|
|
100
127
|
}
|
|
101
128
|
resolve();
|
|
102
129
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
130
|
+
|
|
131
|
+
client.on('error', function (err) {
|
|
132
|
+
// ECONNREFUSED, ENOTFOUND, TLS errors, etc. can land here
|
|
133
|
+
_connectionTerminated(err);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
client.on('close', function (code, reasonBuf) {
|
|
137
|
+
// reasonBuf may be a Buffer in ws; keep it simple
|
|
138
|
+
_connectionTerminated(`connection closed (${code})`);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Optional but useful: HTTP-level failures (proxies, 401, 403, 502...)
|
|
142
|
+
client.on('unexpected-response', function (req, res) {
|
|
143
|
+
_connectionTerminated(`unexpected-response: ${res.statusCode}`);
|
|
108
144
|
});
|
|
109
145
|
});
|
|
110
146
|
}
|
|
@@ -131,13 +167,14 @@ function _cancelBackoffTimer() {
|
|
|
131
167
|
}
|
|
132
168
|
}
|
|
133
169
|
|
|
134
|
-
async function _setupAndMaintainConnection(
|
|
170
|
+
async function _setupAndMaintainConnection(resolveOnFirstConnect, reject) {
|
|
135
171
|
backoffTimer = null;
|
|
136
172
|
function connected() {
|
|
137
173
|
_resetBackoffTime();
|
|
138
|
-
if(
|
|
139
|
-
|
|
140
|
-
|
|
174
|
+
if(resolveOnFirstConnect){
|
|
175
|
+
resolveOnFirstConnect("connected");
|
|
176
|
+
resolveOnFirstConnect = null;
|
|
177
|
+
reject = null;
|
|
141
178
|
// setup hibernate timer on first connection
|
|
142
179
|
activityInHibernateInterval = 1;
|
|
143
180
|
hibernateTimer = setInterval(_checkActivityForHibernation, INACTIVITY_TIME_FOR_HIBERNATE);
|
|
@@ -160,8 +197,8 @@ async function _setupAndMaintainConnection(firstConnectionCb, neverConnectedCB)
|
|
|
160
197
|
client && client.userClosedConnectionCB && client.userClosedConnectionCB();
|
|
161
198
|
client = cocoDBEndPointURL = cocoAuthKey = null;
|
|
162
199
|
id = 0;
|
|
163
|
-
if(
|
|
164
|
-
|
|
200
|
+
if(reject){
|
|
201
|
+
reject(new Error("user Cancelled"));
|
|
165
202
|
}
|
|
166
203
|
}
|
|
167
204
|
|
|
@@ -219,7 +256,7 @@ export function close() {
|
|
|
219
256
|
currentClient.userClosedConnection = true;
|
|
220
257
|
currentClient.userClosedConnectionCB = function () {
|
|
221
258
|
for(let entry of pendingSendMessages){
|
|
222
|
-
entry.reject();
|
|
259
|
+
entry.reject(new Error('Connection closed'));
|
|
223
260
|
}
|
|
224
261
|
pendingSendMessages = [];
|
|
225
262
|
resolve();
|
|
@@ -239,7 +276,7 @@ export function close() {
|
|
|
239
276
|
* @returns {string} A function that increments the id variable and returns the new value as a hexadecimal string.
|
|
240
277
|
*/
|
|
241
278
|
function getId() {
|
|
242
|
-
id++;
|
|
279
|
+
id++; // Will take about 300 years to run out at 1 million sustained tps to db with Number.MAX_SAFE_INTEGER
|
|
243
280
|
return id.toString(16);
|
|
244
281
|
}
|
|
245
282
|
|
|
@@ -256,7 +293,7 @@ function _sendMessage(message, resolve, reject) {
|
|
|
256
293
|
reject('Please provide valid Object');
|
|
257
294
|
return;
|
|
258
295
|
}
|
|
259
|
-
if (!isString(message.fn) || !(message.fn
|
|
296
|
+
if (!isString(message.fn) || !isValidFunction(message.fn)) {
|
|
260
297
|
reject('please provide valid function name');
|
|
261
298
|
return;
|
|
262
299
|
}
|
|
@@ -284,7 +321,7 @@ function _sendPendingMessages() {
|
|
|
284
321
|
*/
|
|
285
322
|
export function sendMessage(message) {
|
|
286
323
|
// make a copy as the user may start modifying the object while we are sending it.
|
|
287
|
-
message =
|
|
324
|
+
message = JSON.parse(JSON.stringify(message)); // faster than structured clone for most cases
|
|
288
325
|
return new Promise(function (resolve, reject) {
|
|
289
326
|
if(bufferRequests){
|
|
290
327
|
if(pendingSendMessages.length > MAX_PENDING_SEND_BUFFER_SIZE){
|