@better-webhook/cli 3.5.0 → 3.6.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 +31 -0
- package/dist/index.cjs +117 -18
- package/dist/index.js +118 -19
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -43,6 +43,37 @@ These providers are auto-detected from headers but signature generation is not y
|
|
|
43
43
|
|
|
44
44
|
## Installation
|
|
45
45
|
|
|
46
|
+
### Standalone Binary (Recommended)
|
|
47
|
+
|
|
48
|
+
Download a standalone binary - no Node.js required:
|
|
49
|
+
|
|
50
|
+
**macOS (Homebrew)**
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
brew install endalk200/tap/better-webhook
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Manual Download**
|
|
57
|
+
|
|
58
|
+
Download the latest binary for your platform from [GitHub Releases](https://github.com/endalk200/better-webhook/releases):
|
|
59
|
+
|
|
60
|
+
| Platform | Download |
|
|
61
|
+
| ------------- | --------------------------------------------------------------------------------------------- |
|
|
62
|
+
| macOS (ARM) | [better-webhook-darwin-arm64](https://github.com/endalk200/better-webhook/releases/latest) |
|
|
63
|
+
| macOS (Intel) | [better-webhook-darwin-x64](https://github.com/endalk200/better-webhook/releases/latest) |
|
|
64
|
+
| Linux (x64) | [better-webhook-linux-x64](https://github.com/endalk200/better-webhook/releases/latest) |
|
|
65
|
+
| Linux (ARM) | [better-webhook-linux-arm64](https://github.com/endalk200/better-webhook/releases/latest) |
|
|
66
|
+
| Windows | [better-webhook-windows-x64.exe](https://github.com/endalk200/better-webhook/releases/latest) |
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Example: macOS ARM
|
|
70
|
+
curl -L https://github.com/endalk200/better-webhook/releases/latest/download/better-webhook-darwin-arm64 -o better-webhook
|
|
71
|
+
chmod +x better-webhook
|
|
72
|
+
sudo mv better-webhook /usr/local/bin/
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### NPM (Alternative)
|
|
76
|
+
|
|
46
77
|
```bash
|
|
47
78
|
# NPM
|
|
48
79
|
npm install -g @better-webhook/cli
|
package/dist/index.cjs
CHANGED
|
@@ -2738,6 +2738,89 @@ function createDashboardApiRouter(options = {}) {
|
|
|
2738
2738
|
|
|
2739
2739
|
// src/core/dashboard-server.ts
|
|
2740
2740
|
var import_meta = {};
|
|
2741
|
+
function isStandaloneBinary() {
|
|
2742
|
+
if (typeof STANDALONE_BINARY !== "undefined" && STANDALONE_BINARY) {
|
|
2743
|
+
return true;
|
|
2744
|
+
}
|
|
2745
|
+
if (typeof globalThis.embeddedDashboardFiles !== "undefined" && globalThis.embeddedDashboardFiles) {
|
|
2746
|
+
return true;
|
|
2747
|
+
}
|
|
2748
|
+
return false;
|
|
2749
|
+
}
|
|
2750
|
+
function getMimeType(filePath) {
|
|
2751
|
+
const ext = import_path4.default.extname(filePath).toLowerCase();
|
|
2752
|
+
const mimeTypes = {
|
|
2753
|
+
".html": "text/html; charset=utf-8",
|
|
2754
|
+
".js": "application/javascript; charset=utf-8",
|
|
2755
|
+
".css": "text/css; charset=utf-8",
|
|
2756
|
+
".json": "application/json; charset=utf-8",
|
|
2757
|
+
".png": "image/png",
|
|
2758
|
+
".jpg": "image/jpeg",
|
|
2759
|
+
".jpeg": "image/jpeg",
|
|
2760
|
+
".gif": "image/gif",
|
|
2761
|
+
".svg": "image/svg+xml",
|
|
2762
|
+
".ico": "image/x-icon",
|
|
2763
|
+
".woff": "font/woff",
|
|
2764
|
+
".woff2": "font/woff2",
|
|
2765
|
+
".ttf": "font/ttf",
|
|
2766
|
+
".eot": "application/vnd.ms-fontobject"
|
|
2767
|
+
};
|
|
2768
|
+
return mimeTypes[ext] || "application/octet-stream";
|
|
2769
|
+
}
|
|
2770
|
+
function createEmbeddedDashboardMiddleware() {
|
|
2771
|
+
const filePathMap = /* @__PURE__ */ new Map();
|
|
2772
|
+
let indexHtmlPath = null;
|
|
2773
|
+
if (typeof globalThis.embeddedDashboardFiles !== "undefined") {
|
|
2774
|
+
for (const [key, filePath] of Object.entries(
|
|
2775
|
+
globalThis.embeddedDashboardFiles
|
|
2776
|
+
)) {
|
|
2777
|
+
const servePath = "/" + key.replace(/^dashboard\//, "");
|
|
2778
|
+
filePathMap.set(servePath, filePath);
|
|
2779
|
+
if (servePath === "/index.html") {
|
|
2780
|
+
indexHtmlPath = filePath;
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
const staticMiddleware = async (req, res, next) => {
|
|
2785
|
+
if (!Bun) {
|
|
2786
|
+
return next();
|
|
2787
|
+
}
|
|
2788
|
+
const requestPath = req.path === "/" ? "/index.html" : req.path;
|
|
2789
|
+
const filePath = filePathMap.get(requestPath);
|
|
2790
|
+
if (filePath) {
|
|
2791
|
+
try {
|
|
2792
|
+
const file = Bun.file(filePath);
|
|
2793
|
+
const content = await file.arrayBuffer();
|
|
2794
|
+
res.setHeader("Content-Type", getMimeType(requestPath));
|
|
2795
|
+
res.setHeader("Content-Length", content.byteLength);
|
|
2796
|
+
res.send(Buffer.from(content));
|
|
2797
|
+
} catch (err) {
|
|
2798
|
+
console.error(`Failed to serve embedded file ${requestPath}:`, err);
|
|
2799
|
+
next();
|
|
2800
|
+
}
|
|
2801
|
+
} else {
|
|
2802
|
+
next();
|
|
2803
|
+
}
|
|
2804
|
+
};
|
|
2805
|
+
const spaFallback = async (req, res, next) => {
|
|
2806
|
+
if (req.path.startsWith("/api") || req.path === "/health") {
|
|
2807
|
+
return next();
|
|
2808
|
+
}
|
|
2809
|
+
if (!Bun || !indexHtmlPath) {
|
|
2810
|
+
return next();
|
|
2811
|
+
}
|
|
2812
|
+
try {
|
|
2813
|
+
const file = Bun.file(indexHtmlPath);
|
|
2814
|
+
const content = await file.arrayBuffer();
|
|
2815
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
2816
|
+
res.setHeader("Content-Length", content.byteLength);
|
|
2817
|
+
res.send(Buffer.from(content));
|
|
2818
|
+
} catch {
|
|
2819
|
+
next();
|
|
2820
|
+
}
|
|
2821
|
+
};
|
|
2822
|
+
return { staticMiddleware, spaFallback };
|
|
2823
|
+
}
|
|
2741
2824
|
function resolveDashboardDistDir(runtimeDir) {
|
|
2742
2825
|
const candidates = [
|
|
2743
2826
|
// Bundled CLI: dist/index.js -> dist/dashboard
|
|
@@ -2791,18 +2874,24 @@ async function startDashboardServer(options = {}) {
|
|
|
2791
2874
|
);
|
|
2792
2875
|
const host = options.host || "localhost";
|
|
2793
2876
|
const port = options.port ?? 4e3;
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2877
|
+
if (isStandaloneBinary()) {
|
|
2878
|
+
const { staticMiddleware, spaFallback } = createEmbeddedDashboardMiddleware();
|
|
2879
|
+
app.use(staticMiddleware);
|
|
2880
|
+
app.get("*", spaFallback);
|
|
2881
|
+
} else {
|
|
2882
|
+
const runtimeDir = typeof __dirname !== "undefined" ? (
|
|
2883
|
+
// eslint-disable-next-line no-undef
|
|
2884
|
+
__dirname
|
|
2885
|
+
) : import_path4.default.dirname((0, import_url.fileURLToPath)(import_meta.url));
|
|
2886
|
+
const { distDir: dashboardDistDir, indexHtml: dashboardIndexHtml } = resolveDashboardDistDir(runtimeDir);
|
|
2887
|
+
app.use(import_express2.default.static(dashboardDistDir));
|
|
2888
|
+
app.get("*", (req, res, next) => {
|
|
2889
|
+
if (req.path.startsWith("/api") || req.path === "/health") return next();
|
|
2890
|
+
res.sendFile(dashboardIndexHtml, (err) => {
|
|
2891
|
+
if (err) next();
|
|
2892
|
+
});
|
|
2804
2893
|
});
|
|
2805
|
-
}
|
|
2894
|
+
}
|
|
2806
2895
|
const server = (0, import_http2.createServer)(app);
|
|
2807
2896
|
const wss = new import_ws2.WebSocketServer({ server, path: "/ws" });
|
|
2808
2897
|
wss.on("connection", async (ws) => {
|
|
@@ -2929,14 +3018,24 @@ var dashboard = new import_commander6.Command().name("dashboard").description("S
|
|
|
2929
3018
|
|
|
2930
3019
|
// src/index.ts
|
|
2931
3020
|
var import_meta2 = {};
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
)
|
|
3021
|
+
function getVersion() {
|
|
3022
|
+
if (typeof CLI_VERSION !== "undefined") {
|
|
3023
|
+
return CLI_VERSION;
|
|
3024
|
+
}
|
|
3025
|
+
try {
|
|
3026
|
+
const packageJsonPath = (0, import_node_url.fileURLToPath)(
|
|
3027
|
+
new URL("../package.json", import_meta2.url)
|
|
3028
|
+
);
|
|
3029
|
+
const packageJson = JSON.parse(
|
|
3030
|
+
(0, import_node_fs.readFileSync)(packageJsonPath, { encoding: "utf8" })
|
|
3031
|
+
);
|
|
3032
|
+
return packageJson.version;
|
|
3033
|
+
} catch {
|
|
3034
|
+
return "0.0.0-unknown";
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
2938
3037
|
var program = new import_commander7.Command().name("better-webhook").description(
|
|
2939
3038
|
"Modern CLI for developing, capturing, and replaying webhooks locally"
|
|
2940
|
-
).version(
|
|
3039
|
+
).version(getVersion());
|
|
2941
3040
|
program.addCommand(templates).addCommand(run).addCommand(capture).addCommand(captures).addCommand(replay).addCommand(dashboard);
|
|
2942
3041
|
program.parseAsync(process.argv);
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command as Command7 } from "commander";
|
|
5
|
-
import { readFileSync as
|
|
5
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
6
6
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7
7
|
|
|
8
8
|
// src/commands/templates.ts
|
|
@@ -2731,6 +2731,89 @@ function createDashboardApiRouter(options = {}) {
|
|
|
2731
2731
|
}
|
|
2732
2732
|
|
|
2733
2733
|
// src/core/dashboard-server.ts
|
|
2734
|
+
function isStandaloneBinary() {
|
|
2735
|
+
if (typeof STANDALONE_BINARY !== "undefined" && STANDALONE_BINARY) {
|
|
2736
|
+
return true;
|
|
2737
|
+
}
|
|
2738
|
+
if (typeof globalThis.embeddedDashboardFiles !== "undefined" && globalThis.embeddedDashboardFiles) {
|
|
2739
|
+
return true;
|
|
2740
|
+
}
|
|
2741
|
+
return false;
|
|
2742
|
+
}
|
|
2743
|
+
function getMimeType(filePath) {
|
|
2744
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
2745
|
+
const mimeTypes = {
|
|
2746
|
+
".html": "text/html; charset=utf-8",
|
|
2747
|
+
".js": "application/javascript; charset=utf-8",
|
|
2748
|
+
".css": "text/css; charset=utf-8",
|
|
2749
|
+
".json": "application/json; charset=utf-8",
|
|
2750
|
+
".png": "image/png",
|
|
2751
|
+
".jpg": "image/jpeg",
|
|
2752
|
+
".jpeg": "image/jpeg",
|
|
2753
|
+
".gif": "image/gif",
|
|
2754
|
+
".svg": "image/svg+xml",
|
|
2755
|
+
".ico": "image/x-icon",
|
|
2756
|
+
".woff": "font/woff",
|
|
2757
|
+
".woff2": "font/woff2",
|
|
2758
|
+
".ttf": "font/ttf",
|
|
2759
|
+
".eot": "application/vnd.ms-fontobject"
|
|
2760
|
+
};
|
|
2761
|
+
return mimeTypes[ext] || "application/octet-stream";
|
|
2762
|
+
}
|
|
2763
|
+
function createEmbeddedDashboardMiddleware() {
|
|
2764
|
+
const filePathMap = /* @__PURE__ */ new Map();
|
|
2765
|
+
let indexHtmlPath = null;
|
|
2766
|
+
if (typeof globalThis.embeddedDashboardFiles !== "undefined") {
|
|
2767
|
+
for (const [key, filePath] of Object.entries(
|
|
2768
|
+
globalThis.embeddedDashboardFiles
|
|
2769
|
+
)) {
|
|
2770
|
+
const servePath = "/" + key.replace(/^dashboard\//, "");
|
|
2771
|
+
filePathMap.set(servePath, filePath);
|
|
2772
|
+
if (servePath === "/index.html") {
|
|
2773
|
+
indexHtmlPath = filePath;
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
const staticMiddleware = async (req, res, next) => {
|
|
2778
|
+
if (!Bun) {
|
|
2779
|
+
return next();
|
|
2780
|
+
}
|
|
2781
|
+
const requestPath = req.path === "/" ? "/index.html" : req.path;
|
|
2782
|
+
const filePath = filePathMap.get(requestPath);
|
|
2783
|
+
if (filePath) {
|
|
2784
|
+
try {
|
|
2785
|
+
const file = Bun.file(filePath);
|
|
2786
|
+
const content = await file.arrayBuffer();
|
|
2787
|
+
res.setHeader("Content-Type", getMimeType(requestPath));
|
|
2788
|
+
res.setHeader("Content-Length", content.byteLength);
|
|
2789
|
+
res.send(Buffer.from(content));
|
|
2790
|
+
} catch (err) {
|
|
2791
|
+
console.error(`Failed to serve embedded file ${requestPath}:`, err);
|
|
2792
|
+
next();
|
|
2793
|
+
}
|
|
2794
|
+
} else {
|
|
2795
|
+
next();
|
|
2796
|
+
}
|
|
2797
|
+
};
|
|
2798
|
+
const spaFallback = async (req, res, next) => {
|
|
2799
|
+
if (req.path.startsWith("/api") || req.path === "/health") {
|
|
2800
|
+
return next();
|
|
2801
|
+
}
|
|
2802
|
+
if (!Bun || !indexHtmlPath) {
|
|
2803
|
+
return next();
|
|
2804
|
+
}
|
|
2805
|
+
try {
|
|
2806
|
+
const file = Bun.file(indexHtmlPath);
|
|
2807
|
+
const content = await file.arrayBuffer();
|
|
2808
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
2809
|
+
res.setHeader("Content-Length", content.byteLength);
|
|
2810
|
+
res.send(Buffer.from(content));
|
|
2811
|
+
} catch {
|
|
2812
|
+
next();
|
|
2813
|
+
}
|
|
2814
|
+
};
|
|
2815
|
+
return { staticMiddleware, spaFallback };
|
|
2816
|
+
}
|
|
2734
2817
|
function resolveDashboardDistDir(runtimeDir) {
|
|
2735
2818
|
const candidates = [
|
|
2736
2819
|
// Bundled CLI: dist/index.js -> dist/dashboard
|
|
@@ -2784,18 +2867,24 @@ async function startDashboardServer(options = {}) {
|
|
|
2784
2867
|
);
|
|
2785
2868
|
const host = options.host || "localhost";
|
|
2786
2869
|
const port = options.port ?? 4e3;
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2870
|
+
if (isStandaloneBinary()) {
|
|
2871
|
+
const { staticMiddleware, spaFallback } = createEmbeddedDashboardMiddleware();
|
|
2872
|
+
app.use(staticMiddleware);
|
|
2873
|
+
app.get("*", spaFallback);
|
|
2874
|
+
} else {
|
|
2875
|
+
const runtimeDir = typeof __dirname !== "undefined" ? (
|
|
2876
|
+
// eslint-disable-next-line no-undef
|
|
2877
|
+
__dirname
|
|
2878
|
+
) : path.dirname(fileURLToPath(import.meta.url));
|
|
2879
|
+
const { distDir: dashboardDistDir, indexHtml: dashboardIndexHtml } = resolveDashboardDistDir(runtimeDir);
|
|
2880
|
+
app.use(express2.static(dashboardDistDir));
|
|
2881
|
+
app.get("*", (req, res, next) => {
|
|
2882
|
+
if (req.path.startsWith("/api") || req.path === "/health") return next();
|
|
2883
|
+
res.sendFile(dashboardIndexHtml, (err) => {
|
|
2884
|
+
if (err) next();
|
|
2885
|
+
});
|
|
2797
2886
|
});
|
|
2798
|
-
}
|
|
2887
|
+
}
|
|
2799
2888
|
const server = createServer2(app);
|
|
2800
2889
|
const wss = new WebSocketServer2({ server, path: "/ws" });
|
|
2801
2890
|
wss.on("connection", async (ws) => {
|
|
@@ -2921,14 +3010,24 @@ var dashboard = new Command6().name("dashboard").description("Start the local da
|
|
|
2921
3010
|
});
|
|
2922
3011
|
|
|
2923
3012
|
// src/index.ts
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
3013
|
+
function getVersion() {
|
|
3014
|
+
if (typeof CLI_VERSION !== "undefined") {
|
|
3015
|
+
return CLI_VERSION;
|
|
3016
|
+
}
|
|
3017
|
+
try {
|
|
3018
|
+
const packageJsonPath = fileURLToPath2(
|
|
3019
|
+
new URL("../package.json", import.meta.url)
|
|
3020
|
+
);
|
|
3021
|
+
const packageJson = JSON.parse(
|
|
3022
|
+
readFileSync5(packageJsonPath, { encoding: "utf8" })
|
|
3023
|
+
);
|
|
3024
|
+
return packageJson.version;
|
|
3025
|
+
} catch {
|
|
3026
|
+
return "0.0.0-unknown";
|
|
3027
|
+
}
|
|
3028
|
+
}
|
|
2930
3029
|
var program = new Command7().name("better-webhook").description(
|
|
2931
3030
|
"Modern CLI for developing, capturing, and replaying webhooks locally"
|
|
2932
|
-
).version(
|
|
3031
|
+
).version(getVersion());
|
|
2933
3032
|
program.addCommand(templates).addCommand(run).addCommand(capture).addCommand(captures).addCommand(replay).addCommand(dashboard);
|
|
2934
3033
|
program.parseAsync(process.argv);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-webhook/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "Modern CLI for developing, capturing, and replaying webhooks locally with dashboard UI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"zod": "^3.23.8"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
+
"@types/bun": "^1.2.18",
|
|
63
64
|
"@types/express": "^4.17.21",
|
|
64
65
|
"@types/node": "^24.3.1",
|
|
65
66
|
"@types/prompts": "^2.4.9",
|
|
@@ -72,6 +73,8 @@
|
|
|
72
73
|
"scripts": {
|
|
73
74
|
"build:cli": "tsup --format cjs,esm --dts && node ./scripts/copy-dashboard.mjs",
|
|
74
75
|
"build": "pnpm --filter @better-webhook/dashboard build && pnpm run build:cli",
|
|
76
|
+
"build:binary": "bun ./scripts/build-binary.ts",
|
|
77
|
+
"build:binary:all": "bun ./scripts/build-binary.ts --all",
|
|
75
78
|
"dev": "tsup --watch",
|
|
76
79
|
"start": "tsx src/index.ts",
|
|
77
80
|
"lint": "tsc",
|