@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.d.mts CHANGED
@@ -104,9 +104,11 @@ interface BinaryType {
104
104
  declare class Binary {
105
105
  private static isDownloading;
106
106
  private static downloadPromise;
107
+ private static cachedBinaries;
107
108
  static ensureBinariesExist(): Promise<void>;
108
109
  private static downloadBinaries;
109
110
  private static getBinDir;
111
+ private static findVersionedBinary;
110
112
  static get(): Promise<BinaryType>;
111
113
  }
112
114
 
package/dist/index.d.ts CHANGED
@@ -104,9 +104,11 @@ interface BinaryType {
104
104
  declare class Binary {
105
105
  private static isDownloading;
106
106
  private static downloadPromise;
107
+ private static cachedBinaries;
107
108
  static ensureBinariesExist(): Promise<void>;
108
109
  private static downloadBinaries;
109
110
  private static getBinDir;
111
+ private static findVersionedBinary;
110
112
  static get(): Promise<BinaryType>;
111
113
  }
112
114
 
package/dist/index.js CHANGED
@@ -131,10 +131,103 @@ import followRedirects from "follow-redirects";
131
131
  import * as unzipper from "unzipper";
132
132
  import ora from "ora";
133
133
  import chalk from "chalk";
134
+ import { fileURLToPath } from "url";
135
+ import { dirname } from "path";
134
136
  var { https } = followRedirects;
135
137
  var Downloader = class {
136
138
  static mainSpinner = null;
137
139
  static currentSpinner = null;
140
+ static VERSION_URLS = {
141
+ query: "https://raw.githubusercontent.com/Dbcube/binaries/main/query-engines.json",
142
+ schema: "https://raw.githubusercontent.com/Dbcube/binaries/main/schema-engines.json",
143
+ sqlite: "https://raw.githubusercontent.com/Dbcube/binaries/main/sqlite-engines.json"
144
+ };
145
+ /**
146
+ * Fetch latest version from GitHub
147
+ */
148
+ static async fetchLatestVersion(prefix) {
149
+ const url = this.VERSION_URLS[prefix];
150
+ return new Promise((resolve5, reject) => {
151
+ https.get(url, (response) => {
152
+ let data = "";
153
+ response.on("data", (chunk) => {
154
+ data += chunk;
155
+ });
156
+ response.on("end", () => {
157
+ try {
158
+ const versions = JSON.parse(data);
159
+ if (versions && versions.length > 0) {
160
+ resolve5(versions[0].version);
161
+ } else {
162
+ reject(new Error("No versions found"));
163
+ }
164
+ } catch (error) {
165
+ reject(error);
166
+ }
167
+ });
168
+ response.on("error", reject);
169
+ }).on("error", reject);
170
+ });
171
+ }
172
+ /**
173
+ * Extract version from binary filename
174
+ * Example: schema-engine-v1.0.0-windows-x64.exe -> v1.0.0
175
+ */
176
+ static extractVersionFromFilename(filename) {
177
+ const match = filename.match(/-(v\d+\.\d+\.\d+)-/);
178
+ return match ? match[1] : null;
179
+ }
180
+ /**
181
+ * Get local version of installed binary
182
+ */
183
+ static getLocalVersion(binDir, prefix) {
184
+ try {
185
+ const files = fs.readdirSync(binDir);
186
+ const binaryPattern = new RegExp(`^${prefix}-engine-v`);
187
+ const binaryFile = files.find((f) => binaryPattern.test(f));
188
+ if (binaryFile) {
189
+ return this.extractVersionFromFilename(binaryFile);
190
+ }
191
+ } catch (error) {
192
+ }
193
+ return null;
194
+ }
195
+ /**
196
+ * Compare versions (returns true if remote is newer)
197
+ */
198
+ static isNewerVersion(localVersion, remoteVersion) {
199
+ if (!localVersion) return true;
200
+ const cleanLocal = localVersion.replace(/^v/, "");
201
+ const cleanRemote = remoteVersion.replace(/^v/, "");
202
+ const localParts = cleanLocal.split(".").map(Number);
203
+ const remoteParts = cleanRemote.split(".").map(Number);
204
+ for (let i = 0; i < 3; i++) {
205
+ if (remoteParts[i] > localParts[i]) return true;
206
+ if (remoteParts[i] < localParts[i]) return false;
207
+ }
208
+ return false;
209
+ }
210
+ /**
211
+ * Delete old binary files
212
+ */
213
+ static deleteOldBinary(binDir, prefix) {
214
+ try {
215
+ const files = fs.readdirSync(binDir);
216
+ const binaryPattern = new RegExp(`^${prefix}-engine-`);
217
+ files.forEach((file) => {
218
+ if (binaryPattern.test(file)) {
219
+ const filePath = path.join(binDir, file);
220
+ try {
221
+ fs.unlinkSync(filePath);
222
+ console.log(`\u{1F5D1}\uFE0F Deleted old binary: ${file}`);
223
+ } catch (err) {
224
+ console.warn(`\u26A0\uFE0F Could not delete: ${file}`);
225
+ }
226
+ }
227
+ });
228
+ } catch (error) {
229
+ }
230
+ }
138
231
  static get(prefix) {
139
232
  const arch2 = new Arquitecture();
140
233
  const platform2 = arch2.getPlatform();
@@ -157,6 +250,7 @@ var Downloader = class {
157
250
  return {
158
251
  name: binaryName,
159
252
  url,
253
+ version: "latest",
160
254
  query_engine: binaryName,
161
255
  schema_engine: `${prefix}-engine-${plat}-${archSuffix}${platform2 === "windows" ? ".exe" : ""}`
162
256
  };
@@ -164,69 +258,125 @@ var Downloader = class {
164
258
  return {
165
259
  name: "",
166
260
  url: "",
261
+ version: "",
262
+ query_engine: "",
263
+ schema_engine: ""
264
+ };
265
+ }
266
+ /**
267
+ * Get binary info with actual version from GitHub
268
+ */
269
+ static async getWithVersion(prefix) {
270
+ const arch2 = new Arquitecture();
271
+ const platform2 = arch2.getPlatform();
272
+ const architecture = arch2.getArchitecture();
273
+ const platformMap = {
274
+ windows: "windows",
275
+ linux: "linux",
276
+ darwin: "macos"
277
+ };
278
+ const archMap = {
279
+ x86_64: "x64",
280
+ aarch64: "arm64"
281
+ };
282
+ const plat = platformMap[platform2];
283
+ const archSuffix = archMap[architecture];
284
+ if (plat && archSuffix) {
285
+ const version = await this.fetchLatestVersion(prefix);
286
+ const baseName = `${prefix}-engine-${version}-${plat}-${archSuffix}`;
287
+ const binaryName = platform2 === "windows" ? `${baseName}.exe` : baseName;
288
+ const url = `https://github.com/Dbcube/binaries/releases/download/${prefix}-engine/${prefix}-engine-${version}-${plat}-${archSuffix}.zip`;
289
+ return {
290
+ name: binaryName,
291
+ url,
292
+ version,
293
+ query_engine: binaryName,
294
+ schema_engine: binaryName
295
+ };
296
+ }
297
+ return {
298
+ name: "",
299
+ url: "",
300
+ version: "",
167
301
  query_engine: "",
168
302
  schema_engine: ""
169
303
  };
170
304
  }
171
305
  static async download(targetDir) {
172
- const binaries = ["schema", "query", "sqlite"];
173
306
  const binDir = targetDir || this.getDefaultBinDir();
174
307
  fs.mkdirSync(binDir, { recursive: true });
175
308
  this.mainSpinner = ora({
176
- text: chalk.blue("Descargando binarios necesarios..."),
309
+ text: chalk.blue("Verificando versiones de binarios..."),
177
310
  spinner: "dots12"
178
311
  }).start();
179
- const binariesToDownload = [];
180
- let existingCount = 0;
181
- for (const prefix of binaries) {
182
- const binaryInfo = this.get(prefix);
183
- if (!binaryInfo.name || !binaryInfo.url) {
184
- throw new Error(`Plataforma o arquitectura no soportada para ${prefix}`);
185
- }
186
- const finalBinaryPath = path.join(binDir, binaryInfo.name);
187
- if (fs.existsSync(finalBinaryPath)) {
188
- existingCount++;
189
- continue;
312
+ const binariesToProcess = [];
313
+ for (const prefix of ["query", "schema", "sqlite"]) {
314
+ try {
315
+ const localVersion = this.getLocalVersion(binDir, prefix);
316
+ const remoteVersion = await this.fetchLatestVersion(prefix);
317
+ const needsUpdate = this.isNewerVersion(localVersion, remoteVersion);
318
+ binariesToProcess.push({
319
+ prefix,
320
+ needsUpdate,
321
+ localVersion,
322
+ remoteVersion
323
+ });
324
+ if (needsUpdate) {
325
+ console.log(`
326
+ \u{1F4E6} ${prefix}-engine: ${localVersion || "not installed"} \u2192 ${remoteVersion}`);
327
+ } else if (localVersion) {
328
+ console.log(`
329
+ \u2705 ${prefix}-engine: ${localVersion} (up to date)`);
330
+ }
331
+ } catch (error) {
332
+ console.warn(`\u26A0\uFE0F Could not check version for ${prefix}-engine, will attempt download`);
333
+ binariesToProcess.push({
334
+ prefix,
335
+ needsUpdate: true,
336
+ localVersion: null,
337
+ remoteVersion: "latest"
338
+ });
190
339
  }
191
- binariesToDownload.push({
192
- prefix,
193
- binaryInfo,
194
- tempZipPath: path.join(os2.tmpdir(), `dbcube-${prefix}-${Date.now()}.zip`),
195
- finalBinaryPath
196
- });
197
340
  }
341
+ const binariesToDownload = binariesToProcess.filter((b) => b.needsUpdate);
198
342
  if (binariesToDownload.length === 0) {
199
- this.mainSpinner.succeed(chalk.green("Todos los binarios ya est\xE1n descargados"));
343
+ this.mainSpinner.succeed(chalk.green("All binaries are up to date"));
200
344
  return;
201
345
  }
202
- this.updateMainProgress("paralelo", existingCount, binaries.length, "downloading");
346
+ this.mainSpinner.text = chalk.blue(`Updating ${binariesToDownload.length} binary(ies)...`);
203
347
  try {
204
- await Promise.all(binariesToDownload.map(async (binary, index) => {
348
+ await Promise.all(binariesToDownload.map(async (binary) => {
205
349
  const maxRetries = 3;
206
350
  let attempt = 0;
207
351
  while (attempt <= maxRetries) {
208
352
  try {
209
- await this.downloadFileWithProgress(binary.binaryInfo.url, binary.tempZipPath, binary.prefix);
210
- await this.extractBinary(binary.tempZipPath, binary.finalBinaryPath, binary.prefix);
211
- const completed = existingCount + index + 1;
212
- this.updateMainProgress(binary.prefix, completed, binaries.length, "completed");
353
+ const binaryInfo = await this.getWithVersion(binary.prefix);
354
+ if (!binaryInfo.name || !binaryInfo.url) {
355
+ throw new Error(`Platform or architecture not supported for ${binary.prefix}`);
356
+ }
357
+ const tempZipPath = path.join(os2.tmpdir(), `dbcube-${binary.prefix}-${Date.now()}.zip`);
358
+ const finalBinaryPath = path.join(binDir, binaryInfo.name);
359
+ this.deleteOldBinary(binDir, binary.prefix);
360
+ await this.downloadFileWithProgress(binaryInfo.url, tempZipPath, binary.prefix);
361
+ await this.extractBinary(tempZipPath, finalBinaryPath, binary.prefix);
362
+ console.log(`\u2705 ${binary.prefix}-engine updated to ${binary.remoteVersion}`);
213
363
  break;
214
364
  } catch (error) {
215
- const errorMessage = error instanceof Error ? error.message : "Error desconocido";
365
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
216
366
  if (attempt < maxRetries && (errorMessage.includes("ECONNRESET") || errorMessage.includes("timeout") || errorMessage.includes("ETIMEDOUT") || errorMessage.includes("ENOTFOUND"))) {
217
367
  attempt++;
218
- this.updateMainProgress(binary.prefix, existingCount, binaries.length, "retrying", attempt);
368
+ console.log(`\u{1F504} Retrying ${binary.prefix}-engine (${attempt}/${maxRetries})...`);
219
369
  await new Promise((resolve5) => setTimeout(resolve5, 1e3 + Math.random() * 1e3));
220
370
  } else {
221
- throw new Error(`Error descargando ${binary.prefix}: ${errorMessage}`);
371
+ throw new Error(`Error downloading ${binary.prefix}: ${errorMessage}`);
222
372
  }
223
373
  }
224
374
  }
225
375
  }));
226
- this.mainSpinner.succeed(chalk.green("Binarios descargados correctamente"));
376
+ this.mainSpinner.succeed(chalk.green("Binaries updated successfully"));
227
377
  } catch (error) {
228
- const errorMessage = error instanceof Error ? error.message : "Error desconocido";
229
- this.mainSpinner.fail(chalk.red(`Error en descarga paralela: ${errorMessage}`));
378
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
379
+ this.mainSpinner.fail(chalk.red(`Error updating binaries: ${errorMessage}`));
230
380
  throw error;
231
381
  }
232
382
  }
@@ -361,6 +511,8 @@ var Downloader = class {
361
511
  }
362
512
  }
363
513
  static getDefaultBinDir() {
514
+ const __filename2 = typeof import.meta !== "undefined" && import.meta.url ? fileURLToPath(import.meta.url) : "";
515
+ const __dirname = __filename2 ? dirname(__filename2) : process.cwd();
364
516
  const possibleDirs = [
365
517
  path.resolve(process.cwd(), ".dbcube", "bin"),
366
518
  path.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
@@ -389,25 +541,18 @@ var Downloader = class {
389
541
  import * as fs2 from "fs";
390
542
  import * as path2 from "path";
391
543
  import * as os3 from "os";
544
+ import { fileURLToPath as fileURLToPath2 } from "url";
545
+ import { dirname as dirname2 } from "path";
392
546
  var Binary = class {
393
547
  static isDownloading = false;
394
548
  static downloadPromise = null;
549
+ static cachedBinaries = {};
395
550
  static async ensureBinariesExist() {
396
551
  if (this.isDownloading && this.downloadPromise) {
397
552
  await this.downloadPromise;
398
553
  return;
399
554
  }
400
555
  const binDir = this.getBinDir();
401
- const binaries = ["schema", "query", "sqlite"];
402
- const allExist = binaries.every((prefix) => {
403
- const binaryInfo = Downloader.get(prefix);
404
- if (!binaryInfo.name) return false;
405
- const binaryPath = path2.join(binDir, binaryInfo.name);
406
- return fs2.existsSync(binaryPath);
407
- });
408
- if (allExist) {
409
- return;
410
- }
411
556
  if (!this.isDownloading) {
412
557
  this.isDownloading = true;
413
558
  this.downloadPromise = this.downloadBinaries();
@@ -429,6 +574,8 @@ var Binary = class {
429
574
  }
430
575
  }
431
576
  static getBinDir() {
577
+ const __filename2 = typeof import.meta !== "undefined" && import.meta.url ? fileURLToPath2(import.meta.url) : "";
578
+ const __dirname = __filename2 ? dirname2(__filename2) : process.cwd();
432
579
  const possibleDirs = [
433
580
  path2.resolve(process.cwd(), ".dbcube", "bin"),
434
581
  path2.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
@@ -448,58 +595,50 @@ var Binary = class {
448
595
  fs2.mkdirSync(tempDir, { recursive: true });
449
596
  return tempDir;
450
597
  }
598
+ static findVersionedBinary(binDir, prefix, platform2, arch2) {
599
+ const cacheKey = `${prefix}-${platform2}-${arch2}`;
600
+ if (this.cachedBinaries[cacheKey]) {
601
+ const cachedPath = path2.join(binDir, this.cachedBinaries[cacheKey]);
602
+ if (fs2.existsSync(cachedPath)) {
603
+ return cachedPath;
604
+ }
605
+ }
606
+ try {
607
+ const files = fs2.readdirSync(binDir);
608
+ const extension = platform2 === "windows" ? ".exe" : "";
609
+ const pattern = new RegExp(`^${prefix}-engine-v\\d+\\.\\d+\\.\\d+-${platform2}-${arch2}${extension.replace(".", "\\.")}$`);
610
+ const matchingFile = files.find((f) => pattern.test(f));
611
+ if (matchingFile) {
612
+ this.cachedBinaries[cacheKey] = matchingFile;
613
+ return path2.join(binDir, matchingFile);
614
+ }
615
+ } catch (error) {
616
+ }
617
+ const fallbackName = `${prefix}-engine-${platform2}-${arch2}${platform2 === "windows" ? ".exe" : ""}`;
618
+ return path2.join(binDir, fallbackName);
619
+ }
451
620
  static async get() {
452
621
  await this.ensureBinariesExist();
453
622
  const arch2 = new Arquitecture();
454
623
  const platform2 = arch2.getPlatform();
455
624
  const architecture = arch2.getArchitecture();
456
625
  const binDir = this.getBinDir();
457
- const getFullPath = (binaryName) => {
458
- return path2.join(binDir, binaryName);
626
+ const platformMap = {
627
+ windows: "windows",
628
+ linux: "linux",
629
+ darwin: "macos"
459
630
  };
460
- switch (platform2) {
461
- case "windows":
462
- if (architecture == "x86_64") {
463
- return {
464
- query_engine: getFullPath("query-engine-windows-x64.exe"),
465
- schema_engine: getFullPath("schema-engine-windows-x64.exe")
466
- };
467
- }
468
- if (architecture == "aarch64") {
469
- return {
470
- query_engine: getFullPath("query-engine-windows-arm64.exe"),
471
- schema_engine: getFullPath("schema-engine-windows-arm64.exe")
472
- };
473
- }
474
- break;
475
- case "linux":
476
- if (architecture == "x86_64") {
477
- return {
478
- query_engine: getFullPath("query-engine-linux-x64"),
479
- schema_engine: getFullPath("schema-engine-linux-x64")
480
- };
481
- }
482
- if (architecture == "aarch64") {
483
- return {
484
- query_engine: getFullPath("query-engine-linux-arm64"),
485
- schema_engine: getFullPath("schema-engine-linux-arm64")
486
- };
487
- }
488
- break;
489
- case "macos":
490
- if (architecture == "x86_64") {
491
- return {
492
- query_engine: getFullPath("query-engine-macos-x64"),
493
- schema_engine: getFullPath("schema-engine-macos-x64")
494
- };
495
- }
496
- if (architecture == "aarch64") {
497
- return {
498
- query_engine: getFullPath("query-engine-macos-arm64"),
499
- schema_engine: getFullPath("schema-engine-macos-arm64")
500
- };
501
- }
502
- break;
631
+ const archMap = {
632
+ x86_64: "x64",
633
+ aarch64: "arm64"
634
+ };
635
+ const plat = platformMap[platform2];
636
+ const archSuffix = archMap[architecture];
637
+ if (plat && archSuffix) {
638
+ return {
639
+ query_engine: this.findVersionedBinary(binDir, "query", plat, archSuffix),
640
+ schema_engine: this.findVersionedBinary(binDir, "schema", plat, archSuffix)
641
+ };
503
642
  }
504
643
  return {
505
644
  query_engine: "",
@@ -1291,6 +1430,8 @@ import * as path5 from "path";
1291
1430
  import * as fs3 from "fs";
1292
1431
  import { promisify } from "util";
1293
1432
  import { createRequire as createRequire3 } from "module";
1433
+ import { fileURLToPath as fileURLToPath3 } from "url";
1434
+ import { dirname as dirname3 } from "path";
1294
1435
  var execAsync = promisify(exec);
1295
1436
  var SqliteExecutor = class {
1296
1437
  binaryPath;
@@ -1300,6 +1441,8 @@ var SqliteExecutor = class {
1300
1441
  this.binaryPath = this.getBinaryPath();
1301
1442
  }
1302
1443
  getBinaryPath() {
1444
+ const __filename2 = typeof import.meta !== "undefined" && import.meta.url ? fileURLToPath3(import.meta.url) : "";
1445
+ const __dirname = __filename2 ? dirname3(__filename2) : process.cwd();
1303
1446
  const possibleDirs = [
1304
1447
  path5.resolve(process.cwd(), ".dbcube", "bin"),
1305
1448
  path5.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
@@ -1422,7 +1565,8 @@ var SqliteExecutor = class {
1422
1565
  }
1423
1566
  // Para compatibilidad con better-sqlite3 API sincrona usando deasync si es necesario
1424
1567
  prepareSync(sql) {
1425
- const requireUrl = typeof __filename !== "undefined" ? __filename : process.cwd();
1568
+ const __filename2 = typeof import.meta !== "undefined" && import.meta.url ? fileURLToPath3(import.meta.url) : "";
1569
+ const requireUrl = __filename2 || import.meta.url;
1426
1570
  const require2 = createRequire3(requireUrl);
1427
1571
  const deasync = require2("deasync");
1428
1572
  return {