unplugin-https-reverse-proxy 1.0.0-beta.13 → 1.0.0-beta.15

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/webpack.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  unpluginFactory
3
- } from "./chunk-MMFIKYNA.js";
4
- import "./chunk-RUJE3YFB.js";
3
+ } from "./chunk-GV7Y22GZ.js";
4
+ import "./chunk-UGWFCSQS.js";
5
5
 
6
6
  // src/webpack.ts
7
7
  import { createWebpackPlugin } from "unplugin";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "unplugin-https-reverse-proxy",
3
3
  "type": "module",
4
- "version": "1.0.0-beta.13",
4
+ "version": "1.0.0-beta.15",
5
5
  "description": "",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/zcf0508/unplugin-https-reverse-proxy#readme",
@@ -135,18 +135,20 @@
135
135
  "@rspack/core": "^0.5.4",
136
136
  "@types/kill-port": "^2.0.3",
137
137
  "@types/node": "^20.11.19",
138
+ "@types/proper-lockfile": "^4.1.4",
138
139
  "@vue/cli": "^5.0.8",
139
140
  "bumpp": "^9.3.0",
140
141
  "chalk": "^5.3.0",
141
142
  "eslint": "^8.56.0",
142
143
  "fast-glob": "^3.3.2",
143
144
  "nodemon": "^3.0.3",
145
+ "proper-lockfile": "^4.1.2",
144
146
  "rimraf": "^5.0.5",
145
147
  "rollup": "^3.29.4",
146
148
  "tsup": "^7.3.0",
147
149
  "typescript": "^5.3.3",
148
150
  "vite": "^4.5.2",
149
- "vitest": "^0.34.6",
151
+ "vitest": "^2.0.5",
150
152
  "webpack": "^5.90.3"
151
153
  },
152
154
  "scripts": {
@@ -162,6 +164,6 @@
162
164
  "play:vuecli4": "npm -C examples/vuecli4 run serve",
163
165
  "release": "bumpp",
164
166
  "start": "tsx src/index.ts",
165
- "test": "vitest"
167
+ "test": "UHRP_CADDY_PATH='./test/.uhrp' vitest"
166
168
  }
167
169
  }
@@ -50,6 +50,7 @@ var import_node_os2 = require("os");
50
50
  var import_node_process4 = __toESM(require("process"), 1);
51
51
  var import_node_fs2 = require("fs");
52
52
  var import_node_child_process3 = require("child_process");
53
+ var import_promises2 = require("fs/promises");
53
54
  var import_got_cjs = require("got-cjs");
54
55
  var import_http_proxy_agent = require("http-proxy-agent");
55
56
  var import_https_proxy_agent = require("https-proxy-agent");
@@ -85,6 +86,7 @@ function resolvePath(path2) {
85
86
  var TEMP_DIR = resolvePath(import_node_process3.default.env.UHRP_CADDY_PATH || import_node_process3.default.env.TEMP || import_node_process3.default.env.TMPDIR || "/tmp");
86
87
  var caddyPath = (0, import_node_path2.join)(TEMP_DIR, `caddy${import_node_process3.default.platform === "win32" ? ".exe" : ""}`);
87
88
  var caddyFilePath = (0, import_node_path2.join)(TEMP_DIR, "CADDYFILE");
89
+ var caddyLockFilePath = (0, import_node_path2.join)(TEMP_DIR, "caddylock");
88
90
  var supportList = [
89
91
  {
90
92
  platform: "dragonfly",
@@ -16,6 +16,7 @@ function resolvePath(path: string) {
16
16
  export const TEMP_DIR = resolvePath(process.env.UHRP_CADDY_PATH || process.env.TEMP || process.env.TMPDIR || '/tmp')
17
17
  export const caddyPath = join(TEMP_DIR, `caddy${process.platform === 'win32' ? '.exe' : ''}`)
18
18
  export const caddyFilePath = join(TEMP_DIR, 'CADDYFILE')
19
+ export const caddyLockFilePath = join(TEMP_DIR, 'caddylock')
19
20
 
20
21
  export const supportList = [
21
22
  {
@@ -1,14 +1,15 @@
1
1
  import { platform } from 'node:os'
2
2
  import process from 'node:process'
3
- import { chmodSync, createWriteStream, existsSync, mkdirSync, unlinkSync } from 'node:fs'
3
+ import { chmodSync, createWriteStream, existsSync, mkdirSync, unlinkSync, writeFileSync } from 'node:fs'
4
4
  import { spawn } from 'node:child_process'
5
+ import { readFile, unlink, writeFile } from 'node:fs/promises'
5
6
  import { got } from 'got-cjs'
6
7
  import { HttpProxyAgent } from 'http-proxy-agent'
7
8
  import { HttpsProxyAgent } from 'https-proxy-agent'
8
9
  import kill from 'kill-port'
9
10
  import { chmodRecursive, consola, once } from '../utils'
10
11
  import { addHost, removeHost } from '../host'
11
- import { TEMP_DIR, caddyPath, supportList } from './constants'
12
+ import { TEMP_DIR, caddyFilePath, caddyLockFilePath, caddyPath, supportList } from './constants'
12
13
  import { logProgress, logProgressOver, tryPort } from './utils'
13
14
 
14
15
  export async function download() {
@@ -103,10 +104,57 @@ export class CaddyInstant {
103
104
  private inited = false
104
105
  private stoped = false
105
106
 
107
+ /** has locked */
108
+ private locked = false
109
+ private caddyfile: string | undefined
110
+
111
+ private lockfile: typeof import('proper-lockfile')
112
+
106
113
  constructor() {
107
- testCaddy().then(() => {
114
+ testCaddy().then(async () => {
115
+ await this.getCaddyfile()
116
+
108
117
  this.inited = true
109
118
  })
119
+
120
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
121
+ this.lockfile = require('proper-lockfile')
122
+
123
+ this.locked = this.checkLock()
124
+ }
125
+
126
+ checkLock() {
127
+ if (!existsSync(caddyLockFilePath))
128
+ writeFileSync(caddyLockFilePath, '')
129
+ return this.lockfile.checkSync(caddyLockFilePath)
130
+ }
131
+
132
+ async getCaddyfile() {
133
+ if (!existsSync(caddyFilePath))
134
+ await this.initCaddyfile()
135
+
136
+ this.caddyfile = await readFile(caddyFilePath, 'utf-8')
137
+ return this.caddyfile
138
+ }
139
+
140
+ async initCaddyfile() {
141
+ const contet = `
142
+ {
143
+ debug
144
+ auto_https disable_redirects
145
+ }
146
+
147
+ `
148
+ await writeFile(caddyFilePath, contet)
149
+ this.caddyfile = contet
150
+ }
151
+
152
+ async writeCaddyfile() {
153
+ return await writeFile(caddyFilePath, this.caddyfile || '')
154
+ }
155
+
156
+ async deleteCaddyfile() {
157
+ return await unlink(caddyFilePath)
110
158
  }
111
159
 
112
160
  async init() {
@@ -131,110 +179,162 @@ export class CaddyInstant {
131
179
  if (!this.inited)
132
180
  await this.init()
133
181
 
134
- if (https && await tryPort(443))
135
- await kill(443, 'tcp')
136
- if ((process.platform === 'win32' || !https) && await tryPort(80))
137
- await kill(80, 'tcp')
138
-
139
182
  if (!await addHost(source.split(':')[0], target.split(':')[0]))
140
183
  throw new Error('update host failed')
141
184
  consola.success('update host success\n')
142
185
 
186
+ await this.getCaddyfile()
187
+
188
+ if (!(this.caddyfile || '').includes(`${target.split(':')[0]}${https ? '' : ':80'}`)) {
189
+ this.caddyfile = `${this.caddyfile}
190
+ ${target.split(':')[0]}${https ? '' : ':80'} {
191
+ ${https ? 'tls internal' : ''}
192
+ reverse_proxy http://${source}
193
+ }
194
+
195
+ `
196
+
197
+ await this.writeCaddyfile()
198
+ }
199
+ if (!existsSync(caddyLockFilePath))
200
+ writeFileSync(caddyLockFilePath, '')
201
+
202
+ if (!this.locked) {
203
+ if (await tryPort(443))
204
+ await kill(443, 'tcp')
205
+ if ((process.platform === 'win32' || !https) && await tryPort(80))
206
+ await kill(80, 'tcp')
207
+ }
208
+
143
209
  return new Promise<void>((resolve, reject) => {
144
- // caddy reverse-proxy --from target --to source --internal-certs
145
- const child = process.platform !== 'win32'
146
- ? spawn('sudo', ['-E', caddyPath, 'reverse-proxy', '--from', `${target.split(':')[0]}${https ? '' : ':80'}`, '--to', `${source}`, '--internal-certs', '--insecure', '--disable-redirects'])
147
- : spawn(caddyPath, ['reverse-proxy', '--from', `${target.split(':')[0]}`, '--to', `${source}`, '--internal-certs'])
148
-
149
- child.on('error', (err) => {
150
- return reject(err)
151
- })
152
-
153
- child.stderr.on('data', (data) => {
154
- const lines = (data.toString() as string).split('\n').map(line => line.trim())
155
- for (const line of lines) {
156
- // caddy log
157
- // eslint-disable-next-line no-console
158
- showCaddyLog && line && console.info(line)
159
- if (line.includes('Error:') || (line && JSON.parse(line).level === 'error')) {
160
- consola.error(line)
161
- // child.kill()
162
- return reject(line)
210
+ const setupCleanup = () => {
211
+ process.on('SIGINT', async () => {
212
+ if (!restore || this.stoped)
213
+ return
214
+
215
+ await this.baseCleanup()
216
+
217
+ try {
218
+ if (await removeHost(source.split(':')[0], target.split(':')[0]))
219
+ consola.success('Restore host success.\n')
220
+
221
+ else
222
+ consola.fail('Restore host failed.\n')
223
+ }
224
+ catch (e) {
225
+ consola.error(e)
226
+ consola.fail('Restore host failed.\n')
227
+ }
228
+ finally {
229
+ this.stoped = true
230
+ process.nextTick(() => {
231
+ process.exit()
232
+ })
233
+ }
234
+ })
235
+
236
+ const originalExit = process.exit.bind(process)
237
+
238
+ // @ts-expect-error override
239
+ process.exit = async (code?: number) => {
240
+ const port = Number(source.split(':')[1])
241
+ if (!Number.isNaN(port) && await tryPort(port))
242
+ await kill(port, 'tcp')
243
+
244
+ // fix `Error: EPERM: operation not permitted`
245
+ const pwd = process.cwd()
246
+ const viteCacheDir = `${pwd}/node_modules/.vite`
247
+ if (existsSync(viteCacheDir))
248
+ chmodRecursive(viteCacheDir, 0o777)
249
+ const nuxtCacheDir = `${pwd}/.nuxt`
250
+ if (existsSync(nuxtCacheDir))
251
+ await chmodRecursive(nuxtCacheDir, 0o777)
252
+ const webpackCacheDir = `${pwd}/node_modules/.cache`
253
+ if (existsSync(webpackCacheDir))
254
+ chmodRecursive(webpackCacheDir, 0o777)
255
+
256
+ if (!restore || this.stoped)
257
+ return originalExit(code)
258
+
259
+ await this.baseCleanup()
260
+
261
+ try {
262
+ if (await removeHost(source.split(':')[0], target.split(':')[0]))
263
+ consola.success('Restore host success.\n')
264
+
265
+ else
266
+ consola.fail('Restore host failed.\n')
267
+ }
268
+ catch (e) {
269
+ consola.error(e)
270
+ consola.fail('Restore host failed.\n')
271
+ }
272
+ finally {
273
+ this.stoped = true
274
+ process.nextTick(() => {
275
+ originalExit(code)
276
+ })
163
277
  }
164
- if (line.includes('caddy proxying'))
165
- return resolve()
166
278
  }
167
- })
279
+ }
280
+
281
+ if (!this.locked) {
282
+ const child = process.platform !== 'win32'
283
+ ? spawn('sudo', ['-E', caddyPath, 'run', '--config', caddyFilePath, '--watch'])
284
+ : spawn(caddyPath, ['run', '--config', caddyFilePath, '--watch'])
285
+
286
+ this.lockfile.lockSync(caddyLockFilePath)
287
+
288
+ child.on('error', (err) => {
289
+ return reject(err)
290
+ })
291
+
292
+ child.stderr.on('data', (data) => {
293
+ const lines = (data.toString() as string).split('\n').map(line => line.trim())
294
+ for (const line of lines) {
295
+ // caddy log
296
+ // eslint-disable-next-line no-console
297
+ showCaddyLog && line && console.info(line)
298
+ if (line.includes('Error:') || (line && JSON.parse(line).level === 'error')) {
299
+ consola.error(`${line}\n`)
300
+ // child.kill()
301
+ return reject(line)
302
+ }
303
+ if (line.includes('config file changed'))
304
+ consola.success('Detect added a new reverse proxy config, restarted.\n')
305
+
306
+ if (line.includes('caddy proxying') || line.includes('serving initial'))
307
+ return resolve()
308
+ }
309
+ })
168
310
 
169
- child.stdout.on('data', (_data) => {
170
- consola.info(_data.toString())
171
- resolve()
172
- })
311
+ child.stdout.on('data', (_data) => {
312
+ consola.info(_data.toString())
313
+ resolve()
314
+ })
173
315
 
174
- process.on('SIGINT', async () => {
175
- if (!restore || this.stoped)
176
- return
316
+ setupCleanup()
317
+ }
318
+ else {
319
+ consola.info('Caddy is running in another process.')
177
320
 
178
- try {
179
- if (await removeHost(source.split(':')[0], target.split(':')[0]))
180
- consola.success('restore host success\n')
321
+ setupCleanup()
181
322
 
182
- else
183
- consola.fail('restore host failed\n')
184
- }
185
- catch (e) {
186
- consola.error(e)
187
- consola.fail('restore host failed\n')
188
- }
189
- finally {
190
- this.stoped = true
191
- process.nextTick(() => {
192
- process.exit()
193
- })
194
- }
195
- })
196
-
197
- const originalExit = process.exit.bind(process)
198
-
199
- // @ts-expect-error override
200
- process.exit = async (code?: number) => {
201
- const port = Number(source.split(':')[1])
202
- if (!Number.isNaN(port) && await tryPort(port))
203
- await kill(port, 'tcp')
204
-
205
- // fix `Error: EPERM: operation not permitted`
206
- const pwd = process.cwd()
207
- const viteCacheDir = `${pwd}/node_modules/.vite`
208
- if (existsSync(viteCacheDir))
209
- chmodRecursive(viteCacheDir, 0o777)
210
- const nuxtCacheDir = `${pwd}/.nuxt`
211
- if (existsSync(nuxtCacheDir))
212
- await chmodRecursive(nuxtCacheDir, 0o777)
213
- const webpackCacheDir = `${pwd}/node_modules/.cache`
214
- if (existsSync(webpackCacheDir))
215
- chmodRecursive(webpackCacheDir, 0o777)
216
-
217
- if (!restore || this.stoped)
218
- return originalExit(code)
219
-
220
- try {
221
- if (await removeHost(source.split(':')[0], target.split(':')[0]))
222
- consola.success('restore host success\n')
223
-
224
- else
225
- consola.fail('restore host failed\n')
226
- }
227
- catch (e) {
228
- consola.error(e)
229
- consola.fail('restore host failed\n')
230
- }
231
- finally {
232
- this.stoped = true
233
- process.nextTick(() => {
234
- originalExit(code)
235
- })
236
- }
323
+ return resolve()
237
324
  }
238
325
  })
239
326
  }
327
+
328
+ async baseCleanup() {
329
+ if (!this.locked) {
330
+ try {
331
+ await this.lockfile.unlock(caddyLockFilePath)
332
+ await unlink(caddyFilePath)
333
+ await unlink(caddyLockFilePath)
334
+ }
335
+ catch (e) {
336
+ // consola.error(e)
337
+ }
338
+ }
339
+ }
240
340
  }