unplugin-https-reverse-proxy 1.0.0-beta.13 → 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-MMFIKYNA.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,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.14",
5
5
  "description": "",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/zcf0508/unplugin-https-reverse-proxy#readme",
@@ -135,12 +135,14 @@
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",
@@ -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,110 +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'])
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)
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
+ }
163
223
  }
164
- if (line.includes('caddy proxying'))
165
- return resolve()
166
- }
167
- })
168
224
 
169
- child.stdout.on('data', (_data) => {
170
- consola.info(_data.toString())
171
- resolve()
172
- })
225
+ try {
226
+ if (await removeHost(source.split(':')[0], target.split(':')[0]))
227
+ consola.success('Restore host success.\n')
173
228
 
174
- process.on('SIGINT', async () => {
175
- if (!restore || this.stoped)
176
- 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
+ }
177
277
 
178
- try {
179
- if (await removeHost(source.split(':')[0], target.split(':')[0]))
180
- 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')
181
281
 
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
- })
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
+ }
236
295
  }
237
296
  }
297
+
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()
325
+ }
326
+ })
327
+
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
+ }
238
342
  })
239
343
  }
240
344
  }