@scriptdb/client 1.1.0 → 1.1.2

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/dist/index.js CHANGED
@@ -1,72 +1,116 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
1
30
  // src/index.ts
2
- import * as net from "net";
3
- import * as tls from "tls";
4
- import { URL } from "url";
5
- import * as crypto from "crypto";
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ ScriptDBClient: () => ScriptDBClient,
34
+ default: () => index_default
35
+ });
36
+ module.exports = __toCommonJS(index_exports);
37
+ var net = __toESM(require("net"));
38
+ var tls = __toESM(require("tls"));
39
+ var import_url = require("url");
40
+ var crypto = __toESM(require("crypto"));
6
41
  var noopLogger = {
7
- debug: () => {},
8
- info: () => {},
9
- warn: () => {},
10
- error: () => {}
42
+ debug: () => {
43
+ },
44
+ info: () => {
45
+ },
46
+ warn: () => {
47
+ },
48
+ error: () => {
49
+ }
11
50
  };
12
-
13
- class ScriptDBClient {
14
- options;
15
- socketTimeout = 0;
16
- maxMessageSize = 0;
17
- _mask = () => {};
18
- _maskArgs = () => [];
19
- logger = {};
20
- secure = true;
21
- requestTimeout = 0;
22
- retries = 0;
23
- retryDelay = 0;
24
- frame = "ndjson";
25
- uri = "";
26
- protocolName = "";
27
- username = null;
28
- password = null;
29
- host = "";
30
- port = 0;
31
- database = null;
32
- client = null;
33
- buffer = Buffer.alloc(0);
34
- _nextId = 1;
35
- _pending = new Map;
36
- _maxPending = 0;
37
- _maxQueue = 0;
38
- _pendingQueue = [];
39
- _connected = false;
40
- _authenticating = false;
41
- token = null;
42
- _currentRetries = 0;
43
- tokenExpiry = null;
44
- _destroyed = false;
45
- _reconnectTimer = null;
46
- signing = null;
47
- _stringify = JSON.stringify;
48
- ready = Promise.resolve();
49
- _resolveReadyFn = null;
50
- _rejectReadyFn = null;
51
- _connecting = null;
52
- _authPendingId = null;
51
+ var ScriptDBClient = class {
52
+ /**
53
+ * Create a new client. Do NOT auto-connect in constructor — call connect()
54
+ * @param uri - Connection URI
55
+ * @param options - Client options
56
+ * @param options.secure - use TLS
57
+ * @param options.logger - { debug, info, warn, error }
58
+ * @param options.requestTimeout - Request timeout in ms
59
+ * @param options.retries - Reconnection retries
60
+ * @param options.retryDelay - Initial retry delay in ms
61
+ * @param options.tlsOptions - Passed to tls.connect when secure
62
+ */
53
63
  constructor(uri, options = {}) {
54
- if (!uri || typeof uri !== "string")
55
- throw new Error("uri required");
64
+ this.socketTimeout = 0;
65
+ this.maxMessageSize = 0;
66
+ this._mask = () => {
67
+ };
68
+ this._maskArgs = () => [];
69
+ this.logger = {};
70
+ this.secure = true;
71
+ this.requestTimeout = 0;
72
+ this.retries = 0;
73
+ this.retryDelay = 0;
74
+ this.frame = "ndjson";
75
+ this.uri = "";
76
+ this.protocolName = "";
77
+ this.username = null;
78
+ this.password = null;
79
+ this.host = "";
80
+ this.port = 0;
81
+ this.database = null;
82
+ this.client = null;
83
+ this.buffer = Buffer.alloc(0);
84
+ this._nextId = 1;
85
+ this._pending = /* @__PURE__ */ new Map();
86
+ this._maxPending = 0;
87
+ this._maxQueue = 0;
88
+ this._pendingQueue = [];
89
+ this._connected = false;
90
+ this._authenticating = false;
91
+ this.token = null;
92
+ this._currentRetries = 0;
93
+ this.tokenExpiry = null;
94
+ this._destroyed = false;
95
+ this._reconnectTimer = null;
96
+ this.signing = null;
97
+ this._stringify = JSON.stringify;
98
+ this.ready = Promise.resolve();
99
+ this._resolveReadyFn = null;
100
+ this._rejectReadyFn = null;
101
+ this._connecting = null;
102
+ this._authPendingId = null;
103
+ if (!uri || typeof uri !== "string") throw new Error("uri required");
56
104
  this.options = Object.assign({}, options);
57
105
  this.socketTimeout = Number.isFinite(this.options.socketTimeout) ? this.options.socketTimeout : 0;
58
106
  this.maxMessageSize = Number.isFinite(this.options.maxMessageSize) ? this.options.maxMessageSize : 5 * 1024 * 1024;
59
107
  this._mask = (obj) => {
60
108
  try {
61
- if (!obj || typeof obj !== "object")
62
- return obj;
109
+ if (!obj || typeof obj !== "object") return obj;
63
110
  const copy = Array.isArray(obj) ? obj.slice() : Object.assign({}, obj);
64
- if (copy.token)
65
- copy.token = "****";
66
- if (copy.password)
67
- copy.password = "****";
68
- if (copy.data && copy.data.password)
69
- copy.data.password = "****";
111
+ if (copy.token) copy.token = "****";
112
+ if (copy.password) copy.password = "****";
113
+ if (copy.data && copy.data.password) copy.data.password = "****";
70
114
  return copy;
71
115
  } catch (e) {
72
116
  return obj;
@@ -75,10 +119,8 @@ class ScriptDBClient {
75
119
  const rawLogger = this.options.logger && typeof this.options.logger === "object" ? this.options.logger : noopLogger;
76
120
  this._maskArgs = (args) => {
77
121
  return args.map((a) => {
78
- if (!a)
79
- return a;
80
- if (typeof a === "string")
81
- return a;
122
+ if (!a) return a;
123
+ if (typeof a === "string") return a;
82
124
  return this._mask(a);
83
125
  });
84
126
  };
@@ -90,14 +132,16 @@ class ScriptDBClient {
90
132
  };
91
133
  this.secure = typeof this.options.secure === "boolean" ? !!this.options.secure : true;
92
134
  if (!this.secure)
93
- this.logger.warn?.("Warning: connecting in insecure mode (secure=false). This is not recommended.");
135
+ this.logger.warn?.(
136
+ "Warning: connecting in insecure mode (secure=false). This is not recommended."
137
+ );
94
138
  this.requestTimeout = Number.isFinite(this.options.requestTimeout) ? this.options.requestTimeout : 0;
95
139
  this.retries = Number.isFinite(this.options.retries) ? this.options.retries : 3;
96
- this.retryDelay = Number.isFinite(this.options.retryDelay) ? this.options.retryDelay : 1000;
140
+ this.retryDelay = Number.isFinite(this.options.retryDelay) ? this.options.retryDelay : 1e3;
97
141
  this.frame = this.options.frame === "length-prefix" || this.options.preferLengthPrefix ? "length-prefix" : "ndjson";
98
142
  let parsed;
99
143
  try {
100
- parsed = new URL(uri);
144
+ parsed = new import_url.URL(uri);
101
145
  } catch (e) {
102
146
  throw new Error("Invalid uri");
103
147
  }
@@ -109,7 +153,9 @@ class ScriptDBClient {
109
153
  this.username = (typeof this.options.username === "string" ? this.options.username : parsed.username) || null;
110
154
  this.password = (typeof this.options.password === "string" ? this.options.password : parsed.password) || null;
111
155
  if (parsed.username && !(typeof this.options.username === "string")) {
112
- this.logger.warn?.("Credentials found in URI — consider passing credentials via options instead of embedding in URI");
156
+ this.logger.warn?.(
157
+ "Credentials found in URI \u2014 consider passing credentials via options instead of embedding in URI"
158
+ );
113
159
  }
114
160
  try {
115
161
  parsed.username = "";
@@ -124,9 +170,9 @@ class ScriptDBClient {
124
170
  this.client = null;
125
171
  this.buffer = Buffer.alloc(0);
126
172
  this._nextId = 1;
127
- this._pending = new Map;
173
+ this._pending = /* @__PURE__ */ new Map();
128
174
  this._maxPending = Number.isFinite(this.options.maxPending) ? this.options.maxPending : 100;
129
- this._maxQueue = Number.isFinite(this.options.maxQueue) ? this.options.maxQueue : 1000;
175
+ this._maxQueue = Number.isFinite(this.options.maxQueue) ? this.options.maxQueue : 1e3;
130
176
  this._pendingQueue = [];
131
177
  this._connected = false;
132
178
  this._authenticating = false;
@@ -149,7 +195,8 @@ class ScriptDBClient {
149
195
  if (this._resolveReadyFn) {
150
196
  try {
151
197
  this._resolveReadyFn(value);
152
- } catch (e) {}
198
+ } catch (e) {
199
+ }
153
200
  this._resolveReadyFn = null;
154
201
  this._rejectReadyFn = null;
155
202
  }
@@ -162,16 +209,22 @@ class ScriptDBClient {
162
209
  process.nextTick(() => {
163
210
  try {
164
211
  rejectFn(err);
165
- } catch (e) {}
212
+ } catch (e) {
213
+ }
166
214
  });
167
215
  }
168
216
  }
217
+ /**
218
+ * Check if connected
219
+ */
169
220
  get connected() {
170
221
  return this._connected;
171
222
  }
223
+ /**
224
+ * Connect to server and authenticate. Returns a Promise that resolves when authenticated.
225
+ */
172
226
  connect() {
173
- if (this._connecting)
174
- return this._connecting;
227
+ if (this._connecting) return this._connecting;
175
228
  this._connecting = new Promise((resolve, reject) => {
176
229
  const opts = { host: this.host, port: this.port };
177
230
  const onConnect = () => {
@@ -192,7 +245,11 @@ class ScriptDBClient {
192
245
  try {
193
246
  if (this.secure) {
194
247
  const connectionOpts = { host: opts.host, port: opts.port };
195
- const tlsOptions = Object.assign({}, this.options.tlsOptions || {}, connectionOpts);
248
+ const tlsOptions = Object.assign(
249
+ {},
250
+ this.options.tlsOptions || {},
251
+ connectionOpts
252
+ );
196
253
  if (typeof tlsOptions.rejectUnauthorized === "undefined")
197
254
  tlsOptions.rejectUnauthorized = true;
198
255
  this.client = tls.connect(tlsOptions, onConnect);
@@ -214,7 +271,10 @@ class ScriptDBClient {
214
271
  return reject(error);
215
272
  }
216
273
  const onError = (err) => {
217
- this.logger?.error?.("Client socket error:", err && err.message ? err.message : err);
274
+ this.logger?.error?.(
275
+ "Client socket error:",
276
+ err && err.message ? err.message : err
277
+ );
218
278
  this._handleDisconnect(err);
219
279
  };
220
280
  const onClose = (hadError) => {
@@ -229,7 +289,8 @@ class ScriptDBClient {
229
289
  this.logger?.warn?.("Socket timeout, destroying connection");
230
290
  try {
231
291
  this.client?.destroy();
232
- } catch (e) {}
292
+ } catch (e) {
293
+ }
233
294
  });
234
295
  }
235
296
  }).catch((err) => {
@@ -239,8 +300,7 @@ class ScriptDBClient {
239
300
  return this._connecting;
240
301
  }
241
302
  _setupListeners() {
242
- if (!this.client)
243
- return;
303
+ if (!this.client) return;
244
304
  console.log("ScriptDBClient _setupListeners: called, client exists:", !!this.client);
245
305
  this.client.removeAllListeners("data");
246
306
  this.buffer = Buffer.alloc(0);
@@ -258,28 +318,32 @@ class ScriptDBClient {
258
318
  while (this.buffer.length >= 4) {
259
319
  const len = this.buffer.readUInt32BE(0);
260
320
  if (len > this.maxMessageSize) {
261
- this.logger?.error?.("Incoming length-prefixed frame exceeds maxMessageSize — closing connection");
321
+ this.logger?.error?.(
322
+ "Incoming length-prefixed frame exceeds maxMessageSize \u2014 closing connection"
323
+ );
262
324
  try {
263
325
  this.client?.destroy();
264
- } catch (e) {}
326
+ } catch (e) {
327
+ }
265
328
  return;
266
329
  }
267
- if (this.buffer.length < 4 + len)
268
- break;
330
+ if (this.buffer.length < 4 + len) break;
269
331
  const payload = this.buffer.slice(4, 4 + len);
270
332
  this.buffer = this.buffer.slice(4 + len);
271
333
  let msg;
272
334
  try {
273
335
  msg = JSON.parse(payload.toString("utf8"));
274
336
  } catch (e) {
275
- this.logger?.error?.("Invalid JSON frame", e && e.message ? e.message : e);
337
+ this.logger?.error?.(
338
+ "Invalid JSON frame",
339
+ e && e.message ? e.message : e
340
+ );
276
341
  continue;
277
342
  }
278
- if (!msg || typeof msg !== "object")
279
- continue;
343
+ if (!msg || typeof msg !== "object") continue;
280
344
  const validSchema = (typeof msg.id === "undefined" || typeof msg.id === "number") && (typeof msg.action === "string" || typeof msg.action === "undefined") && (typeof msg.command === "string" || typeof msg.command === "undefined") && (typeof msg.message === "string" || typeof msg.message === "undefined") && (typeof msg.data === "object" || typeof msg.data === "undefined" || msg.data === null);
281
345
  if (!validSchema) {
282
- this.logger?.warn?.("Message failed schema validation ignoring");
346
+ this.logger?.warn?.("Message failed schema validation \u2014 ignoring");
283
347
  continue;
284
348
  }
285
349
  this._handleMessage(msg);
@@ -303,48 +367,53 @@ class ScriptDBClient {
303
367
  while ((idx2 = chunk.indexOf(10, start)) !== -1) {
304
368
  const lineBuf = chunk.slice(start, idx2);
305
369
  start = idx2 + 1;
306
- if (lineBuf.length === 0)
307
- continue;
370
+ if (lineBuf.length === 0) continue;
308
371
  let msg;
309
372
  try {
310
373
  msg = JSON.parse(lineBuf.toString("utf8"));
311
374
  } catch (e) {
312
- this.logger?.error?.("Invalid JSON from server", e && e.message ? e.message : e);
375
+ this.logger?.error?.(
376
+ "Invalid JSON from server",
377
+ e && e.message ? e.message : e
378
+ );
313
379
  continue;
314
380
  }
315
- if (!msg || typeof msg !== "object")
316
- continue;
381
+ if (!msg || typeof msg !== "object") continue;
317
382
  const validSchema = (typeof msg.id === "undefined" || typeof msg.id === "number") && (typeof msg.action === "string" || typeof msg.action === "undefined") && (typeof msg.command === "string" || typeof msg.command === "undefined") && (typeof msg.message === "string" || typeof msg.message === "undefined");
318
- if (!validSchema)
319
- continue;
383
+ if (!validSchema) continue;
320
384
  this._handleMessage(msg);
321
385
  }
322
386
  return;
323
387
  }
324
388
  this.buffer = Buffer.concat([this.buffer, chunk]);
325
389
  if (this.buffer.length > this.maxMessageSize) {
326
- this.logger?.error?.("Incoming message exceeds maxMessageSize — closing connection");
390
+ this.logger?.error?.(
391
+ "Incoming message exceeds maxMessageSize \u2014 closing connection"
392
+ );
327
393
  try {
328
394
  this.client?.destroy();
329
- } catch (e) {}
395
+ } catch (e) {
396
+ }
330
397
  return;
331
398
  }
332
399
  let idx;
333
400
  while ((idx = this.buffer.indexOf(10)) !== -1) {
334
401
  const lineBuf = this.buffer.slice(0, idx);
335
402
  this.buffer = this.buffer.slice(idx + 1);
336
- if (lineBuf.length === 0)
337
- continue;
403
+ if (lineBuf.length === 0) continue;
338
404
  let msg;
339
405
  try {
340
406
  msg = JSON.parse(lineBuf.toString("utf8"));
341
407
  } catch (e) {
342
- this.logger?.error?.("Invalid JSON from server", e && e.message ? e.message : e);
408
+ this.logger?.error?.(
409
+ "Invalid JSON from server",
410
+ e && e.message ? e.message : e
411
+ );
343
412
  continue;
344
413
  }
345
414
  const validSchema = (typeof msg.id === "undefined" || typeof msg.id === "number") && (typeof msg.action === "string" || typeof msg.action === "undefined") && (typeof msg.command === "string" || typeof msg.command === "undefined") && (typeof msg.message === "string" || typeof msg.message === "undefined");
346
415
  if (!validSchema) {
347
- this.logger?.warn?.("Message failed schema validation ignoring");
416
+ this.logger?.warn?.("Message failed schema validation \u2014 ignoring");
348
417
  continue;
349
418
  }
350
419
  this._handleMessage(msg);
@@ -352,13 +421,19 @@ class ScriptDBClient {
352
421
  });
353
422
  }
354
423
  }
424
+ // build the final buffer for sending using current token and signing settings
355
425
  _buildFinalBuffer(payloadBase, id) {
356
- const payloadObj = Object.assign({ id, action: payloadBase.action }, payloadBase.data !== undefined ? { data: payloadBase.data } : {});
357
- if (this.token)
358
- payloadObj.token = this.token;
426
+ const payloadObj = Object.assign(
427
+ { id, action: payloadBase.action },
428
+ payloadBase.data !== void 0 ? { data: payloadBase.data } : {}
429
+ );
430
+ if (this.token) payloadObj.token = this.token;
359
431
  const payloadStr = this._stringify(payloadObj);
360
432
  if (this.signing && this.signing.secret) {
361
- const hmac = crypto.createHmac(this.signing.algorithm || "sha256", this.signing.secret);
433
+ const hmac = crypto.createHmac(
434
+ this.signing.algorithm || "sha256",
435
+ this.signing.secret
436
+ );
362
437
  hmac.update(payloadStr);
363
438
  const sig = hmac.digest("hex");
364
439
  const envelope = { id, signature: sig, payload: payloadObj };
@@ -370,8 +445,7 @@ class ScriptDBClient {
370
445
  body.copy(buf, 4);
371
446
  return buf;
372
447
  }
373
- return Buffer.from(envelopeStr + `
374
- `, "utf8");
448
+ return Buffer.from(envelopeStr + "\n", "utf8");
375
449
  }
376
450
  if (this.frame === "length-prefix") {
377
451
  const body = Buffer.from(payloadStr, "utf8");
@@ -380,8 +454,7 @@ class ScriptDBClient {
380
454
  body.copy(buf, 4);
381
455
  return buf;
382
456
  }
383
- return Buffer.from(payloadStr + `
384
- `, "utf8");
457
+ return Buffer.from(payloadStr + "\n", "utf8");
385
458
  }
386
459
  _handleMessage(msg) {
387
460
  console.log("ScriptDBClient _handleMessage:", JSON.stringify(msg));
@@ -395,8 +468,7 @@ class ScriptDBClient {
395
468
  return;
396
469
  }
397
470
  const { resolve, reject, timer } = pending;
398
- if (timer)
399
- clearTimeout(timer);
471
+ if (timer) clearTimeout(timer);
400
472
  this._pending.delete(msg.id);
401
473
  this._processQueue();
402
474
  if (msg.action === "login" || msg.command === "login") {
@@ -412,7 +484,8 @@ class ScriptDBClient {
412
484
  const errorMsg = msg.data || "Authentication failed";
413
485
  try {
414
486
  this.client?.end();
415
- } catch (e) {}
487
+ } catch (e) {
488
+ }
416
489
  return reject(new Error(typeof errorMsg === "string" ? errorMsg : "Authentication failed"));
417
490
  }
418
491
  }
@@ -456,27 +529,22 @@ class ScriptDBClient {
456
529
  }
457
530
  this._pending.set(id, {
458
531
  resolve: (data) => {
459
- if (timer)
460
- clearTimeout(timer);
532
+ if (timer) clearTimeout(timer);
461
533
  this._authenticating = false;
462
- if (data && data.token)
463
- this.token = data.token;
534
+ if (data && data.token) this.token = data.token;
464
535
  resolve(data);
465
536
  },
466
537
  reject: (err) => {
467
- if (timer)
468
- clearTimeout(timer);
538
+ if (timer) clearTimeout(timer);
469
539
  this._authenticating = false;
470
540
  reject(err);
471
541
  },
472
542
  timer
473
543
  });
474
544
  try {
475
- const buf = Buffer.from(JSON.stringify(payload) + `
476
- `, "utf8");
545
+ const buf = Buffer.from(JSON.stringify(payload) + "\n", "utf8");
477
546
  this._write(buf).catch((err) => {
478
- if (timer)
479
- clearTimeout(timer);
547
+ if (timer) clearTimeout(timer);
480
548
  this._pending.delete(id);
481
549
  this._authenticating = false;
482
550
  reject(err);
@@ -498,18 +566,18 @@ class ScriptDBClient {
498
566
  throw err;
499
567
  });
500
568
  }
569
+ // internal write helper that respects backpressure
501
570
  _write(buf) {
502
571
  return new Promise((resolve, reject) => {
503
572
  if (!this.client || !this._connected)
504
573
  return reject(new Error("Not connected"));
505
574
  try {
506
575
  const ok = this.client.write(buf, (err) => {
507
- if (err)
508
- return reject(err);
509
- resolve(undefined);
576
+ if (err) return reject(err);
577
+ resolve(void 0);
510
578
  });
511
579
  if (!ok) {
512
- this.client.once("drain", () => resolve(undefined));
580
+ this.client.once("drain", () => resolve(void 0));
513
581
  }
514
582
  } catch (e) {
515
583
  reject(e);
@@ -526,7 +594,8 @@ class ScriptDBClient {
526
594
  clearTimeout(timer);
527
595
  try {
528
596
  reject(new Error("Token expired and refresh failed"));
529
- } catch (e) {}
597
+ } catch (e) {
598
+ }
530
599
  continue;
531
600
  }
532
601
  }
@@ -537,7 +606,8 @@ class ScriptDBClient {
537
606
  clearTimeout(timer);
538
607
  try {
539
608
  reject(e);
540
- } catch (er) {}
609
+ } catch (er) {
610
+ }
541
611
  continue;
542
612
  }
543
613
  this._pending.set(id, { resolve, reject, timer });
@@ -548,24 +618,29 @@ class ScriptDBClient {
548
618
  this._pending.delete(id);
549
619
  try {
550
620
  reject(e);
551
- } catch (er) {}
621
+ } catch (er) {
622
+ }
552
623
  }
553
624
  }
554
625
  }
626
+ /**
627
+ * Execute a command. Supports concurrent requests via request id mapping.
628
+ * Returns a Promise resolved with response.data or rejected on ERROR/timeout.
629
+ */
555
630
  async execute(payload) {
556
631
  try {
557
632
  await this.ready;
558
633
  } catch (err) {
559
- throw new Error("Not authenticated: " + (err && err.message ? err.message : err));
634
+ throw new Error(
635
+ "Not authenticated: " + (err && err.message ? err.message : err)
636
+ );
560
637
  }
561
- if (!this.token)
562
- throw new Error("Not authenticated");
638
+ if (!this.token) throw new Error("Not authenticated");
563
639
  const id = this._nextId++;
564
640
  const payloadBase = { action: payload.action, data: payload.data };
565
641
  if (this.tokenExpiry && Date.now() >= this.tokenExpiry) {
566
642
  const refreshed = await this._maybeRefreshToken();
567
- if (!refreshed)
568
- throw new Error("Token expired");
643
+ if (!refreshed) throw new Error("Token expired");
569
644
  }
570
645
  return new Promise((resolve, reject) => {
571
646
  let timer = null;
@@ -579,12 +654,12 @@ class ScriptDBClient {
579
654
  }
580
655
  if (this._pending.size >= this._maxPending) {
581
656
  if (this._pendingQueue.length >= this._maxQueue) {
582
- if (timer)
583
- clearTimeout(timer);
657
+ if (timer) clearTimeout(timer);
584
658
  return reject(new Error("Pending queue full"));
585
659
  }
586
660
  this._pendingQueue.push({ payloadBase, id, resolve, reject, timer });
587
- this._processQueue().catch(() => {});
661
+ this._processQueue().catch(() => {
662
+ });
588
663
  return;
589
664
  }
590
665
  let finalBuf;
@@ -596,13 +671,16 @@ class ScriptDBClient {
596
671
  }
597
672
  this._pending.set(id, { resolve, reject, timer });
598
673
  this._write(finalBuf).catch((e) => {
599
- if (timer)
600
- clearTimeout(timer);
674
+ if (timer) clearTimeout(timer);
601
675
  this._pending.delete(id);
602
676
  reject(e);
603
677
  });
604
678
  });
605
679
  }
680
+ /**
681
+ * Attempt to refresh token using provided tokenRefresh option if token expired.
682
+ * options.tokenRefresh should be async function that returns { token, expiresAt }
683
+ */
606
684
  async _maybeRefreshToken() {
607
685
  if (!this.options.tokenRefresh || typeof this.options.tokenRefresh !== "function")
608
686
  return false;
@@ -610,12 +688,14 @@ class ScriptDBClient {
610
688
  const res = await this.options.tokenRefresh();
611
689
  if (res && res.token) {
612
690
  this.token = res.token;
613
- if (res.expiresAt)
614
- this.tokenExpiry = res.expiresAt;
691
+ if (res.expiresAt) this.tokenExpiry = res.expiresAt;
615
692
  return true;
616
693
  }
617
694
  } catch (e) {
618
- this.logger?.error?.("Token refresh failed", e && e.message ? e.message : String(e));
695
+ this.logger?.error?.(
696
+ "Token refresh failed",
697
+ e && e.message ? e.message : String(e)
698
+ );
619
699
  }
620
700
  return false;
621
701
  }
@@ -627,18 +707,18 @@ class ScriptDBClient {
627
707
  }
628
708
  this._rejectReady(new Error("Client destroyed"));
629
709
  this._pending.forEach((pending, id) => {
630
- if (pending.timer)
631
- clearTimeout(pending.timer);
710
+ if (pending.timer) clearTimeout(pending.timer);
632
711
  try {
633
712
  pending.reject(new Error("Client destroyed"));
634
- } catch (e) {}
713
+ } catch (e) {
714
+ }
635
715
  this._pending.delete(id);
636
716
  });
637
717
  this._pendingQueue = [];
638
718
  try {
639
- if (this.client)
640
- this.client.destroy();
641
- } catch (e) {}
719
+ if (this.client) this.client.destroy();
720
+ } catch (e) {
721
+ }
642
722
  this.client = null;
643
723
  }
644
724
  _handleDisconnect(err) {
@@ -647,13 +727,13 @@ class ScriptDBClient {
647
727
  }
648
728
  const wasAuthenticating = this._authenticating;
649
729
  this._pending.forEach((pending, id) => {
650
- if (pending.timer)
651
- clearTimeout(pending.timer);
730
+ if (pending.timer) clearTimeout(pending.timer);
652
731
  const errorMsg = wasAuthenticating ? "Authentication failed - credentials may be required" : err && err.message ? err.message : "Disconnected";
653
732
  process.nextTick(() => {
654
733
  try {
655
734
  pending.reject(new Error(errorMsg));
656
- } catch (e) {}
735
+ } catch (e) {
736
+ }
657
737
  });
658
738
  this._pending.delete(id);
659
739
  });
@@ -664,16 +744,22 @@ class ScriptDBClient {
664
744
  const rejectErr = err || new Error("Authentication failed and no retries configured");
665
745
  try {
666
746
  this._rejectReady(rejectErr);
667
- } catch (e) {}
747
+ } catch (e) {
748
+ }
668
749
  return;
669
750
  }
670
751
  if (this._currentRetries < this.retries) {
671
752
  this._createReady();
672
- const base = Math.min(this.retryDelay * Math.pow(2, this._currentRetries), 30000);
673
- const jitter = Math.floor(Math.random() * Math.min(1000, base));
753
+ const base = Math.min(
754
+ this.retryDelay * Math.pow(2, this._currentRetries),
755
+ 3e4
756
+ );
757
+ const jitter = Math.floor(Math.random() * Math.min(1e3, base));
674
758
  const delay = base + jitter;
675
759
  this._currentRetries += 1;
676
- this.logger?.info?.("Attempting reconnect in " + delay + "ms (attempt " + this._currentRetries + ")");
760
+ this.logger?.info?.(
761
+ "Attempting reconnect in " + delay + "ms (attempt " + this._currentRetries + ")"
762
+ );
677
763
  this.token = null;
678
764
  setTimeout(() => {
679
765
  this.connect().catch((e) => {
@@ -683,62 +769,130 @@ class ScriptDBClient {
683
769
  } else {
684
770
  try {
685
771
  this._rejectReady(err || new Error("Disconnected and no retries left"));
686
- } catch (e) {}
772
+ } catch (e) {
773
+ }
687
774
  }
688
775
  }
689
776
  close() {
690
- if (!this.client)
691
- return;
777
+ if (!this.client) return;
692
778
  try {
693
779
  this.client.removeAllListeners("data");
694
780
  this.client.removeAllListeners("error");
695
781
  this.client.removeAllListeners("close");
696
782
  this.client.end();
697
- } catch (e) {}
783
+ } catch (e) {
784
+ }
698
785
  this.client = null;
699
786
  }
787
+ /**
788
+ * Disconnect (alias for close)
789
+ */
700
790
  disconnect() {
701
791
  this.close();
702
792
  }
793
+ /**
794
+ * Send request helper (for public API methods)
795
+ */
703
796
  async sendRequest(action, data = {}) {
704
797
  return this.execute({ action, data });
705
798
  }
799
+ // ========== Public API Methods ==========
800
+ /**
801
+ * Login with username and password
802
+ */
706
803
  async login(username, password) {
707
804
  return this.sendRequest("login", { username, password });
708
805
  }
806
+ /**
807
+ * Logout from server
808
+ */
709
809
  async logout() {
710
810
  return this.sendRequest("logout", {});
711
811
  }
812
+ /**
813
+ * List all databases
814
+ */
712
815
  async listDatabases() {
713
816
  return this.sendRequest("list-dbs", {});
714
817
  }
818
+ /**
819
+ * Create a new database
820
+ */
715
821
  async createDatabase(name) {
716
822
  return this.sendRequest("create-db", { databaseName: name });
717
823
  }
824
+ /**
825
+ * Remove a database
826
+ */
718
827
  async removeDatabase(name) {
719
828
  return this.sendRequest("remove-db", { databaseName: name });
720
829
  }
830
+ /**
831
+ * Rename a database
832
+ */
721
833
  async renameDatabase(oldName, newName) {
722
834
  return this.sendRequest("rename-db", { databaseName: oldName, newName });
723
835
  }
836
+ /**
837
+ * Execute code in a database
838
+ */
724
839
  async run(code, databaseName) {
725
- return this.sendRequest("script-code", { code, databaseName });
840
+ let stringCode;
841
+ if (typeof code === "function") {
842
+ const funcStr = code.toString();
843
+ const arrowMatch = funcStr.match(/^[\s]*\(?\s*\)?\s*=>\s*{?/);
844
+ const functionMatch = funcStr.match(/^[\s]*function\s*\(?[\w\s]*\)?\s*{/);
845
+ const match = arrowMatch || functionMatch;
846
+ const start = match ? match[0].length : 0;
847
+ const end = funcStr.lastIndexOf("}");
848
+ stringCode = funcStr.substring(start, end);
849
+ stringCode = stringCode.replace(/^[\s\r\n]+/, "").replace(/[\s\r\n]+$/, "");
850
+ stringCode = stringCode.replace(
851
+ /import\s*\(\s*([^)]+?)\s*\)\s*\.from\s*\(\s*(['"])([^'"]+)\2\s*\)/g,
852
+ (_, importArg, quote, modulePath) => {
853
+ const trimmed = importArg.trim();
854
+ if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
855
+ const inner = trimmed.slice(1, -1).trim();
856
+ return `import { ${inner} } from ${quote}${modulePath}${quote}`;
857
+ } else {
858
+ return `import ${trimmed} from ${quote}${modulePath}${quote}`;
859
+ }
860
+ }
861
+ );
862
+ stringCode = stringCode.split("\n").map((line) => line.trim()).join("\n").trim();
863
+ } else {
864
+ stringCode = code;
865
+ }
866
+ return this.sendRequest("script-code", { code: stringCode, databaseName });
726
867
  }
868
+ /**
869
+ * Save a database to disk
870
+ */
727
871
  async saveDatabase(databaseName) {
728
872
  return this.sendRequest("save-db", { databaseName });
729
873
  }
874
+ /**
875
+ * Update database metadata
876
+ */
730
877
  async updateDatabase(databaseName, data) {
731
878
  return this.sendRequest("update-db", { databaseName, ...data });
732
879
  }
880
+ /**
881
+ * Get server information
882
+ */
733
883
  async getInfo() {
734
884
  return this.sendRequest("get-info", {});
735
885
  }
886
+ /**
887
+ * Execute shell command on server
888
+ */
736
889
  async executeShell(command) {
737
890
  return this.sendRequest("shell-command", { command });
738
891
  }
739
- }
740
- var src_default = ScriptDBClient;
741
- export {
742
- src_default as default,
743
- ScriptDBClient
744
892
  };
893
+ var index_default = ScriptDBClient;
894
+ // Annotate the CommonJS export names for ESM import in node:
895
+ 0 && (module.exports = {
896
+ ScriptDBClient
897
+ });
898
+ //# sourceMappingURL=index.js.map