planche 0.5.2 → 0.5.3

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/dist/index.js +79 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -526,6 +526,7 @@ var MySqlDriver = class {
526
526
  var mysqlDriverFactory = {
527
527
  async open(config) {
528
528
  const connection = await mysql.createConnection(toConnectionOptions(config));
529
+ connection.on("error", (err) => console.error("[mysql] Connection error:", err.message));
529
530
  return new MySqlDriver(connection, config);
530
531
  },
531
532
  async test(config) {
@@ -719,6 +720,7 @@ var postgresDriverFactory = {
719
720
  async open(config) {
720
721
  const client = new pg.Client(toClientConfig(config));
721
722
  await client.connect();
723
+ client.on("error", (err) => console.error("[postgres] Connection error:", err.message));
722
724
  const driver = new PostgresDriver(client, config);
723
725
  await driver.loadTypeNames();
724
726
  return driver;
@@ -1520,6 +1522,69 @@ function testDirect(config) {
1520
1522
  }
1521
1523
  }
1522
1524
 
1525
+ // src/drivers/connection-lost.ts
1526
+ var ConnectionLostError = class extends Error {
1527
+ status = 404;
1528
+ constructor(message) {
1529
+ super(message);
1530
+ this.name = "ConnectionLostError";
1531
+ }
1532
+ };
1533
+ var LOST_CODES = /* @__PURE__ */ new Set([
1534
+ // mysql2
1535
+ "PROTOCOL_CONNECTION_LOST",
1536
+ "PROTOCOL_ENQUEUE_AFTER_FATAL_ERROR",
1537
+ "PROTOCOL_ENQUEUE_AFTER_QUIT",
1538
+ "PROTOCOL_ENQUEUE_AFTER_DESTROY",
1539
+ // node sockets (pg, mssql/tedious surface these directly)
1540
+ "ECONNRESET",
1541
+ "EPIPE",
1542
+ "ETIMEDOUT",
1543
+ "ECONNABORTED",
1544
+ "ENETUNREACH",
1545
+ "EHOSTUNREACH",
1546
+ "ENETDOWN",
1547
+ // mssql
1548
+ "ESOCKET",
1549
+ "ECLOSE",
1550
+ "ENOTOPEN",
1551
+ // pg: admin_shutdown / crash_shutdown / cannot_connect_now
1552
+ "57P01",
1553
+ "57P02",
1554
+ "57P03"
1555
+ ]);
1556
+ var LOST_MESSAGES = [
1557
+ /connection is in closed state/i,
1558
+ // mysql2 "Can't add new command when connection is in closed state"
1559
+ /connection lost/i,
1560
+ /connection terminated/i,
1561
+ // pg
1562
+ /client has encountered a connection error/i,
1563
+ // pg
1564
+ /client was closed and is not queryable/i,
1565
+ // pg
1566
+ /connection is closed/i,
1567
+ // mssql
1568
+ /socket hang up/i,
1569
+ /ORA-0311[34]\b/,
1570
+ /ORA-01012\b/,
1571
+ /ORA-12541\b/,
1572
+ /ORA-03135\b/,
1573
+ /NJS-500\b/,
1574
+ /NJS-521\b/
1575
+ // oracle
1576
+ ];
1577
+ function isConnectionLost(err) {
1578
+ if (!err || typeof err !== "object") return false;
1579
+ const e = err;
1580
+ if (typeof e.code === "string" && LOST_CODES.has(e.code)) return true;
1581
+ if (e.fatal === true) return true;
1582
+ if (typeof e.errorNum === "number" && [3113, 3114, 1012, 12541, 3135].includes(e.errorNum)) return true;
1583
+ const message = typeof e.message === "string" ? e.message : "";
1584
+ if (LOST_MESSAGES.some((re) => re.test(message))) return true;
1585
+ return e.originalError !== void 0 && e.originalError !== err && isConnectionLost(e.originalError);
1586
+ }
1587
+
1523
1588
  // src/tunneling.ts
1524
1589
  var IDLE_TIMEOUT_MS = Number(process.env.PLANCHE_IDLE_TIMEOUT_MS) || 30 * 60 * 1e3;
1525
1590
  var MAX_CONNECTIONS = Number(process.env.PLANCHE_MAX_CONNECTIONS) || 64;
@@ -1567,7 +1632,16 @@ var ConnectionManager = class {
1567
1632
  throw new Error(`Connection not found: ${connectionId}`);
1568
1633
  }
1569
1634
  this.lastUsed.set(connectionId, Date.now());
1570
- return driver.query(sql2, database);
1635
+ try {
1636
+ return await driver.query(sql2, database);
1637
+ } catch (err) {
1638
+ if (!isConnectionLost(err)) throw err;
1639
+ console.log(`[ConnectionManager] Connection lost, evicting: ${connectionId}`);
1640
+ this.connections.delete(connectionId);
1641
+ this.lastUsed.delete(connectionId);
1642
+ await driver.close().catch(() => void 0);
1643
+ throw new ConnectionLostError(`Connection lost: ${err instanceof Error ? err.message : String(err)}`);
1644
+ }
1571
1645
  }
1572
1646
  /**
1573
1647
  * Close and remove a connection.
@@ -1818,6 +1892,10 @@ function createAgent(options) {
1818
1892
  } catch (err) {
1819
1893
  const message = errorMessage(err);
1820
1894
  console.error("[query] Error:", message);
1895
+ if (err instanceof ConnectionLostError) {
1896
+ fail(res, 404, message);
1897
+ return;
1898
+ }
1821
1899
  fail(res, 422, message);
1822
1900
  }
1823
1901
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "planche",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Local agent for Planche — lets the browser-based Planche SQL client reach MySQL/MariaDB/PostgreSQL/SQLite/SQL Server/Oracle/Neon/Supabase/Cloudflare D1 databases from your machine.",
5
5
  "license": "UNLICENSED",
6
6
  "homepage": "https://planche.dev",