fix: admin/plugins/updates: empty list if HFS is restarted while the page is open
Massimo Melina committed
Dec 2, 2025 at 11:25 UTC
a2dcfc33b3acafff28f58c0b5c036383edf8f1fb
2 files changed
+8
-5
src/api.plugins.ts
+2
-1
@@ -2,7 +2,7 @@
2
3
import {
4
InactivePlugin, enablePlugins, getInactivePlugins, getPluginConfigFields, mapPlugins, Plugin, pluginsConfig,
5
- PATH as PLUGINS_PATH, enablePlugin, getPluginInfo, setPluginConfig, isPluginRunning,
5
+ PATH as PLUGINS_PATH, enablePlugin, getPluginInfo, setPluginConfig, isPluginRunning, pluginsScanned,
6
stopPlugin, startPlugin, CommonPluginInterface, getMissingDependencies, findPluginByRepo, suspendPlugins,
7
} from './plugins'
8
import _ from 'lodash'
@@ -43,6 +43,7 @@ const apis: ApiHandlers = {
43
list.update({ id }, { updated: true })
44
}
45
})
46
+ await pluginsScanned
47
await Promise.allSettled(_.map(getFolder2repo(), async (repo, folder) => {
48
try {
49
if (!repo) return
src/plugins.ts
+6
-4
@@ -9,7 +9,7 @@ import {
9
import * as Const from './const'
10
import Koa from 'koa'
11
import {
12
- adjustStaticPathForGlob, callable, Callback, CFG, debounceAsync, Dict, objSameKeys, onlyTruthy, prefix,
12
+ escapeGlobPath, callable, Callback, CFG, debounceAsync, Dict, objSameKeys, onlyTruthy, prefix,
13
PendingPromise, pendingPromise, Promisable, same, tryJson, wait, waitFor, wantArray, watchDir, objFromKeys, patchKey
14
} from './misc'
15
import * as misc from './misc'
@@ -39,6 +39,7 @@ export const PATH = 'plugins'
39
export const DISABLING_SUFFIX = '-disabled'
40
export const DELETE_ME_SUFFIX = '-delete_me' + DISABLING_SUFFIX
41
export const STORAGE_FOLDER = 'storage'
42
+export const pluginsScanned = pendingPromise()
43
44
setTimeout(async () => { // delete leftovers, if any
45
for (const x of await readdir(PATH))
@@ -415,20 +416,21 @@ export async function rescan() {
416
const patterns = [PATH + '/*']
417
if (APP_PATH !== process.cwd())
418
patterns.unshift(escapeGlobPath(APP_PATH) + '/' + patterns[0]) // first search bundled plugins, because otherwise they won't be loaded because of the folders with same name in .hfs/plugins (used for storage)
418
- const met = []
419
+ const existing = []
420
for (const { path, dirent } of await glob(patterns, { onlyFiles: false, suppressErrors: true, objectMode: true })) {
421
if (!dirent.isDirectory() || path.endsWith(DISABLING_SUFFIX)) continue
422
const id = path.split('/').slice(-1)[0]!
422
- met.push(id)
423
+ existing.push(id)
424
if (!pluginWatchers.has(id))
425
pluginWatchers.set(id, watchPlugin(id, join(path, PLUGIN_MAIN_FILE)))
426
}
427
for (const [id, cancelWatcher] of pluginWatchers.entries())
427
- if (!met.includes(id)) {
428
+ if (!existing.includes(id)) {
429
enablePlugin(id, false)
430
cancelWatcher()
431
pluginWatchers.delete(id)
432
}
433
+ pluginsScanned.resolve()
434
}
435
436
function watchPlugin(id: string, path: string) {