@fileverse/api 0.0.2 → 0.0.4

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/cli/index.js CHANGED
@@ -528,250 +528,247 @@ var init_infra = __esm({
528
528
  }
529
529
  });
530
530
 
531
- // src/infra/database/adapters/sqlite-adapter.ts
532
- import Database from "better-sqlite3";
533
- var SqliteAdapter;
534
- var init_sqlite_adapter = __esm({
535
- "src/infra/database/adapters/sqlite-adapter.ts"() {
531
+ // src/infra/database/adapters/sql-compat.ts
532
+ function sqliteToPostgres(sql) {
533
+ let result = "";
534
+ let paramIndex = 0;
535
+ let inString = false;
536
+ for (let i = 0; i < sql.length; i++) {
537
+ const ch = sql[i];
538
+ if (ch === "'") {
539
+ if (inString && i + 1 < sql.length && sql[i + 1] === "'") {
540
+ result += "''";
541
+ i++;
542
+ continue;
543
+ }
544
+ inString = !inString;
545
+ result += ch;
546
+ } else if (ch === "?" && !inString) {
547
+ paramIndex++;
548
+ result += `$${paramIndex}`;
549
+ } else {
550
+ result += ch;
551
+ }
552
+ }
553
+ return result;
554
+ }
555
+ var init_sql_compat = __esm({
556
+ "src/infra/database/adapters/sql-compat.ts"() {
536
557
  "use strict";
537
558
  init_esm_shims();
559
+ }
560
+ });
561
+
562
+ // src/infra/database/adapters/postgres-adapter.ts
563
+ var postgres_adapter_exports = {};
564
+ __export(postgres_adapter_exports, {
565
+ PostgresAdapter: () => PostgresAdapter
566
+ });
567
+ async function getPg() {
568
+ if (!pgModule) {
569
+ pgModule = await import("pg");
570
+ }
571
+ return pgModule;
572
+ }
573
+ var pgModule, PostgresAdapter;
574
+ var init_postgres_adapter = __esm({
575
+ "src/infra/database/adapters/postgres-adapter.ts"() {
576
+ "use strict";
577
+ init_esm_shims();
578
+ init_sql_compat();
538
579
  init_infra();
539
- init_config();
540
- SqliteAdapter = class {
541
- db;
542
- constructor(dbPath) {
543
- this.db = new Database(dbPath, {
544
- verbose: config.NODE_ENV === "development" ? (msg) => logger.debug(String(msg)) : void 0
545
- });
546
- this.db.pragma("journal_mode = WAL");
547
- this.db.pragma("foreign_keys = ON");
548
- this.db.prepare("SELECT 1").get();
549
- logger.info(`SQLite database connected: ${dbPath}`);
580
+ pgModule = null;
581
+ PostgresAdapter = class {
582
+ pool = null;
583
+ connectionUrl;
584
+ connected = false;
585
+ dialect = "postgres";
586
+ constructor(connectionUrl) {
587
+ this.connectionUrl = connectionUrl;
588
+ }
589
+ async getPool() {
590
+ if (!this.pool) {
591
+ const pg = await getPg();
592
+ this.pool = new pg.default.Pool({
593
+ connectionString: this.connectionUrl,
594
+ max: 10,
595
+ ssl: this.connectionUrl.includes("sslmode=require") || this.connectionUrl.includes("amazonaws.com") || this.connectionUrl.includes("heroku") ? { rejectUnauthorized: false } : void 0
596
+ });
597
+ const client = await this.pool.connect();
598
+ client.release();
599
+ this.connected = true;
600
+ logger.info("PostgreSQL database connected");
601
+ }
602
+ return this.pool;
550
603
  }
551
604
  async select(sql, params = []) {
552
- const stmt = this.db.prepare(sql);
553
- return stmt.all(params);
605
+ const pool = await this.getPool();
606
+ const pgSql = sqliteToPostgres(sql);
607
+ const result = await pool.query(pgSql, params);
608
+ return result.rows;
554
609
  }
555
610
  async selectOne(sql, params = []) {
556
- const stmt = this.db.prepare(sql);
557
- return stmt.get(params);
611
+ const pool = await this.getPool();
612
+ const pgSql = sqliteToPostgres(sql);
613
+ const result = await pool.query(pgSql, params);
614
+ return result.rows[0] ?? void 0;
558
615
  }
559
616
  async execute(sql, params = []) {
560
- const stmt = this.db.prepare(sql);
561
- const result = stmt.run(params);
617
+ const pool = await this.getPool();
618
+ const pgSql = sqliteToPostgres(sql);
619
+ const result = await pool.query(pgSql, params);
562
620
  return {
563
- changes: result.changes,
564
- lastInsertRowid: result.lastInsertRowid
621
+ changes: result.rowCount ?? 0,
622
+ lastInsertRowid: 0
565
623
  };
566
624
  }
567
625
  async transaction(callback) {
568
- this.db.exec("SAVEPOINT txn");
626
+ const pool = await this.getPool();
627
+ const client = await pool.connect();
569
628
  try {
570
- const result = await callback(this);
571
- this.db.exec("RELEASE txn");
629
+ await client.query("BEGIN");
630
+ const result = await callback();
631
+ await client.query("COMMIT");
572
632
  return result;
573
- } catch (err) {
574
- this.db.exec("ROLLBACK TO txn");
575
- throw err;
633
+ } catch (error) {
634
+ await client.query("ROLLBACK");
635
+ throw error;
636
+ } finally {
637
+ client.release();
576
638
  }
577
639
  }
578
640
  async exec(sql) {
579
- this.db.exec(sql);
641
+ const pool = await this.getPool();
642
+ await pool.query(sql);
580
643
  }
581
644
  async close() {
582
- this.db.close();
583
- logger.info("Database connection closed");
645
+ if (this.pool) {
646
+ await this.pool.end();
647
+ this.pool = null;
648
+ this.connected = false;
649
+ logger.info("Database connection closed");
650
+ }
651
+ }
652
+ isConnected() {
653
+ return this.connected;
584
654
  }
585
655
  };
586
656
  }
587
657
  });
588
658
 
589
- // src/infra/database/adapters/pg-adapter.ts
590
- import pg from "pg";
591
- function translateParams(sql) {
592
- let idx = 0;
593
- return sql.replace(/\?/g, () => `$${++idx}`);
594
- }
595
- function mapRow(row) {
596
- const mapped = {};
597
- for (const [key, value] of Object.entries(row)) {
598
- const mappedKey = COLUMN_NAME_MAP[key] ?? key;
599
- mapped[mappedKey] = value instanceof Date ? value.toISOString() : value;
600
- }
601
- return mapped;
602
- }
603
- var Pool, COLUMN_NAME_MAP, PgClientAdapter, PgAdapter;
604
- var init_pg_adapter = __esm({
605
- "src/infra/database/adapters/pg-adapter.ts"() {
659
+ // src/infra/database/adapters/sqlite-adapter.ts
660
+ var sqlite_adapter_exports = {};
661
+ __export(sqlite_adapter_exports, {
662
+ SqliteAdapter: () => SqliteAdapter
663
+ });
664
+ import Database from "better-sqlite3";
665
+ var SqliteAdapter;
666
+ var init_sqlite_adapter = __esm({
667
+ "src/infra/database/adapters/sqlite-adapter.ts"() {
606
668
  "use strict";
607
669
  init_esm_shims();
608
670
  init_infra();
609
- ({ Pool } = pg);
610
- COLUMN_NAME_MAP = {
611
- ddocid: "ddocId",
612
- localversion: "localVersion",
613
- onchainversion: "onchainVersion",
614
- syncstatus: "syncStatus",
615
- isdeleted: "isDeleted",
616
- onchainfileid: "onChainFileId",
617
- portaladdress: "portalAddress",
618
- createdat: "createdAt",
619
- updatedat: "updatedAt",
620
- linkkey: "linkKey",
621
- linkkeynonce: "linkKeyNonce",
622
- commentkey: "commentKey",
623
- portalseed: "portalSeed",
624
- owneraddress: "ownerAddress",
625
- apikeyseed: "apiKeySeed",
626
- collaboratoraddress: "collaboratorAddress",
627
- fileid: "fileId",
628
- retrycount: "retryCount",
629
- lasterror: "lastError",
630
- lockedat: "lockedAt",
631
- nextretryat: "nextRetryAt",
632
- userophash: "userOpHash",
633
- pendingpayload: "pendingPayload",
634
- folderid: "folderId",
635
- folderref: "folderRef",
636
- foldername: "folderName",
637
- metadataipfshash: "metadataIPFSHash",
638
- contentipfshash: "contentIPFSHash",
639
- lasttransactionhash: "lastTransactionHash",
640
- lasttransactionblocknumber: "lastTransactionBlockNumber",
641
- lasttransactionblocktimestamp: "lastTransactionBlockTimestamp",
642
- created_at: "created_at",
643
- updated_at: "updated_at"
644
- };
645
- PgClientAdapter = class {
646
- constructor(client) {
647
- this.client = client;
648
- }
649
- async select(sql, params = []) {
650
- const result = await this.client.query(translateParams(sql), params);
651
- return result.rows.map((row) => mapRow(row));
652
- }
653
- async selectOne(sql, params = []) {
654
- const result = await this.client.query(translateParams(sql), params);
655
- return result.rows[0] ? mapRow(result.rows[0]) : void 0;
656
- }
657
- async execute(sql, params = []) {
658
- const result = await this.client.query(translateParams(sql), params);
659
- return { changes: result.rowCount ?? 0, lastInsertRowid: 0 };
671
+ SqliteAdapter = class {
672
+ constructor(dbPath) {
673
+ this.dbPath = dbPath;
660
674
  }
661
- async transaction(callback) {
662
- await this.client.query("SAVEPOINT nested_txn");
663
- try {
664
- const result = await callback(this);
665
- await this.client.query("RELEASE SAVEPOINT nested_txn");
666
- return result;
667
- } catch (err) {
668
- await this.client.query("ROLLBACK TO SAVEPOINT nested_txn");
669
- throw err;
675
+ db = null;
676
+ dialect = "sqlite";
677
+ getDb() {
678
+ if (!this.db) {
679
+ this.db = new Database(this.dbPath);
680
+ this.db.pragma("journal_mode = WAL");
681
+ this.db.pragma("foreign_keys = ON");
682
+ this.db.prepare("SELECT 1").get();
683
+ logger.info(`SQLite database connected: ${this.dbPath}`);
670
684
  }
671
- }
672
- async exec(sql) {
673
- await this.client.query(sql);
674
- }
675
- async close() {
676
- }
677
- };
678
- PgAdapter = class {
679
- pool;
680
- constructor(connectionString) {
681
- const url = new URL(connectionString);
682
- const isLocal = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "::1";
683
- const sslDisabled = connectionString.includes("sslmode=disable");
684
- const needsSsl = !isLocal && !sslDisabled;
685
- this.pool = new Pool({
686
- connectionString,
687
- // pg requires password to be a string; local trust/peer auth uses empty string
688
- password: url.password || "",
689
- max: 20,
690
- idleTimeoutMillis: 3e4,
691
- ssl: needsSsl ? { rejectUnauthorized: false } : void 0
692
- });
693
- logger.info(`PostgreSQL pool created (ssl: ${needsSsl ? "on" : "off"})`);
685
+ return this.db;
694
686
  }
695
687
  async select(sql, params = []) {
696
- const result = await this.pool.query(translateParams(sql), params);
697
- return result.rows.map((row) => mapRow(row));
688
+ const stmt = this.getDb().prepare(sql);
689
+ return stmt.all(params);
698
690
  }
699
691
  async selectOne(sql, params = []) {
700
- const result = await this.pool.query(translateParams(sql), params);
701
- return result.rows[0] ? mapRow(result.rows[0]) : void 0;
692
+ const stmt = this.getDb().prepare(sql);
693
+ return stmt.get(params);
702
694
  }
703
695
  async execute(sql, params = []) {
704
- const result = await this.pool.query(translateParams(sql), params);
705
- return { changes: result.rowCount ?? 0, lastInsertRowid: 0 };
696
+ const stmt = this.getDb().prepare(sql);
697
+ const result = stmt.run(params);
698
+ return {
699
+ changes: result.changes,
700
+ lastInsertRowid: result.lastInsertRowid
701
+ };
706
702
  }
707
703
  async transaction(callback) {
708
- const client = await this.pool.connect();
704
+ const db = this.getDb();
705
+ const savepointName = `sp_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
706
+ db.exec(`SAVEPOINT ${savepointName}`);
709
707
  try {
710
- await client.query("BEGIN");
711
- const clientAdapter = new PgClientAdapter(client);
712
- const result = await callback(clientAdapter);
713
- await client.query("COMMIT");
708
+ const result = await callback();
709
+ db.exec(`RELEASE ${savepointName}`);
714
710
  return result;
715
- } catch (err) {
716
- await client.query("ROLLBACK");
717
- throw err;
718
- } finally {
719
- client.release();
711
+ } catch (error) {
712
+ db.exec(`ROLLBACK TO ${savepointName}`);
713
+ db.exec(`RELEASE ${savepointName}`);
714
+ throw error;
720
715
  }
721
716
  }
722
717
  async exec(sql) {
723
- await this.pool.query(sql);
718
+ this.getDb().exec(sql);
724
719
  }
725
720
  async close() {
726
- await this.pool.end();
727
- logger.info("PostgreSQL pool closed");
721
+ if (this.db) {
722
+ this.db.close();
723
+ this.db = null;
724
+ logger.info("Database connection closed");
725
+ }
726
+ }
727
+ isConnected() {
728
+ return this.db !== null && this.db.open;
728
729
  }
729
730
  };
730
731
  }
731
732
  });
732
733
 
733
734
  // src/infra/database/connection.ts
734
- var connection_exports = {};
735
- __export(connection_exports, {
736
- closeAdapter: () => closeAdapter,
737
- getAdapter: () => getAdapter,
738
- getAdapterSync: () => getAdapterSync
739
- });
740
- async function getAdapter() {
735
+ import path5 from "path";
736
+ import fs3 from "fs";
737
+ async function initializeAdapter() {
741
738
  if (adapter) return adapter;
742
- const databaseUrl = config.DATABASE_URL;
743
- const dbPath = config.DB_PATH;
739
+ const databaseUrl = process.env.DATABASE_URL;
740
+ const dbPath = process.env.DB_PATH;
744
741
  if (databaseUrl) {
745
- adapter = new PgAdapter(databaseUrl);
742
+ const { PostgresAdapter: PostgresAdapter2 } = await Promise.resolve().then(() => (init_postgres_adapter(), postgres_adapter_exports));
743
+ adapter = new PostgresAdapter2(databaseUrl);
744
+ logger.info("Using PostgreSQL adapter");
746
745
  } else if (dbPath) {
747
- adapter = new SqliteAdapter(dbPath);
746
+ const dbDir = path5.dirname(dbPath.trim());
747
+ if (!fs3.existsSync(dbDir)) {
748
+ fs3.mkdirSync(dbDir, { recursive: true });
749
+ }
750
+ const { SqliteAdapter: SqliteAdapter2 } = await Promise.resolve().then(() => (init_sqlite_adapter(), sqlite_adapter_exports));
751
+ adapter = new SqliteAdapter2(dbPath);
752
+ logger.info("Using SQLite adapter");
748
753
  } else {
749
- throw new Error("Either DATABASE_URL or DB_PATH must be set");
750
- }
751
- return adapter;
752
- }
753
- function getAdapterSync() {
754
- if (!adapter) {
755
754
  throw new Error(
756
- "Database adapter not initialized. Call getAdapter() at startup first."
755
+ "No database configured. Set DATABASE_URL (PostgreSQL) or DB_PATH (SQLite)."
757
756
  );
758
757
  }
759
758
  return adapter;
760
759
  }
761
- async function closeAdapter() {
762
- if (adapter) {
763
- await adapter.close();
764
- adapter = null;
760
+ async function getAdapter() {
761
+ if (!adapter) {
762
+ return initializeAdapter();
765
763
  }
764
+ return adapter;
766
765
  }
767
766
  var adapter;
768
767
  var init_connection = __esm({
769
768
  "src/infra/database/connection.ts"() {
770
769
  "use strict";
771
770
  init_esm_shims();
772
- init_sqlite_adapter();
773
- init_pg_adapter();
774
- init_config();
771
+ init_infra();
775
772
  adapter = null;
776
773
  }
777
774
  });
@@ -796,16 +793,20 @@ var init_query_builder = __esm({
796
793
  init_constants3();
797
794
  QueryBuilder = class {
798
795
  static async select(sql, params = []) {
799
- return getAdapterSync().select(sql, params);
796
+ const adapter2 = await getAdapter();
797
+ return adapter2.select(sql, params);
800
798
  }
801
799
  static async selectOne(sql, params = []) {
802
- return getAdapterSync().selectOne(sql, params);
800
+ const adapter2 = await getAdapter();
801
+ return adapter2.selectOne(sql, params);
803
802
  }
804
803
  static async execute(sql, params = []) {
805
- return getAdapterSync().execute(sql, params);
804
+ const adapter2 = await getAdapter();
805
+ return adapter2.execute(sql, params);
806
806
  }
807
807
  static async transaction(callback) {
808
- return getAdapterSync().transaction(callback);
808
+ const adapter2 = await getAdapter();
809
+ return adapter2.transaction(callback);
809
810
  }
810
811
  static paginate(sql, options = {}) {
811
812
  let query = sql;
@@ -1017,7 +1018,7 @@ __export(migrations_exports, {
1017
1018
  runMigrations: () => runMigrations
1018
1019
  });
1019
1020
  async function runMigrations() {
1020
- const adapter2 = getAdapterSync();
1021
+ const adapter2 = await getAdapter();
1021
1022
  await adapter2.exec(STABLE_SCHEMA);
1022
1023
  logger.debug("Database schema ready");
1023
1024
  }
@@ -1377,7 +1378,7 @@ var decryptSavedData = async (apiKey, encryptedData) => {
1377
1378
  };
1378
1379
 
1379
1380
  // src/cli/index.ts
1380
- var program = new Command().name("fileverse-api").description("Run the Fileverse API server").version("0.0.2").option("--apiKey <key>", "API key for authentication").option("--rpcUrl <url>", "RPC URL for blockchain connection").option("--port <port>", "Port to run the server on", "8001").option("--db <path>", "Database path").action(async (options) => {
1381
+ var program = new Command().name("fileverse-api").description("Run the Fileverse API server").version("0.0.3").option("--apiKey <key>", "API key for authentication").option("--rpcUrl <url>", "RPC URL for blockchain connection").option("--port <port>", "Port to run the server on", "8001").option("--db <path>", "Database path").action(async (options) => {
1381
1382
  try {
1382
1383
  console.log("Fileverse API - Starting initialization...\n");
1383
1384
  if (needsPrompting(options)) {
@@ -1402,8 +1403,6 @@ var program = new Command().name("fileverse-api").description("Run the Fileverse
1402
1403
  loadConfig();
1403
1404
  console.log(`\u2713 Configuration saved to ${envPath}
1404
1405
  `);
1405
- const { getAdapter: getAdapter2 } = await Promise.resolve().then(() => (init_connection(), connection_exports));
1406
- await getAdapter2();
1407
1406
  const { runMigrations: runMigrations2 } = await Promise.resolve().then(() => (init_migrations(), migrations_exports));
1408
1407
  await runMigrations2();
1409
1408
  console.log("\u2713 Database migrations complete");