@dbcube/core 4.1.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
@@ -183,6 +183,97 @@ var { https } = import_follow_redirects.default;
183
183
  var Downloader = class {
184
184
  static mainSpinner = null;
185
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
+ }
186
277
  static get(prefix) {
187
278
  const arch2 = new Arquitecture();
188
279
  const platform2 = arch2.getPlatform();
@@ -205,6 +296,7 @@ var Downloader = class {
205
296
  return {
206
297
  name: binaryName,
207
298
  url,
299
+ version: "latest",
208
300
  query_engine: binaryName,
209
301
  schema_engine: `${prefix}-engine-${plat}-${archSuffix}${platform2 === "windows" ? ".exe" : ""}`
210
302
  };
@@ -212,69 +304,125 @@ var Downloader = class {
212
304
  return {
213
305
  name: "",
214
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: "",
215
347
  query_engine: "",
216
348
  schema_engine: ""
217
349
  };
218
350
  }
219
351
  static async download(targetDir) {
220
- const binaries = ["schema", "query", "sqlite"];
221
352
  const binDir = targetDir || this.getDefaultBinDir();
222
353
  fs.mkdirSync(binDir, { recursive: true });
223
354
  this.mainSpinner = (0, import_ora.default)({
224
- text: import_chalk.default.blue("Descargando binarios necesarios..."),
355
+ text: import_chalk.default.blue("Verificando versiones de binarios..."),
225
356
  spinner: "dots12"
226
357
  }).start();
227
- const binariesToDownload = [];
228
- let existingCount = 0;
229
- for (const prefix of binaries) {
230
- const binaryInfo = this.get(prefix);
231
- if (!binaryInfo.name || !binaryInfo.url) {
232
- throw new Error(`Plataforma o arquitectura no soportada para ${prefix}`);
233
- }
234
- const finalBinaryPath = path.join(binDir, binaryInfo.name);
235
- if (fs.existsSync(finalBinaryPath)) {
236
- existingCount++;
237
- 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
+ });
238
385
  }
239
- binariesToDownload.push({
240
- prefix,
241
- binaryInfo,
242
- tempZipPath: path.join(os2.tmpdir(), `dbcube-${prefix}-${Date.now()}.zip`),
243
- finalBinaryPath
244
- });
245
386
  }
387
+ const binariesToDownload = binariesToProcess.filter((b) => b.needsUpdate);
246
388
  if (binariesToDownload.length === 0) {
247
- 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"));
248
390
  return;
249
391
  }
250
- this.updateMainProgress("paralelo", existingCount, binaries.length, "downloading");
392
+ this.mainSpinner.text = import_chalk.default.blue(`Updating ${binariesToDownload.length} binary(ies)...`);
251
393
  try {
252
- await Promise.all(binariesToDownload.map(async (binary, index) => {
394
+ await Promise.all(binariesToDownload.map(async (binary) => {
253
395
  const maxRetries = 3;
254
396
  let attempt = 0;
255
397
  while (attempt <= maxRetries) {
256
398
  try {
257
- await this.downloadFileWithProgress(binary.binaryInfo.url, binary.tempZipPath, binary.prefix);
258
- await this.extractBinary(binary.tempZipPath, binary.finalBinaryPath, binary.prefix);
259
- const completed = existingCount + index + 1;
260
- 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}`);
261
409
  break;
262
410
  } catch (error) {
263
- const errorMessage = error instanceof Error ? error.message : "Error desconocido";
411
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
264
412
  if (attempt < maxRetries && (errorMessage.includes("ECONNRESET") || errorMessage.includes("timeout") || errorMessage.includes("ETIMEDOUT") || errorMessage.includes("ENOTFOUND"))) {
265
413
  attempt++;
266
- this.updateMainProgress(binary.prefix, existingCount, binaries.length, "retrying", attempt);
414
+ console.log(`\u{1F504} Retrying ${binary.prefix}-engine (${attempt}/${maxRetries})...`);
267
415
  await new Promise((resolve5) => setTimeout(resolve5, 1e3 + Math.random() * 1e3));
268
416
  } else {
269
- throw new Error(`Error descargando ${binary.prefix}: ${errorMessage}`);
417
+ throw new Error(`Error downloading ${binary.prefix}: ${errorMessage}`);
270
418
  }
271
419
  }
272
420
  }
273
421
  }));
274
- this.mainSpinner.succeed(import_chalk.default.green("Binarios descargados correctamente"));
422
+ this.mainSpinner.succeed(import_chalk.default.green("Binaries updated successfully"));
275
423
  } catch (error) {
276
- const errorMessage = error instanceof Error ? error.message : "Error desconocido";
277
- 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}`));
278
426
  throw error;
279
427
  }
280
428
  }
@@ -445,22 +593,13 @@ var import_meta2 = {};
445
593
  var Binary = class {
446
594
  static isDownloading = false;
447
595
  static downloadPromise = null;
596
+ static cachedBinaries = {};
448
597
  static async ensureBinariesExist() {
449
598
  if (this.isDownloading && this.downloadPromise) {
450
599
  await this.downloadPromise;
451
600
  return;
452
601
  }
453
602
  const binDir = this.getBinDir();
454
- const binaries = ["schema", "query", "sqlite"];
455
- const allExist = binaries.every((prefix) => {
456
- const binaryInfo = Downloader.get(prefix);
457
- if (!binaryInfo.name) return false;
458
- const binaryPath = path2.join(binDir, binaryInfo.name);
459
- return fs2.existsSync(binaryPath);
460
- });
461
- if (allExist) {
462
- return;
463
- }
464
603
  if (!this.isDownloading) {
465
604
  this.isDownloading = true;
466
605
  this.downloadPromise = this.downloadBinaries();
@@ -503,58 +642,50 @@ var Binary = class {
503
642
  fs2.mkdirSync(tempDir, { recursive: true });
504
643
  return tempDir;
505
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
+ }
506
667
  static async get() {
507
668
  await this.ensureBinariesExist();
508
669
  const arch2 = new Arquitecture();
509
670
  const platform2 = arch2.getPlatform();
510
671
  const architecture = arch2.getArchitecture();
511
672
  const binDir = this.getBinDir();
512
- const getFullPath = (binaryName) => {
513
- return path2.join(binDir, binaryName);
673
+ const platformMap = {
674
+ windows: "windows",
675
+ linux: "linux",
676
+ darwin: "macos"
514
677
  };
515
- switch (platform2) {
516
- case "windows":
517
- if (architecture == "x86_64") {
518
- return {
519
- query_engine: getFullPath("query-engine-windows-x64.exe"),
520
- schema_engine: getFullPath("schema-engine-windows-x64.exe")
521
- };
522
- }
523
- if (architecture == "aarch64") {
524
- return {
525
- query_engine: getFullPath("query-engine-windows-arm64.exe"),
526
- schema_engine: getFullPath("schema-engine-windows-arm64.exe")
527
- };
528
- }
529
- break;
530
- case "linux":
531
- if (architecture == "x86_64") {
532
- return {
533
- query_engine: getFullPath("query-engine-linux-x64"),
534
- schema_engine: getFullPath("schema-engine-linux-x64")
535
- };
536
- }
537
- if (architecture == "aarch64") {
538
- return {
539
- query_engine: getFullPath("query-engine-linux-arm64"),
540
- schema_engine: getFullPath("schema-engine-linux-arm64")
541
- };
542
- }
543
- break;
544
- case "macos":
545
- if (architecture == "x86_64") {
546
- return {
547
- query_engine: getFullPath("query-engine-macos-x64"),
548
- schema_engine: getFullPath("schema-engine-macos-x64")
549
- };
550
- }
551
- if (architecture == "aarch64") {
552
- return {
553
- query_engine: getFullPath("query-engine-macos-arm64"),
554
- schema_engine: getFullPath("schema-engine-macos-arm64")
555
- };
556
- }
557
- 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
+ };
558
689
  }
559
690
  return {
560
691
  query_engine: "",