@jonathanleelx/meddle 0.4.0-beta.3 → 0.4.0-beta.4
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/commands/update.js +10 -4
- package/bin/lib/update-check.js +48 -21
- package/package.json +1 -1
package/bin/commands/update.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Usage:
|
|
5
5
|
* meddle update check and upgrade to the latest version
|
|
6
|
+
* meddle update --beta check and upgrade to the latest beta version
|
|
6
7
|
* meddle update --check only check, print the available version
|
|
7
8
|
* meddle update --version <x.y.z> install a specific version
|
|
8
9
|
* meddle update --auto on|off enable/disable auto-update (default off)
|
|
@@ -45,7 +46,9 @@ meddle update - 检查并升级 meddle
|
|
|
45
46
|
|
|
46
47
|
用法:
|
|
47
48
|
meddle update 检查并升级到最新版本
|
|
49
|
+
meddle update --beta 检查并升级到最新的 beta 测试版本
|
|
48
50
|
meddle update --check 仅检查,提示可用版本 (有新版本时退出码为 2)
|
|
51
|
+
meddle update --check --beta 仅检查 beta 版本
|
|
49
52
|
meddle update --version <x.y.z> 安装指定版本
|
|
50
53
|
meddle update --auto on|off 启用/禁用自动更新 (默认关闭)
|
|
51
54
|
meddle update status 查看安装方式、当前版本和自动更新开关
|
|
@@ -53,12 +56,13 @@ meddle update - 检查并升级 meddle
|
|
|
53
56
|
`)
|
|
54
57
|
}
|
|
55
58
|
|
|
56
|
-
async function resolveLatest({ force = false, notify = true } = {}) {
|
|
59
|
+
async function resolveLatest({ force = false, notify = true, channel = 'stable' } = {}) {
|
|
57
60
|
const info = await checkForUpdate({
|
|
58
61
|
home,
|
|
59
62
|
installMethod,
|
|
60
63
|
current,
|
|
61
64
|
force,
|
|
65
|
+
channel,
|
|
62
66
|
})
|
|
63
67
|
if (notify) {
|
|
64
68
|
if (info.outdated) {
|
|
@@ -114,6 +118,7 @@ async function run() {
|
|
|
114
118
|
const flag = args.find((a) => a === '--check' || a === 'status' || a === '--help' || a === '-h')
|
|
115
119
|
const versionFlagIndex = args.indexOf('--version')
|
|
116
120
|
const autoFlagIndex = args.indexOf('--auto')
|
|
121
|
+
const channel = args.includes('--beta') ? 'beta' : 'stable'
|
|
117
122
|
|
|
118
123
|
if (flag === '--help' || flag === '-h') {
|
|
119
124
|
showHelp()
|
|
@@ -121,9 +126,10 @@ async function run() {
|
|
|
121
126
|
}
|
|
122
127
|
|
|
123
128
|
if (flag === 'status') {
|
|
124
|
-
const info = await resolveLatest({ notify: false })
|
|
129
|
+
const info = await resolveLatest({ notify: false, channel })
|
|
125
130
|
output.header('Meddle Update Status')
|
|
126
131
|
output.kv('Install method', installMethod)
|
|
132
|
+
output.kv('Channel', channel)
|
|
127
133
|
output.kv('Current', info.current)
|
|
128
134
|
output.kv('Latest', info.latest)
|
|
129
135
|
output.kv('Auto-update', getAutoUpdate(home) ? 'on' : 'off')
|
|
@@ -170,13 +176,13 @@ async function run() {
|
|
|
170
176
|
}
|
|
171
177
|
|
|
172
178
|
if (flag === '--check') {
|
|
173
|
-
const info = await resolveLatest()
|
|
179
|
+
const info = await resolveLatest({ channel })
|
|
174
180
|
if (info.outdated) process.exit(2)
|
|
175
181
|
return
|
|
176
182
|
}
|
|
177
183
|
|
|
178
184
|
// default: check + upgrade
|
|
179
|
-
const info = await resolveLatest()
|
|
185
|
+
const info = await resolveLatest({ channel })
|
|
180
186
|
if (!info.outdated) return
|
|
181
187
|
await installVersion(info.latest)
|
|
182
188
|
}
|
package/bin/lib/update-check.js
CHANGED
|
@@ -20,7 +20,9 @@ const { resolveMeddleHome } = require('./meddle-home')
|
|
|
20
20
|
const PACKAGE_NAME = '@jonathanleelx/meddle'
|
|
21
21
|
const REPO = 'JonathanLee-LX/meddle'
|
|
22
22
|
const DEFAULT_NPM_REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`
|
|
23
|
+
const DEFAULT_NPM_BETA_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/beta`
|
|
23
24
|
const DEFAULT_GITHUB_LATEST_URL = `https://github.com/${REPO}/releases/latest`
|
|
25
|
+
const DEFAULT_GITHUB_RELEASES_URL = `https://api.github.com/repos/${REPO}/releases`
|
|
24
26
|
const DEFAULT_DOWNLOAD_BASE_URL = `https://github.com/${REPO}/releases/download`
|
|
25
27
|
const DEFAULT_CACHE_TTL_MS = 24 * 60 * 60 * 1000
|
|
26
28
|
const DEFAULT_TIMEOUT_MS = 5000
|
|
@@ -95,12 +97,14 @@ function compareVersions(a, b) {
|
|
|
95
97
|
|
|
96
98
|
/**
|
|
97
99
|
* Fetch the latest version from the npm registry.
|
|
98
|
-
* @param {{ fetchImpl?: Function, registryUrl?: string, timeoutMs?: number }} opts
|
|
100
|
+
* @param {{ fetchImpl?: Function, registryUrl?: string, timeoutMs?: number, distTag?: string }} opts
|
|
99
101
|
* @returns {Promise<string>}
|
|
100
102
|
*/
|
|
101
|
-
async function getLatestVersionNpm({ fetchImpl, registryUrl, timeoutMs } = {}) {
|
|
103
|
+
async function getLatestVersionNpm({ fetchImpl, registryUrl, timeoutMs, distTag } = {}) {
|
|
102
104
|
const doFetch = fetchImpl || fetch
|
|
103
|
-
const url = registryUrl
|
|
105
|
+
const url = registryUrl
|
|
106
|
+
|| process.env.MEDDLE_NPM_REGISTRY_URL
|
|
107
|
+
|| (distTag === 'beta' ? DEFAULT_NPM_BETA_URL : DEFAULT_NPM_REGISTRY_URL)
|
|
104
108
|
const response = await doFetch(url, { signal: AbortSignal.timeout(timeoutMs || DEFAULT_TIMEOUT_MS) })
|
|
105
109
|
if (!response.ok) throw new Error(`npm registry responded ${response.status}`)
|
|
106
110
|
const data = await response.json()
|
|
@@ -110,24 +114,42 @@ async function getLatestVersionNpm({ fetchImpl, registryUrl, timeoutMs } = {}) {
|
|
|
110
114
|
}
|
|
111
115
|
|
|
112
116
|
/**
|
|
113
|
-
* Fetch the latest version from the
|
|
114
|
-
*
|
|
117
|
+
* Fetch the latest version from GitHub. For stable, follow the releases/latest
|
|
118
|
+
* redirect (prereleases excluded). For includePrerelease, list releases via the
|
|
119
|
+
* GitHub API and pick the highest version.
|
|
120
|
+
* @param {{ fetchImpl?: Function, latestUrl?: string, timeoutMs?: number, includePrerelease?: boolean, releasesUrl?: string }} opts
|
|
115
121
|
* @returns {Promise<string>}
|
|
116
122
|
*/
|
|
117
|
-
async function getLatestVersionGithub({ fetchImpl, latestUrl, timeoutMs } = {}) {
|
|
123
|
+
async function getLatestVersionGithub({ fetchImpl, latestUrl, timeoutMs, includePrerelease = false, releasesUrl } = {}) {
|
|
118
124
|
const doFetch = fetchImpl || fetch
|
|
119
|
-
|
|
125
|
+
if (!includePrerelease) {
|
|
126
|
+
const url = latestUrl || process.env.MEDDLE_GITHUB_LATEST_URL || DEFAULT_GITHUB_LATEST_URL
|
|
127
|
+
const response = await doFetch(url, {
|
|
128
|
+
redirect: 'manual',
|
|
129
|
+
signal: AbortSignal.timeout(timeoutMs || DEFAULT_TIMEOUT_MS),
|
|
130
|
+
})
|
|
131
|
+
if (response.status < 300 || response.status >= 400) {
|
|
132
|
+
throw new Error(`GitHub latest release did not redirect (${response.status})`)
|
|
133
|
+
}
|
|
134
|
+
const location = response.headers.get('location') || ''
|
|
135
|
+
const match = /\/tag\/(v?[\d][\w.-]*)$/.exec(location)
|
|
136
|
+
if (!match) throw new Error(`Could not resolve latest release tag`)
|
|
137
|
+
return match[1].replace(/^v/, '')
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const url = releasesUrl || process.env.MEDDLE_GITHUB_RELEASES_URL || DEFAULT_GITHUB_RELEASES_URL
|
|
120
141
|
const response = await doFetch(url, {
|
|
121
|
-
redirect: 'manual',
|
|
122
142
|
signal: AbortSignal.timeout(timeoutMs || DEFAULT_TIMEOUT_MS),
|
|
123
143
|
})
|
|
124
|
-
if (response.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
144
|
+
if (!response.ok) throw new Error(`GitHub releases API responded ${response.status}`)
|
|
145
|
+
const data = await response.json()
|
|
146
|
+
const versions = (Array.isArray(data) ? data : [])
|
|
147
|
+
.filter((r) => r && typeof r === 'object' && r.prerelease === true && typeof r.tag_name === 'string')
|
|
148
|
+
.map((r) => r.tag_name.replace(/^v/, ''))
|
|
149
|
+
.filter(isValidVersion)
|
|
150
|
+
if (versions.length === 0) throw new Error(`No prerelease found on GitHub releases`)
|
|
151
|
+
versions.sort((a, b) => compareVersions(b, a))
|
|
152
|
+
return versions[0]
|
|
131
153
|
}
|
|
132
154
|
|
|
133
155
|
/**
|
|
@@ -152,8 +174,9 @@ function updateCachePath(home) {
|
|
|
152
174
|
/**
|
|
153
175
|
* @param {{ home: string, fetchImpl?: Function, installMethod: string, current: string,
|
|
154
176
|
* now?: number, ttlMs?: number, force?: boolean,
|
|
155
|
-
* registryUrl?: string, latestUrl?: string, timeoutMs?: number
|
|
156
|
-
*
|
|
177
|
+
* registryUrl?: string, latestUrl?: string, timeoutMs?: number,
|
|
178
|
+
* channel?: string }} opts
|
|
179
|
+
* @returns {Promise<{ current: string, latest: string, outdated: boolean, fromCache: boolean, checkedAt: number, channel: string }>}
|
|
157
180
|
*/
|
|
158
181
|
async function checkForUpdate(opts) {
|
|
159
182
|
const {
|
|
@@ -167,6 +190,7 @@ async function checkForUpdate(opts) {
|
|
|
167
190
|
registryUrl,
|
|
168
191
|
latestUrl,
|
|
169
192
|
timeoutMs,
|
|
193
|
+
channel = 'stable',
|
|
170
194
|
} = opts
|
|
171
195
|
|
|
172
196
|
const cacheFile = updateCachePath(home)
|
|
@@ -175,7 +199,8 @@ async function checkForUpdate(opts) {
|
|
|
175
199
|
cached = JSON.parse(fs.readFileSync(cacheFile, 'utf8'))
|
|
176
200
|
} catch (_) {}
|
|
177
201
|
|
|
178
|
-
if (!force && cached && typeof cached.version === 'string' && typeof cached.checkedAt === 'number'
|
|
202
|
+
if (!force && cached && typeof cached.version === 'string' && typeof cached.checkedAt === 'number'
|
|
203
|
+
&& (cached.channel || 'stable') === channel) {
|
|
179
204
|
if (now - cached.checkedAt < ttlMs) {
|
|
180
205
|
return {
|
|
181
206
|
current,
|
|
@@ -183,18 +208,19 @@ async function checkForUpdate(opts) {
|
|
|
183
208
|
outdated: compareVersions(cached.version, current) > 0,
|
|
184
209
|
fromCache: true,
|
|
185
210
|
checkedAt: cached.checkedAt,
|
|
211
|
+
channel,
|
|
186
212
|
}
|
|
187
213
|
}
|
|
188
214
|
}
|
|
189
215
|
|
|
190
216
|
const latest = installMethod === 'binary'
|
|
191
|
-
? await getLatestVersionGithub({ fetchImpl, latestUrl, timeoutMs })
|
|
192
|
-
: await getLatestVersionNpm({ fetchImpl, registryUrl, timeoutMs })
|
|
217
|
+
? await getLatestVersionGithub({ fetchImpl, latestUrl, timeoutMs, includePrerelease: channel === 'beta' })
|
|
218
|
+
: await getLatestVersionNpm({ fetchImpl, registryUrl, timeoutMs, distTag: channel })
|
|
193
219
|
|
|
194
220
|
const checkedAt = now
|
|
195
221
|
try {
|
|
196
222
|
fs.mkdirSync(path.dirname(cacheFile), { recursive: true })
|
|
197
|
-
fs.writeFileSync(cacheFile, JSON.stringify({ version: latest, checkedAt }), 'utf8')
|
|
223
|
+
fs.writeFileSync(cacheFile, JSON.stringify({ version: latest, checkedAt, channel }), 'utf8')
|
|
198
224
|
} catch (_) {}
|
|
199
225
|
|
|
200
226
|
return {
|
|
@@ -203,6 +229,7 @@ async function checkForUpdate(opts) {
|
|
|
203
229
|
outdated: compareVersions(latest, current) > 0,
|
|
204
230
|
fromCache: false,
|
|
205
231
|
checkedAt,
|
|
232
|
+
channel,
|
|
206
233
|
}
|
|
207
234
|
}
|
|
208
235
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jonathanleelx/meddle",
|
|
3
|
-
"version": "0.4.0-beta.
|
|
3
|
+
"version": "0.4.0-beta.4",
|
|
4
4
|
"description": "A simple development proxy server with custom routing rules, mock responses, HTTPS interception, and a plugin system",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "index.js",
|