@dbcube/core 4.0.4 → 4.1.5

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.cjs CHANGED
@@ -44,7 +44,7 @@ __export(index_exports, {
44
44
  module.exports = __toCommonJS(index_exports);
45
45
 
46
46
  // src/lib/Engine.ts
47
- var import_path = __toESM(require("path"));
47
+ var import_path3 = __toESM(require("path"));
48
48
 
49
49
  // src/lib/Arquitecture.ts
50
50
  var os = __toESM(require("os"));
@@ -176,10 +176,104 @@ var import_follow_redirects = __toESM(require("follow-redirects"));
176
176
  var unzipper = __toESM(require("unzipper"));
177
177
  var import_ora = __toESM(require("ora"));
178
178
  var import_chalk = __toESM(require("chalk"));
179
+ var import_url = require("url");
180
+ var import_path = require("path");
181
+ var import_meta = {};
179
182
  var { https } = import_follow_redirects.default;
180
183
  var Downloader = class {
181
184
  static mainSpinner = null;
182
185
  static currentSpinner = null;
186
+ static VERSION_URLS = {
187
+ query: "https://raw.githubusercontent.com/Dbcube/binaries/main/query-engines.json",
188
+ schema: "https://raw.githubusercontent.com/Dbcube/binaries/main/schema-engines.json",
189
+ sqlite: "https://raw.githubusercontent.com/Dbcube/binaries/main/sqlite-engines.json"
190
+ };
191
+ /**
192
+ * Fetch latest version from GitHub
193
+ */
194
+ static async fetchLatestVersion(prefix) {
195
+ const url = this.VERSION_URLS[prefix];
196
+ return new Promise((resolve5, reject) => {
197
+ https.get(url, (response) => {
198
+ let data = "";
199
+ response.on("data", (chunk) => {
200
+ data += chunk;
201
+ });
202
+ response.on("end", () => {
203
+ try {
204
+ const versions = JSON.parse(data);
205
+ if (versions && versions.length > 0) {
206
+ resolve5(versions[0].version);
207
+ } else {
208
+ reject(new Error("No versions found"));
209
+ }
210
+ } catch (error) {
211
+ reject(error);
212
+ }
213
+ });
214
+ response.on("error", reject);
215
+ }).on("error", reject);
216
+ });
217
+ }
218
+ /**
219
+ * Extract version from binary filename
220
+ * Example: schema-engine-v1.0.0-windows-x64.exe -> v1.0.0
221
+ */
222
+ static extractVersionFromFilename(filename) {
223
+ const match = filename.match(/-(v\d+\.\d+\.\d+)-/);
224
+ return match ? match[1] : null;
225
+ }
226
+ /**
227
+ * Get local version of installed binary
228
+ */
229
+ static getLocalVersion(binDir, prefix) {
230
+ try {
231
+ const files = fs.readdirSync(binDir);
232
+ const binaryPattern = new RegExp(`^${prefix}-engine-v`);
233
+ const binaryFile = files.find((f) => binaryPattern.test(f));
234
+ if (binaryFile) {
235
+ return this.extractVersionFromFilename(binaryFile);
236
+ }
237
+ } catch (error) {
238
+ }
239
+ return null;
240
+ }
241
+ /**
242
+ * Compare versions (returns true if remote is newer)
243
+ */
244
+ static isNewerVersion(localVersion, remoteVersion) {
245
+ if (!localVersion) return true;
246
+ const cleanLocal = localVersion.replace(/^v/, "");
247
+ const cleanRemote = remoteVersion.replace(/^v/, "");
248
+ const localParts = cleanLocal.split(".").map(Number);
249
+ const remoteParts = cleanRemote.split(".").map(Number);
250
+ for (let i = 0; i < 3; i++) {
251
+ if (remoteParts[i] > localParts[i]) return true;
252
+ if (remoteParts[i] < localParts[i]) return false;
253
+ }
254
+ return false;
255
+ }
256
+ /**
257
+ * Delete old binary files
258
+ */
259
+ static deleteOldBinary(binDir, prefix) {
260
+ try {
261
+ const files = fs.readdirSync(binDir);
262
+ const binaryPattern = new RegExp(`^${prefix}-engine-`);
263
+ files.forEach((file) => {
264
+ if (binaryPattern.test(file)) {
265
+ const filePath = path.join(binDir, file);
266
+ try {
267
+ fs.unlinkSync(filePath);
268
+ console.log(`\u{1F5D1}\uFE0F Deleted old binary: ${file}`);
269
+ } catch (err) {
270
+ console.warn(`\u26A0\uFE0F Could not delete: ${file}`);
271
+ }
272
+ }
273
+ });
274
+ } catch (error) {
275
+ }
276
+ }
183
277
  static get(prefix) {
184
278
  const arch2 = new Arquitecture();
185
279
  const platform2 = arch2.getPlatform();
@@ -202,6 +296,7 @@ var Downloader = class {
202
296
  return {
203
297
  name: binaryName,
204
298
  url,
299
+ version: "latest",
205
300
  query_engine: binaryName,
206
301
  schema_engine: `${prefix}-engine-${plat}-${archSuffix}${platform2 === "windows" ? ".exe" : ""}`
207
302
  };
@@ -209,69 +304,125 @@ var Downloader = class {
209
304
  return {
210
305
  name: "",
211
306
  url: "",
307
+ version: "",
308
+ query_engine: "",
309
+ schema_engine: ""
310
+ };
311
+ }
312
+ /**
313
+ * Get binary info with actual version from GitHub
314
+ */
315
+ static async getWithVersion(prefix) {
316
+ const arch2 = new Arquitecture();
317
+ const platform2 = arch2.getPlatform();
318
+ const architecture = arch2.getArchitecture();
319
+ const platformMap = {
320
+ windows: "windows",
321
+ linux: "linux",
322
+ darwin: "macos"
323
+ };
324
+ const archMap = {
325
+ x86_64: "x64",
326
+ aarch64: "arm64"
327
+ };
328
+ const plat = platformMap[platform2];
329
+ const archSuffix = archMap[architecture];
330
+ if (plat && archSuffix) {
331
+ const version = await this.fetchLatestVersion(prefix);
332
+ const baseName = `${prefix}-engine-${version}-${plat}-${archSuffix}`;
333
+ const binaryName = platform2 === "windows" ? `${baseName}.exe` : baseName;
334
+ const url = `https://github.com/Dbcube/binaries/releases/download/${prefix}-engine/${prefix}-engine-${version}-${plat}-${archSuffix}.zip`;
335
+ return {
336
+ name: binaryName,
337
+ url,
338
+ version,
339
+ query_engine: binaryName,
340
+ schema_engine: binaryName
341
+ };
342
+ }
343
+ return {
344
+ name: "",
345
+ url: "",
346
+ version: "",
212
347
  query_engine: "",
213
348
  schema_engine: ""
214
349
  };
215
350
  }
216
351
  static async download(targetDir) {
217
- const binaries = ["schema", "query", "sqlite"];
218
352
  const binDir = targetDir || this.getDefaultBinDir();
219
353
  fs.mkdirSync(binDir, { recursive: true });
220
354
  this.mainSpinner = (0, import_ora.default)({
221
- text: import_chalk.default.blue("Descargando binarios necesarios..."),
355
+ text: import_chalk.default.blue("Verificando versiones de binarios..."),
222
356
  spinner: "dots12"
223
357
  }).start();
224
- const binariesToDownload = [];
225
- let existingCount = 0;
226
- for (const prefix of binaries) {
227
- const binaryInfo = this.get(prefix);
228
- if (!binaryInfo.name || !binaryInfo.url) {
229
- throw new Error(`Plataforma o arquitectura no soportada para ${prefix}`);
230
- }
231
- const finalBinaryPath = path.join(binDir, binaryInfo.name);
232
- if (fs.existsSync(finalBinaryPath)) {
233
- existingCount++;
234
- continue;
358
+ const binariesToProcess = [];
359
+ for (const prefix of ["query", "schema", "sqlite"]) {
360
+ try {
361
+ const localVersion = this.getLocalVersion(binDir, prefix);
362
+ const remoteVersion = await this.fetchLatestVersion(prefix);
363
+ const needsUpdate = this.isNewerVersion(localVersion, remoteVersion);
364
+ binariesToProcess.push({
365
+ prefix,
366
+ needsUpdate,
367
+ localVersion,
368
+ remoteVersion
369
+ });
370
+ if (needsUpdate) {
371
+ console.log(`
372
+ \u{1F4E6} ${prefix}-engine: ${localVersion || "not installed"} \u2192 ${remoteVersion}`);
373
+ } else if (localVersion) {
374
+ console.log(`
375
+ \u2705 ${prefix}-engine: ${localVersion} (up to date)`);
376
+ }
377
+ } catch (error) {
378
+ console.warn(`\u26A0\uFE0F Could not check version for ${prefix}-engine, will attempt download`);
379
+ binariesToProcess.push({
380
+ prefix,
381
+ needsUpdate: true,
382
+ localVersion: null,
383
+ remoteVersion: "latest"
384
+ });
235
385
  }
236
- binariesToDownload.push({
237
- prefix,
238
- binaryInfo,
239
- tempZipPath: path.join(os2.tmpdir(), `dbcube-${prefix}-${Date.now()}.zip`),
240
- finalBinaryPath
241
- });
242
386
  }
387
+ const binariesToDownload = binariesToProcess.filter((b) => b.needsUpdate);
243
388
  if (binariesToDownload.length === 0) {
244
- this.mainSpinner.succeed(import_chalk.default.green("Todos los binarios ya est\xE1n descargados"));
389
+ this.mainSpinner.succeed(import_chalk.default.green("All binaries are up to date"));
245
390
  return;
246
391
  }
247
- this.updateMainProgress("paralelo", existingCount, binaries.length, "downloading");
392
+ this.mainSpinner.text = import_chalk.default.blue(`Updating ${binariesToDownload.length} binary(ies)...`);
248
393
  try {
249
- await Promise.all(binariesToDownload.map(async (binary, index) => {
394
+ await Promise.all(binariesToDownload.map(async (binary) => {
250
395
  const maxRetries = 3;
251
396
  let attempt = 0;
252
397
  while (attempt <= maxRetries) {
253
398
  try {
254
- await this.downloadFileWithProgress(binary.binaryInfo.url, binary.tempZipPath, binary.prefix);
255
- await this.extractBinary(binary.tempZipPath, binary.finalBinaryPath, binary.prefix);
256
- const completed = existingCount + index + 1;
257
- this.updateMainProgress(binary.prefix, completed, binaries.length, "completed");
399
+ const binaryInfo = await this.getWithVersion(binary.prefix);
400
+ if (!binaryInfo.name || !binaryInfo.url) {
401
+ throw new Error(`Platform or architecture not supported for ${binary.prefix}`);
402
+ }
403
+ const tempZipPath = path.join(os2.tmpdir(), `dbcube-${binary.prefix}-${Date.now()}.zip`);
404
+ const finalBinaryPath = path.join(binDir, binaryInfo.name);
405
+ this.deleteOldBinary(binDir, binary.prefix);
406
+ await this.downloadFileWithProgress(binaryInfo.url, tempZipPath, binary.prefix);
407
+ await this.extractBinary(tempZipPath, finalBinaryPath, binary.prefix);
408
+ console.log(`\u2705 ${binary.prefix}-engine updated to ${binary.remoteVersion}`);
258
409
  break;
259
410
  } catch (error) {
260
- const errorMessage = error instanceof Error ? error.message : "Error desconocido";
411
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
261
412
  if (attempt < maxRetries && (errorMessage.includes("ECONNRESET") || errorMessage.includes("timeout") || errorMessage.includes("ETIMEDOUT") || errorMessage.includes("ENOTFOUND"))) {
262
413
  attempt++;
263
- this.updateMainProgress(binary.prefix, existingCount, binaries.length, "retrying", attempt);
414
+ console.log(`\u{1F504} Retrying ${binary.prefix}-engine (${attempt}/${maxRetries})...`);
264
415
  await new Promise((resolve5) => setTimeout(resolve5, 1e3 + Math.random() * 1e3));
265
416
  } else {
266
- throw new Error(`Error descargando ${binary.prefix}: ${errorMessage}`);
417
+ throw new Error(`Error downloading ${binary.prefix}: ${errorMessage}`);
267
418
  }
268
419
  }
269
420
  }
270
421
  }));
271
- this.mainSpinner.succeed(import_chalk.default.green("Binarios descargados correctamente"));
422
+ this.mainSpinner.succeed(import_chalk.default.green("Binaries updated successfully"));
272
423
  } catch (error) {
273
- const errorMessage = error instanceof Error ? error.message : "Error desconocido";
274
- this.mainSpinner.fail(import_chalk.default.red(`Error en descarga paralela: ${errorMessage}`));
424
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
425
+ this.mainSpinner.fail(import_chalk.default.red(`Error updating binaries: ${errorMessage}`));
275
426
  throw error;
276
427
  }
277
428
  }
@@ -406,6 +557,8 @@ var Downloader = class {
406
557
  }
407
558
  }
408
559
  static getDefaultBinDir() {
560
+ const __filename2 = typeof import_meta !== "undefined" && import_meta.url ? (0, import_url.fileURLToPath)(import_meta.url) : "";
561
+ const __dirname = __filename2 ? (0, import_path.dirname)(__filename2) : process.cwd();
409
562
  const possibleDirs = [
410
563
  path.resolve(process.cwd(), ".dbcube", "bin"),
411
564
  path.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
@@ -434,25 +587,19 @@ var Downloader = class {
434
587
  var fs2 = __toESM(require("fs"));
435
588
  var path2 = __toESM(require("path"));
436
589
  var os3 = __toESM(require("os"));
590
+ var import_url2 = require("url");
591
+ var import_path2 = require("path");
592
+ var import_meta2 = {};
437
593
  var Binary = class {
438
594
  static isDownloading = false;
439
595
  static downloadPromise = null;
596
+ static cachedBinaries = {};
440
597
  static async ensureBinariesExist() {
441
598
  if (this.isDownloading && this.downloadPromise) {
442
599
  await this.downloadPromise;
443
600
  return;
444
601
  }
445
602
  const binDir = this.getBinDir();
446
- const binaries = ["schema", "query", "sqlite"];
447
- const allExist = binaries.every((prefix) => {
448
- const binaryInfo = Downloader.get(prefix);
449
- if (!binaryInfo.name) return false;
450
- const binaryPath = path2.join(binDir, binaryInfo.name);
451
- return fs2.existsSync(binaryPath);
452
- });
453
- if (allExist) {
454
- return;
455
- }
456
603
  if (!this.isDownloading) {
457
604
  this.isDownloading = true;
458
605
  this.downloadPromise = this.downloadBinaries();
@@ -474,6 +621,8 @@ var Binary = class {
474
621
  }
475
622
  }
476
623
  static getBinDir() {
624
+ const __filename2 = typeof import_meta2 !== "undefined" && import_meta2.url ? (0, import_url2.fileURLToPath)(import_meta2.url) : "";
625
+ const __dirname = __filename2 ? (0, import_path2.dirname)(__filename2) : process.cwd();
477
626
  const possibleDirs = [
478
627
  path2.resolve(process.cwd(), ".dbcube", "bin"),
479
628
  path2.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
@@ -493,58 +642,50 @@ var Binary = class {
493
642
  fs2.mkdirSync(tempDir, { recursive: true });
494
643
  return tempDir;
495
644
  }
645
+ static findVersionedBinary(binDir, prefix, platform2, arch2) {
646
+ const cacheKey = `${prefix}-${platform2}-${arch2}`;
647
+ if (this.cachedBinaries[cacheKey]) {
648
+ const cachedPath = path2.join(binDir, this.cachedBinaries[cacheKey]);
649
+ if (fs2.existsSync(cachedPath)) {
650
+ return cachedPath;
651
+ }
652
+ }
653
+ try {
654
+ const files = fs2.readdirSync(binDir);
655
+ const extension = platform2 === "windows" ? ".exe" : "";
656
+ const pattern = new RegExp(`^${prefix}-engine-v\\d+\\.\\d+\\.\\d+-${platform2}-${arch2}${extension.replace(".", "\\.")}$`);
657
+ const matchingFile = files.find((f) => pattern.test(f));
658
+ if (matchingFile) {
659
+ this.cachedBinaries[cacheKey] = matchingFile;
660
+ return path2.join(binDir, matchingFile);
661
+ }
662
+ } catch (error) {
663
+ }
664
+ const fallbackName = `${prefix}-engine-${platform2}-${arch2}${platform2 === "windows" ? ".exe" : ""}`;
665
+ return path2.join(binDir, fallbackName);
666
+ }
496
667
  static async get() {
497
668
  await this.ensureBinariesExist();
498
669
  const arch2 = new Arquitecture();
499
670
  const platform2 = arch2.getPlatform();
500
671
  const architecture = arch2.getArchitecture();
501
672
  const binDir = this.getBinDir();
502
- const getFullPath = (binaryName) => {
503
- return path2.join(binDir, binaryName);
673
+ const platformMap = {
674
+ windows: "windows",
675
+ linux: "linux",
676
+ darwin: "macos"
504
677
  };
505
- switch (platform2) {
506
- case "windows":
507
- if (architecture == "x86_64") {
508
- return {
509
- query_engine: getFullPath("query-engine-windows-x64.exe"),
510
- schema_engine: getFullPath("schema-engine-windows-x64.exe")
511
- };
512
- }
513
- if (architecture == "aarch64") {
514
- return {
515
- query_engine: getFullPath("query-engine-windows-arm64.exe"),
516
- schema_engine: getFullPath("schema-engine-windows-arm64.exe")
517
- };
518
- }
519
- break;
520
- case "linux":
521
- if (architecture == "x86_64") {
522
- return {
523
- query_engine: getFullPath("query-engine-linux-x64"),
524
- schema_engine: getFullPath("schema-engine-linux-x64")
525
- };
526
- }
527
- if (architecture == "aarch64") {
528
- return {
529
- query_engine: getFullPath("query-engine-linux-arm64"),
530
- schema_engine: getFullPath("schema-engine-linux-arm64")
531
- };
532
- }
533
- break;
534
- case "macos":
535
- if (architecture == "x86_64") {
536
- return {
537
- query_engine: getFullPath("query-engine-macos-x64"),
538
- schema_engine: getFullPath("schema-engine-macos-x64")
539
- };
540
- }
541
- if (architecture == "aarch64") {
542
- return {
543
- query_engine: getFullPath("query-engine-macos-arm64"),
544
- schema_engine: getFullPath("schema-engine-macos-arm64")
545
- };
546
- }
547
- break;
678
+ const archMap = {
679
+ x86_64: "x64",
680
+ aarch64: "arm64"
681
+ };
682
+ const plat = platformMap[platform2];
683
+ const archSuffix = archMap[architecture];
684
+ if (plat && archSuffix) {
685
+ return {
686
+ query_engine: this.findVersionedBinary(binDir, "query", plat, archSuffix),
687
+ schema_engine: this.findVersionedBinary(binDir, "schema", plat, archSuffix)
688
+ };
548
689
  }
549
690
  return {
550
691
  query_engine: "",
@@ -650,7 +791,7 @@ var Engine = class {
650
791
  setConfig(name) {
651
792
  const configInstance = new Config();
652
793
  try {
653
- const configFilePath = import_path.default.resolve(process.cwd(), "dbcube.config.js");
794
+ const configFilePath = import_path3.default.resolve(process.cwd(), "dbcube.config.js");
654
795
  const requireUrl = typeof __filename !== "undefined" ? __filename : process.cwd();
655
796
  const require2 = (0, import_module.createRequire)(requireUrl);
656
797
  if (require2.cache && require2.resolve) {
@@ -769,7 +910,7 @@ var Engine = class {
769
910
  };
770
911
 
771
912
  // src/lib/QueryEngine.ts
772
- var import_path2 = __toESM(require("path"));
913
+ var import_path4 = __toESM(require("path"));
773
914
  var import_module2 = require("module");
774
915
  var net = __toESM(require("net"));
775
916
  var import_child_process2 = require("child_process");
@@ -859,7 +1000,7 @@ var QueryEngine = class {
859
1000
  setConfig(name) {
860
1001
  const configInstance = new Config();
861
1002
  try {
862
- const configFilePath = import_path2.default.resolve(process.cwd(), "dbcube.config.js");
1003
+ const configFilePath = import_path4.default.resolve(process.cwd(), "dbcube.config.js");
863
1004
  const requireUrl = typeof __filename !== "undefined" ? __filename : process.cwd();
864
1005
  const require2 = (0, import_module2.createRequire)(requireUrl);
865
1006
  if (require2.cache && require2.resolve) {
@@ -1336,6 +1477,9 @@ var path5 = __toESM(require("path"));
1336
1477
  var fs3 = __toESM(require("fs"));
1337
1478
  var import_util = require("util");
1338
1479
  var import_module3 = require("module");
1480
+ var import_url3 = require("url");
1481
+ var import_path5 = require("path");
1482
+ var import_meta3 = {};
1339
1483
  var execAsync = (0, import_util.promisify)(import_child_process3.exec);
1340
1484
  var SqliteExecutor = class {
1341
1485
  binaryPath;
@@ -1345,6 +1489,8 @@ var SqliteExecutor = class {
1345
1489
  this.binaryPath = this.getBinaryPath();
1346
1490
  }
1347
1491
  getBinaryPath() {
1492
+ const __filename2 = typeof import_meta3 !== "undefined" && import_meta3.url ? (0, import_url3.fileURLToPath)(import_meta3.url) : "";
1493
+ const __dirname = __filename2 ? (0, import_path5.dirname)(__filename2) : process.cwd();
1348
1494
  const possibleDirs = [
1349
1495
  path5.resolve(process.cwd(), ".dbcube", "bin"),
1350
1496
  path5.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
@@ -1467,7 +1613,8 @@ var SqliteExecutor = class {
1467
1613
  }
1468
1614
  // Para compatibilidad con better-sqlite3 API sincrona usando deasync si es necesario
1469
1615
  prepareSync(sql) {
1470
- const requireUrl = typeof __filename !== "undefined" ? __filename : process.cwd();
1616
+ const __filename2 = typeof import_meta3 !== "undefined" && import_meta3.url ? (0, import_url3.fileURLToPath)(import_meta3.url) : "";
1617
+ const requireUrl = __filename2 || import_meta3.url;
1471
1618
  const require2 = (0, import_module3.createRequire)(requireUrl);
1472
1619
  const deasync = require2("deasync");
1473
1620
  return {