@aicore/cocodb-ws-client 1.0.23 → 1.0.25

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.
Files changed (2) hide show
  1. package/package.json +9 -9
  2. package/src/utils/client.js +35 -14
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aicore/cocodb-ws-client",
3
- "version": "1.0.23",
3
+ "version": "1.0.25",
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/template-nodejs.git"
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.0",
51
- "@commitlint/config-conventional": "19.8.0",
50
+ "@commitlint/cli": "19.8.1",
51
+ "@commitlint/config-conventional": "19.8.1",
52
52
  "c8": "10.1.3",
53
- "chai": "5.2.0",
53
+ "chai": "5.3.3",
54
54
  "cli-color": "2.0.4",
55
55
  "documentation": "14.0.3",
56
- "eslint": "9.25.0",
57
- "glob": "11.0.1",
56
+ "eslint": "9.39.2",
57
+ "glob": "11.1.0",
58
58
  "husky": "9.1.7",
59
- "mocha": "11.1.0"
59
+ "mocha": "11.7.5"
60
60
  },
61
61
  "dependencies": {
62
62
  "@aicore/libcommonutils": "1.0.20",
63
- "ws": "8.18.1"
63
+ "ws": "8.18.3"
64
64
  },
65
65
  "optionalDependencies": {
66
66
  "bufferutil": "4.0.9",
@@ -34,6 +34,7 @@ function _checkActivityForHibernation() {
34
34
  return;
35
35
  }
36
36
  if(!client || client.hibernating
37
+ || client.userClosedConnection
37
38
  || !client.connectionEstablished // cant hibernate if connection isnt already established/ is being establised
38
39
  || ID_TO_RESOLVE_REJECT_MAP.size > 0){ // if there are any pending responses, we cant hibernate
39
40
  return;
@@ -91,8 +92,18 @@ function _setupClientAndWaitForClose(connectedCb) {
91
92
  __receiveMessage(data);
92
93
  });
93
94
 
95
+ let terminated = false;
94
96
  function _connectionTerminated(reason) {
97
+ if (terminated) {
98
+ return;
99
+ }
100
+ terminated = true;
101
+
95
102
  console.log(reason);
103
+ // not set bufferRequests = true for unexpected failures.
104
+ // Real connection failures → reject immediately, don't buffer
105
+ // Hibernation → buffer and reconnect transparently
106
+
96
107
  client.connectionEstablished = false;
97
108
  for (let [sequenceNumber, handler] of ID_TO_RESOLVE_REJECT_MAP) {
98
109
  handler.reject(reason);
@@ -100,11 +111,20 @@ function _setupClientAndWaitForClose(connectedCb) {
100
111
  }
101
112
  resolve();
102
113
  }
103
- client.on('close', function () {
104
- // https://websockets.spec.whatwg.org/#eventdef-websocket-error
105
- // https://stackoverflow.com/questions/40084398/is-onclose-always-called-after-onerror-for-websocket
106
- // we do not need to listen for error event as an error event is immediately followed by a close event.
107
- _connectionTerminated('connection closed');
114
+
115
+ client.on('error', function (err) {
116
+ // ECONNREFUSED, ENOTFOUND, TLS errors, etc. can land here
117
+ _connectionTerminated(err);
118
+ });
119
+
120
+ client.on('close', function (code, reasonBuf) {
121
+ // reasonBuf may be a Buffer in ws; keep it simple
122
+ _connectionTerminated(`connection closed (${code})`);
123
+ });
124
+
125
+ // Optional but useful: HTTP-level failures (proxies, 401, 403, 502...)
126
+ client.on('unexpected-response', function (req, res) {
127
+ _connectionTerminated(`unexpected-response: ${res.statusCode}`);
108
128
  });
109
129
  });
110
130
  }
@@ -131,13 +151,14 @@ function _cancelBackoffTimer() {
131
151
  }
132
152
  }
133
153
 
134
- async function _setupAndMaintainConnection(firstConnectionCb, neverConnectedCB) {
154
+ async function _setupAndMaintainConnection(resolveOnFirstConnect, reject) {
135
155
  backoffTimer = null;
136
156
  function connected() {
137
157
  _resetBackoffTime();
138
- if(firstConnectionCb){
139
- firstConnectionCb("connected");
140
- firstConnectionCb = null;
158
+ if(resolveOnFirstConnect){
159
+ resolveOnFirstConnect("connected");
160
+ resolveOnFirstConnect = null;
161
+ reject = null;
141
162
  // setup hibernate timer on first connection
142
163
  activityInHibernateInterval = 1;
143
164
  hibernateTimer = setInterval(_checkActivityForHibernation, INACTIVITY_TIME_FOR_HIBERNATE);
@@ -160,8 +181,8 @@ async function _setupAndMaintainConnection(firstConnectionCb, neverConnectedCB)
160
181
  client && client.userClosedConnectionCB && client.userClosedConnectionCB();
161
182
  client = cocoDBEndPointURL = cocoAuthKey = null;
162
183
  id = 0;
163
- if(neverConnectedCB){
164
- neverConnectedCB(new Error("user Cancelled"));
184
+ if(reject){
185
+ reject(new Error("user Cancelled"));
165
186
  }
166
187
  }
167
188
 
@@ -219,7 +240,7 @@ export function close() {
219
240
  currentClient.userClosedConnection = true;
220
241
  currentClient.userClosedConnectionCB = function () {
221
242
  for(let entry of pendingSendMessages){
222
- entry.reject();
243
+ entry.reject(new Error('Connection closed'));
223
244
  }
224
245
  pendingSendMessages = [];
225
246
  resolve();
@@ -239,7 +260,7 @@ export function close() {
239
260
  * @returns {string} A function that increments the id variable and returns the new value as a hexadecimal string.
240
261
  */
241
262
  function getId() {
242
- id++;
263
+ id++; // Will take about 300 years to run out at 1 million sustained tps to db with Number.MAX_SAFE_INTEGER
243
264
  return id.toString(16);
244
265
  }
245
266
 
@@ -284,7 +305,7 @@ function _sendPendingMessages() {
284
305
  */
285
306
  export function sendMessage(message) {
286
307
  // make a copy as the user may start modifying the object while we are sending it.
287
- message = structuredClone(message);
308
+ message = JSON.parse(JSON.stringify(message)); // faster than structured clone for most cases
288
309
  return new Promise(function (resolve, reject) {
289
310
  if(bufferRequests){
290
311
  if(pendingSendMessages.length > MAX_PENDING_SEND_BUFFER_SIZE){