@hienlh/ppm 0.8.36 → 0.8.37
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/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/scripts/release.sh +4 -3
- package/src/server/index.ts +10 -2
- package/src/server/routes/tunnel.ts +0 -17
- package/src/services/tunnel.service.ts +15 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.8.37] - 2026-03-24
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **Intel Mac AVX crash**: Use baseline x64 builds that work on all Intel CPUs (no AVX requirement)
|
|
7
|
+
- **Linux ARM64**: Add `ppm-linux-arm64` binary for Raspberry Pi / ARM servers
|
|
8
|
+
|
|
3
9
|
## [0.8.36] - 2026-03-24
|
|
4
10
|
|
|
5
11
|
### Changed
|
package/package.json
CHANGED
package/scripts/release.sh
CHANGED
|
@@ -23,9 +23,10 @@ mkdir -p dist
|
|
|
23
23
|
|
|
24
24
|
TARGETS=(
|
|
25
25
|
"bun-darwin-arm64:ppm-darwin-arm64"
|
|
26
|
-
"bun-darwin-x64:ppm-darwin-x64"
|
|
27
|
-
"bun-linux-x64:ppm-linux-x64"
|
|
28
|
-
"bun-
|
|
26
|
+
"bun-darwin-x64-baseline:ppm-darwin-x64"
|
|
27
|
+
"bun-linux-x64-baseline:ppm-linux-x64"
|
|
28
|
+
"bun-linux-arm64:ppm-linux-arm64"
|
|
29
|
+
"bun-windows-x64-baseline:ppm-windows-x64.exe"
|
|
29
30
|
)
|
|
30
31
|
|
|
31
32
|
for entry in "${TARGETS[@]}"; do
|
package/src/server/index.ts
CHANGED
|
@@ -237,6 +237,14 @@ export async function startServer(options: {
|
|
|
237
237
|
}
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
+
// Write preliminary status.json so child process can read shareUrl on startup
|
|
241
|
+
// (child reads this before parent has a chance to write PID — fixes race condition)
|
|
242
|
+
writeFileSync(statusFile, JSON.stringify({
|
|
243
|
+
port, host,
|
|
244
|
+
shareUrl: shareUrl ?? null,
|
|
245
|
+
tunnelPid: tunnelPid ?? null,
|
|
246
|
+
}));
|
|
247
|
+
|
|
240
248
|
// Spawn server child process with log file
|
|
241
249
|
const { openSync } = await import("node:fs");
|
|
242
250
|
const logFile = resolve(ppmDir, "ppm.log");
|
|
@@ -300,8 +308,8 @@ export async function startServer(options: {
|
|
|
300
308
|
process.exit(1);
|
|
301
309
|
}
|
|
302
310
|
|
|
303
|
-
//
|
|
304
|
-
const status = { pid: childPid, port, host, shareUrl, tunnelPid, serverScript: script };
|
|
311
|
+
// Update status file with child PID + server script path for restart
|
|
312
|
+
const status = { pid: childPid, port, host, shareUrl: shareUrl ?? null, tunnelPid: tunnelPid ?? null, serverScript: script };
|
|
305
313
|
writeFileSync(statusFile, JSON.stringify(status));
|
|
306
314
|
writeFileSync(pidFile, String(childPid));
|
|
307
315
|
|
|
@@ -1,24 +1,9 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { resolve } from "node:path";
|
|
4
|
-
import { homedir } from "node:os";
|
|
5
2
|
import { tunnelService } from "../../services/tunnel.service.ts";
|
|
6
3
|
import { configService } from "../../services/config.service.ts";
|
|
7
4
|
import { getLocalIp } from "../../lib/network-utils.ts";
|
|
8
5
|
import { ok, err } from "../../types/api.ts";
|
|
9
6
|
|
|
10
|
-
/** Patch shareUrl + tunnelPid in status.json so `ppm status` reflects web-started tunnels */
|
|
11
|
-
function patchStatusFile(shareUrl: string | null): void {
|
|
12
|
-
const path = resolve(homedir(), ".ppm", "status.json");
|
|
13
|
-
if (!existsSync(path)) return;
|
|
14
|
-
try {
|
|
15
|
-
const data = JSON.parse(readFileSync(path, "utf-8"));
|
|
16
|
-
data.shareUrl = shareUrl;
|
|
17
|
-
data.tunnelPid = shareUrl ? tunnelService.getTunnelPid() : null;
|
|
18
|
-
writeFileSync(path, JSON.stringify(data));
|
|
19
|
-
} catch { /* ignore — status.json may be absent in dev */ }
|
|
20
|
-
}
|
|
21
|
-
|
|
22
7
|
export const tunnelRoutes = new Hono();
|
|
23
8
|
|
|
24
9
|
/** GET /api/tunnel — current tunnel status + local URL */
|
|
@@ -40,7 +25,6 @@ tunnelRoutes.post("/start", async (c) => {
|
|
|
40
25
|
try {
|
|
41
26
|
const port = configService.get("port") ?? 8080;
|
|
42
27
|
const url = await tunnelService.startTunnel(port);
|
|
43
|
-
patchStatusFile(url);
|
|
44
28
|
|
|
45
29
|
// Sync tunnel URL to PPM Cloud (if linked)
|
|
46
30
|
import("../../services/cloud.service.ts")
|
|
@@ -58,7 +42,6 @@ tunnelRoutes.post("/start", async (c) => {
|
|
|
58
42
|
/** POST /api/tunnel/stop — stop tunnel */
|
|
59
43
|
tunnelRoutes.post("/stop", (c) => {
|
|
60
44
|
tunnelService.stopTunnel();
|
|
61
|
-
patchStatusFile(null);
|
|
62
45
|
|
|
63
46
|
// Stop cloud heartbeat
|
|
64
47
|
import("../../services/cloud.service.ts")
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Subprocess } from "bun";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
-
import { existsSync, unlinkSync } from "node:fs";
|
|
4
|
+
import { existsSync, unlinkSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { ensureCloudflared } from "./cloudflared.service.ts";
|
|
6
6
|
|
|
7
7
|
const TUNNEL_URL_REGEX = /https:\/\/[a-z0-9-]+\.trycloudflare\.com/;
|
|
@@ -81,6 +81,7 @@ class TunnelService {
|
|
|
81
81
|
});
|
|
82
82
|
|
|
83
83
|
this.url = url;
|
|
84
|
+
this.persistToStatusFile();
|
|
84
85
|
return url;
|
|
85
86
|
}
|
|
86
87
|
|
|
@@ -108,6 +109,7 @@ class TunnelService {
|
|
|
108
109
|
this.externalPid = null;
|
|
109
110
|
}
|
|
110
111
|
this.url = null;
|
|
112
|
+
this.persistToStatusFile();
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
/** Get current tunnel URL (null if not running) */
|
|
@@ -129,6 +131,18 @@ class TunnelService {
|
|
|
129
131
|
setExternalPid(pid: number): void {
|
|
130
132
|
this.externalPid = pid;
|
|
131
133
|
}
|
|
134
|
+
|
|
135
|
+
/** Persist shareUrl + tunnelPid to status.json (central write point) */
|
|
136
|
+
private persistToStatusFile(): void {
|
|
137
|
+
const statusFile = resolve(homedir(), ".ppm", "status.json");
|
|
138
|
+
if (!existsSync(statusFile)) return;
|
|
139
|
+
try {
|
|
140
|
+
const data = JSON.parse(readFileSync(statusFile, "utf-8"));
|
|
141
|
+
data.shareUrl = this.url;
|
|
142
|
+
data.tunnelPid = this.getTunnelPid() ?? null;
|
|
143
|
+
writeFileSync(statusFile, JSON.stringify(data));
|
|
144
|
+
} catch {}
|
|
145
|
+
}
|
|
132
146
|
}
|
|
133
147
|
|
|
134
148
|
/** Singleton tunnel service */
|