@dbcube/core 5.2.2 → 5.2.3

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,3 +1,10 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
1
8
  // src/lib/Engine.ts
2
9
  import path4 from "path";
3
10
 
@@ -132,7 +139,7 @@ import * as unzipper from "unzipper";
132
139
  import ora from "ora";
133
140
  import chalk from "chalk";
134
141
  import { fileURLToPath } from "url";
135
- import { dirname } from "path";
142
+ import { dirname as dirname2 } from "path";
136
143
  var { https } = followRedirects;
137
144
  var Downloader = class {
138
145
  static mainSpinner = null;
@@ -147,7 +154,7 @@ var Downloader = class {
147
154
  */
148
155
  static async fetchLatestVersion(prefix) {
149
156
  const url = this.VERSION_URLS[prefix];
150
- return new Promise((resolve5, reject) => {
157
+ return new Promise((resolve6, reject) => {
151
158
  https.get(url, (response) => {
152
159
  let data = "";
153
160
  response.on("data", (chunk) => {
@@ -157,7 +164,7 @@ var Downloader = class {
157
164
  try {
158
165
  const versions = JSON.parse(data);
159
166
  if (versions && versions.length > 0) {
160
- resolve5(versions[0].version);
167
+ resolve6(versions[0].version);
161
168
  } else {
162
169
  reject(new Error("No versions found"));
163
170
  }
@@ -366,7 +373,7 @@ var Downloader = class {
366
373
  if (attempt < maxRetries && (errorMessage.includes("ECONNRESET") || errorMessage.includes("timeout") || errorMessage.includes("ETIMEDOUT") || errorMessage.includes("ENOTFOUND"))) {
367
374
  attempt++;
368
375
  console.log(`\u{1F504} Retrying ${binary.prefix}-engine (${attempt}/${maxRetries})...`);
369
- await new Promise((resolve5) => setTimeout(resolve5, 1e3 + Math.random() * 1e3));
376
+ await new Promise((resolve6) => setTimeout(resolve6, 1e3 + Math.random() * 1e3));
370
377
  } else {
371
378
  throw new Error(`Error downloading ${binary.prefix}: ${errorMessage}`);
372
379
  }
@@ -414,12 +421,12 @@ var Downloader = class {
414
421
  return `[${filledBar}${emptyBar}] ${percentage}`;
415
422
  }
416
423
  static downloadFileWithProgress(url, outputPath, prefix) {
417
- return new Promise((resolve5, reject) => {
424
+ return new Promise((resolve6, reject) => {
418
425
  const request = https.get(url, { timeout: 0 }, (response) => {
419
426
  if (response.statusCode === 302 || response.statusCode === 301) {
420
427
  const redirectUrl = response.headers.location;
421
428
  if (redirectUrl) {
422
- return this.downloadFileWithProgress(redirectUrl, outputPath, prefix).then(resolve5).catch(reject);
429
+ return this.downloadFileWithProgress(redirectUrl, outputPath, prefix).then(resolve6).catch(reject);
423
430
  }
424
431
  }
425
432
  if (response.statusCode !== 200) {
@@ -442,7 +449,7 @@ var Downloader = class {
442
449
  }
443
450
  });
444
451
  response.on("end", () => {
445
- file.end(() => resolve5());
452
+ file.end(() => resolve6());
446
453
  });
447
454
  response.on("error", (err) => {
448
455
  file.close();
@@ -474,35 +481,47 @@ var Downloader = class {
474
481
  this.mainSpinner.text = `\u{1F4E5} ${chalk.bold(binary)} - ${progressText}`;
475
482
  }
476
483
  static extractBinary(zipPath, outputPath, prefix) {
477
- return new Promise((resolve5, reject) => {
478
- let extracted = false;
484
+ return new Promise((resolve6, reject) => {
485
+ const outDir = path.dirname(outputPath);
486
+ let extracted = 0;
487
+ const pending = [];
479
488
  fs.createReadStream(zipPath).pipe(unzipper.Parse()).on("entry", (entry) => {
480
- if (entry.type === "File" && !extracted) {
481
- extracted = true;
482
- const writeStream = fs.createWriteStream(outputPath);
489
+ if (entry.type !== "File") {
490
+ entry.autodrain();
491
+ return;
492
+ }
493
+ const isMain = extracted === 0;
494
+ extracted++;
495
+ const target = isMain ? outputPath : path.join(outDir, path.basename(entry.path));
496
+ pending.push(new Promise((res, rej) => {
497
+ const writeStream = fs.createWriteStream(target);
483
498
  entry.pipe(writeStream);
484
499
  writeStream.on("finish", () => {
485
500
  if (process.platform !== "win32") {
486
- fs.chmodSync(outputPath, 493);
501
+ try {
502
+ fs.chmodSync(target, 493);
503
+ } catch {
504
+ }
487
505
  }
488
- this.cleanupFile(zipPath);
489
- resolve5();
506
+ res();
490
507
  });
491
- writeStream.on("error", (err) => {
492
- this.cleanupFile(zipPath);
493
- reject(err);
494
- });
495
- } else {
496
- entry.autodrain();
497
- }
508
+ writeStream.on("error", rej);
509
+ }));
498
510
  }).on("error", (err) => {
499
511
  this.cleanupFile(zipPath);
500
512
  reject(err);
501
513
  }).on("close", () => {
502
- if (!extracted) {
514
+ Promise.all(pending).then(() => {
503
515
  this.cleanupFile(zipPath);
504
- reject(new Error(`No se encontr\xF3 archivo v\xE1lido en el ZIP para ${prefix}`));
505
- }
516
+ if (extracted === 0) {
517
+ reject(new Error(`No se encontr\xF3 archivo v\xE1lido en el ZIP para ${prefix}`));
518
+ } else {
519
+ resolve6();
520
+ }
521
+ }).catch((err) => {
522
+ this.cleanupFile(zipPath);
523
+ reject(err);
524
+ });
506
525
  });
507
526
  });
508
527
  }
@@ -516,7 +535,7 @@ var Downloader = class {
516
535
  }
517
536
  static getDefaultBinDir() {
518
537
  const __filename2 = typeof import.meta !== "undefined" && import.meta.url ? fileURLToPath(import.meta.url) : "";
519
- const __dirname = __filename2 ? dirname(__filename2) : process.cwd();
538
+ const __dirname = __filename2 ? dirname2(__filename2) : process.cwd();
520
539
  const possibleDirs = [
521
540
  path.resolve(process.cwd(), ".dbcube", "bin"),
522
541
  path.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
@@ -546,7 +565,7 @@ import * as fs2 from "fs";
546
565
  import * as path2 from "path";
547
566
  import * as os3 from "os";
548
567
  import { fileURLToPath as fileURLToPath2 } from "url";
549
- import { dirname as dirname2 } from "path";
568
+ import { dirname as dirname3 } from "path";
550
569
  var Binary = class {
551
570
  static isDownloading = false;
552
571
  static downloadPromise = null;
@@ -579,7 +598,7 @@ var Binary = class {
579
598
  }
580
599
  static getBinDir() {
581
600
  const __filename2 = typeof import.meta !== "undefined" && import.meta.url ? fileURLToPath2(import.meta.url) : "";
582
- const __dirname = __filename2 ? dirname2(__filename2) : process.cwd();
601
+ const __dirname = __filename2 ? dirname3(__filename2) : process.cwd();
583
602
  const possibleDirs = [
584
603
  path2.resolve(process.cwd(), ".dbcube", "bin"),
585
604
  path2.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
@@ -816,22 +835,22 @@ var DaemonClient = class _DaemonClient {
816
835
  child.unref();
817
836
  }
818
837
  tryConnect(port) {
819
- return new Promise((resolve5) => {
838
+ return new Promise((resolve6) => {
820
839
  const socket = net.createConnection({ host: "127.0.0.1", port }, async () => {
821
840
  socket.setNoDelay(true);
822
841
  this.attach(socket);
823
842
  try {
824
843
  const pong = await this.send({ action: "ping" }, 2e3);
825
- resolve5(pong.status === 200);
844
+ resolve6(pong.status === 200);
826
845
  } catch {
827
846
  this.detach();
828
- resolve5(false);
847
+ resolve6(false);
829
848
  }
830
849
  });
831
- socket.once("error", () => resolve5(false));
850
+ socket.once("error", () => resolve6(false));
832
851
  socket.setTimeout(3e3, () => {
833
852
  socket.destroy();
834
- resolve5(false);
853
+ resolve6(false);
835
854
  });
836
855
  });
837
856
  }
@@ -879,7 +898,7 @@ var DaemonClient = class _DaemonClient {
879
898
  * single socket, so pending requests resolve in send order.
880
899
  */
881
900
  send(payload, timeoutMs) {
882
- return new Promise((resolve5, reject) => {
901
+ return new Promise((resolve6, reject) => {
883
902
  if (!this.socket || this.socket.destroyed) {
884
903
  reject(new Error("Daemon not connected"));
885
904
  return;
@@ -890,12 +909,12 @@ var DaemonClient = class _DaemonClient {
890
909
  reject(new Error("Daemon request timeout"));
891
910
  this.detach();
892
911
  }, timeoutMs ?? this.requestTimeout);
893
- this.pending.push({ resolve: resolve5, reject, timer });
912
+ this.pending.push({ resolve: resolve6, reject, timer });
894
913
  this.socket.write(JSON.stringify(payload) + "\n");
895
914
  });
896
915
  }
897
916
  async execute(dml, txId) {
898
- const payload = { action: "execute", dml: JSON.stringify(dml) };
917
+ const payload = { action: "execute", dml };
899
918
  if (txId) payload.tx_id = txId;
900
919
  return this.send(payload);
901
920
  }
@@ -962,8 +981,8 @@ var Engine = class {
962
981
  const binaryPath = this.binary["query_engine"];
963
982
  if (!binaryPath) return null;
964
983
  const client = DaemonClient.get(this.name, binaryPath, this.arguments);
965
- const ok = await client.ensure();
966
- if (!ok) {
984
+ const ok2 = await client.ensure();
985
+ if (!ok2) {
967
986
  this.daemonFailed = true;
968
987
  return null;
969
988
  }
@@ -1094,7 +1113,7 @@ var Engine = class {
1094
1113
  if (!this.binary) {
1095
1114
  throw new Error("Binary not initialized");
1096
1115
  }
1097
- return new Promise((resolve5, reject) => {
1116
+ return new Promise((resolve6, reject) => {
1098
1117
  const child = spawn2(this.binary[binary], [...this.arguments, ...args]);
1099
1118
  let stdoutBuffer = "";
1100
1119
  let stderrBuffer = "";
@@ -1110,7 +1129,7 @@ var Engine = class {
1110
1129
  if (!isResolved) {
1111
1130
  isResolved = true;
1112
1131
  clearTimeout(timeoutId);
1113
- resolve5(response);
1132
+ resolve6(response);
1114
1133
  }
1115
1134
  };
1116
1135
  const tryParseLines = (buffer) => {
@@ -1175,14 +1194,265 @@ var Engine = class {
1175
1194
  };
1176
1195
 
1177
1196
  // src/lib/QueryEngine.ts
1178
- import path5 from "path";
1197
+ import path6 from "path";
1198
+
1199
+ // src/lib/EmbeddedEngine.ts
1200
+ import * as fs4 from "fs";
1201
+ import * as path5 from "path";
1202
+ if (!process.env.UV_THREADPOOL_SIZE) {
1203
+ process.env.UV_THREADPOOL_SIZE = "16";
1204
+ }
1205
+ var backend = null;
1206
+ var loadFailed = false;
1207
+ var handles = /* @__PURE__ */ new Map();
1208
+ var connecting = /* @__PURE__ */ new Map();
1209
+ function platTag() {
1210
+ const arch2 = process.arch === "arm64" ? "arm64" : "x64";
1211
+ if (process.platform === "win32") return { plat: "windows", ext: "dll", arch: arch2 };
1212
+ if (process.platform === "darwin") return { plat: "macos", ext: "dylib", arch: arch2 };
1213
+ return { plat: "linux", ext: "so", arch: arch2 };
1214
+ }
1215
+ function findFile(name) {
1216
+ const candidates = [
1217
+ path5.resolve(process.cwd(), ".dbcube", "bin", name),
1218
+ path5.resolve(process.cwd(), "node_modules", ".dbcube", "bin", name)
1219
+ ];
1220
+ for (const c of candidates) {
1221
+ if (fs4.existsSync(c)) return c;
1222
+ }
1223
+ return null;
1224
+ }
1225
+ function ok(data) {
1226
+ return { status: 200, message: "OK", data };
1227
+ }
1228
+ function errResp(e) {
1229
+ const msg = e instanceof Error ? e.message : String(e);
1230
+ return { status: 500, message: msg, data: null };
1231
+ }
1232
+ function loadNapiBackend() {
1233
+ const { plat, arch: arch2 } = platTag();
1234
+ const addonPath = findFile(`query-engine-node-${plat}-${arch2}.node`);
1235
+ if (!addonPath) return null;
1236
+ try {
1237
+ const addon = __require(addonPath);
1238
+ if (typeof addon.connect !== "function") return null;
1239
+ return {
1240
+ async connect(cfgJson) {
1241
+ return Number(await addon.connect(cfgJson));
1242
+ },
1243
+ async execute(handle, dml, txId) {
1244
+ try {
1245
+ const rows = await addon.execute(handle, dml, txId ?? void 0);
1246
+ return ok(rows);
1247
+ } catch (e) {
1248
+ return errResp(e);
1249
+ }
1250
+ },
1251
+ async executeBatch(handle, ops) {
1252
+ try {
1253
+ const results = await addon.executeBatch(handle, ops);
1254
+ return ok(results);
1255
+ } catch (e) {
1256
+ return errResp(e);
1257
+ }
1258
+ },
1259
+ async raw(handle, query, params, txId) {
1260
+ try {
1261
+ const rows = await addon.raw(handle, query, params, txId ?? void 0);
1262
+ return ok(rows);
1263
+ } catch (e) {
1264
+ return errResp(e);
1265
+ }
1266
+ },
1267
+ async begin(handle) {
1268
+ try {
1269
+ const txId = await addon.begin(handle);
1270
+ return ok({ tx_id: txId });
1271
+ } catch (e) {
1272
+ return errResp(e);
1273
+ }
1274
+ },
1275
+ async commit(_handle, txId) {
1276
+ try {
1277
+ await addon.commit(txId);
1278
+ return ok(null);
1279
+ } catch (e) {
1280
+ return errResp(e);
1281
+ }
1282
+ },
1283
+ async rollback(_handle, txId) {
1284
+ try {
1285
+ await addon.rollback(txId);
1286
+ return ok(null);
1287
+ } catch (e) {
1288
+ return errResp(e);
1289
+ }
1290
+ },
1291
+ async disconnect(handle) {
1292
+ try {
1293
+ addon.disconnect(handle);
1294
+ } catch {
1295
+ }
1296
+ }
1297
+ };
1298
+ } catch {
1299
+ return null;
1300
+ }
1301
+ }
1302
+ function loadKoffiBackend() {
1303
+ const { plat, ext, arch: arch2 } = platTag();
1304
+ const libPath = findFile(`query-engine-embedded-${plat}-${arch2}.${ext}`);
1305
+ if (!libPath) return null;
1306
+ try {
1307
+ const koffi = __require("koffi");
1308
+ const lib = koffi.load(libPath);
1309
+ const cConnect = lib.func("dbc_connect", "void *", ["str"]);
1310
+ const cExecute = lib.func("dbc_execute", "void *", ["uint64", "str", "str"]);
1311
+ const cExecuteBatch = lib.func("dbc_execute_batch", "void *", ["uint64", "str"]);
1312
+ const cRaw = lib.func("dbc_raw", "void *", ["uint64", "str", "str", "str"]);
1313
+ const cBegin = lib.func("dbc_begin", "void *", ["uint64"]);
1314
+ const cCommit = lib.func("dbc_commit", "void *", ["uint64", "str"]);
1315
+ const cRollback = lib.func("dbc_rollback", "void *", ["uint64", "str"]);
1316
+ const cDisconnect = lib.func("dbc_disconnect", "void *", ["uint64"]);
1317
+ const cFree = lib.func("dbc_free", "void", ["void *"]);
1318
+ const take = (ptr) => {
1319
+ if (!ptr) return { status: 500, message: "embedded engine returned null", data: null };
1320
+ const s = koffi.decode(ptr, "char", -1);
1321
+ cFree(ptr);
1322
+ try {
1323
+ const r = JSON.parse(s);
1324
+ return { status: r.status ?? 500, message: r.message ?? "", data: r.data ?? null };
1325
+ } catch (e) {
1326
+ return { status: 500, message: `Invalid embedded response: ${e.message}`, data: null };
1327
+ }
1328
+ };
1329
+ const call = (fn, ...args) => new Promise((resolve6, reject) => {
1330
+ fn.async(...args, (err, ptr) => {
1331
+ if (err) return reject(err);
1332
+ resolve6(take(ptr));
1333
+ });
1334
+ });
1335
+ return {
1336
+ async connect(cfgJson) {
1337
+ const res = await call(cConnect, cfgJson);
1338
+ if (res.status !== 200 || !res.data?.handle) {
1339
+ throw new Error(String(res.message || "embedded connect failed"));
1340
+ }
1341
+ return Number(res.data.handle);
1342
+ },
1343
+ execute: (handle, dml, txId) => call(cExecute, handle, JSON.stringify(dml), txId),
1344
+ executeBatch: (handle, ops) => call(cExecuteBatch, handle, JSON.stringify(ops)),
1345
+ raw: (handle, query, params, txId) => call(cRaw, handle, query, JSON.stringify(params ?? []), txId),
1346
+ begin: (handle) => call(cBegin, handle),
1347
+ commit: (handle, txId) => call(cCommit, handle, txId),
1348
+ rollback: (handle, txId) => call(cRollback, handle, txId),
1349
+ async disconnect(handle) {
1350
+ try {
1351
+ await call(cDisconnect, handle);
1352
+ } catch {
1353
+ }
1354
+ }
1355
+ };
1356
+ } catch {
1357
+ return null;
1358
+ }
1359
+ }
1360
+ function loadBackend() {
1361
+ if (backend) return backend;
1362
+ if (loadFailed) return null;
1363
+ if (process.env.DBCUBE_EMBEDDED === "0" || process.env.DBCUBE_EMBEDDED === "false") {
1364
+ loadFailed = true;
1365
+ return null;
1366
+ }
1367
+ backend = loadNapiBackend() ?? loadKoffiBackend();
1368
+ if (!backend) loadFailed = true;
1369
+ return backend;
1370
+ }
1371
+ var EmbeddedEngine = class {
1372
+ /** true si algún backend nativo está disponible en esta instalación. */
1373
+ static available() {
1374
+ return loadBackend() !== null;
1375
+ }
1376
+ static async handleFor(connectionId, config) {
1377
+ const existing = handles.get(connectionId);
1378
+ if (existing) return existing;
1379
+ const inFlight = connecting.get(connectionId);
1380
+ if (inFlight) return inFlight;
1381
+ const promise = (async () => {
1382
+ const be = loadBackend();
1383
+ if (!be) throw new Error("embedded engine not available");
1384
+ const motor = config.type === "postgres" ? "postgresql" : config.type;
1385
+ const cfg = {
1386
+ databaseRef: connectionId,
1387
+ motor,
1388
+ database: config.type === "sqlite" ? `${config.config.DATABASE}.db` : config.config.DATABASE,
1389
+ host: config.config.HOST,
1390
+ port: config.config.PORT != null ? Number(config.config.PORT) : void 0,
1391
+ user: config.config.USER,
1392
+ password: config.config.PASSWORD,
1393
+ maxConnections: config.pool?.maxConnections,
1394
+ minConnections: config.pool?.minConnections,
1395
+ acquireTimeoutMs: config.pool?.acquireTimeoutMs,
1396
+ idleTimeoutMs: config.pool?.idleTimeoutMs
1397
+ };
1398
+ const handle = await be.connect(JSON.stringify(cfg));
1399
+ handles.set(connectionId, handle);
1400
+ return handle;
1401
+ })();
1402
+ connecting.set(connectionId, promise);
1403
+ try {
1404
+ return await promise;
1405
+ } finally {
1406
+ connecting.delete(connectionId);
1407
+ }
1408
+ }
1409
+ static async executeDml(connectionId, config, dml, txId) {
1410
+ const be = loadBackend();
1411
+ const handle = await this.handleFor(connectionId, config);
1412
+ return be.execute(handle, dml, txId ?? null);
1413
+ }
1414
+ static async executeBatch(connectionId, config, ops) {
1415
+ const be = loadBackend();
1416
+ const handle = await this.handleFor(connectionId, config);
1417
+ return be.executeBatch(handle, ops);
1418
+ }
1419
+ static async rawQuery(connectionId, config, query, params, txId) {
1420
+ const be = loadBackend();
1421
+ const handle = await this.handleFor(connectionId, config);
1422
+ return be.raw(handle, query, params ?? [], txId ?? null);
1423
+ }
1424
+ static async begin(connectionId, config) {
1425
+ const be = loadBackend();
1426
+ const handle = await this.handleFor(connectionId, config);
1427
+ return be.begin(handle);
1428
+ }
1429
+ static async commit(connectionId, config, txId) {
1430
+ const be = loadBackend();
1431
+ const handle = await this.handleFor(connectionId, config);
1432
+ return be.commit(handle, txId);
1433
+ }
1434
+ static async rollback(connectionId, config, txId) {
1435
+ const be = loadBackend();
1436
+ const handle = await this.handleFor(connectionId, config);
1437
+ return be.rollback(handle, txId);
1438
+ }
1439
+ static async disconnect(connectionId) {
1440
+ const be = loadBackend();
1441
+ const handle = handles.get(connectionId);
1442
+ if (be && handle) {
1443
+ handles.delete(connectionId);
1444
+ await be.disconnect(handle);
1445
+ }
1446
+ }
1447
+ };
1448
+
1449
+ // src/lib/QueryEngine.ts
1179
1450
  import { createRequire as createRequire2 } from "module";
1180
1451
  import * as net2 from "net";
1181
1452
  import { spawn as spawn3 } from "child_process";
1182
1453
  var globalTcpServers = /* @__PURE__ */ new Map();
1183
- var globalTcpConnections = /* @__PURE__ */ new Map();
1184
- var connectionQueues = /* @__PURE__ */ new Map();
1185
- var connectionProcessing = /* @__PURE__ */ new Map();
1454
+ var socketPools = /* @__PURE__ */ new Map();
1455
+ var CLIENT_POOL_SIZE = 10;
1186
1456
  var queryCache = /* @__PURE__ */ new Map();
1187
1457
  var MAX_CACHE_SIZE = 500;
1188
1458
  var QueryEngine = class {
@@ -1213,12 +1483,12 @@ var QueryEngine = class {
1213
1483
  throw new Error("No available ports found in range 9900-9944");
1214
1484
  }
1215
1485
  isPortAvailable(port) {
1216
- return new Promise((resolve5) => {
1486
+ return new Promise((resolve6) => {
1217
1487
  const tester = net2.createServer();
1218
- tester.once("error", () => resolve5(false));
1488
+ tester.once("error", () => resolve6(false));
1219
1489
  tester.once("listening", () => {
1220
1490
  tester.close();
1221
- resolve5(true);
1491
+ resolve6(true);
1222
1492
  });
1223
1493
  tester.listen(port, "127.0.0.1");
1224
1494
  });
@@ -1279,7 +1549,7 @@ var QueryEngine = class {
1279
1549
  setConfig(name) {
1280
1550
  const configInstance = new Config();
1281
1551
  try {
1282
- const configFilePath = path5.resolve(process.cwd(), "dbcube.config.js");
1552
+ const configFilePath = path6.resolve(process.cwd(), "dbcube.config.js");
1283
1553
  const requireUrl = typeof __filename !== "undefined" ? __filename : process.cwd();
1284
1554
  const require2 = createRequire2(requireUrl);
1285
1555
  if (require2.cache && require2.resolve) {
@@ -1325,38 +1595,79 @@ var QueryEngine = class {
1325
1595
  }
1326
1596
  return command;
1327
1597
  }
1598
+ /** El motor embebido (FFI) es el camino por defecto cuando la librería
1599
+ * nativa está disponible; el daemon TCP queda como fallback y como modo
1600
+ * multi-proceso explícito. */
1601
+ useEmbedded() {
1602
+ return EmbeddedEngine.available();
1603
+ }
1328
1604
  /**
1329
- * Executes a DML plan over the persistent TCP server.
1605
+ * Executes a DML plan. Embedded engine when available (in-process FFI,
1606
+ * no network hop); persistent TCP daemon otherwise.
1330
1607
  * Pass txId to run it inside an active transaction.
1331
1608
  */
1332
1609
  async executeDml(dml, txId) {
1333
- const command = { action: "execute", dml: JSON.stringify(dml) };
1610
+ if (this.useEmbedded()) {
1611
+ return EmbeddedEngine.executeDml(this.connectionId, this.config, dml, txId);
1612
+ }
1613
+ const command = { action: "execute", dml };
1334
1614
  if (txId) command.tx_id = txId;
1335
1615
  return this.executeWithTcpServer(command);
1336
1616
  }
1337
1617
  /**
1338
- * Executes raw SQL (or a MongoDB command document) with bound parameters
1339
- * over the persistent TCP server.
1618
+ * Atomic batch: N write plans inside one transaction with a single
1619
+ * engine round-trip. Falls back to begin/ops/commit over the daemon
1620
+ * when the embedded engine is not available.
1621
+ */
1622
+ async executeBatch(ops) {
1623
+ if (this.useEmbedded()) {
1624
+ return EmbeddedEngine.executeBatch(this.connectionId, this.config, ops);
1625
+ }
1626
+ const txId = await this.beginTransaction();
1627
+ try {
1628
+ const results = [];
1629
+ for (const op of ops) {
1630
+ const res = await this.executeDml(op, txId);
1631
+ if (res.status !== 200) {
1632
+ throw new Error(String(res.message));
1633
+ }
1634
+ results.push(res.data);
1635
+ }
1636
+ await this.commitTransaction(txId);
1637
+ return { status: 200, message: "Batch committed", data: results };
1638
+ } catch (error) {
1639
+ try {
1640
+ await this.rollbackTransaction(txId);
1641
+ } catch {
1642
+ }
1643
+ return { status: 500, message: error?.message ?? String(error), data: null };
1644
+ }
1645
+ }
1646
+ /**
1647
+ * Executes raw SQL (or a MongoDB command document) with bound parameters.
1340
1648
  */
1341
1649
  async rawQuery(query, params = [], txId) {
1650
+ if (this.useEmbedded()) {
1651
+ return EmbeddedEngine.rawQuery(this.connectionId, this.config, query, params, txId);
1652
+ }
1342
1653
  const command = { action: "raw", query, params };
1343
1654
  if (txId) command.tx_id = txId;
1344
1655
  return this.executeWithTcpServer(command);
1345
1656
  }
1346
- /** Starts a server-side transaction and returns its id. */
1657
+ /** Starts a transaction and returns its id. */
1347
1658
  async beginTransaction() {
1348
- const res = await this.executeWithTcpServer({ action: "begin" });
1659
+ const res = this.useEmbedded() ? await EmbeddedEngine.begin(this.connectionId, this.config) : await this.executeWithTcpServer({ action: "begin" });
1349
1660
  if (res.status !== 200 || !res.data?.tx_id) {
1350
1661
  throw new Error(String(res.message || "Failed to begin transaction (update the query-engine binary: npx dbcube update)"));
1351
1662
  }
1352
1663
  return res.data.tx_id;
1353
1664
  }
1354
1665
  async commitTransaction(txId) {
1355
- const res = await this.executeWithTcpServer({ action: "commit", tx_id: txId });
1666
+ const res = this.useEmbedded() ? await EmbeddedEngine.commit(this.connectionId, this.config, txId) : await this.executeWithTcpServer({ action: "commit", tx_id: txId });
1356
1667
  if (res.status !== 200) throw new Error(String(res.message || "Failed to commit transaction"));
1357
1668
  }
1358
1669
  async rollbackTransaction(txId) {
1359
- const res = await this.executeWithTcpServer({ action: "rollback", tx_id: txId });
1670
+ const res = this.useEmbedded() ? await EmbeddedEngine.rollback(this.connectionId, this.config, txId) : await this.executeWithTcpServer({ action: "rollback", tx_id: txId });
1360
1671
  if (res.status !== 200) throw new Error(String(res.message || "Failed to rollback transaction"));
1361
1672
  }
1362
1673
  async executeWithTcpServer(command) {
@@ -1375,7 +1686,63 @@ var QueryEngine = class {
1375
1686
  await this.startTcpServer();
1376
1687
  await this.waitForServerReady();
1377
1688
  }
1378
- return this.sendTcpRequestFast(command);
1689
+ const port = globalTcpServers.get(this.connectionId).port;
1690
+ const socket = await this.acquireSocket(port);
1691
+ try {
1692
+ const result = await this.executeOnConnection(socket, command);
1693
+ this.releaseSocket(socket, false);
1694
+ return result;
1695
+ } catch (error) {
1696
+ this.releaseSocket(socket, true);
1697
+ throw error;
1698
+ }
1699
+ }
1700
+ poolFor() {
1701
+ let pool = socketPools.get(this.connectionId);
1702
+ if (!pool) {
1703
+ pool = { free: [], total: 0, waiters: [] };
1704
+ socketPools.set(this.connectionId, pool);
1705
+ }
1706
+ return pool;
1707
+ }
1708
+ async acquireSocket(port) {
1709
+ const pool = this.poolFor();
1710
+ while (pool.free.length > 0) {
1711
+ const s = pool.free.pop();
1712
+ if (!s.destroyed) return s;
1713
+ pool.total--;
1714
+ }
1715
+ if (pool.total < CLIENT_POOL_SIZE) {
1716
+ pool.total++;
1717
+ try {
1718
+ return await this.createNewConnection(port);
1719
+ } catch (e) {
1720
+ pool.total--;
1721
+ throw e;
1722
+ }
1723
+ }
1724
+ return new Promise((resolve6) => pool.waiters.push(resolve6));
1725
+ }
1726
+ releaseSocket(socket, broken) {
1727
+ const pool = socketPools.get(this.connectionId);
1728
+ if (!pool) {
1729
+ socket.destroy();
1730
+ return;
1731
+ }
1732
+ if (broken || socket.destroyed) {
1733
+ pool.total--;
1734
+ try {
1735
+ socket.destroy();
1736
+ } catch {
1737
+ }
1738
+ return;
1739
+ }
1740
+ const waiter = pool.waiters.shift();
1741
+ if (waiter) {
1742
+ waiter(socket);
1743
+ } else {
1744
+ pool.free.push(socket);
1745
+ }
1379
1746
  }
1380
1747
  async waitForServerReady() {
1381
1748
  const maxRetries = 10;
@@ -1393,25 +1760,25 @@ var QueryEngine = class {
1393
1760
  throw new Error("TCP server failed to become ready within timeout");
1394
1761
  }
1395
1762
  async isServerResponding(port) {
1396
- return new Promise((resolve5) => {
1763
+ return new Promise((resolve6) => {
1397
1764
  const client = new net2.Socket();
1398
1765
  const timeout = setTimeout(() => {
1399
1766
  client.destroy();
1400
- resolve5(false);
1767
+ resolve6(false);
1401
1768
  }, 1e3);
1402
1769
  client.connect(port, "127.0.0.1", () => {
1403
1770
  clearTimeout(timeout);
1404
1771
  client.destroy();
1405
- resolve5(true);
1772
+ resolve6(true);
1406
1773
  });
1407
1774
  client.on("error", () => {
1408
1775
  clearTimeout(timeout);
1409
- resolve5(false);
1776
+ resolve6(false);
1410
1777
  });
1411
1778
  });
1412
1779
  }
1413
1780
  sleep(ms) {
1414
- return new Promise((resolve5) => setTimeout(resolve5, ms));
1781
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
1415
1782
  }
1416
1783
  getCachedDML(dmlJson) {
1417
1784
  if (queryCache.has(dmlJson)) {
@@ -1431,7 +1798,7 @@ var QueryEngine = class {
1431
1798
  throw new Error("Binary not initialized");
1432
1799
  }
1433
1800
  this.tcpPort = await this.findAvailablePort(this.tcpPort);
1434
- return new Promise((resolve5, reject) => {
1801
+ return new Promise((resolve6, reject) => {
1435
1802
  const serverArgs = [...this.arguments, "--action", "server", "--tcp-port", this.tcpPort.toString()];
1436
1803
  const serverProcess = spawn3(this.binary["query_engine"], serverArgs);
1437
1804
  let started = false;
@@ -1451,7 +1818,7 @@ var QueryEngine = class {
1451
1818
  port: this.tcpPort,
1452
1819
  process: serverProcess
1453
1820
  });
1454
- resolve5();
1821
+ resolve6();
1455
1822
  }
1456
1823
  }
1457
1824
  });
@@ -1469,60 +1836,8 @@ var QueryEngine = class {
1469
1836
  });
1470
1837
  });
1471
1838
  }
1472
- async sendTcpRequestFast(command) {
1473
- return new Promise((resolve5, reject) => {
1474
- let queue = connectionQueues.get(this.connectionId);
1475
- if (!queue) {
1476
- queue = [];
1477
- connectionQueues.set(this.connectionId, queue);
1478
- }
1479
- queue.push({ command, resolve: resolve5, reject });
1480
- this.processQueue();
1481
- });
1482
- }
1483
- async processQueue() {
1484
- if (connectionProcessing.get(this.connectionId)) {
1485
- return;
1486
- }
1487
- const queue = connectionQueues.get(this.connectionId);
1488
- if (!queue || queue.length === 0) {
1489
- return;
1490
- }
1491
- connectionProcessing.set(this.connectionId, true);
1492
- try {
1493
- const serverInfo = globalTcpServers.get(this.connectionId);
1494
- if (!serverInfo) {
1495
- throw new Error("Server not initialized");
1496
- }
1497
- while (queue.length > 0) {
1498
- const request = queue.shift();
1499
- if (!request) break;
1500
- try {
1501
- let connection = globalTcpConnections.get(this.connectionId);
1502
- if (!connection || connection.destroyed || connection.readyState !== "open") {
1503
- connection = await this.createNewConnection(serverInfo.port);
1504
- globalTcpConnections.set(this.connectionId, connection);
1505
- }
1506
- const result = await this.executeOnConnection(connection, request.command);
1507
- request.resolve(result);
1508
- } catch (error) {
1509
- const staleConnection = globalTcpConnections.get(this.connectionId);
1510
- if (staleConnection) {
1511
- try {
1512
- staleConnection.destroy();
1513
- } catch {
1514
- }
1515
- }
1516
- globalTcpConnections.delete(this.connectionId);
1517
- request.reject(error);
1518
- }
1519
- }
1520
- } finally {
1521
- connectionProcessing.set(this.connectionId, false);
1522
- }
1523
- }
1524
1839
  async createNewConnection(port) {
1525
- return new Promise((resolve5, reject) => {
1840
+ return new Promise((resolve6, reject) => {
1526
1841
  const client = new net2.Socket();
1527
1842
  client.setNoDelay(true);
1528
1843
  client.setKeepAlive(true, 6e4);
@@ -1532,7 +1847,7 @@ var QueryEngine = class {
1532
1847
  }, 5e3);
1533
1848
  client.connect(port, "127.0.0.1", () => {
1534
1849
  clearTimeout(timeout);
1535
- resolve5(client);
1850
+ resolve6(client);
1536
1851
  });
1537
1852
  client.on("error", (error) => {
1538
1853
  clearTimeout(timeout);
@@ -1541,7 +1856,7 @@ var QueryEngine = class {
1541
1856
  });
1542
1857
  }
1543
1858
  async executeOnConnection(connection, command) {
1544
- return new Promise((resolve5, reject) => {
1859
+ return new Promise((resolve6, reject) => {
1545
1860
  let responseBuffer = "";
1546
1861
  let isResolved = false;
1547
1862
  const timeout = setTimeout(() => {
@@ -1566,7 +1881,7 @@ var QueryEngine = class {
1566
1881
  connection.removeListener("error", onError);
1567
1882
  try {
1568
1883
  const response = JSON.parse(line.slice(marker + "PROCESS_RESPONSE:".length));
1569
- resolve5({
1884
+ resolve6({
1570
1885
  status: response.status,
1571
1886
  message: response.message,
1572
1887
  data: response.data
@@ -1595,7 +1910,7 @@ var QueryEngine = class {
1595
1910
  if (!this.binary) {
1596
1911
  throw new Error("Binary not initialized");
1597
1912
  }
1598
- return new Promise((resolve5, reject) => {
1913
+ return new Promise((resolve6, reject) => {
1599
1914
  const child = spawn3(this.binary[binary], [...this.arguments, ...args]);
1600
1915
  let stdoutBuffer = "";
1601
1916
  let stderrBuffer = "";
@@ -1611,7 +1926,7 @@ var QueryEngine = class {
1611
1926
  if (!isResolved) {
1612
1927
  isResolved = true;
1613
1928
  clearTimeout(timeoutId);
1614
- resolve5(response);
1929
+ resolve6(response);
1615
1930
  }
1616
1931
  };
1617
1932
  const tryParseLines = (buffer) => {
@@ -1668,11 +1983,16 @@ var QueryEngine = class {
1668
1983
  });
1669
1984
  }
1670
1985
  async disconnect() {
1671
- const connection = globalTcpConnections.get(this.connectionId);
1672
- if (connection && connection.readyState === "open") {
1673
- connection.write(JSON.stringify({ action: "disconnect" }));
1674
- connection.destroy();
1675
- globalTcpConnections.delete(this.connectionId);
1986
+ await EmbeddedEngine.disconnect(this.connectionId);
1987
+ const pool = socketPools.get(this.connectionId);
1988
+ if (pool) {
1989
+ for (const s of pool.free) {
1990
+ try {
1991
+ s.destroy();
1992
+ } catch {
1993
+ }
1994
+ }
1995
+ socketPools.delete(this.connectionId);
1676
1996
  }
1677
1997
  const serverInfo = globalTcpServers.get(this.connectionId);
1678
1998
  if (serverInfo && serverInfo.process && !serverInfo.process.killed) {
@@ -1694,12 +2014,12 @@ var QueryEngine = class {
1694
2014
 
1695
2015
  // src/lib/SqliteExecutor.ts
1696
2016
  import { exec } from "child_process";
1697
- import * as path6 from "path";
1698
- import * as fs4 from "fs";
2017
+ import * as path7 from "path";
2018
+ import * as fs5 from "fs";
1699
2019
  import { promisify } from "util";
1700
2020
  import { createRequire as createRequire3 } from "module";
1701
2021
  import { fileURLToPath as fileURLToPath3 } from "url";
1702
- import { dirname as dirname3 } from "path";
2022
+ import { dirname as dirname4 } from "path";
1703
2023
  var execAsync = promisify(exec);
1704
2024
  var SqliteExecutor = class {
1705
2025
  binaryPath;
@@ -1710,13 +2030,13 @@ var SqliteExecutor = class {
1710
2030
  }
1711
2031
  findVersionedBinary(binDir, platform2) {
1712
2032
  try {
1713
- const files = fs4.readdirSync(binDir);
2033
+ const files = fs5.readdirSync(binDir);
1714
2034
  const extension = platform2 === "win32" ? ".exe" : "";
1715
2035
  const platformName = platform2 === "win32" ? "windows" : platform2 === "darwin" ? "macos" : "linux";
1716
2036
  const pattern = new RegExp(`^sqlite-engine-v\\d+\\.\\d+\\.\\d+-${platformName}-x64${extension.replace(".", "\\.")}$`);
1717
2037
  const matchingFile = files.find((f) => pattern.test(f));
1718
2038
  if (matchingFile) {
1719
- return path6.join(binDir, matchingFile);
2039
+ return path7.join(binDir, matchingFile);
1720
2040
  }
1721
2041
  } catch (error) {
1722
2042
  }
@@ -1724,36 +2044,36 @@ var SqliteExecutor = class {
1724
2044
  }
1725
2045
  getBinaryPath() {
1726
2046
  const __filename2 = typeof import.meta !== "undefined" && import.meta.url ? fileURLToPath3(import.meta.url) : "";
1727
- const __dirname = __filename2 ? dirname3(__filename2) : process.cwd();
2047
+ const __dirname = __filename2 ? dirname4(__filename2) : process.cwd();
1728
2048
  const possibleDirs = [
1729
- path6.resolve(process.cwd(), ".dbcube", "bin"),
1730
- path6.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
1731
- path6.resolve(__dirname, "..", "bin")
2049
+ path7.resolve(process.cwd(), ".dbcube", "bin"),
2050
+ path7.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
2051
+ path7.resolve(__dirname, "..", "bin")
1732
2052
  ];
1733
2053
  const platform2 = process.platform;
1734
2054
  const extension = platform2 === "win32" ? ".exe" : "";
1735
2055
  const platformName = platform2 === "win32" ? "windows" : platform2 === "darwin" ? "macos" : "linux";
1736
2056
  for (const dir of possibleDirs) {
1737
2057
  const versionedPath = this.findVersionedBinary(dir, platform2);
1738
- if (versionedPath && fs4.existsSync(versionedPath)) {
2058
+ if (versionedPath && fs5.existsSync(versionedPath)) {
1739
2059
  return versionedPath;
1740
2060
  }
1741
2061
  }
1742
2062
  const binaryName = `sqlite-engine-${platformName}-x64${extension}`;
1743
2063
  for (const dir of possibleDirs) {
1744
- const fullPath = path6.join(dir, binaryName);
1745
- if (fs4.existsSync(fullPath)) {
2064
+ const fullPath = path7.join(dir, binaryName);
2065
+ if (fs5.existsSync(fullPath)) {
1746
2066
  return fullPath;
1747
2067
  }
1748
2068
  }
1749
2069
  const fallbackName = `sqlite-engine${extension}`;
1750
2070
  for (const dir of possibleDirs) {
1751
- const fullPath = path6.join(dir, fallbackName);
1752
- if (fs4.existsSync(fullPath)) {
2071
+ const fullPath = path7.join(dir, fallbackName);
2072
+ if (fs5.existsSync(fullPath)) {
1753
2073
  return fullPath;
1754
2074
  }
1755
2075
  }
1756
- return path6.join(possibleDirs[0], binaryName);
2076
+ return path7.join(possibleDirs[0], binaryName);
1757
2077
  }
1758
2078
  async executeBinary(args) {
1759
2079
  const escapedArgs = args.map((arg) => {
@@ -1904,9 +2224,9 @@ var SqliteExecutor = class {
1904
2224
  };
1905
2225
 
1906
2226
  // src/lib/DbConfig.ts
1907
- import * as path7 from "path";
1908
- import fs5 from "fs";
1909
- var rootPath = path7.resolve(process.cwd(), ".dbcube");
2227
+ import * as path8 from "path";
2228
+ import fs6 from "fs";
2229
+ var rootPath = path8.resolve(process.cwd(), ".dbcube");
1910
2230
  var SQLite = class {
1911
2231
  executor = null;
1912
2232
  database;
@@ -1916,11 +2236,11 @@ var SQLite = class {
1916
2236
  async ifExist() {
1917
2237
  if (this.database) {
1918
2238
  const dbPath = this.database || ":memory:";
1919
- const configPath = path7.join(rootPath, dbPath + ".db");
1920
- if (!fs5.existsSync(rootPath)) {
1921
- fs5.mkdirSync(rootPath, { recursive: true });
2239
+ const configPath = path8.join(rootPath, dbPath + ".db");
2240
+ if (!fs6.existsSync(rootPath)) {
2241
+ fs6.mkdirSync(rootPath, { recursive: true });
1922
2242
  }
1923
- if (fs5.existsSync(configPath)) {
2243
+ if (fs6.existsSync(configPath)) {
1924
2244
  return true;
1925
2245
  }
1926
2246
  if (!this.executor) {
@@ -1931,13 +2251,13 @@ var SQLite = class {
1931
2251
  return false;
1932
2252
  }
1933
2253
  async connect() {
1934
- return new Promise(async (resolve5, reject) => {
2254
+ return new Promise(async (resolve6, reject) => {
1935
2255
  try {
1936
2256
  if (!this.executor) {
1937
2257
  const dbPath = this.database || ":memory:";
1938
- const configPath = path7.join(rootPath, dbPath + ".db");
1939
- if (!fs5.existsSync(rootPath)) {
1940
- fs5.mkdirSync(rootPath, { recursive: true });
2258
+ const configPath = path8.join(rootPath, dbPath + ".db");
2259
+ if (!fs6.existsSync(rootPath)) {
2260
+ fs6.mkdirSync(rootPath, { recursive: true });
1941
2261
  }
1942
2262
  this.executor = new SqliteExecutor(configPath);
1943
2263
  const connected = await this.executor.connect();
@@ -1945,22 +2265,22 @@ var SQLite = class {
1945
2265
  throw new Error("Failed to connect to SQLite database");
1946
2266
  }
1947
2267
  }
1948
- resolve5(this.executor);
2268
+ resolve6(this.executor);
1949
2269
  } catch (error) {
1950
2270
  reject(error);
1951
2271
  }
1952
2272
  });
1953
2273
  }
1954
2274
  async disconnect() {
1955
- return new Promise((resolve5) => {
2275
+ return new Promise((resolve6) => {
1956
2276
  if (this.executor) {
1957
2277
  this.executor = null;
1958
2278
  }
1959
- resolve5();
2279
+ resolve6();
1960
2280
  });
1961
2281
  }
1962
2282
  async query(sqlQuery) {
1963
- return new Promise(async (resolve5) => {
2283
+ return new Promise(async (resolve6) => {
1964
2284
  try {
1965
2285
  if (typeof sqlQuery !== "string") {
1966
2286
  throw new Error("The SQL query must be a string.");
@@ -1973,20 +2293,20 @@ var SQLite = class {
1973
2293
  }
1974
2294
  const result = await this.executor.queryMultiple(sqlQuery);
1975
2295
  if (result.status === "error") {
1976
- resolve5({
2296
+ resolve6({
1977
2297
  status: "error",
1978
2298
  message: result.message,
1979
2299
  data: null
1980
2300
  });
1981
2301
  } else {
1982
- resolve5({
2302
+ resolve6({
1983
2303
  status: "success",
1984
2304
  message: "Query executed successfully",
1985
2305
  data: result.data
1986
2306
  });
1987
2307
  }
1988
2308
  } catch (error) {
1989
- resolve5({
2309
+ resolve6({
1990
2310
  status: "error",
1991
2311
  message: error.message || "An error occurred while executing the query.",
1992
2312
  data: null
@@ -1995,7 +2315,7 @@ var SQLite = class {
1995
2315
  });
1996
2316
  }
1997
2317
  async queryWithParameters(sqlQuery, params = []) {
1998
- return new Promise(async (resolve5) => {
2318
+ return new Promise(async (resolve6) => {
1999
2319
  try {
2000
2320
  if (typeof sqlQuery !== "string") {
2001
2321
  throw new Error("The SQL query must be a string.");
@@ -2011,13 +2331,13 @@ var SQLite = class {
2011
2331
  }
2012
2332
  const result = await this.executor.query(sqlQuery, params);
2013
2333
  if (result.status === "error") {
2014
- resolve5({
2334
+ resolve6({
2015
2335
  status: "error",
2016
2336
  message: result.message,
2017
2337
  data: null
2018
2338
  });
2019
2339
  } else {
2020
- resolve5({
2340
+ resolve6({
2021
2341
  status: "success",
2022
2342
  message: "Query executed successfully",
2023
2343
  data: result.data
@@ -2025,7 +2345,7 @@ var SQLite = class {
2025
2345
  }
2026
2346
  } catch (error) {
2027
2347
  console.log(error);
2028
- resolve5({
2348
+ resolve6({
2029
2349
  status: "error",
2030
2350
  message: error.message || "An error occurred while executing the query.",
2031
2351
  data: null
@@ -2119,8 +2439,8 @@ var DbConfig = new SQLite({ DATABASE: "config" });
2119
2439
  var DbConfig_default = DbConfig;
2120
2440
 
2121
2441
  // src/lib/FileLogger.ts
2122
- import * as fs6 from "fs";
2123
- import * as path8 from "path";
2442
+ import * as fs7 from "fs";
2443
+ import * as path9 from "path";
2124
2444
  import { EventEmitter } from "events";
2125
2445
  var FileLogger = class _FileLogger extends EventEmitter {
2126
2446
  static watchers = /* @__PURE__ */ new Map();
@@ -2135,9 +2455,9 @@ var FileLogger = class _FileLogger extends EventEmitter {
2135
2455
  */
2136
2456
  static async write(filePath, message, level = "INFO", append = true) {
2137
2457
  try {
2138
- const dir = path8.dirname(filePath);
2139
- if (!fs6.existsSync(dir)) {
2140
- fs6.mkdirSync(dir, { recursive: true });
2458
+ const dir = path9.dirname(filePath);
2459
+ if (!fs7.existsSync(dir)) {
2460
+ fs7.mkdirSync(dir, { recursive: true });
2141
2461
  }
2142
2462
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
2143
2463
  const formattedMessage = `[${timestamp}] [${level}] ${message}
@@ -2147,9 +2467,9 @@ var FileLogger = class _FileLogger extends EventEmitter {
2147
2467
  return true;
2148
2468
  }
2149
2469
  if (append) {
2150
- await fs6.promises.appendFile(filePath, formattedMessage, "utf8");
2470
+ await fs7.promises.appendFile(filePath, formattedMessage, "utf8");
2151
2471
  } else {
2152
- await fs6.promises.writeFile(filePath, formattedMessage, "utf8");
2472
+ await fs7.promises.writeFile(filePath, formattedMessage, "utf8");
2153
2473
  }
2154
2474
  return true;
2155
2475
  } catch (error) {
@@ -2174,12 +2494,12 @@ var FileLogger = class _FileLogger extends EventEmitter {
2174
2494
  const buffer = _FileLogger.buffers.get(filePath);
2175
2495
  if (buffer && buffer.length > 0) {
2176
2496
  try {
2177
- const dir = path8.dirname(filePath);
2178
- if (!fs6.existsSync(dir)) {
2179
- fs6.mkdirSync(dir, { recursive: true });
2497
+ const dir = path9.dirname(filePath);
2498
+ if (!fs7.existsSync(dir)) {
2499
+ fs7.mkdirSync(dir, { recursive: true });
2180
2500
  }
2181
2501
  const content = buffer.join("");
2182
- await fs6.promises.appendFile(filePath, content, "utf8");
2502
+ await fs7.promises.appendFile(filePath, content, "utf8");
2183
2503
  _FileLogger.buffers.delete(filePath);
2184
2504
  return true;
2185
2505
  } catch (error) {
@@ -2315,10 +2635,10 @@ var FileLogger = class _FileLogger extends EventEmitter {
2315
2635
  // Si debe retornar como array de líneas
2316
2636
  } = options;
2317
2637
  try {
2318
- if (!fs6.existsSync(filePath)) {
2638
+ if (!fs7.existsSync(filePath)) {
2319
2639
  return asArray ? [] : "";
2320
2640
  }
2321
- let content = await fs6.promises.readFile(filePath, "utf8");
2641
+ let content = await fs7.promises.readFile(filePath, "utf8");
2322
2642
  if (asArray) {
2323
2643
  let linesArray = content.split("\n").filter((line) => line.trim() !== "");
2324
2644
  if (lines !== null) {
@@ -2361,15 +2681,15 @@ var FileLogger = class _FileLogger extends EventEmitter {
2361
2681
  } = options;
2362
2682
  let lastSize = 0;
2363
2683
  let lastPosition = 0;
2364
- if (fs6.existsSync(filePath)) {
2365
- const stats = fs6.statSync(filePath);
2684
+ if (fs7.existsSync(filePath)) {
2685
+ const stats = fs7.statSync(filePath);
2366
2686
  lastSize = stats.size;
2367
2687
  lastPosition = fromEnd ? stats.size : 0;
2368
2688
  }
2369
2689
  const listener = async (curr, prev) => {
2370
2690
  try {
2371
2691
  if (curr.size > lastSize) {
2372
- const stream = fs6.createReadStream(filePath, {
2692
+ const stream = fs7.createReadStream(filePath, {
2373
2693
  start: lastPosition,
2374
2694
  end: curr.size - 1,
2375
2695
  encoding: "utf8"
@@ -2397,7 +2717,7 @@ var FileLogger = class _FileLogger extends EventEmitter {
2397
2717
  console.error("Error en watcher:", error);
2398
2718
  }
2399
2719
  };
2400
- fs6.watchFile(filePath, { persistent, interval }, listener);
2720
+ fs7.watchFile(filePath, { persistent, interval }, listener);
2401
2721
  const watcherId = `${filePath}_${Date.now()}`;
2402
2722
  _FileLogger.watchers.set(watcherId, listener);
2403
2723
  return {
@@ -2405,7 +2725,7 @@ var FileLogger = class _FileLogger extends EventEmitter {
2405
2725
  stop: () => {
2406
2726
  const storedListener = _FileLogger.watchers.get(watcherId);
2407
2727
  if (storedListener) {
2408
- fs6.unwatchFile(filePath, storedListener);
2728
+ fs7.unwatchFile(filePath, storedListener);
2409
2729
  _FileLogger.watchers.delete(watcherId);
2410
2730
  }
2411
2731
  },
@@ -2418,7 +2738,7 @@ var FileLogger = class _FileLogger extends EventEmitter {
2418
2738
  static stopAllWatchers() {
2419
2739
  for (const [watcherId] of _FileLogger.watchers) {
2420
2740
  const filePath = watcherId.split("_")[0];
2421
- fs6.unwatchFile(filePath);
2741
+ fs7.unwatchFile(filePath);
2422
2742
  }
2423
2743
  _FileLogger.watchers.clear();
2424
2744
  }
@@ -2448,7 +2768,7 @@ var FileLogger = class _FileLogger extends EventEmitter {
2448
2768
  if (lines.length > maxLines) {
2449
2769
  const keepLines = lines.slice(-maxLines);
2450
2770
  const content = keepLines.join("\n") + "\n";
2451
- await fs6.promises.writeFile(filePath, content, "utf8");
2771
+ await fs7.promises.writeFile(filePath, content, "utf8");
2452
2772
  return lines.length - maxLines;
2453
2773
  }
2454
2774
  return 0;
@@ -2463,8 +2783,8 @@ var FileLogger = class _FileLogger extends EventEmitter {
2463
2783
  */
2464
2784
  static async deleteLogFile(filePath) {
2465
2785
  try {
2466
- if (fs6.existsSync(filePath)) {
2467
- await fs6.promises.unlink(filePath);
2786
+ if (fs7.existsSync(filePath)) {
2787
+ await fs7.promises.unlink(filePath);
2468
2788
  return true;
2469
2789
  }
2470
2790
  return false;