unplugin-https-reverse-proxy 1.0.0-beta.12 → 1.0.0-beta.14

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-XLSIGDFU.js";
4
- import "./chunk-RUJE3YFB.js";
3
+ } from "./chunk-SD5AGUG6.js";
4
+ import "./chunk-UGWFCSQS.js";
5
5
 
6
6
  // src/webpack.ts
7
7
  import { createWebpackPlugin } from "unplugin";
package/package.json CHANGED
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "name": "unplugin-https-reverse-proxy",
3
3
  "type": "module",
4
- "version": "1.0.0-beta.12",
5
- "packageManager": "pnpm@8.15.3",
4
+ "version": "1.0.0-beta.14",
6
5
  "description": "",
7
6
  "license": "MIT",
8
7
  "homepage": "https://github.com/zcf0508/unplugin-https-reverse-proxy#readme",
@@ -136,12 +135,14 @@
136
135
  "@rspack/core": "^0.5.4",
137
136
  "@types/kill-port": "^2.0.3",
138
137
  "@types/node": "^20.11.19",
138
+ "@types/proper-lockfile": "^4.1.4",
139
139
  "@vue/cli": "^5.0.8",
140
140
  "bumpp": "^9.3.0",
141
141
  "chalk": "^5.3.0",
142
142
  "eslint": "^8.56.0",
143
143
  "fast-glob": "^3.3.2",
144
144
  "nodemon": "^3.0.3",
145
+ "proper-lockfile": "^4.1.2",
145
146
  "rimraf": "^5.0.5",
146
147
  "rollup": "^3.29.4",
147
148
  "tsup": "^7.3.0",
@@ -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,56 @@ 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
+ }
138
+
139
+ async initCaddyfile() {
140
+ const contet = `
141
+ {
142
+ debug
143
+ auto_https disable_redirects
144
+ }
145
+
146
+ `
147
+ await writeFile(caddyFilePath, contet)
148
+ this.caddyfile = contet
149
+ }
150
+
151
+ async writeCaddyfile() {
152
+ return await writeFile(caddyFilePath, this.caddyfile || '')
153
+ }
154
+
155
+ async deleteCaddyfile() {
156
+ return await unlink(caddyFilePath)
110
157
  }
111
158
 
112
159
  async init() {
@@ -131,108 +178,167 @@ export class CaddyInstant {
131
178
  if (!this.inited)
132
179
  await this.init()
133
180
 
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
181
  if (!await addHost(source.split(':')[0], target.split(':')[0]))
140
182
  throw new Error('update host failed')
141
183
  consola.success('update host success\n')
142
184
 
185
+ await this.getCaddyfile()
186
+
187
+ if (!(this.caddyfile || '').includes(`${target.split(':')[0]}${https ? '' : ':80'}`)) {
188
+ this.caddyfile = `${this.caddyfile}
189
+ ${target.split(':')[0]}${https ? '' : ':80'} {
190
+ ${https ? 'tls internal' : ''}
191
+ reverse_proxy http://${source}
192
+ }
193
+
194
+ `
195
+
196
+ await this.writeCaddyfile()
197
+ }
198
+ if (!existsSync(caddyLockFilePath))
199
+ writeFileSync(caddyLockFilePath, '')
200
+
201
+ if (!this.locked) {
202
+ if (https && await tryPort(443))
203
+ await kill(443, 'tcp')
204
+ if ((process.platform === 'win32' || !https) && await tryPort(80))
205
+ await kill(80, 'tcp')
206
+ }
207
+
143
208
  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'])
209
+ const setupCleanup = () => {
210
+ process.on('SIGINT', async () => {
211
+ if (!restore || this.stoped)
212
+ return
213
+
214
+ if (!this.locked) {
215
+ try {
216
+ await this.lockfile.unlock(caddyLockFilePath)
217
+ await unlink(caddyFilePath)
218
+ await unlink(caddyLockFilePath)
219
+ }
220
+ catch (e) {
221
+ // consola.error(e)
222
+ }
223
+ }
148
224
 
149
- child.on('error', (err) => {
150
- return reject(err)
151
- })
225
+ try {
226
+ if (await removeHost(source.split(':')[0], target.split(':')[0]))
227
+ consola.success('Restore host success.\n')
152
228
 
153
- process.on('SIGINT', async () => {
154
- if (!restore || this.stoped)
155
- return
229
+ else
230
+ consola.fail('Restore host failed.\n')
231
+ }
232
+ catch (e) {
233
+ consola.error(e)
234
+ consola.fail('Restore host failed.\n')
235
+ }
236
+ finally {
237
+ this.stoped = true
238
+ process.nextTick(() => {
239
+ process.exit()
240
+ })
241
+ }
242
+ })
243
+
244
+ const originalExit = process.exit.bind(process)
245
+
246
+ // @ts-expect-error override
247
+ process.exit = async (code?: number) => {
248
+ const port = Number(source.split(':')[1])
249
+ if (!Number.isNaN(port) && await tryPort(port))
250
+ await kill(port, 'tcp')
251
+
252
+ // fix `Error: EPERM: operation not permitted`
253
+ const pwd = process.cwd()
254
+ const viteCacheDir = `${pwd}/node_modules/.vite`
255
+ if (existsSync(viteCacheDir))
256
+ chmodRecursive(viteCacheDir, 0o777)
257
+ const nuxtCacheDir = `${pwd}/.nuxt`
258
+ if (existsSync(nuxtCacheDir))
259
+ await chmodRecursive(nuxtCacheDir, 0o777)
260
+ const webpackCacheDir = `${pwd}/node_modules/.cache`
261
+ if (existsSync(webpackCacheDir))
262
+ chmodRecursive(webpackCacheDir, 0o777)
263
+
264
+ if (!restore || this.stoped)
265
+ return originalExit(code)
266
+
267
+ if (!this.locked) {
268
+ try {
269
+ await this.lockfile.unlock(caddyLockFilePath)
270
+ await unlink(caddyFilePath)
271
+ await unlink(caddyLockFilePath)
272
+ }
273
+ catch (e) {
274
+ // consola.error(e)
275
+ }
276
+ }
156
277
 
157
- try {
158
- if (await removeHost(source.split(':')[0], target.split(':')[0]))
159
- consola.success('restore host success\n')
278
+ try {
279
+ if (await removeHost(source.split(':')[0], target.split(':')[0]))
280
+ consola.success('Restore host success.\n')
160
281
 
161
- else
162
- consola.fail('restore host failed\n')
163
- }
164
- catch (e) {
165
- consola.error(e)
166
- consola.fail('restore host failed\n')
167
- }
168
- finally {
169
- this.stoped = true
170
- process.nextTick(() => {
171
- process.exit()
172
- })
173
- }
174
- })
175
-
176
- const originalExit = process.exit.bind(process)
177
-
178
- // @ts-expect-error override
179
- process.exit = async (code?: number) => {
180
- const port = Number(source.split(':')[1])
181
- if (!Number.isNaN(port) && await tryPort(port))
182
- await kill(port, 'tcp')
183
-
184
- // fix `Error: EPERM: operation not permitted`
185
- const pwd = process.cwd()
186
- const viteCacheDir = `${pwd}/node_modules/.vite`
187
- if (existsSync(viteCacheDir))
188
- chmodRecursive(viteCacheDir, 0o777)
189
- const nuxtCacheDir = `${pwd}/.nuxt`
190
- if (existsSync(nuxtCacheDir))
191
- await chmodRecursive(nuxtCacheDir, 0o777)
192
- const webpackCacheDir = `${pwd}/node_modules/.cache`
193
- if (existsSync(webpackCacheDir))
194
- chmodRecursive(webpackCacheDir, 0o777)
195
-
196
- if (!restore || this.stoped)
197
- return originalExit(code)
198
-
199
- try {
200
- if (await removeHost(source.split(':')[0], target.split(':')[0]))
201
- consola.success('restore host success\n')
202
-
203
- else
204
- consola.fail('restore host failed\n')
205
- }
206
- catch (e) {
207
- consola.error(e)
208
- consola.fail('restore host failed\n')
209
- }
210
- finally {
211
- this.stoped = true
212
- process.nextTick(() => {
213
- originalExit(code)
214
- })
282
+ else
283
+ consola.fail('Restore host failed.\n')
284
+ }
285
+ catch (e) {
286
+ consola.error(e)
287
+ consola.fail('Restore host failed.\n')
288
+ }
289
+ finally {
290
+ this.stoped = true
291
+ process.nextTick(() => {
292
+ originalExit(code)
293
+ })
294
+ }
215
295
  }
216
296
  }
217
297
 
218
- child.stderr.on('data', (data) => {
219
- const lines = (data.toString() as string).split('\n').map(line => line.trim())
220
- for (const line of lines) {
221
- // caddy log
222
- // eslint-disable-next-line no-console
223
- showCaddyLog && line && console.info(line)
224
- if (line.includes('Error:') || (line && JSON.parse(line).level === 'error')) {
225
- consola.error(line)
226
- // child.kill()
227
- return reject(line)
298
+ if (!this.locked) {
299
+ const child = process.platform !== 'win32'
300
+ ? spawn('sudo', ['-E', caddyPath, 'run', '--config', caddyFilePath, '--watch'])
301
+ : spawn(caddyPath, ['run', '--config', caddyFilePath, '--watch'])
302
+
303
+ this.lockfile.lockSync(caddyLockFilePath)
304
+
305
+ child.on('error', (err) => {
306
+ return reject(err)
307
+ })
308
+
309
+ child.stderr.on('data', (data) => {
310
+ const lines = (data.toString() as string).split('\n').map(line => line.trim())
311
+ for (const line of lines) {
312
+ // caddy log
313
+ // eslint-disable-next-line no-console
314
+ showCaddyLog && line && console.info(line)
315
+ if (line.includes('Error:') || (line && JSON.parse(line).level === 'error')) {
316
+ consola.error(`${line}\n`)
317
+ // child.kill()
318
+ return reject(line)
319
+ }
320
+ if (line.includes('config file changed'))
321
+ consola.success('Detect added a new reverse proxy config, restarted.\n')
322
+
323
+ if (line.includes('caddy proxying') || line.includes('serving initial'))
324
+ return resolve()
228
325
  }
229
- }
230
- })
326
+ })
231
327
 
232
- child.stdout.on('data', (_data) => {
233
- consola.info(_data.toString())
234
- resolve()
235
- })
328
+ child.stdout.on('data', (_data) => {
329
+ consola.info(_data.toString())
330
+ resolve()
331
+ })
332
+
333
+ setupCleanup()
334
+ }
335
+ else {
336
+ consola.info('Caddy is running in another process.')
337
+
338
+ setupCleanup()
339
+
340
+ return resolve()
341
+ }
236
342
  })
237
343
  }
238
344
  }