unplugin-https-reverse-proxy 0.0.4 → 0.0.6
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/package.json +3 -2
- package/src/caddy/constants.ts +117 -0
- package/src/caddy/index.ts +212 -0
- package/src/caddy/utils.ts +26 -0
- package/src/esbuild.ts +4 -0
- package/src/index.ts +105 -0
- package/src/nuxt.ts +22 -0
- package/src/rollup.ts +4 -0
- package/src/types.ts +4 -0
- package/src/vite.ts +4 -0
- package/src/webpack.ts +4 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "unplugin-https-reverse-proxy",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.6",
|
|
5
5
|
"packageManager": "pnpm@8.6.12",
|
|
6
6
|
"description": "",
|
|
7
7
|
"license": "MIT",
|
|
@@ -70,7 +70,8 @@
|
|
|
70
70
|
}
|
|
71
71
|
},
|
|
72
72
|
"files": [
|
|
73
|
-
"dist"
|
|
73
|
+
"dist",
|
|
74
|
+
"src"
|
|
74
75
|
],
|
|
75
76
|
"peerDependencies": {
|
|
76
77
|
"@nuxt/kit": "^3",
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { join } from 'node:path'
|
|
2
|
+
import process from 'node:process'
|
|
3
|
+
|
|
4
|
+
const TEMP_DIR = process.env.TEMP || process.env.TMPDIR || '/tmp'
|
|
5
|
+
export const caddyPath = join(TEMP_DIR, `caddy${process.platform === 'win32' ? '.exe' : ''}`)
|
|
6
|
+
export const caddyFilePath = join(TEMP_DIR, 'CADDYFILE')
|
|
7
|
+
|
|
8
|
+
export const supportList = [
|
|
9
|
+
{
|
|
10
|
+
platform: 'dragonfly',
|
|
11
|
+
arch: 'amd64',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
platform: 'freebsd',
|
|
15
|
+
arch: 'amd64',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
platform: 'freebsd',
|
|
19
|
+
arch: 'arm-6',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
platform: 'freebsd',
|
|
23
|
+
arch: 'arm-7',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
platform: 'freebsd',
|
|
27
|
+
arch: 'arm64',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
platform: 'linux',
|
|
31
|
+
arch: 'amd64',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
platform: 'linux',
|
|
35
|
+
arch: 'arm-5',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
platform: 'linux',
|
|
39
|
+
arch: 'arm-6',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
platform: 'linux',
|
|
43
|
+
arch: 'arm-7',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
platform: 'linux',
|
|
47
|
+
arch: 'arm64',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
platform: 'linux',
|
|
51
|
+
arch: 'mips',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
platform: 'linux',
|
|
55
|
+
arch: 'mips64',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
platform: 'linux',
|
|
59
|
+
arch: 'mips64le',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
platform: 'linux',
|
|
63
|
+
arch: 'mipsle',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
platform: 'linux',
|
|
67
|
+
arch: 'ppc64',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
platform: 'linux',
|
|
71
|
+
arch: 'ppc64le',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
platform: 'linux',
|
|
75
|
+
arch: 's390x',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
platform: 'darwin',
|
|
79
|
+
arch: 'amd64',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
platform: 'darwin',
|
|
83
|
+
arch: 'arm64',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
platform: 'openbsd',
|
|
87
|
+
arch: 'amd64',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
platform: 'openbsd',
|
|
91
|
+
arch: 'arm-6',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
platform: 'openbsd',
|
|
95
|
+
arch: 'arm-7',
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
platform: 'openbsd',
|
|
99
|
+
arch: 'arm64',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
platform: 'windows',
|
|
103
|
+
arch: 'amd64',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
platform: 'windows',
|
|
107
|
+
arch: 'arm-6',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
platform: 'windows',
|
|
111
|
+
arch: 'arm-7',
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
platform: 'windows',
|
|
115
|
+
arch: 'arm64',
|
|
116
|
+
},
|
|
117
|
+
]
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { platform } from 'node:os'
|
|
2
|
+
import process from 'node:process'
|
|
3
|
+
import { chmodSync, createWriteStream, existsSync, unlinkSync } from 'node:fs'
|
|
4
|
+
import { spawn } from 'node:child_process'
|
|
5
|
+
import { got } from 'got-cjs'
|
|
6
|
+
import { HttpProxyAgent } from 'http-proxy-agent'
|
|
7
|
+
import { HttpsProxyAgent } from 'https-proxy-agent'
|
|
8
|
+
import * as hostile from 'hostile'
|
|
9
|
+
import kill from 'kill-port'
|
|
10
|
+
import { caddyPath, supportList } from './constants'
|
|
11
|
+
import { tryPort } from './utils'
|
|
12
|
+
|
|
13
|
+
export async function download() {
|
|
14
|
+
if (await testCaddy())
|
|
15
|
+
return caddyPath
|
|
16
|
+
|
|
17
|
+
return new Promise<string>((resolve, reject) => {
|
|
18
|
+
// https://caddyserver.com/api/download?os=darwin&arch=amd64
|
|
19
|
+
|
|
20
|
+
const file = createWriteStream(caddyPath)
|
|
21
|
+
|
|
22
|
+
let _platform = platform().toString()
|
|
23
|
+
// win32 -> windows
|
|
24
|
+
_platform === 'win32' && (_platform = 'windows')
|
|
25
|
+
let _arch = process.arch.toString()
|
|
26
|
+
// x64 -> amd64
|
|
27
|
+
_arch === 'x64' && (_arch = 'amd64')
|
|
28
|
+
|
|
29
|
+
const support = supportList.find(item => item.platform === _platform && item.arch === _arch)
|
|
30
|
+
|
|
31
|
+
if (!support)
|
|
32
|
+
return reject(new Error('not support'))
|
|
33
|
+
|
|
34
|
+
const dowmloadLink = `https://caddyserver.com/api/download?os=${support.platform}&arch=${support.arch}`
|
|
35
|
+
|
|
36
|
+
existsSync(caddyPath) && unlinkSync(caddyPath)
|
|
37
|
+
|
|
38
|
+
const httpProxy = process.env.HTTP_PROXY || process.env.http_proxy
|
|
39
|
+
const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy
|
|
40
|
+
|
|
41
|
+
const httpAgent = httpProxy ? new HttpProxyAgent(httpProxy) : undefined
|
|
42
|
+
const httpsAgent = httpsProxy ? new HttpsProxyAgent(httpsProxy) : undefined
|
|
43
|
+
|
|
44
|
+
got.stream(dowmloadLink, {
|
|
45
|
+
agent: {
|
|
46
|
+
http: httpAgent,
|
|
47
|
+
https: httpsAgent,
|
|
48
|
+
},
|
|
49
|
+
}).pipe(file).on('finish', () => {
|
|
50
|
+
if (process.platform === 'win32')
|
|
51
|
+
return resolve(caddyPath)
|
|
52
|
+
// chmod +x
|
|
53
|
+
chmodSync(caddyPath, 0o755)
|
|
54
|
+
resolve(caddyPath)
|
|
55
|
+
}).on('error', (err) => {
|
|
56
|
+
// console.log(err)
|
|
57
|
+
reject(err)
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function testCaddy() {
|
|
63
|
+
return new Promise((resolve, reject) => {
|
|
64
|
+
if (!existsSync(caddyPath))
|
|
65
|
+
return resolve(false)
|
|
66
|
+
chmodSync(caddyPath, 0o755)
|
|
67
|
+
const child = process.platform === 'win32' ? spawn(caddyPath, []) : spawn('sudo', [caddyPath])
|
|
68
|
+
child.on('close', () => {
|
|
69
|
+
return resolve(true)
|
|
70
|
+
})
|
|
71
|
+
child.on('error', (err) => {
|
|
72
|
+
return reject(err)
|
|
73
|
+
})
|
|
74
|
+
child.stdout.on('data', (_data) => {
|
|
75
|
+
return resolve(true)
|
|
76
|
+
})
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
interface RunOptions {
|
|
81
|
+
restore: boolean
|
|
82
|
+
base: string
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export class CaddyInstant {
|
|
86
|
+
private inited = false
|
|
87
|
+
|
|
88
|
+
constructor() {
|
|
89
|
+
testCaddy().then(() => {
|
|
90
|
+
this.inited = true
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async init() {
|
|
95
|
+
await download()
|
|
96
|
+
this.inited = true
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private async updateHost(ip: string, host: string) {
|
|
100
|
+
['localhost', '0.0.0.0'].includes(ip) && (ip = '127.0.0.1')
|
|
101
|
+
return new Promise<boolean>((resolve, reject) => {
|
|
102
|
+
hostile.set(ip, host, (err) => {
|
|
103
|
+
if (err) {
|
|
104
|
+
return reject(err)
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
if (process.platform === 'win32') {
|
|
108
|
+
spawn('ipconfig', ['/flushdns']).on('error', (err) => {
|
|
109
|
+
return reject(err)
|
|
110
|
+
}).on('close', () => {
|
|
111
|
+
resolve(true)
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
spawn('sudo', ['killall', '-HUP', 'mDNSResponder']).on('error', (err) => {
|
|
116
|
+
return reject(err)
|
|
117
|
+
}).on('close', () => {
|
|
118
|
+
resolve(true)
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private async restoreHost(ip: string, host: string) {
|
|
127
|
+
['localhost', '0.0.0.0'].includes(ip) && (ip = '127.0.0.1')
|
|
128
|
+
return new Promise<boolean>((resolve, reject) => {
|
|
129
|
+
hostile.remove(ip, host, (err) => {
|
|
130
|
+
if (err) {
|
|
131
|
+
return reject(err)
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
if (process.platform === 'win32') {
|
|
135
|
+
spawn('ipconfig', ['/flushdns']).on('error', (err) => {
|
|
136
|
+
return reject(err)
|
|
137
|
+
}).on('close', () => {
|
|
138
|
+
resolve(true)
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
spawn('sudo', ['killall', '-HUP', 'mDNSResponder']).on('error', (err) => {
|
|
143
|
+
return reject(err)
|
|
144
|
+
}).on('close', () => {
|
|
145
|
+
resolve(true)
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @param source like `127.0.0.1:8080`
|
|
155
|
+
* @param target like `test.abc.com`. And if you provide a port ,it will be ignore.
|
|
156
|
+
* @returns
|
|
157
|
+
*/
|
|
158
|
+
async run(source: string, target: string, options?: Partial<RunOptions>) {
|
|
159
|
+
source = source.replace('0.0.0.0', '127.0.0.1').replace('localhost', '127.0.0.1')
|
|
160
|
+
const {
|
|
161
|
+
restore = true,
|
|
162
|
+
base = '/',
|
|
163
|
+
} = options || {}
|
|
164
|
+
|
|
165
|
+
if (!this.inited)
|
|
166
|
+
await this.init()
|
|
167
|
+
|
|
168
|
+
if (!await this.updateHost(source.split(':')[0], target.split(':')[0]))
|
|
169
|
+
throw new Error('update host failed')
|
|
170
|
+
|
|
171
|
+
if (await tryPort(443))
|
|
172
|
+
await kill(443, 'tcp')
|
|
173
|
+
if (process.platform === 'win32' && await tryPort(80))
|
|
174
|
+
await kill(80, 'tcp')
|
|
175
|
+
|
|
176
|
+
return new Promise<() => Promise<void>>((resolve, reject) => {
|
|
177
|
+
// caddy reverse-proxy --from target --to source --internal-certs
|
|
178
|
+
const child = process.platform !== 'win32'
|
|
179
|
+
? spawn('sudo', [caddyPath, 'reverse-proxy', '--from', `${target.split(':')[0]}`, '--to', `${source}`, '--internal-certs'])
|
|
180
|
+
: spawn(caddyPath, ['reverse-proxy', '--from', `${target.split(':')[0]}`, '--to', `${source}`, '--internal-certs'])
|
|
181
|
+
|
|
182
|
+
child.on('error', (err) => {
|
|
183
|
+
return reject(err)
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
child.stderr.on('data', (data) => {
|
|
187
|
+
if ((data.toString() as string).includes('Error')) {
|
|
188
|
+
child.kill()
|
|
189
|
+
return reject(data.toString())
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
child.stdout.on('data', (_data) => {
|
|
194
|
+
// eslint-disable-next-line no-console
|
|
195
|
+
console.log(_data.toString())
|
|
196
|
+
resolve(async () => {
|
|
197
|
+
if (!restore)
|
|
198
|
+
return
|
|
199
|
+
|
|
200
|
+
if (await this.restoreHost(source.split(':')[0], target.split(':')[0])) {
|
|
201
|
+
// eslint-disable-next-line no-console
|
|
202
|
+
console.log('restore host success\n')
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
console.error('restore host failed\n')
|
|
206
|
+
}
|
|
207
|
+
child.kill()
|
|
208
|
+
})
|
|
209
|
+
})
|
|
210
|
+
})
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createServer } from 'node:net'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @returns whether the port is in use
|
|
5
|
+
*/
|
|
6
|
+
export function tryPort(port: number) {
|
|
7
|
+
return new Promise<boolean>((resolve, reject) => {
|
|
8
|
+
try {
|
|
9
|
+
const server = createServer().listen(port)
|
|
10
|
+
server.on('listening', () => {
|
|
11
|
+
server.close()
|
|
12
|
+
resolve(false)
|
|
13
|
+
})
|
|
14
|
+
server.on('error', (err) => {
|
|
15
|
+
// @ts-expect-error err.code
|
|
16
|
+
if (err.code === 'EADDRINUSE')
|
|
17
|
+
resolve(true)
|
|
18
|
+
server.close()
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
catch (e) {
|
|
22
|
+
// console.log(e)
|
|
23
|
+
resolve(true)
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
}
|
package/src/esbuild.ts
ADDED
package/src/index.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import process from 'node:process'
|
|
2
|
+
import type { UnpluginFactory } from 'unplugin'
|
|
3
|
+
import { createUnplugin } from 'unplugin'
|
|
4
|
+
import type { ResolvedConfig } from 'vite'
|
|
5
|
+
import c from 'picocolors'
|
|
6
|
+
import type { Options } from './types'
|
|
7
|
+
import { CaddyInstant } from './caddy'
|
|
8
|
+
|
|
9
|
+
let config: ResolvedConfig
|
|
10
|
+
|
|
11
|
+
let caddy: CaddyInstant
|
|
12
|
+
|
|
13
|
+
export const unpluginFactory: UnpluginFactory<Options> = options => ({
|
|
14
|
+
name: 'unplugin-https-reverse-proxy',
|
|
15
|
+
enforce: 'post',
|
|
16
|
+
vite: {
|
|
17
|
+
configResolved(_config) {
|
|
18
|
+
config = _config
|
|
19
|
+
},
|
|
20
|
+
configureServer(server) {
|
|
21
|
+
const {
|
|
22
|
+
target = '',
|
|
23
|
+
} = options
|
|
24
|
+
if (!target) {
|
|
25
|
+
// eslint-disable-next-line no-console
|
|
26
|
+
console.log('please provide target')
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
server.printUrls = () => {
|
|
30
|
+
let source = `localhost:${config.server.port}`
|
|
31
|
+
const url = server.resolvedUrls?.local[0]
|
|
32
|
+
if (url) {
|
|
33
|
+
const u = new URL(url)
|
|
34
|
+
source = u.host
|
|
35
|
+
}
|
|
36
|
+
const base = server.config.base || '/'
|
|
37
|
+
try {
|
|
38
|
+
const caddy = new CaddyInstant()
|
|
39
|
+
caddy.run(source, target, {
|
|
40
|
+
base,
|
|
41
|
+
}).then((stop) => {
|
|
42
|
+
const colorUrl = (url: string) => c.green(url.replace(/:(\d+)\//, (_, port) => `:${c.bold(port)}/`))
|
|
43
|
+
// eslint-disable-next-line no-console
|
|
44
|
+
console.log(` ${c.green('➜')} ${c.bold('run caddy reverse proxy success')}: ${colorUrl(`https://${target}${base}`)}`)
|
|
45
|
+
|
|
46
|
+
process.on('SIGINT', async () => {
|
|
47
|
+
await stop()
|
|
48
|
+
server.close()
|
|
49
|
+
process.exit()
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
console.error(e)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
webpack(compiler) {
|
|
60
|
+
const {
|
|
61
|
+
target = '',
|
|
62
|
+
} = options
|
|
63
|
+
if (!target) {
|
|
64
|
+
// eslint-disable-next-line no-console
|
|
65
|
+
console.log('please provide target')
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
// @ts-expect-error vuecli
|
|
70
|
+
const devServer = compiler.options.devServer || process.VUE_CLI_SERVICE.projectOptions.devServer
|
|
71
|
+
const source = `${devServer?.host || '127.0.0.1'}:${devServer?.port || '8080'}`
|
|
72
|
+
|
|
73
|
+
if (caddy)
|
|
74
|
+
return
|
|
75
|
+
|
|
76
|
+
caddy = new CaddyInstant()
|
|
77
|
+
|
|
78
|
+
caddy.run(source, target).then((stop) => {
|
|
79
|
+
const colorUrl = (url: string) => c.green(url.replace(/:(\d+)\//, (_, port) => `:${c.bold(port)}/`))
|
|
80
|
+
|
|
81
|
+
compiler.hooks.done.tap('unplugin-https-reverse-proxy', (stats) => {
|
|
82
|
+
if (stats.hasErrors())
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
// eslint-disable-next-line no-console
|
|
86
|
+
console.log(` ${c.green('➜')} ${c.bold('run caddy reverse proxy success')}: ${colorUrl(`https://${target}`)}`)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
process.on('SIGINT', async () => {
|
|
90
|
+
await stop()
|
|
91
|
+
process.exit()
|
|
92
|
+
})
|
|
93
|
+
}).catch((e) => {
|
|
94
|
+
throw e
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
catch (e) {
|
|
98
|
+
console.error(e)
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
export const unplugin = /* #__PURE__ */ createUnplugin(unpluginFactory)
|
|
104
|
+
|
|
105
|
+
export default unplugin
|
package/src/nuxt.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { addVitePlugin, addWebpackPlugin, defineNuxtModule } from '@nuxt/kit'
|
|
2
|
+
import vite from './vite'
|
|
3
|
+
import webpack from './webpack'
|
|
4
|
+
import type { Options } from './types'
|
|
5
|
+
import '@nuxt/schema'
|
|
6
|
+
|
|
7
|
+
export interface ModuleOptions extends Options {
|
|
8
|
+
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default defineNuxtModule<ModuleOptions>({
|
|
12
|
+
meta: {
|
|
13
|
+
name: 'nuxt-unplugin-https-reverse-proxy',
|
|
14
|
+
configKey: 'unpluginHttpsReverseProxy',
|
|
15
|
+
},
|
|
16
|
+
setup(options, _nuxt) {
|
|
17
|
+
addVitePlugin(() => vite(options))
|
|
18
|
+
addWebpackPlugin(() => webpack(options))
|
|
19
|
+
|
|
20
|
+
// ...
|
|
21
|
+
},
|
|
22
|
+
})
|
package/src/rollup.ts
ADDED
package/src/types.ts
ADDED
package/src/vite.ts
ADDED
package/src/webpack.ts
ADDED