planche 0.5.1 → 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.
- package/README.md +1 -0
- package/dist/index.js +83 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,6 +40,7 @@ npx planche [options]
|
|
|
40
40
|
-p, --port <n> Port to listen on (default: 8888)
|
|
41
41
|
--addr <host> Address to bind (default: 127.0.0.1)
|
|
42
42
|
--token <str> Auth token (default: random on each start)
|
|
43
|
+
--print-token Print the token (hidden by default; the pairing link is enough)
|
|
43
44
|
--no-open Print the pairing link without opening a browser
|
|
44
45
|
--verbose Log every request
|
|
45
46
|
-h, --help Show help
|
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
|
-
|
|
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
|
});
|
|
@@ -1879,6 +1957,7 @@ Options:
|
|
|
1879
1957
|
-p, --port <n> Port to listen on (default: 8888, env PLANCHE_PORT)
|
|
1880
1958
|
--addr <host> Address to bind (default: 127.0.0.1, env PLANCHE_ADDR)
|
|
1881
1959
|
--token <str> Auth token (default: random, env PLANCHE_AUTH_TOKEN)
|
|
1960
|
+
--print-token Print the token (for manual setup); hidden by default
|
|
1882
1961
|
--app <url> Web app to open (default: ${DEFAULT_APP_URL}, env PLANCHE_APP_URL)
|
|
1883
1962
|
--origin <url> Extra browser origin allowed to use the agent (repeatable,
|
|
1884
1963
|
env PLANCHE_ALLOWED_ORIGINS as a comma-separated list)
|
|
@@ -1931,6 +2010,7 @@ function main() {
|
|
|
1931
2010
|
open: { type: "boolean" },
|
|
1932
2011
|
verbose: { type: "boolean" },
|
|
1933
2012
|
"allow-remote": { type: "boolean" },
|
|
2013
|
+
"print-token": { type: "boolean" },
|
|
1934
2014
|
version: { type: "boolean", short: "v" },
|
|
1935
2015
|
help: { type: "boolean", short: "h" }
|
|
1936
2016
|
},
|
|
@@ -2011,7 +2091,8 @@ function main() {
|
|
|
2011
2091
|
|
|
2012
2092
|
${pairUrl}
|
|
2013
2093
|
`);
|
|
2014
|
-
|
|
2094
|
+
if (flags["print-token"]) console.log(`Auth token: ${authToken}`);
|
|
2095
|
+
else console.log(tokenFromEnv ? "Auth token: (from PLANCHE_AUTH_TOKEN)" : "Auth token: hidden \u2014 run with --print-token to show it for manual setup");
|
|
2015
2096
|
console.log(`Allowed origins: ${allowedOrigins.join(", ")}`);
|
|
2016
2097
|
if (!loopback) {
|
|
2017
2098
|
console.error(`WARNING: bound to ${addr} without TLS \u2014 anyone who can reach this port and knows the token can use your databases, and anyone on the path can read the traffic.`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "planche",
|
|
3
|
-
"version": "0.5.
|
|
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",
|