@wwkit/cft 1.0.18 → 1.0.20

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/bin/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { execSync } from 'node:child_process'
4
4
  import { readFileSync } from 'node:fs'
5
- import { install, status, clear, showConfig, showEnv } from '../src/index.js'
5
+ import { install, status, clear, showConfig, showEnv, getProxy } from '../src/index.js'
6
6
 
7
7
  const pkgVersion = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version
8
8
 
@@ -45,7 +45,10 @@ if (command === 'install') {
45
45
  } else if (command === 'env') {
46
46
  showEnv()
47
47
  } else if (command === 'upgrade') {
48
- execSync('npm install -g @wwkit/cft@latest', { stdio: 'inherit' })
48
+ const proxy = getProxy()
49
+ const npmArgs = ['install', '-g', '@wwkit/cft@latest']
50
+ if (proxy) npmArgs.push('--proxy', proxy)
51
+ execSync(`npm ${npmArgs.join(' ')}`, { stdio: 'inherit', shell: true })
49
52
  } else if (command === 'version') {
50
53
  console.log(pkgVersion)
51
54
  } else if (command === 'help' || command === undefined) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wwkit/cft",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "author": "bluesliu <langcai163@163.com>",
5
5
  "description": "Chrome for Testing (CFT) installer — download, extract, chmod, dep-check",
6
6
  "type": "module",
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "extract-zip": "^2.0.1",
39
- "@wwkit/shared": "1.0.18"
39
+ "@wwkit/shared": "1.0.20"
40
40
  },
41
41
  "devDependencies": {
42
42
  "jest": "^29.7.0"
package/src/config.js CHANGED
@@ -9,6 +9,8 @@ const INSTALL_DIR = getXdgConfigDir('cft')
9
9
  const _loader = createConfigLoader({
10
10
  builtinConfigPath: path.join(__dirname, 'config.json5'),
11
11
  userConfigDir: INSTALL_DIR,
12
+ envContentVar: 'CFT_CONFIG_CONTENT',
13
+ envDirVar: 'CFT_CONFIG_DIR',
12
14
  })
13
15
 
14
16
  export const INSTALL_LOCATION = INSTALL_DIR
package/src/installer.js CHANGED
@@ -9,7 +9,7 @@ import { getOs, VALID_OS_TYPES } from './platform.js'
9
9
  import { find as findExe } from './exefinder.js'
10
10
  import { check as checkDeps, mapToPackages, install as installDeps, isSupported as depsSupported, detectPackageManager } from './depchecker.js'
11
11
  import { getVersion, getRegistry, getProxy, getLocation, copyBuiltinConfig } from './config.js'
12
- import { parseProxy, openTunnel } from './proxy.js'
12
+ import { parseProxy, openTunnel } from '@wwkit/shared'
13
13
 
14
14
  const USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 cft-installer'
15
15
  const MANUAL_DOWNLOAD_HINT = '资源下载失败,请在 http://deepbluenet.com/webwork/#/mirror 手动下载资源,并将资源解压到 ~/.config/cft 目录,然后将地址添加到 ~/.config/webwork/webwork.json5 中的 env.SELENIUM_CFT_DIR 属性上'
@@ -75,6 +75,9 @@ function checkUrlReachable(url, proxyValue) {
75
75
  response.resume()
76
76
  if (response.statusCode >= 200 && response.statusCode < 400) {
77
77
  resolve(true)
78
+ } else if (response.statusCode === 405) {
79
+ // 405 Method Not Allowed — 服务器已响应,仅不支持 HEAD
80
+ resolve(true)
78
81
  } else {
79
82
  resolve(false)
80
83
  }
@@ -253,7 +256,7 @@ export async function install(opts = {}) {
253
256
  const registry = getRegistry()
254
257
  const location = getLocation()
255
258
  const osType = getOs()
256
- const proxy = opts.proxy ?? getProxy()
259
+ const proxy = opts.proxy || getProxy()
257
260
 
258
261
  if (!VALID_OS_TYPES.includes(osType)) {
259
262
  throw new Error(`Unsupported OS: ${osType}`)
package/src/proxy.js DELETED
@@ -1,72 +0,0 @@
1
- import net from 'node:net'
2
- import http from 'node:http'
3
-
4
- export function parseProxy(raw) {
5
- if (!raw) return null
6
- try {
7
- const u = new URL(raw)
8
- if (!u.hostname) return null
9
- if (u.protocol !== 'http:' && u.protocol !== 'https:' && u.protocol !== 'socks5:' && u.protocol !== 'socks:') {
10
- return null
11
- }
12
- return u
13
- } catch {
14
- return null
15
- }
16
- }
17
-
18
- function socks5Connect(proxy, host, port) {
19
- return new Promise((resolve, reject) => {
20
- const sock = net.connect(Number(proxy.port) || 1080, proxy.hostname)
21
- let phase = 'greeting'
22
- const cleanup = (err) => { sock.removeAllListeners(); sock.destroy(); reject(err) }
23
- sock.once('error', cleanup)
24
- sock.once('connect', () => {
25
- sock.write(Buffer.from([0x05, 0x01, 0x00]))
26
- })
27
- sock.on('data', (data) => {
28
- if (phase === 'greeting') {
29
- if (data[0] !== 0x05 || data[1] !== 0x00) { cleanup(new Error(`socks5 代理拒绝无认证 (method=${data[1]})`)); return }
30
- phase = 'connect'
31
- const hostBuf = Buffer.from(host, 'utf8')
32
- const req = Buffer.alloc(7 + hostBuf.length)
33
- req[0] = 0x05; req[1] = 0x01; req[2] = 0x00; req[3] = 0x03
34
- req[4] = hostBuf.length
35
- hostBuf.copy(req, 5)
36
- req.writeUInt16BE(port, 5 + hostBuf.length)
37
- sock.write(req)
38
- } else if (phase === 'connect') {
39
- if (data[0] !== 0x05 || data[1] !== 0x00) { cleanup(new Error(`socks5 连接失败 (code=${data[1]})`)); return }
40
- sock.removeAllListeners('data')
41
- sock.removeListener('error', cleanup)
42
- resolve(sock)
43
- }
44
- })
45
- })
46
- }
47
-
48
- function httpConnect(proxy, host, port) {
49
- return new Promise((resolve, reject) => {
50
- const req = http.request({
51
- method: 'CONNECT',
52
- host: proxy.hostname,
53
- port: Number(proxy.port) || 80,
54
- path: `${host}:${port}`,
55
- })
56
- req.once('error', reject)
57
- req.once('connect', (res, socket) => {
58
- if (res.statusCode !== 200) { socket.destroy(); reject(new Error(`HTTP 代理 CONNECT 返回 ${res.statusCode}`)); return }
59
- resolve(socket)
60
- })
61
- req.end()
62
- })
63
- }
64
-
65
- export async function openTunnel(proxy, target) {
66
- const host = target.hostname
67
- const port = Number(target.port) || (target.protocol === 'https:' ? 443 : 80)
68
- if (proxy.protocol === 'socks5:' || proxy.protocol === 'socks:') {
69
- return socks5Connect(proxy, host, port)
70
- }
71
- return httpConnect(proxy, host, port)
72
- }