episoda 0.2.46 → 0.2.47
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.
|
@@ -2693,7 +2693,7 @@ var require_package = __commonJS({
|
|
|
2693
2693
|
"package.json"(exports2, module2) {
|
|
2694
2694
|
module2.exports = {
|
|
2695
2695
|
name: "episoda",
|
|
2696
|
-
version: "0.2.
|
|
2696
|
+
version: "0.2.47",
|
|
2697
2697
|
description: "CLI tool for Episoda local development workflow orchestration",
|
|
2698
2698
|
main: "dist/index.js",
|
|
2699
2699
|
types: "dist/index.d.ts",
|
|
@@ -4107,14 +4107,11 @@ var TUNNEL_PID_DIR = path7.join(os2.homedir(), ".episoda", "tunnels");
|
|
|
4107
4107
|
var TUNNEL_TIMEOUTS = {
|
|
4108
4108
|
/** Time to wait for Named Tunnel connection (includes API token fetch + connect) */
|
|
4109
4109
|
NAMED_TUNNEL_CONNECT: 6e4,
|
|
4110
|
-
/** Time to wait for Quick Tunnel connection (simpler, faster connection) */
|
|
4111
|
-
QUICK_TUNNEL_CONNECT: 3e4,
|
|
4112
4110
|
/** Time to wait for cloudflared process to start before giving up */
|
|
4113
4111
|
PROCESS_START: 1e4,
|
|
4114
4112
|
/** Grace period after starting cloudflared before checking status */
|
|
4115
4113
|
STARTUP_GRACE: 2e3
|
|
4116
4114
|
};
|
|
4117
|
-
var TUNNEL_URL_REGEX = /https:\/\/[a-z0-9-]+\.trycloudflare\.com/i;
|
|
4118
4115
|
var DEFAULT_RECONNECT_CONFIG = {
|
|
4119
4116
|
maxRetries: 5,
|
|
4120
4117
|
initialDelayMs: 1e3,
|
|
@@ -4569,151 +4566,21 @@ var TunnelManager = class extends import_events.EventEmitter {
|
|
|
4569
4566
|
});
|
|
4570
4567
|
}
|
|
4571
4568
|
/**
|
|
4572
|
-
* EP948:
|
|
4569
|
+
* EP948: Start tunnel process (Named Tunnels only)
|
|
4570
|
+
* EP1020: Removed Quick Tunnel fallback - Named Tunnels are the only supported mode
|
|
4573
4571
|
*/
|
|
4574
4572
|
async startTunnelProcess(options, existingState) {
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
return
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
return this.startQuickTunnelProcess(options, existingState);
|
|
4581
|
-
}
|
|
4582
|
-
/**
|
|
4583
|
-
* EP672-9: Internal method to start the tunnel process (Quick Tunnel mode)
|
|
4584
|
-
* Separated from startTunnel to support reconnection
|
|
4585
|
-
*/
|
|
4586
|
-
async startQuickTunnelProcess(options, existingState) {
|
|
4587
|
-
const { moduleUid, port = 3e3, onUrl, onStatusChange } = options;
|
|
4588
|
-
if (!this.cloudflaredPath) {
|
|
4589
|
-
try {
|
|
4590
|
-
this.cloudflaredPath = await ensureCloudflared();
|
|
4591
|
-
} catch (error) {
|
|
4592
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4593
|
-
return { success: false, error: `Failed to get cloudflared: ${errorMessage}` };
|
|
4594
|
-
}
|
|
4595
|
-
}
|
|
4596
|
-
return new Promise((resolve3) => {
|
|
4597
|
-
const tunnelInfo = {
|
|
4598
|
-
moduleUid,
|
|
4599
|
-
url: "",
|
|
4600
|
-
port,
|
|
4601
|
-
status: "starting",
|
|
4602
|
-
startedAt: /* @__PURE__ */ new Date(),
|
|
4603
|
-
process: null
|
|
4604
|
-
// Will be set below
|
|
4605
|
-
};
|
|
4606
|
-
const process2 = (0, import_child_process6.spawn)(this.cloudflaredPath, [
|
|
4607
|
-
"tunnel",
|
|
4608
|
-
"--url",
|
|
4609
|
-
`http://localhost:${port}`
|
|
4610
|
-
], {
|
|
4611
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
4612
|
-
});
|
|
4613
|
-
tunnelInfo.process = process2;
|
|
4614
|
-
tunnelInfo.pid = process2.pid;
|
|
4615
|
-
if (process2.pid) {
|
|
4616
|
-
this.writePidFile(moduleUid, process2.pid);
|
|
4617
|
-
}
|
|
4618
|
-
const state = existingState || {
|
|
4619
|
-
info: tunnelInfo,
|
|
4620
|
-
options,
|
|
4621
|
-
intentionallyStopped: false,
|
|
4622
|
-
retryCount: 0,
|
|
4623
|
-
retryTimeoutId: null
|
|
4624
|
-
};
|
|
4625
|
-
state.info = tunnelInfo;
|
|
4626
|
-
this.tunnelStates.set(moduleUid, state);
|
|
4627
|
-
let urlFound = false;
|
|
4628
|
-
let stdoutBuffer = "";
|
|
4629
|
-
let stderrBuffer = "";
|
|
4630
|
-
const parseOutput = (data) => {
|
|
4631
|
-
if (urlFound) return;
|
|
4632
|
-
const match = data.match(TUNNEL_URL_REGEX);
|
|
4633
|
-
if (match) {
|
|
4634
|
-
urlFound = true;
|
|
4635
|
-
tunnelInfo.url = match[0];
|
|
4636
|
-
tunnelInfo.status = "connected";
|
|
4637
|
-
onStatusChange?.("connected");
|
|
4638
|
-
onUrl?.(tunnelInfo.url);
|
|
4639
|
-
this.emitEvent({
|
|
4640
|
-
type: "started",
|
|
4641
|
-
moduleUid,
|
|
4642
|
-
url: tunnelInfo.url
|
|
4643
|
-
});
|
|
4644
|
-
resolve3({ success: true, url: tunnelInfo.url });
|
|
4645
|
-
}
|
|
4573
|
+
if (!options.tunnelToken) {
|
|
4574
|
+
console.error(`[Tunnel] EP1020: No tunnel token available for ${options.moduleUid}`);
|
|
4575
|
+
return {
|
|
4576
|
+
success: false,
|
|
4577
|
+
error: "Named Tunnel token required. Quick Tunnels are no longer supported."
|
|
4646
4578
|
};
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
parseOutput(stdoutBuffer);
|
|
4650
|
-
});
|
|
4651
|
-
process2.stderr?.on("data", (data) => {
|
|
4652
|
-
stderrBuffer += data.toString();
|
|
4653
|
-
parseOutput(stderrBuffer);
|
|
4654
|
-
});
|
|
4655
|
-
process2.on("exit", (code, signal) => {
|
|
4656
|
-
const wasConnected = tunnelInfo.status === "connected";
|
|
4657
|
-
tunnelInfo.status = "disconnected";
|
|
4658
|
-
const currentState = this.tunnelStates.get(moduleUid);
|
|
4659
|
-
if (!urlFound) {
|
|
4660
|
-
const errorMsg = `Tunnel process exited with code ${code}`;
|
|
4661
|
-
tunnelInfo.status = "error";
|
|
4662
|
-
tunnelInfo.error = errorMsg;
|
|
4663
|
-
if (currentState && !currentState.intentionallyStopped) {
|
|
4664
|
-
this.attemptReconnect(moduleUid);
|
|
4665
|
-
} else {
|
|
4666
|
-
this.tunnelStates.delete(moduleUid);
|
|
4667
|
-
onStatusChange?.("error", errorMsg);
|
|
4668
|
-
this.emitEvent({ type: "error", moduleUid, error: errorMsg });
|
|
4669
|
-
}
|
|
4670
|
-
resolve3({ success: false, error: errorMsg });
|
|
4671
|
-
} else if (wasConnected) {
|
|
4672
|
-
if (currentState && !currentState.intentionallyStopped) {
|
|
4673
|
-
console.log(`[Tunnel] ${moduleUid} crashed unexpectedly, attempting reconnect...`);
|
|
4674
|
-
onStatusChange?.("reconnecting");
|
|
4675
|
-
this.attemptReconnect(moduleUid);
|
|
4676
|
-
} else {
|
|
4677
|
-
this.tunnelStates.delete(moduleUid);
|
|
4678
|
-
onStatusChange?.("disconnected");
|
|
4679
|
-
this.emitEvent({ type: "stopped", moduleUid });
|
|
4680
|
-
}
|
|
4681
|
-
}
|
|
4682
|
-
});
|
|
4683
|
-
process2.on("error", (error) => {
|
|
4684
|
-
tunnelInfo.status = "error";
|
|
4685
|
-
tunnelInfo.error = error.message;
|
|
4686
|
-
const currentState = this.tunnelStates.get(moduleUid);
|
|
4687
|
-
if (currentState && !currentState.intentionallyStopped) {
|
|
4688
|
-
this.attemptReconnect(moduleUid);
|
|
4689
|
-
} else {
|
|
4690
|
-
this.tunnelStates.delete(moduleUid);
|
|
4691
|
-
onStatusChange?.("error", error.message);
|
|
4692
|
-
this.emitEvent({ type: "error", moduleUid, error: error.message });
|
|
4693
|
-
}
|
|
4694
|
-
if (!urlFound) {
|
|
4695
|
-
resolve3({ success: false, error: error.message });
|
|
4696
|
-
}
|
|
4697
|
-
});
|
|
4698
|
-
setTimeout(() => {
|
|
4699
|
-
if (!urlFound) {
|
|
4700
|
-
process2.kill();
|
|
4701
|
-
const errorMsg = "Tunnel startup timed out after 30 seconds";
|
|
4702
|
-
tunnelInfo.status = "error";
|
|
4703
|
-
tunnelInfo.error = errorMsg;
|
|
4704
|
-
const currentState = this.tunnelStates.get(moduleUid);
|
|
4705
|
-
if (currentState && !currentState.intentionallyStopped) {
|
|
4706
|
-
this.attemptReconnect(moduleUid);
|
|
4707
|
-
} else {
|
|
4708
|
-
this.tunnelStates.delete(moduleUid);
|
|
4709
|
-
onStatusChange?.("error", errorMsg);
|
|
4710
|
-
this.emitEvent({ type: "error", moduleUid, error: errorMsg });
|
|
4711
|
-
}
|
|
4712
|
-
resolve3({ success: false, error: errorMsg });
|
|
4713
|
-
}
|
|
4714
|
-
}, TUNNEL_TIMEOUTS.QUICK_TUNNEL_CONNECT);
|
|
4715
|
-
});
|
|
4579
|
+
}
|
|
4580
|
+
return this.startNamedTunnelProcess(options, existingState);
|
|
4716
4581
|
}
|
|
4582
|
+
// EP1020: startQuickTunnelProcess removed - Quick Tunnels no longer supported
|
|
4583
|
+
// All tunnels now use Named Tunnels via Cloudflare API
|
|
4717
4584
|
/**
|
|
4718
4585
|
* Start a tunnel for a module
|
|
4719
4586
|
*
|
|
@@ -4782,8 +4649,11 @@ var TunnelManager = class extends import_events.EventEmitter {
|
|
|
4782
4649
|
previewUrl: provisionResult.tunnel.preview_url
|
|
4783
4650
|
};
|
|
4784
4651
|
} else {
|
|
4785
|
-
console.
|
|
4786
|
-
|
|
4652
|
+
console.error(`[Tunnel] EP1020: Named Tunnel provisioning failed for ${moduleUid}: ${provisionResult.error}`);
|
|
4653
|
+
return {
|
|
4654
|
+
success: false,
|
|
4655
|
+
error: `Named Tunnel provisioning failed: ${provisionResult.error}`
|
|
4656
|
+
};
|
|
4787
4657
|
}
|
|
4788
4658
|
}
|
|
4789
4659
|
return this.startTunnelProcess(resolvedOptions);
|
|
@@ -9265,18 +9135,6 @@ var Daemon = class _Daemon {
|
|
|
9265
9135
|
const result2 = await previewManager.restartPreview(moduleUid);
|
|
9266
9136
|
if (result2.success && result2.previewUrl) {
|
|
9267
9137
|
console.log(`[Daemon] EP833: Preview restarted for ${moduleUid}: ${result2.previewUrl}`);
|
|
9268
|
-
try {
|
|
9269
|
-
await fetchWithAuth(`${apiUrl}/api/modules/${moduleUid}/tunnel`, {
|
|
9270
|
-
method: "POST",
|
|
9271
|
-
body: JSON.stringify({
|
|
9272
|
-
tunnel_url: result2.previewUrl,
|
|
9273
|
-
tunnel_error: null,
|
|
9274
|
-
restart_reason: "health_check_failure"
|
|
9275
|
-
})
|
|
9276
|
-
});
|
|
9277
|
-
} catch (e) {
|
|
9278
|
-
console.warn(`[Daemon] EP833: Failed to report restarted tunnel URL`);
|
|
9279
|
-
}
|
|
9280
9138
|
} else {
|
|
9281
9139
|
console.error(`[Daemon] EP833: Preview restart failed for ${moduleUid}: ${result2.error}`);
|
|
9282
9140
|
}
|
|
@@ -9301,18 +9159,6 @@ var Daemon = class _Daemon {
|
|
|
9301
9159
|
});
|
|
9302
9160
|
if (result.success && result.previewUrl) {
|
|
9303
9161
|
console.log(`[Daemon] EP833: Preview started for ${moduleUid}: ${result.previewUrl}`);
|
|
9304
|
-
try {
|
|
9305
|
-
await fetchWithAuth(`${apiUrl}/api/modules/${moduleUid}/tunnel`, {
|
|
9306
|
-
method: "POST",
|
|
9307
|
-
body: JSON.stringify({
|
|
9308
|
-
tunnel_url: result.previewUrl,
|
|
9309
|
-
tunnel_error: null,
|
|
9310
|
-
restart_reason: "health_check_failure"
|
|
9311
|
-
})
|
|
9312
|
-
});
|
|
9313
|
-
} catch (e) {
|
|
9314
|
-
console.warn(`[Daemon] EP833: Failed to report restarted tunnel URL`);
|
|
9315
|
-
}
|
|
9316
9162
|
} else {
|
|
9317
9163
|
console.error(`[Daemon] EP833: Preview start failed for ${moduleUid}: ${result.error}`);
|
|
9318
9164
|
}
|