UNPKG

3.46 kBJavaScriptView Raw
1const fetch = require("node-fetch");
2const fs = require("fs");
3const os = require("os");
4const path = require("path");
5const execa = require("execa");
6const chalk = require("chalk");
7const { fetchLatest, updateAvailable } = require("gh-release-fetch");
8const {
9 NETLIFYDEVLOG,
10 // NETLIFYDEVWARN,
11 NETLIFYDEVERR
12} = require("netlify-cli-logo");
13
14async function createTunnel(siteId, netlifyApiToken, log) {
15 await installTunnelClient(log);
16
17 if (!siteId) {
18 // eslint-disable-next-line no-console
19 console.error(
20 `${NETLIFYDEVERR} Error: no siteId defined, did you forget to run ${chalk.yellow(
21 "netlify init"
22 )} or ${chalk.yellow("netlify link")}?`
23 );
24 process.exit(1);
25 }
26 log(`${NETLIFYDEVLOG} Creating Live Tunnel for ` + siteId);
27 const url = `https://api.netlify.com/api/v1/live_sessions?site_id=${siteId}`;
28
29 const response = await fetch(url, {
30 method: "POST",
31 headers: {
32 "Content-Type": "application/json",
33 Authorization: `Bearer ${netlifyApiToken}`
34 },
35 body: JSON.stringify({})
36 });
37
38 const data = await response.json();
39
40 if (response.status !== 201) {
41 throw new Error(data.message);
42 }
43
44 return data;
45}
46
47async function connectTunnel(session, netlifyApiToken, localPort, log) {
48 const execPath = path.join(
49 os.homedir(),
50 ".netlify",
51 "tunnel",
52 "bin",
53 "live-tunnel-client"
54 );
55 const args = [
56 "connect",
57 "-s",
58 session.id,
59 "-t",
60 netlifyApiToken,
61 "-l",
62 localPort
63 ];
64 if (process.env.DEBUG) {
65 args.push("-v");
66 log(execPath, args);
67 }
68
69 const ps = execa(execPath, args, { stdio: "inherit" });
70 ps.on("close", code => process.exit(code));
71 ps.on("SIGINT", process.exit);
72 ps.on("SIGTERM", process.exit);
73}
74
75async function installTunnelClient(log) {
76 const binPath = path.join(os.homedir(), ".netlify", "tunnel", "bin");
77 const execPath = path.join(binPath, "live-tunnel-client");
78 const newVersion = await fetchTunnelClient(execPath);
79 if (!newVersion) {
80 return;
81 }
82
83 log(`${NETLIFYDEVLOG} Installing Live Tunnel Client`);
84
85 const win = isWindows();
86 const platform = win ? "windows" : process.platform;
87 const extension = win ? "zip" : "tar.gz";
88 const release = {
89 repository: "netlify/live-tunnel-client",
90 package: `live-tunnel-client-${platform}-amd64.${extension}`,
91 destination: binPath,
92 extract: true
93 };
94 await fetchLatest(release);
95}
96
97async function fetchTunnelClient(execPath) {
98 if (!execExist(execPath)) {
99 return true;
100 }
101
102 const { stdout } = await execa(execPath, ["version"]);
103 if (!stdout) {
104 return false;
105 }
106
107 const match = stdout.match(/^live-tunnel-client\/v?([^\s]+)/);
108 if (!match) {
109 return false;
110 }
111
112 return updateAvailable("netlify/live-tunnel-client", match[1]);
113}
114
115function execExist(binPath) {
116 if (!fs.existsSync(binPath)) {
117 return false;
118 }
119 const stat = fs.statSync(binPath);
120 return stat && stat.isFile() && isExe(stat.mode, stat.gid, stat.uid);
121}
122
123function isExe(mode, gid, uid) {
124 if (isWindows()) {
125 return true;
126 }
127
128 const isGroup = gid ? process.getgid && gid === process.getgid() : true;
129 const isUser = uid ? process.getuid && uid === process.getuid() : true;
130
131 return Boolean(
132 mode & 0o0001 || (mode & 0o0010 && isGroup) || (mode & 0o0100 && isUser)
133 );
134}
135
136function isWindows() {
137 return process.platform === "win32";
138}
139
140module.exports = {
141 createTunnel: createTunnel,
142 connectTunnel: connectTunnel
143};