@iicp/client 0.7.54 → 0.7.57

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/tunnel.js ADDED
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Quick-Tunnel escalation — #520 rung 5 of the NAT ladder.
5
+ * TypeScript port of iicp-client-python/tunnel.py (0f97ca1).
6
+ *
7
+ * When every NAT variant fails (no direct endpoint, no UPnP pinhole, no IPv6
8
+ * GUA, no relay-capable peer in the directory), the node can still become
9
+ * publicly reachable with ZERO account, domain, or router changes: spawn
10
+ * `cloudflared tunnel --url http://127.0.0.1:<port>` and register the issued
11
+ * `https://*.trycloudflare.com` URL as the endpoint.
12
+ *
13
+ * Lifecycle is fully automatic: setup (binary detection — never auto-installed),
14
+ * initiation (spawn + URL parse ≤20 s), supervision (bounded respawn; URL
15
+ * rotates → caller re-registers), teardown (close() idempotent + process-exit
16
+ * hook so a normal exit never orphans the child).
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.QuickTunnel = exports.INSTALL_HINT = exports.MAX_RESPAWNS = exports.TUNNEL_START_TIMEOUT_MS = void 0;
20
+ exports.cloudflaredPath = cloudflaredPath;
21
+ exports.openQuickTunnel = openQuickTunnel;
22
+ const node_child_process_1 = require("node:child_process");
23
+ const fs = require("node:fs");
24
+ const path = require("node:path");
25
+ const URL_RE = /https:\/\/[a-z0-9-]+\.trycloudflare\.com/;
26
+ /** cloudflared usually prints the URL within ~5 s; 20 s covers slow first runs. */
27
+ exports.TUNNEL_START_TIMEOUT_MS = 20_000;
28
+ /** Bounded self-healing: after this many unexpected deaths, stop respawning. */
29
+ exports.MAX_RESPAWNS = 3;
30
+ exports.INSTALL_HINT = "cloudflared not found — install it to become reachable without router " +
31
+ "changes (zero-account Quick Tunnel): " +
32
+ "macOS `brew install cloudflared` · Linux: https://pkg.cloudflare.com · " +
33
+ "Windows `winget install Cloudflare.cloudflared`";
34
+ /** Locate the cloudflared binary on PATH, or null (we never auto-install it). */
35
+ function cloudflaredPath() {
36
+ const exts = process.platform === "win32" ? [".exe", ".cmd", ""] : [""];
37
+ for (const dir of (process.env.PATH ?? "").split(path.delimiter)) {
38
+ if (!dir)
39
+ continue;
40
+ for (const ext of exts) {
41
+ const candidate = path.join(dir, `cloudflared${ext}`);
42
+ try {
43
+ fs.accessSync(candidate, fs.constants.X_OK);
44
+ return candidate;
45
+ }
46
+ catch {
47
+ /* keep scanning */
48
+ }
49
+ }
50
+ }
51
+ return null;
52
+ }
53
+ /** A running Quick Tunnel: public `url` → `http://127.0.0.1:<localPort>`. */
54
+ class QuickTunnel {
55
+ process;
56
+ url;
57
+ localPort;
58
+ _binary;
59
+ _closed = false;
60
+ _respawns = 0;
61
+ _exitHook;
62
+ constructor(proc, url, localPort, binary) {
63
+ this.process = proc;
64
+ this.url = url;
65
+ this.localPort = localPort;
66
+ this._binary = binary;
67
+ this._exitHook = () => this.close();
68
+ process.on("exit", this._exitHook);
69
+ }
70
+ get respawns() {
71
+ return this._respawns;
72
+ }
73
+ /**
74
+ * Start the watchdog: on unexpected exit, respawn (bounded) and call
75
+ * `onNewUrl(newUrl)` — Quick Tunnel URLs rotate per process, so the caller
76
+ * MUST re-register. After MAX_RESPAWNS, `onDead()` fires once.
77
+ */
78
+ watch(onNewUrl, onDead) {
79
+ const arm = (proc) => {
80
+ proc.once("exit", () => {
81
+ if (this._closed)
82
+ return;
83
+ void (async () => {
84
+ this._respawns += 1;
85
+ if (this._respawns > exports.MAX_RESPAWNS) {
86
+ console.error(`[quick-tunnel] died ${this._respawns - 1} times — giving up. ` +
87
+ "Node is no longer publicly reachable; restart `iicp-node serve` to recover.");
88
+ onDead();
89
+ return;
90
+ }
91
+ console.warn(`[quick-tunnel] exited unexpectedly — respawning (${this._respawns}/${exports.MAX_RESPAWNS})…`);
92
+ let fresh;
93
+ try {
94
+ fresh = await openQuickTunnel(this.localPort, exports.TUNNEL_START_TIMEOUT_MS, this._binary);
95
+ }
96
+ catch (exc) {
97
+ console.error(`[quick-tunnel] respawn failed: ${exc instanceof Error ? exc.message : exc}`);
98
+ onDead();
99
+ return;
100
+ }
101
+ // Adopt the fresh child; drop its own exit-hook (ours stays armed).
102
+ process.removeListener("exit", fresh._exitHook);
103
+ this.process = fresh.process;
104
+ this.url = fresh.url;
105
+ console.log(`[quick-tunnel] back up at ${this.url} — re-registering.`);
106
+ arm(this.process);
107
+ onNewUrl(this.url);
108
+ })();
109
+ });
110
+ };
111
+ arm(this.process);
112
+ }
113
+ /** Terminate the tunnel child. Idempotent; also runs on process exit. */
114
+ close() {
115
+ if (this._closed)
116
+ return;
117
+ this._closed = true;
118
+ process.removeListener("exit", this._exitHook);
119
+ if (this.process.exitCode === null && !this.process.killed) {
120
+ this.process.kill("SIGTERM");
121
+ }
122
+ }
123
+ }
124
+ exports.QuickTunnel = QuickTunnel;
125
+ /**
126
+ * Spawn cloudflared and resolve with the running tunnel + its public URL.
127
+ * Rejects with INSTALL_HINT when the binary is absent, or a timeout error
128
+ * when no URL appears within `timeoutMs`.
129
+ */
130
+ function openQuickTunnel(localPort, timeoutMs = exports.TUNNEL_START_TIMEOUT_MS, binary) {
131
+ return new Promise((resolve, reject) => {
132
+ const resolved = binary ?? cloudflaredPath();
133
+ if (!resolved) {
134
+ reject(new Error(exports.INSTALL_HINT));
135
+ return;
136
+ }
137
+ const proc = (0, node_child_process_1.spawn)(resolved, ["tunnel", "--url", `http://127.0.0.1:${localPort}`], {
138
+ stdio: ["ignore", "pipe", "pipe"],
139
+ });
140
+ let settled = false;
141
+ const timer = setTimeout(() => {
142
+ if (settled)
143
+ return;
144
+ settled = true;
145
+ proc.kill("SIGTERM");
146
+ reject(new Error(`cloudflared produced no tunnel URL within ${timeoutMs / 1000}s`));
147
+ }, timeoutMs);
148
+ const onChunk = (chunk) => {
149
+ if (settled)
150
+ return; // keep draining (streams stay flowing) but ignore
151
+ const m = URL_RE.exec(chunk.toString());
152
+ if (m) {
153
+ settled = true;
154
+ clearTimeout(timer);
155
+ console.log(`[quick-tunnel] up: ${m[0]} → http://127.0.0.1:${localPort}`);
156
+ resolve(new QuickTunnel(proc, m[0], localPort, resolved));
157
+ }
158
+ };
159
+ // cloudflared logs to stderr; read both to be version-proof. Attaching
160
+ // handlers keeps the pipes flowing so the child never blocks on a full pipe.
161
+ proc.stdout?.on("data", onChunk);
162
+ proc.stderr?.on("data", onChunk);
163
+ proc.once("exit", (code) => {
164
+ if (settled)
165
+ return;
166
+ settled = true;
167
+ clearTimeout(timer);
168
+ reject(new Error(`cloudflared exited (code=${code}) before printing a tunnel URL`));
169
+ });
170
+ proc.once("error", (err) => {
171
+ if (settled)
172
+ return;
173
+ settled = true;
174
+ clearTimeout(timer);
175
+ reject(err);
176
+ });
177
+ });
178
+ }
179
+ //# sourceMappingURL=tunnel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tunnel.js","sourceRoot":"","sources":["../src/tunnel.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iicp/client",
3
- "version": "0.7.54",
3
+ "version": "0.7.57",
4
4
  "description": "Official TypeScript/JavaScript SDK for the IICP protocol (ADR-016)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",