@better-webhook/cli 3.6.0 → 3.8.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.
- package/README.md +10 -4
- package/dist/dashboard/assets/{index-Dlqdzwyc.js → index-CZZLwai4.js} +8 -8
- package/dist/dashboard/index.html +1 -1
- package/dist/index.cjs +63 -21
- package/dist/index.js +63 -21
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>better-webhook dashboard</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-CZZLwai4.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="/assets/index-CxrRCNTh.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
package/dist/index.cjs
CHANGED
|
@@ -1297,11 +1297,13 @@ var CaptureServer = class {
|
|
|
1297
1297
|
captureCount = 0;
|
|
1298
1298
|
enableWebSocket;
|
|
1299
1299
|
onCapture;
|
|
1300
|
+
verbose;
|
|
1300
1301
|
constructor(options) {
|
|
1301
1302
|
const capturesDir = typeof options === "string" ? options : options?.capturesDir;
|
|
1302
1303
|
this.capturesDir = capturesDir || (0, import_path2.join)((0, import_os2.homedir)(), ".better-webhook", "captures");
|
|
1303
1304
|
this.enableWebSocket = typeof options === "object" ? options?.enableWebSocket !== false : true;
|
|
1304
1305
|
this.onCapture = typeof options === "object" ? options?.onCapture : void 0;
|
|
1306
|
+
this.verbose = typeof options === "object" ? options?.verbose === true : false;
|
|
1305
1307
|
if (!(0, import_fs2.existsSync)(this.capturesDir)) {
|
|
1306
1308
|
(0, import_fs2.mkdirSync)(this.capturesDir, { recursive: true });
|
|
1307
1309
|
}
|
|
@@ -1399,7 +1401,16 @@ var CaptureServer = class {
|
|
|
1399
1401
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
1400
1402
|
const id = (0, import_crypto2.randomUUID)();
|
|
1401
1403
|
const url = req.url || "/";
|
|
1402
|
-
const
|
|
1404
|
+
const hostHeader = req.headers.host;
|
|
1405
|
+
const hostValue = typeof hostHeader === "string" ? hostHeader : "";
|
|
1406
|
+
const isHostSafe = /^[a-z0-9.-]+(:\d+)?$/i.test(hostValue);
|
|
1407
|
+
const baseUrl = isHostSafe ? `http://${hostValue}` : "http://localhost";
|
|
1408
|
+
let urlParts;
|
|
1409
|
+
try {
|
|
1410
|
+
urlParts = new URL(url, baseUrl);
|
|
1411
|
+
} catch {
|
|
1412
|
+
urlParts = new URL(url, "http://localhost");
|
|
1413
|
+
}
|
|
1403
1414
|
const query = {};
|
|
1404
1415
|
for (const [key, value] of urlParts.searchParams.entries()) {
|
|
1405
1416
|
if (query[key]) {
|
|
@@ -1459,6 +1470,34 @@ var CaptureServer = class {
|
|
|
1459
1470
|
console.log(
|
|
1460
1471
|
`\u{1F4E6} ${req.method} ${urlParts.pathname}${providerStr} -> ${filename}`
|
|
1461
1472
|
);
|
|
1473
|
+
if (this.verbose) {
|
|
1474
|
+
const headerEntries = Object.entries(req.headers).map(([key, value]) => {
|
|
1475
|
+
if (Array.isArray(value)) {
|
|
1476
|
+
return `${key}: ${value.join(", ")}`;
|
|
1477
|
+
}
|
|
1478
|
+
if (value === void 0) {
|
|
1479
|
+
return `${key}:`;
|
|
1480
|
+
}
|
|
1481
|
+
return `${key}: ${value}`;
|
|
1482
|
+
}).join("\n");
|
|
1483
|
+
const method = req.method || "GET";
|
|
1484
|
+
const providerLabel = provider || "unknown";
|
|
1485
|
+
const contentTypeLabel = contentType || "(none)";
|
|
1486
|
+
console.log(
|
|
1487
|
+
[
|
|
1488
|
+
"[debug] request",
|
|
1489
|
+
`method: ${method}`,
|
|
1490
|
+
`path: ${urlParts.pathname}`,
|
|
1491
|
+
`provider: ${providerLabel}`,
|
|
1492
|
+
`content-type: ${contentTypeLabel}`,
|
|
1493
|
+
`body-length: ${rawBody.length}`,
|
|
1494
|
+
"headers:",
|
|
1495
|
+
headerEntries || "(none)",
|
|
1496
|
+
"raw-body:",
|
|
1497
|
+
rawBody
|
|
1498
|
+
].join("\n")
|
|
1499
|
+
);
|
|
1500
|
+
}
|
|
1462
1501
|
this.onCapture?.({ file: filename, capture: captured });
|
|
1463
1502
|
if (this.enableWebSocket) {
|
|
1464
1503
|
this.broadcast({
|
|
@@ -1594,27 +1633,30 @@ var CaptureServer = class {
|
|
|
1594
1633
|
};
|
|
1595
1634
|
|
|
1596
1635
|
// src/commands/capture.ts
|
|
1597
|
-
var capture = new import_commander3.Command().name("capture").description("Start a server to capture incoming webhooks").option("-p, --port <port>", "Port to listen on", "3001").option("-h, --host <host>", "Host to bind to", "0.0.0.0").
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
await server.
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1636
|
+
var capture = new import_commander3.Command().name("capture").description("Start a server to capture incoming webhooks").option("-p, --port <port>", "Port to listen on", "3001").option("-h, --host <host>", "Host to bind to", "0.0.0.0").option("-v, --verbose", "Show raw request details").option("--debug", "Alias for --verbose").action(
|
|
1637
|
+
async (options) => {
|
|
1638
|
+
const port = parseInt(options.port, 10);
|
|
1639
|
+
if (isNaN(port) || port < 0 || port > 65535) {
|
|
1640
|
+
console.error(import_chalk3.default.red("Invalid port number"));
|
|
1641
|
+
process.exitCode = 1;
|
|
1642
|
+
return;
|
|
1643
|
+
}
|
|
1644
|
+
const verbose = Boolean(options.verbose || options.debug);
|
|
1645
|
+
const server = new CaptureServer({ verbose });
|
|
1646
|
+
try {
|
|
1647
|
+
await server.start(port, options.host);
|
|
1648
|
+
const shutdown = async () => {
|
|
1649
|
+
await server.stop();
|
|
1650
|
+
process.exit(0);
|
|
1651
|
+
};
|
|
1652
|
+
process.on("SIGINT", shutdown);
|
|
1653
|
+
process.on("SIGTERM", shutdown);
|
|
1654
|
+
} catch (error) {
|
|
1655
|
+
console.error(import_chalk3.default.red(`Failed to start server: ${error.message}`));
|
|
1656
|
+
process.exitCode = 1;
|
|
1657
|
+
}
|
|
1616
1658
|
}
|
|
1617
|
-
|
|
1659
|
+
);
|
|
1618
1660
|
|
|
1619
1661
|
// src/commands/captures.ts
|
|
1620
1662
|
var import_commander4 = require("commander");
|
package/dist/index.js
CHANGED
|
@@ -1291,11 +1291,13 @@ var CaptureServer = class {
|
|
|
1291
1291
|
captureCount = 0;
|
|
1292
1292
|
enableWebSocket;
|
|
1293
1293
|
onCapture;
|
|
1294
|
+
verbose;
|
|
1294
1295
|
constructor(options) {
|
|
1295
1296
|
const capturesDir = typeof options === "string" ? options : options?.capturesDir;
|
|
1296
1297
|
this.capturesDir = capturesDir || join2(homedir2(), ".better-webhook", "captures");
|
|
1297
1298
|
this.enableWebSocket = typeof options === "object" ? options?.enableWebSocket !== false : true;
|
|
1298
1299
|
this.onCapture = typeof options === "object" ? options?.onCapture : void 0;
|
|
1300
|
+
this.verbose = typeof options === "object" ? options?.verbose === true : false;
|
|
1299
1301
|
if (!existsSync2(this.capturesDir)) {
|
|
1300
1302
|
mkdirSync2(this.capturesDir, { recursive: true });
|
|
1301
1303
|
}
|
|
@@ -1393,7 +1395,16 @@ var CaptureServer = class {
|
|
|
1393
1395
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
1394
1396
|
const id = randomUUID();
|
|
1395
1397
|
const url = req.url || "/";
|
|
1396
|
-
const
|
|
1398
|
+
const hostHeader = req.headers.host;
|
|
1399
|
+
const hostValue = typeof hostHeader === "string" ? hostHeader : "";
|
|
1400
|
+
const isHostSafe = /^[a-z0-9.-]+(:\d+)?$/i.test(hostValue);
|
|
1401
|
+
const baseUrl = isHostSafe ? `http://${hostValue}` : "http://localhost";
|
|
1402
|
+
let urlParts;
|
|
1403
|
+
try {
|
|
1404
|
+
urlParts = new URL(url, baseUrl);
|
|
1405
|
+
} catch {
|
|
1406
|
+
urlParts = new URL(url, "http://localhost");
|
|
1407
|
+
}
|
|
1397
1408
|
const query = {};
|
|
1398
1409
|
for (const [key, value] of urlParts.searchParams.entries()) {
|
|
1399
1410
|
if (query[key]) {
|
|
@@ -1453,6 +1464,34 @@ var CaptureServer = class {
|
|
|
1453
1464
|
console.log(
|
|
1454
1465
|
`\u{1F4E6} ${req.method} ${urlParts.pathname}${providerStr} -> ${filename}`
|
|
1455
1466
|
);
|
|
1467
|
+
if (this.verbose) {
|
|
1468
|
+
const headerEntries = Object.entries(req.headers).map(([key, value]) => {
|
|
1469
|
+
if (Array.isArray(value)) {
|
|
1470
|
+
return `${key}: ${value.join(", ")}`;
|
|
1471
|
+
}
|
|
1472
|
+
if (value === void 0) {
|
|
1473
|
+
return `${key}:`;
|
|
1474
|
+
}
|
|
1475
|
+
return `${key}: ${value}`;
|
|
1476
|
+
}).join("\n");
|
|
1477
|
+
const method = req.method || "GET";
|
|
1478
|
+
const providerLabel = provider || "unknown";
|
|
1479
|
+
const contentTypeLabel = contentType || "(none)";
|
|
1480
|
+
console.log(
|
|
1481
|
+
[
|
|
1482
|
+
"[debug] request",
|
|
1483
|
+
`method: ${method}`,
|
|
1484
|
+
`path: ${urlParts.pathname}`,
|
|
1485
|
+
`provider: ${providerLabel}`,
|
|
1486
|
+
`content-type: ${contentTypeLabel}`,
|
|
1487
|
+
`body-length: ${rawBody.length}`,
|
|
1488
|
+
"headers:",
|
|
1489
|
+
headerEntries || "(none)",
|
|
1490
|
+
"raw-body:",
|
|
1491
|
+
rawBody
|
|
1492
|
+
].join("\n")
|
|
1493
|
+
);
|
|
1494
|
+
}
|
|
1456
1495
|
this.onCapture?.({ file: filename, capture: captured });
|
|
1457
1496
|
if (this.enableWebSocket) {
|
|
1458
1497
|
this.broadcast({
|
|
@@ -1588,27 +1627,30 @@ var CaptureServer = class {
|
|
|
1588
1627
|
};
|
|
1589
1628
|
|
|
1590
1629
|
// src/commands/capture.ts
|
|
1591
|
-
var capture = new Command3().name("capture").description("Start a server to capture incoming webhooks").option("-p, --port <port>", "Port to listen on", "3001").option("-h, --host <host>", "Host to bind to", "0.0.0.0").
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
await server.
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1630
|
+
var capture = new Command3().name("capture").description("Start a server to capture incoming webhooks").option("-p, --port <port>", "Port to listen on", "3001").option("-h, --host <host>", "Host to bind to", "0.0.0.0").option("-v, --verbose", "Show raw request details").option("--debug", "Alias for --verbose").action(
|
|
1631
|
+
async (options) => {
|
|
1632
|
+
const port = parseInt(options.port, 10);
|
|
1633
|
+
if (isNaN(port) || port < 0 || port > 65535) {
|
|
1634
|
+
console.error(chalk3.red("Invalid port number"));
|
|
1635
|
+
process.exitCode = 1;
|
|
1636
|
+
return;
|
|
1637
|
+
}
|
|
1638
|
+
const verbose = Boolean(options.verbose || options.debug);
|
|
1639
|
+
const server = new CaptureServer({ verbose });
|
|
1640
|
+
try {
|
|
1641
|
+
await server.start(port, options.host);
|
|
1642
|
+
const shutdown = async () => {
|
|
1643
|
+
await server.stop();
|
|
1644
|
+
process.exit(0);
|
|
1645
|
+
};
|
|
1646
|
+
process.on("SIGINT", shutdown);
|
|
1647
|
+
process.on("SIGTERM", shutdown);
|
|
1648
|
+
} catch (error) {
|
|
1649
|
+
console.error(chalk3.red(`Failed to start server: ${error.message}`));
|
|
1650
|
+
process.exitCode = 1;
|
|
1651
|
+
}
|
|
1610
1652
|
}
|
|
1611
|
-
|
|
1653
|
+
);
|
|
1612
1654
|
|
|
1613
1655
|
// src/commands/captures.ts
|
|
1614
1656
|
import { Command as Command4 } from "commander";
|