@tongil_kim/clautunnel 1.6.0 → 1.6.2
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/dist/index.js +55 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3000,9 +3000,24 @@ var MobileServerManager = class {
|
|
|
3000
3000
|
let needsInstall = false;
|
|
3001
3001
|
try {
|
|
3002
3002
|
execSync2("which ngrok", { stdio: "pipe" });
|
|
3003
|
+
try {
|
|
3004
|
+
const configOutput = execSync2("ngrok config check", {
|
|
3005
|
+
stdio: "pipe",
|
|
3006
|
+
timeout: 5e3
|
|
3007
|
+
}).toString();
|
|
3008
|
+
if (!configOutput.toLowerCase().includes("valid")) {
|
|
3009
|
+
issues.push(
|
|
3010
|
+
"ngrok authtoken is not configured.\n 1. Sign up at https://ngrok.com\n 2. Copy your authtoken from https://dashboard.ngrok.com/get-started/your-authtoken\n 3. Run: ngrok config add-authtoken <your-token>"
|
|
3011
|
+
);
|
|
3012
|
+
}
|
|
3013
|
+
} catch {
|
|
3014
|
+
issues.push(
|
|
3015
|
+
"ngrok authtoken is not configured.\n 1. Sign up at https://ngrok.com\n 2. Copy your authtoken from https://dashboard.ngrok.com/get-started/your-authtoken\n 3. Run: ngrok config add-authtoken <your-token>"
|
|
3016
|
+
);
|
|
3017
|
+
}
|
|
3003
3018
|
} catch {
|
|
3004
3019
|
issues.push(
|
|
3005
|
-
"ngrok is not installed.\n Install: brew install ngrok\n Sign up
|
|
3020
|
+
"ngrok is not installed.\n Install: brew install ngrok\n Then configure your account:\n 1. Sign up at https://ngrok.com\n 2. Copy your authtoken from https://dashboard.ngrok.com/get-started/your-authtoken\n 3. Run: ngrok config add-authtoken <your-token>"
|
|
3006
3021
|
);
|
|
3007
3022
|
}
|
|
3008
3023
|
const nodeModulesPath = join5(this.mobileProjectPath, "node_modules");
|
|
@@ -3107,28 +3122,58 @@ var MobileServerManager = class {
|
|
|
3107
3122
|
}
|
|
3108
3123
|
}
|
|
3109
3124
|
async startNgrok() {
|
|
3125
|
+
try {
|
|
3126
|
+
execSync2("killall ngrok", { stdio: "pipe" });
|
|
3127
|
+
await this.sleep(500);
|
|
3128
|
+
} catch {
|
|
3129
|
+
}
|
|
3110
3130
|
this.ensureLogDir();
|
|
3111
3131
|
this.ngrokLogStream = createWriteStream(join5(this.logDir, "ngrok.log"));
|
|
3132
|
+
let stderrData = "";
|
|
3112
3133
|
this.ngrokProcess = spawn2("ngrok", ["http", String(this.expoPort)], {
|
|
3113
3134
|
stdio: ["ignore", "pipe", "pipe"],
|
|
3114
3135
|
detached: false
|
|
3115
3136
|
});
|
|
3116
3137
|
this.ngrokProcess.stdout?.pipe(this.ngrokLogStream);
|
|
3117
|
-
this.ngrokProcess.stderr?.
|
|
3138
|
+
this.ngrokProcess.stderr?.on("data", (chunk) => {
|
|
3139
|
+
stderrData += chunk.toString();
|
|
3140
|
+
this.ngrokLogStream?.write(chunk);
|
|
3141
|
+
});
|
|
3118
3142
|
this.ngrokProcess.on("error", () => {
|
|
3119
3143
|
});
|
|
3120
3144
|
for (let i = 0; i < 10; i++) {
|
|
3121
3145
|
await this.sleep(1e3);
|
|
3146
|
+
if (this.ngrokProcess.exitCode !== null) {
|
|
3147
|
+
break;
|
|
3148
|
+
}
|
|
3122
3149
|
const url = await this.getNgrokTunnelUrl();
|
|
3123
3150
|
if (url) {
|
|
3124
3151
|
this.tunnelUrl = url;
|
|
3125
3152
|
return url;
|
|
3126
3153
|
}
|
|
3127
3154
|
}
|
|
3155
|
+
this.ngrokError = this.diagnoseNgrokFailure(stderrData);
|
|
3128
3156
|
this.killProcess(this.ngrokProcess);
|
|
3129
3157
|
this.ngrokProcess = null;
|
|
3130
3158
|
return null;
|
|
3131
3159
|
}
|
|
3160
|
+
/** Last ngrok error diagnosis (available after startNgrok fails) */
|
|
3161
|
+
ngrokError = null;
|
|
3162
|
+
diagnoseNgrokFailure(stderr) {
|
|
3163
|
+
const lower = stderr.toLowerCase();
|
|
3164
|
+
if (lower.includes("authtoken") || lower.includes("err_ngrok_105") || lower.includes("authentication")) {
|
|
3165
|
+
return "ngrok authentication failed.\n Your authtoken may be invalid or expired.\n 1. Get a new token at https://dashboard.ngrok.com/get-started/your-authtoken\n 2. Run: ngrok config add-authtoken <your-token>";
|
|
3166
|
+
}
|
|
3167
|
+
if (lower.includes("tunnel session limit") || lower.includes("err_ngrok_108")) {
|
|
3168
|
+
return "ngrok free plan session limit reached.\n Free accounts allow 1 tunnel at a time.\n Close other ngrok tunnels or upgrade your plan at https://ngrok.com/pricing";
|
|
3169
|
+
}
|
|
3170
|
+
if (lower.includes("tcp dial") || lower.includes("connection refused")) {
|
|
3171
|
+
return `ngrok could not connect to localhost:${this.expoPort}.
|
|
3172
|
+
This is usually a timing issue \u2014 the tunnel started before Expo was ready.`;
|
|
3173
|
+
}
|
|
3174
|
+
return `ngrok tunnel failed to start.
|
|
3175
|
+
Check logs for details: ${join5(this.logDir, "ngrok.log")}`;
|
|
3176
|
+
}
|
|
3132
3177
|
async startExpo(tunnelUrl) {
|
|
3133
3178
|
this.ensureLogDir();
|
|
3134
3179
|
this.expoLogStream = createWriteStream(join5(this.logDir, "expo.log"));
|
|
@@ -3219,7 +3264,7 @@ var MobileServerManager = class {
|
|
|
3219
3264
|
this.onProgress("Starting ngrok tunnel...");
|
|
3220
3265
|
const tunnelUrl = await this.startNgrok();
|
|
3221
3266
|
if (!tunnelUrl) {
|
|
3222
|
-
return { started: false, error: "Failed to start ngrok tunnel" };
|
|
3267
|
+
return { started: false, error: this.ngrokError ?? "Failed to start ngrok tunnel" };
|
|
3223
3268
|
}
|
|
3224
3269
|
this.onProgress("Starting Expo server...");
|
|
3225
3270
|
const expoStarted = await this.startExpo(tunnelUrl);
|
|
@@ -3230,6 +3275,13 @@ var MobileServerManager = class {
|
|
|
3230
3275
|
const host = tunnelUrl.replace(/^https?:\/\//, "");
|
|
3231
3276
|
const expoUrl = `exp://${host}:443`;
|
|
3232
3277
|
console.log("");
|
|
3278
|
+
console.log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
3279
|
+
console.log(" \u2502 Expo Go is required to open this QR code. \u2502");
|
|
3280
|
+
console.log(" \u2502 iOS: https://apps.apple.com/app/id982107779\u2502");
|
|
3281
|
+
console.log(" \u2502 Android: https://play.google.com/store/apps/ \u2502");
|
|
3282
|
+
console.log(" \u2502 details?id=host.exp.exponent \u2502");
|
|
3283
|
+
console.log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
3284
|
+
console.log("");
|
|
3233
3285
|
console.log(" Scan with Expo Go:");
|
|
3234
3286
|
qrcode.generate(expoUrl, { small: true }, (code) => {
|
|
3235
3287
|
for (const line of code.split("\n")) {
|