pipely-ai 1.4.4 → 1.5.0

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.
Files changed (2) hide show
  1. package/index.js +82 -17
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -6,6 +6,7 @@ import { randomBytes, randomUUID } from "node:crypto";
6
6
  import { execSync, fork } from "node:child_process";
7
7
  import { writeFileSync, readFileSync, existsSync, mkdirSync, unlinkSync, rmSync, createWriteStream } from "node:fs";
8
8
  import { join } from "node:path";
9
+ import { pathToFileURL } from "node:url";
9
10
  import { platform, release, arch } from "node:os";
10
11
  import http from "node:http";
11
12
  import https from "node:https";
@@ -515,15 +516,18 @@ function isLocalInstalled() {
515
516
  return existsSync(join(bd, "package.json")) && existsSync(join(bd, "server"));
516
517
  }
517
518
 
519
+ const EP_PORT = 5433;
520
+ const EP_USER = "pipely";
521
+ const EP_DB = "pipely_ai";
522
+
518
523
  function generateLocalEnv() {
519
524
  const jwtSecret = generateKey(64);
520
525
  const setupKey = randomUUID();
521
- const dir = getLocalDir();
522
-
523
- const dbPath = join(dir, "data", "pipely.db").replace(/\\/g, "/").replace(/ /g, "%20");
526
+ const dbPassword = generateKey(16);
524
527
  const frontendPath = join(getBundleDir(), "frontend").replace(/\\/g, "/");
525
528
  const env = `# Pipely AI — Local Mode
526
- DATABASE_URL=file:${dbPath}
529
+ DATABASE_URL=postgresql://${EP_USER}:${dbPassword}@127.0.0.1:${EP_PORT}/${EP_DB}
530
+ DB_PASSWORD=${dbPassword}
527
531
  JWT_SECRET=${jwtSecret}
528
532
  OWNER_SETUP_KEY=${setupKey}
529
533
  FRONTEND_URL=http://localhost:3333
@@ -535,6 +539,36 @@ PORT=3333
535
539
  return { env, setupKey };
536
540
  }
537
541
 
542
+ async function loadEmbeddedPostgres(bundleDir) {
543
+ const epEntry = join(bundleDir, "node_modules", "embedded-postgres", "index.js");
544
+ const mod = await import(pathToFileURL(epEntry).href);
545
+ return mod.default;
546
+ }
547
+
548
+ async function startPostgres(bundleDir, dataDir, password) {
549
+ const EmbeddedPostgres = await loadEmbeddedPostgres(bundleDir);
550
+ const pg = new EmbeddedPostgres({
551
+ databaseDir: dataDir,
552
+ user: EP_USER,
553
+ password: password,
554
+ port: EP_PORT,
555
+ persistent: true,
556
+ });
557
+
558
+ const needsInit = !existsSync(join(dataDir, "PG_VERSION"));
559
+ if (needsInit) {
560
+ await pg.initialise();
561
+ }
562
+
563
+ await pg.start();
564
+
565
+ if (needsInit) {
566
+ try { await pg.createDatabase(EP_DB); } catch {}
567
+ }
568
+
569
+ return pg;
570
+ }
571
+
538
572
  async function installLocal() {
539
573
  const os = detectOS();
540
574
  const dir = getLocalDir();
@@ -544,7 +578,7 @@ async function installLocal() {
544
578
  if (isLocalInstalled()) {
545
579
  console.log(` ${c.green}✓${c.reset} Pipely AI ja instalado em ${c.dim}${dir}${c.reset}\n`);
546
580
  console.log(` Iniciando...\n`);
547
- return runLocal();
581
+ return runLocal(null);
548
582
  }
549
583
 
550
584
  // Download bundle
@@ -607,17 +641,30 @@ async function installLocal() {
607
641
  writeFileSync(getLocalEnvPath(), envContent);
608
642
  console.log(` ${c.green}✓${c.reset} .env gerado`);
609
643
 
610
- // Create data directory
611
- mkdirSync(join(dir, "data"), { recursive: true });
644
+ // Parse DB_PASSWORD from generated env
645
+ const dbPassword = envContent.match(/DB_PASSWORD=(.+)/)?.[1] || generateKey(16);
646
+ const dataDir = join(dir, "data", "db");
647
+
648
+ // Start embedded PostgreSQL
649
+ process.stdout.write(` Iniciando PostgreSQL... `);
650
+ let pg;
651
+ try {
652
+ pg = await startPostgres(bundleDir, dataDir, dbPassword);
653
+ console.log(`${c.green}✓${c.reset}`);
654
+ } catch (err) {
655
+ console.log(`${c.red}✗${c.reset}`);
656
+ console.log(` ${c.red}Erro: ${err.message}${c.reset}\n`);
657
+ process.exit(1);
658
+ }
612
659
 
613
- // Setup database
614
- const dbPath = join(dir, "data", "pipely.db").replace(/\\/g, "/").replace(/ /g, "%20");
615
- process.stdout.write(` Criando banco de dados... `);
660
+ // Setup database schema
661
+ const databaseUrl = `postgresql://${EP_USER}:${dbPassword}@127.0.0.1:${EP_PORT}/${EP_DB}`;
662
+ process.stdout.write(` Criando tabelas... `);
616
663
  try {
617
664
  execSync("npx prisma db push", {
618
665
  cwd: join(bundleDir, "server"),
619
666
  stdio: "pipe",
620
- env: { ...process.env, DATABASE_URL: `file:${dbPath}` },
667
+ env: { ...process.env, DATABASE_URL: databaseUrl },
621
668
  });
622
669
  console.log(`${c.green}✓${c.reset}`);
623
670
  } catch (err) {
@@ -628,7 +675,7 @@ async function installLocal() {
628
675
  console.log(`\n ${c.green}✓${c.reset} Instalacao concluida\n`);
629
676
 
630
677
  printLocalSummary(setupKey, dir);
631
- return runLocal();
678
+ return runLocal(pg);
632
679
  }
633
680
 
634
681
  function printLocalSummary(setupKey, dir) {
@@ -648,7 +695,7 @@ function printLocalSummary(setupKey, dir) {
648
695
  console.log("");
649
696
  console.log(` ${c.bold}Arquivos:${c.reset}`);
650
697
  console.log(` Diretorio: ${c.dim}${dir}${c.reset}`);
651
- console.log(` Banco de dados: ${c.dim}${join(dir, "data/pipely.db")}${c.reset}`);
698
+ console.log(` Banco de dados: ${c.dim}PostgreSQL (porta ${EP_PORT})${c.reset}`);
652
699
  console.log(` Configuracao: ${c.dim}${join(dir, ".env")}${c.reset}`);
653
700
  console.log("");
654
701
  console.log(` ${c.bold}Proximo passo:${c.reset}`);
@@ -666,12 +713,13 @@ function printLocalSummary(setupKey, dir) {
666
713
  console.log("");
667
714
  }
668
715
 
669
- async function runLocal() {
716
+ async function runLocal(existingPg) {
670
717
  if (!isLocalInstalled()) {
671
718
  console.log(` ${c.red}✗ Pipely AI nao instalado. Execute: npx pipely-ai${c.reset}\n`);
672
719
  process.exit(1);
673
720
  }
674
721
 
722
+ const dir = getLocalDir();
675
723
  const bundleDir = getBundleDir();
676
724
 
677
725
  const line = "═".repeat(56);
@@ -688,6 +736,22 @@ async function runLocal() {
688
736
  if (match) envVars[match[1]] = match[2];
689
737
  }
690
738
 
739
+ // Start embedded PostgreSQL if not already running
740
+ let pg = existingPg;
741
+ if (!pg) {
742
+ const dbPassword = envVars.DB_PASSWORD || "";
743
+ const dataDir = join(dir, "data", "db");
744
+ process.stdout.write(` Iniciando PostgreSQL... `);
745
+ try {
746
+ pg = await startPostgres(bundleDir, dataDir, dbPassword);
747
+ console.log(`${c.green}✓${c.reset}`);
748
+ } catch (err) {
749
+ console.log(`${c.red}✗${c.reset}`);
750
+ console.log(` ${c.red}Erro: ${err.message}${c.reset}\n`);
751
+ process.exit(1);
752
+ }
753
+ }
754
+
691
755
  const childEnv = { ...process.env, ...envVars };
692
756
 
693
757
  // Copy .env to bundle subdirs so dotenv/config finds it
@@ -726,17 +790,18 @@ async function runLocal() {
726
790
  console.log(` ${c.green}${line}${c.reset}`);
727
791
  console.log("");
728
792
 
729
- function shutdown() {
793
+ async function shutdown() {
730
794
  console.log(`\n Parando...\n`);
731
795
  server.kill();
732
796
  agent.kill();
797
+ try { await pg.stop(); } catch {}
733
798
  process.exit(0);
734
799
  }
735
800
 
736
801
  process.on("SIGINT", shutdown);
737
802
  process.on("SIGTERM", shutdown);
738
- server.on("exit", (code) => { if (code) { agent.kill(); process.exit(1); } });
739
- agent.on("exit", (code) => { if (code) { server.kill(); process.exit(1); } });
803
+ server.on("exit", (code) => { if (code) { agent.kill(); pg.stop().finally(() => process.exit(1)); } });
804
+ agent.on("exit", (code) => { if (code) { server.kill(); pg.stop().finally(() => process.exit(1)); } });
740
805
 
741
806
  // Keep process alive
742
807
  await new Promise(() => {});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pipely-ai",
3
- "version": "1.4.4",
3
+ "version": "1.5.0",
4
4
  "description": "Pipely AI — Instale, gerencie e atualize com um unico comando",
5
5
  "type": "module",
6
6
  "bin": {