UNPKG

3.4 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('./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(os.homedir(), '.netlify', 'tunnel', 'bin', 'live-tunnel-client')
49 const args = ['connect', '-s', session.id, '-t', netlifyApiToken, '-l', localPort]
50 if (process.env.DEBUG) {
51 args.push('-v')
52 log(execPath, args)
53 }
54
55 const ps = execa(execPath, args, { stdio: 'inherit' })
56 ps.on('close', code => process.exit(code))
57 ps.on('SIGINT', process.exit)
58 ps.on('SIGTERM', process.exit)
59}
60
61async function installTunnelClient(log) {
62 const win = isWindows()
63 const binPath = path.join(os.homedir(), '.netlify', 'tunnel', 'bin')
64 const execName = win ? 'live-tunnel-client.exe' : 'live-tunnel-client'
65 const execPath = path.join(binPath, execName)
66 const newVersion = await fetchTunnelClient(execPath)
67 if (!newVersion) {
68 return
69 }
70
71 log(`${NETLIFYDEVLOG} Installing Live Tunnel Client`)
72
73 const platform = win ? 'windows' : process.platform
74 const extension = win ? 'zip' : 'tar.gz'
75 const release = {
76 repository: 'netlify/live-tunnel-client',
77 package: `live-tunnel-client-${platform}-amd64.${extension}`,
78 destination: binPath,
79 extract: true
80 }
81 await fetchLatest(release)
82}
83
84async function fetchTunnelClient(execPath) {
85 if (!execExist(execPath)) {
86 return true
87 }
88
89 const { stdout } = await execa(execPath, ['version'])
90 if (!stdout) {
91 return false
92 }
93
94 const match = stdout.match(/^live-tunnel-client\/v?([^\s]+)/)
95 if (!match) {
96 return false
97 }
98
99 return updateAvailable('netlify/live-tunnel-client', match[1])
100}
101
102function execExist(binPath) {
103 if (!fs.existsSync(binPath)) {
104 return false
105 }
106 const stat = fs.statSync(binPath)
107 return stat && stat.isFile() && isExe(stat.mode, stat.gid, stat.uid)
108}
109
110function isExe(mode, gid, uid) {
111 if (isWindows()) {
112 return true
113 }
114
115 const isGroup = gid ? process.getgid && gid === process.getgid() : true
116 const isUser = uid ? process.getuid && uid === process.getuid() : true
117
118 return Boolean(mode & 0o0001 || (mode & 0o0010 && isGroup) || (mode & 0o0100 && isUser))
119}
120
121function isWindows() {
122 return process.platform === 'win32'
123}
124
125module.exports = {
126 createTunnel: createTunnel,
127 connectTunnel: connectTunnel
128}