feat(plugins/settings.plugins): restore default plugin repo when needed

This commit is contained in:
PalmDevs 2026-07-28 12:42:29 +07:00
parent da08b94f76
commit 9e2ac7185d
No known key found for this signature in database
GPG key ID: 6FAE8F8677ACA8BA
5 changed files with 82 additions and 30 deletions

View file

@ -79,6 +79,7 @@ export default async function build(dev = Dev, log = true) {
.trim(),
),
__DEV__: String(dev),
// __BUILD_DEFAULT_PLUGIN_REPOSITORY_URL__: ...,
// See types/build.d.ts for what these flags do
__BUILD_FLAG_DEBUG_MODULE_LOOKUPS__: String(dev),

View file

@ -4,6 +4,7 @@ import {
refreshSettingsNavigator,
refreshSettingsOverviewScreen,
} from '@revenge-mod/discord/modules/settings'
import { JsonStorageUpdateMode } from '@revenge-mod/json-storage'
import {
InternalPluginFlags,
isPluginStartedLate,
@ -16,11 +17,14 @@ import {
} from '@revenge-mod/plugins/_/repositories'
import { lookupGeneratedIconComponent } from '@revenge-mod/utils/discord'
import pluginSettings from '../settings'
import { addDefaultRepoIfNeeded } from './repos'
import type { JsonStorage } from '@revenge-mod/json-storage'
import type { PluginApi } from '@revenge-mod/plugins/types'
export interface Storage {
autoUpdate: boolean
lastUpdateCheck?: number
defaultRepoRestored?: boolean
}
const OUTDATED_THRESHOLD = 24 * 60 * 60 * 1000 // 1 day
@ -65,32 +69,8 @@ registerInternalPlugin<{ jsonStorage: Storage }>(
}
const settings = await api.jsonStorage.get()
if (!settings.autoUpdate) return
if (
settings.lastUpdateCheck !== undefined &&
Date.now() - settings.lastUpdateCheck <= OUTDATED_THRESHOLD
)
return
setTimeout(async () => {
try {
const { errors } = await refreshAllRepos()
await updateAllPlugins()
if (!errors.length)
await api.jsonStorage.set({
lastUpdateCheck: Date.now(),
})
} catch (e) {
ToastActionCreators.open({
key: 'PLUGIN_UPDATE_CHECK_FAILED',
content: 'Failed to check for plugin updates',
IconComponent: CircleXIconComponent,
})
api.logger.warn('Failed to check for plugin updates', e)
}
}, AUTO_UPDATE_CHECK_DELAY)
autoUpdateService(settings)
defaultRepoRestoreService(settings, api.jsonStorage)
},
stop({ cleanup }) {
cleanup(refreshSettingsOverviewScreen, refreshSettingsNavigator)
@ -100,5 +80,47 @@ registerInternalPlugin<{ jsonStorage: Storage }>(
InternalPluginFlags.Internal | InternalPluginFlags.Essential,
)
function autoUpdateService(settings: Storage) {
if (!settings.autoUpdate) return
if (
settings.lastUpdateCheck !== undefined &&
Date.now() - settings.lastUpdateCheck <= OUTDATED_THRESHOLD
)
return
setTimeout(async () => {
try {
const { errors } = await refreshAllRepos()
await updateAllPlugins()
if (!errors.length)
await api.jsonStorage.set({
lastUpdateCheck: Date.now(),
})
} catch (e) {
ToastActionCreators.open({
key: 'PLUGIN_UPDATE_CHECK_FAILED',
content: 'Failed to check for plugin updates',
IconComponent: CircleXIconComponent,
})
api.logger.warn('Failed to check for plugin updates', e)
}
}, AUTO_UPDATE_CHECK_DELAY)
}
// TODO: Add UI for this?
function defaultRepoRestoreService(
settings: Storage,
storage: JsonStorage<Storage>,
) {
if (!settings.defaultRepoRestored) addDefaultRepoIfNeeded()
storage.subscribe((update, mode) => {
// If user cleared storage, restore the default repo if needed
if (mode === JsonStorageUpdateMode.Load && !update.defaultRepoRestored)
addDefaultRepoIfNeeded()
})
}
// Exposed for the Advanced settings screen (auto-update toggle)
export let api: PluginApi<{ jsonStorage: Storage }>

View file

@ -0,0 +1,29 @@
import {
listRepos,
refreshRepo,
setRepos,
} from '@revenge-mod/plugins/_/repositories'
import { noop } from '@revenge-mod/utils/callback'
import type { Repo, RepoConfigEntry } from '@revenge-mod/plugins/_/repositories'
export async function addDefaultRepoIfNeeded() {
if (!__BUILD_DEFAULT_PLUGIN_REPOSITORY_URL__) return
const repos = await listRepos()
if (
repos.some(repo => repo.url === __BUILD_DEFAULT_PLUGIN_REPOSITORY_URL__)
)
return
const userRepos = toConfig(repos.filter(repo => !repo.internal))
await setRepos([
{ url: __BUILD_DEFAULT_PLUGIN_REPOSITORY_URL__, enabled: true },
...userRepos,
])
await refreshRepo(__BUILD_DEFAULT_PLUGIN_REPOSITORY_URL__).catch(noop)
}
export function toConfig(list: Repo[]): RepoConfigEntry[] {
return list.map(({ url, enabled }) => ({ url, enabled }))
}

View file

@ -19,6 +19,7 @@ import { lookupGeneratedIconComponent } from '@revenge-mod/utils/discord'
import { useCallback, useEffect, useState } from 'react'
import { ScrollView, View } from 'react-native'
import { api } from '..'
import { toConfig } from '../repos'
import { formatBytes, messageOf, showErrorToast } from '../utils/repos'
import type {
DownloadProgressEvent,
@ -44,10 +45,6 @@ const UpIconComponent = lookupGeneratedIconComponent('ArrowSmallUpIcon')!
const DownIconComponent = lookupGeneratedIconComponent('ArrowSmallDownIcon')!
const TrashIconComponent = lookupGeneratedIconComponent('TrashIcon')!
function toConfig(list: Repo[]): RepoConfigEntry[] {
return list.map(({ url, enabled }) => ({ url, enabled }))
}
function repoSubLabel(repo: Repo, state?: RepoStateEvent['state']) {
if (state === 'refreshing') return `${repo.url} (refreshing...)`
if (state === 'error') return `${repo.url} (refresh failed)`
@ -206,6 +203,8 @@ export default function RevengePluginsAdvancedSettingScreen() {
const removeRepo = useCallback(
async (repo: Repo) => {
// TODO: Add warning for default repo removal, user can clear "Plugin Settings" data to restore the default repo
await commit(toConfig(userRepos.filter(r => r.url !== repo.url)))
// Plugins installed from the removed repository turn Sideloaded

1
types/build.d.ts vendored
View file

@ -4,6 +4,7 @@ declare global {
const __DEV__: boolean
const __BUILD_DISCORD_SERVER_URL__: string
const __BUILD_SOURCE_REPOSITORY_URL__: string
const __BUILD_DEFAULT_PLUGIN_REPOSITORY_URL__: string | undefined
const __BUILD_LICENSE_URL__: string
const __BUILD_COMMIT__: string
const __BUILD_BRANCH__: string