yaver-cli 1.99.102 → 1.99.106
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/package.json +1 -1
- package/src/commands/doctor.js +89 -0
- package/src/postinstall.js +42 -1
package/package.json
CHANGED
package/src/commands/doctor.js
CHANGED
|
@@ -1,7 +1,90 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const dgram = require('dgram');
|
|
4
|
+
const { execSync } = require('child_process');
|
|
2
5
|
const { analyzeProject } = require('../analyzer');
|
|
3
6
|
const { loadSDKManifest } = require('../sdk-manifest');
|
|
4
7
|
|
|
8
|
+
// commandExists checks PATH for an executable. Matches the helper used
|
|
9
|
+
// by postinstall.js — kept inline to avoid a new module dependency.
|
|
10
|
+
function commandExists(name) {
|
|
11
|
+
try {
|
|
12
|
+
execSync(`command -v ${name}`, { stdio: ['ignore', 'pipe', 'ignore'] });
|
|
13
|
+
return true;
|
|
14
|
+
} catch (_) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// stunPing sends one STUN binding request to the given host:port and
|
|
20
|
+
// resolves true if a response comes back within `timeoutMs`. Used to
|
|
21
|
+
// verify WebRTC ICE connectivity during `yaver doctor`. No external
|
|
22
|
+
// libraries required — STUN binding requests are 20 bytes.
|
|
23
|
+
function stunPing(host, port, timeoutMs = 1500) {
|
|
24
|
+
return new Promise((resolve) => {
|
|
25
|
+
const sock = dgram.createSocket('udp4');
|
|
26
|
+
let done = false;
|
|
27
|
+
const finish = (ok) => {
|
|
28
|
+
if (done) return;
|
|
29
|
+
done = true;
|
|
30
|
+
try { sock.close(); } catch (_) {}
|
|
31
|
+
resolve(ok);
|
|
32
|
+
};
|
|
33
|
+
const timer = setTimeout(() => finish(false), timeoutMs);
|
|
34
|
+
sock.on('message', () => {
|
|
35
|
+
clearTimeout(timer);
|
|
36
|
+
finish(true);
|
|
37
|
+
});
|
|
38
|
+
sock.on('error', () => {
|
|
39
|
+
clearTimeout(timer);
|
|
40
|
+
finish(false);
|
|
41
|
+
});
|
|
42
|
+
// STUN binding request (RFC 5389): 0x0001, length 0, magic cookie,
|
|
43
|
+
// 12-byte transaction ID. Total: 20 bytes.
|
|
44
|
+
const buf = Buffer.alloc(20);
|
|
45
|
+
buf.writeUInt16BE(0x0001, 0); // message type: binding request
|
|
46
|
+
buf.writeUInt16BE(0x0000, 2); // length
|
|
47
|
+
buf.writeUInt32BE(0x2112A442, 4); // magic cookie
|
|
48
|
+
for (let i = 0; i < 12; i++) buf[8 + i] = Math.floor(Math.random() * 256);
|
|
49
|
+
sock.send(buf, port, host, (err) => {
|
|
50
|
+
if (err) {
|
|
51
|
+
clearTimeout(timer);
|
|
52
|
+
finish(false);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// reportWebRTCReadiness prints a one-block summary of WebRTC bootstrap
|
|
59
|
+
// state: ffmpeg (mobile container frame encoding), Yaver agent binary
|
|
60
|
+
// (Pion server-side), and STUN reachability for ICE. Each line is
|
|
61
|
+
// independently actionable.
|
|
62
|
+
async function reportWebRTCReadiness() {
|
|
63
|
+
console.log('─── WebRTC + Streaming Readiness ──────────────\n');
|
|
64
|
+
|
|
65
|
+
const ffmpeg = commandExists('ffmpeg');
|
|
66
|
+
console.log(` ${ffmpeg ? '✅' : '❌'} ffmpeg ${ffmpeg ? 'installed' : 'missing — needed for screen capture transcode (auto-installed via `yaver install vibe-preview`)'}`);
|
|
67
|
+
|
|
68
|
+
const yaverBin = commandExists('yaver') || commandExists('yaver.exe');
|
|
69
|
+
console.log(` ${yaverBin ? '✅' : '❌'} yaver agent binary ${yaverBin ? 'on PATH (embeds Pion WebRTC server)' : 'not on PATH'}`);
|
|
70
|
+
|
|
71
|
+
// Best-effort STUN ping to Google's public STUN server. Confirms UDP
|
|
72
|
+
// egress works — without it, ICE candidate gathering fails and the
|
|
73
|
+
// WebRTC stream falls back to relay-jpeg-poll.
|
|
74
|
+
const stunHost = 'stun.l.google.com';
|
|
75
|
+
const stunPort = 19302;
|
|
76
|
+
process.stdout.write(` ⏳ STUN reachability (${stunHost}:${stunPort})…`);
|
|
77
|
+
const stunOk = await stunPing(stunHost, stunPort, 1500);
|
|
78
|
+
process.stdout.write('\r');
|
|
79
|
+
console.log(` ${stunOk ? '✅' : '⚠️ '} STUN ${stunOk ? 'reachable' : 'unreachable — ICE may fail; configure TURN on your relay (relay/deploy/coturn.conf, when added)'} (${stunHost}:${stunPort})`);
|
|
80
|
+
|
|
81
|
+
// Note about TURN. Yaver doesn't ship coturn yet (planned in the
|
|
82
|
+
// Phase 2 WebRTC plan). When the user has a managed relay running
|
|
83
|
+
// coturn, `yaver relay test` will surface its TURN port.
|
|
84
|
+
console.log(' ℹ️ TURN: configured per-relay. `yaver relay test` to verify your relay\'s TURN port.');
|
|
85
|
+
console.log('');
|
|
86
|
+
}
|
|
87
|
+
|
|
5
88
|
async function doctor(options = {}) {
|
|
6
89
|
if (!fs.existsSync('package.json')) {
|
|
7
90
|
console.error('❌ No package.json found. Run this from your RN project root.');
|
|
@@ -77,6 +160,12 @@ async function doctor(options = {}) {
|
|
|
77
160
|
}
|
|
78
161
|
console.log('');
|
|
79
162
|
|
|
163
|
+
// WebRTC + streaming readiness — opt-out with --no-webrtc so CI
|
|
164
|
+
// doesn't pay the 1.5s STUN probe per run. Default on.
|
|
165
|
+
if (options.webrtc !== false) {
|
|
166
|
+
await reportWebRTCReadiness();
|
|
167
|
+
}
|
|
168
|
+
|
|
80
169
|
// Summary
|
|
81
170
|
const total = analysis.availableModules.length + analysis.missingModules.length;
|
|
82
171
|
console.log(`─── Summary ────────────────────────────────────\n`);
|
package/src/postinstall.js
CHANGED
|
@@ -70,6 +70,33 @@ function installMissingCodingRunners() {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
// ensureLinuxHermescBuildDeps installs the apt packages required to
|
|
74
|
+
// compile hermesc from facebook/hermes sources on linux/arm64 (no
|
|
75
|
+
// upstream prebuilt exists for that arch). Best-effort; only runs as
|
|
76
|
+
// root. Mirrors ci/remote/install-hermesc.sh's dep list so the
|
|
77
|
+
// outcome matches the Hetzner test-box bootstrap path.
|
|
78
|
+
function ensureLinuxHermescBuildDeps() {
|
|
79
|
+
try {
|
|
80
|
+
if (process.platform !== "linux") return;
|
|
81
|
+
if (typeof process.geteuid !== "function" || process.geteuid() !== 0) {
|
|
82
|
+
log("linux/arm64 hermesc build needs cmake/ninja/clang/libicu-dev — re-run `npm install -g yaver-cli` as root to provision them, or install manually.");
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const required = ["git", "cmake", "ninja-build", "clang", "python3", "build-essential", "ca-certificates", "libicu-dev", "zlib1g-dev"];
|
|
86
|
+
if (!commandExists("apt-get")) {
|
|
87
|
+
log(`hermesc build deps missing (${required.join(", ")}) and no apt-get available. Install manually then re-run \`yaver install mobile\`.`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
execSync("apt-get update -y", { stdio: ["ignore", "ignore", "ignore"] });
|
|
91
|
+
execSync(`DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ${required.join(" ")}`, {
|
|
92
|
+
stdio: "inherit",
|
|
93
|
+
});
|
|
94
|
+
log("Installed Linux hermesc build deps (cmake/ninja/clang/libicu-dev).");
|
|
95
|
+
} catch (error) {
|
|
96
|
+
log(`Skipping hermesc build deps install: ${error.message}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
73
100
|
function ensureLinuxRunnerSandboxPackages() {
|
|
74
101
|
try {
|
|
75
102
|
if (process.platform !== "linux") return;
|
|
@@ -229,7 +256,21 @@ async function main() {
|
|
|
229
256
|
// Never blocks install — the bundler falls back to project-local RN
|
|
230
257
|
// if this step skipped or failed.
|
|
231
258
|
try {
|
|
232
|
-
|
|
259
|
+
let hermescPath = await ensureHermesc({ quiet: true });
|
|
260
|
+
// linux/arm64 (and any other platform with no upstream prebuilt)
|
|
261
|
+
// falls through to build-from-source. Without this branch the
|
|
262
|
+
// first `yaver-push` on the box pays a 1–2 min CMake bill — bad UX
|
|
263
|
+
// on a fresh Hetzner ARM dev box. Install the toolchain (apt only,
|
|
264
|
+
// when running as root) and try the source build now so push is
|
|
265
|
+
// instant later. Never blocks npm install on failure.
|
|
266
|
+
if (!hermescPath && process.platform === "linux" && process.arch === "arm64") {
|
|
267
|
+
ensureLinuxHermescBuildDeps();
|
|
268
|
+
try {
|
|
269
|
+
hermescPath = await ensureHermesc({ quiet: true, allowBuildFromSource: true });
|
|
270
|
+
} catch (buildErr) {
|
|
271
|
+
log(`Source build of hermesc failed: ${buildErr.message}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
233
274
|
if (hermescPath) {
|
|
234
275
|
log(`Hermes compiler ready at ${hermescPath}.`);
|
|
235
276
|
} else {
|