fix(plugins): remove developer-kit
This plugin has been moved to an external repository. The goal of bundling internal plugins are including what's needed by _the user_ by default. Developer Kit is not needed by most users, nor is it a "safe" plugin (it exposes a few attack surfaces, even if unlikely to be used).
This commit is contained in:
parent
0f75551c36
commit
b258ac70d6
21 changed files with 0 additions and 1137 deletions
14
bun.lock
14
bun.lock
|
|
@ -7,8 +7,6 @@
|
|||
"dependencies": {
|
||||
"@revenge-mod/assets": "workspace:*",
|
||||
"@revenge-mod/components": "workspace:*",
|
||||
"@revenge-mod/devtools-client": "^1.4.0",
|
||||
"@revenge-mod/devtools-shared": "^1.3.0",
|
||||
"@revenge-mod/discord": "workspace:*",
|
||||
"@revenge-mod/externals": "workspace:*",
|
||||
"@revenge-mod/json-storage": "workspace:*",
|
||||
|
|
@ -210,10 +208,6 @@
|
|||
|
||||
"@revenge-mod/components": ["@revenge-mod/components@workspace:lib/components"],
|
||||
|
||||
"@revenge-mod/devtools-client": ["@revenge-mod/devtools-client@1.4.0", "", { "dependencies": { "@revenge-mod/devtools-shared": "^1.3.0", "bippy": "^0.3.8" } }, "sha512-hGmdM0RcK3/IrzpW7lDOXl+it3wYcoF+ePI43Ey3AvIPaBGIDIGqqitKtrB8wIGo5jREsr703fcjseE+bt+aCg=="],
|
||||
|
||||
"@revenge-mod/devtools-shared": ["@revenge-mod/devtools-shared@1.3.0", "", { "dependencies": { "chalk": "^5.6.2", "devalue": "^5.3.2" } }, "sha512-MLox/xQsYtMG78R4R8sy32P5X7ILUNUPAX8IiWjUsPIclkTweDvwEAUadkvbBo8j+/ZJaJdif+Fg/C9YQNlOqg=="],
|
||||
|
||||
"@revenge-mod/discord": ["@revenge-mod/discord@workspace:lib/discord"],
|
||||
|
||||
"@revenge-mod/externals": ["@revenge-mod/externals@workspace:lib/externals"],
|
||||
|
|
@ -304,8 +298,6 @@
|
|||
|
||||
"@types/react": ["@types/react@19.2.17", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw=="],
|
||||
|
||||
"@types/react-reconciler": ["@types/react-reconciler@0.28.9", "", { "peerDependencies": { "@types/react": "*" } }, "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg=="],
|
||||
|
||||
"@typescript/typescript-aix-ppc64": ["@typescript/typescript-aix-ppc64@7.0.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ=="],
|
||||
|
||||
"@typescript/typescript-darwin-arm64": ["@typescript/typescript-darwin-arm64@7.0.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA=="],
|
||||
|
|
@ -406,8 +398,6 @@
|
|||
|
||||
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
||||
|
||||
"bippy": ["bippy@0.3.34", "", { "dependencies": { "@types/react-reconciler": "^0.28.9" }, "peerDependencies": { "react": ">=17.0.1" } }, "sha512-vmptmU/20UdIWHHhq7qCSHhHzK7Ro3YJ1utU0fBG7ujUc58LEfTtilKxcF0IOgSjT5XLcm7CBzDjbv4lcKApGQ=="],
|
||||
|
||||
"buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
|
||||
|
||||
"bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
|
||||
|
|
@ -434,8 +424,6 @@
|
|||
|
||||
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
|
||||
|
||||
"devalue": ["devalue@5.8.2", "", {}, "sha512-DObPPAfdtFbXjxLqK8s2Xk9ZuWz5+ZoFEhC7J76es4GU/rEiXwHTmbImoCdyoCOcBH1UF3+Cz6Z2sYD4hyl5TA=="],
|
||||
|
||||
"dts-resolver": ["dts-resolver@3.0.0", "", { "peerDependencies": { "oxc-resolver": ">=11.0.0" }, "optionalPeers": ["oxc-resolver"] }, "sha512-1T1f+z+4tl9XD+m+0HBgWoL/nm0bOIffyWaUuUSBlFg/86IWvfx+wjNaO/ybU0AJzG9/Mi5hBUgGV6zCmWEN7Q=="],
|
||||
|
||||
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
|
|
@ -592,8 +580,6 @@
|
|||
|
||||
"yuku-parser": ["yuku-parser@0.8.1", "", { "dependencies": { "@yuku-toolchain/types": "^0.8.1", "yuku-ast": "^0.8.1" }, "optionalDependencies": { "@yuku-parser/binding-darwin-arm64": "0.8.1", "@yuku-parser/binding-darwin-x64": "0.8.1", "@yuku-parser/binding-freebsd-x64": "0.8.1", "@yuku-parser/binding-linux-arm-gnu": "0.8.1", "@yuku-parser/binding-linux-arm-musl": "0.8.1", "@yuku-parser/binding-linux-arm64-gnu": "0.8.1", "@yuku-parser/binding-linux-arm64-musl": "0.8.1", "@yuku-parser/binding-linux-x64-gnu": "0.8.1", "@yuku-parser/binding-linux-x64-musl": "0.8.1", "@yuku-parser/binding-win32-arm64": "0.8.1", "@yuku-parser/binding-win32-x64": "0.8.1" } }, "sha512-YvUz2jdFMIq0QjN8LmI32ox+RBCn3l8VToAXVQ5QFfLTxSxmGZS6JP80ptePEju+CpeTdINLmUm7Ewodzh1QnQ=="],
|
||||
|
||||
"@revenge-mod/devtools-shared/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
||||
|
||||
"metro-runtime/@babel/runtime": ["@babel/runtime@7.29.7", "", {}, "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="],
|
||||
|
||||
"pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
|
||||
|
|
|
|||
|
|
@ -41,8 +41,6 @@
|
|||
"dependencies": {
|
||||
"@revenge-mod/assets": "workspace:*",
|
||||
"@revenge-mod/components": "workspace:*",
|
||||
"@revenge-mod/devtools-client": "^1.4.0",
|
||||
"@revenge-mod/devtools-shared": "^1.3.0",
|
||||
"@revenge-mod/discord": "workspace:*",
|
||||
"@revenge-mod/externals": "workspace:*",
|
||||
"@revenge-mod/json-storage": "workspace:*",
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
export const Setting = {
|
||||
// MAIN SETTINGS
|
||||
|
||||
RevengeDeveloper: 'RevengeDeveloper',
|
||||
|
||||
// SUBSETTINGS
|
||||
|
||||
DTAutoConnect: 'DTAutoConnect',
|
||||
DTConnect: 'DTConnect',
|
||||
DTDisconnect: 'DTDisconnect',
|
||||
|
||||
RDTAutoConnect: 'RDTAutoConnect',
|
||||
RDTConnect: 'RDTConnect',
|
||||
RDTDisconnect: 'RDTDisconnect',
|
||||
|
||||
EvalJS: 'EvalJS',
|
||||
AssetBrowser: 'AssetBrowser',
|
||||
TestErrorBoundary: 'TestErrorBoundary',
|
||||
} as const
|
||||
|
||||
export const RouteNames = {
|
||||
[Setting.RevengeDeveloper]: 'Revenge Developer',
|
||||
[Setting.AssetBrowser]: 'Asset Browser',
|
||||
[Setting.EvalJS]: 'Evaluate JavaScript',
|
||||
[Setting.TestErrorBoundary]: 'Test ErrorBoundary',
|
||||
} as const
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
import TableRowAssetIcon from '@revenge-mod/components/TableRowAssetIcon'
|
||||
import { RouteNames, Setting } from '../constants'
|
||||
import defer * as AssetBrowserSettingScreen from '../screens/AssetBrowserSettingScreen'
|
||||
import type { SettingsItem } from '@revenge-mod/discord/modules/settings'
|
||||
|
||||
const AssetBrowserSetting: SettingsItem = {
|
||||
parent: Setting.RevengeDeveloper,
|
||||
type: 'route',
|
||||
IconComponent: () => <TableRowAssetIcon name="ImageIcon" />,
|
||||
useTitle: () => 'Asset Browser',
|
||||
screen: {
|
||||
route: RouteNames[Setting.AssetBrowser],
|
||||
getComponent: () => AssetBrowserSettingScreen.default,
|
||||
},
|
||||
}
|
||||
|
||||
export default AssetBrowserSetting
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
import TableRowAssetIcon from '@revenge-mod/components/TableRowAssetIcon'
|
||||
import { api } from '..'
|
||||
import { Setting } from '../constants'
|
||||
import type { SettingsItem } from '@revenge-mod/discord/modules/settings'
|
||||
|
||||
const DTAutoConnectSetting: SettingsItem = {
|
||||
parent: Setting.RevengeDeveloper,
|
||||
IconComponent: () => <TableRowAssetIcon name="LinkIcon" />,
|
||||
useTitle: () => 'Auto-connect to DevTools',
|
||||
useDescription: () => 'Automatically connect to DevTools during startup.',
|
||||
useValue: () =>
|
||||
api.jsonStorage.use(s => s.devTools?.autoConnect !== undefined)!
|
||||
.devTools.autoConnect,
|
||||
onValueChange: v => {
|
||||
api.jsonStorage.set({ devTools: { autoConnect: v } })
|
||||
},
|
||||
type: 'toggle',
|
||||
}
|
||||
|
||||
export default DTAutoConnectSetting
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
import TableRowAssetIcon from '@revenge-mod/components/TableRowAssetIcon'
|
||||
import { DevToolsClient } from '@revenge-mod/devtools-client'
|
||||
import { Setting } from '../constants'
|
||||
import { connect, useIsConnected } from '../devtools'
|
||||
import type { SettingsItem } from '@revenge-mod/discord/modules/settings'
|
||||
|
||||
const DTConnectSetting: SettingsItem = {
|
||||
parent: Setting.RevengeDeveloper,
|
||||
IconComponent: () => <TableRowAssetIcon name="LinkIcon" />,
|
||||
useTitle: () => 'Connect to DevTools',
|
||||
useDescription: () => `Version: ${DevToolsClient.version}`,
|
||||
usePredicate: () => !useIsConnected(),
|
||||
onPress: connect,
|
||||
type: 'pressable',
|
||||
}
|
||||
|
||||
export default DTConnectSetting
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
import TableRowAssetIcon from '@revenge-mod/components/TableRowAssetIcon'
|
||||
import { Setting } from '../constants'
|
||||
import { disconnect, useIsConnected } from '../devtools'
|
||||
import type { SettingsItem } from '@revenge-mod/discord/modules/settings'
|
||||
|
||||
const DTDisconnectSetting: SettingsItem = {
|
||||
parent: Setting.RevengeDeveloper,
|
||||
IconComponent: () => <TableRowAssetIcon name="DenyIcon" variant="danger" />,
|
||||
variant: 'danger',
|
||||
useTitle: () => 'Disconnect from DevTools',
|
||||
usePredicate: useIsConnected,
|
||||
onPress: disconnect,
|
||||
type: 'pressable',
|
||||
}
|
||||
|
||||
export default DTDisconnectSetting
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
import { TableRowAssetIcon } from '@revenge-mod/components'
|
||||
import { RouteNames, Setting } from '../constants'
|
||||
import EvalJSSettingScreen from '../screens/EvalJSSettingScreen'
|
||||
import type { SettingsItem } from '@revenge-mod/discord/modules/settings'
|
||||
|
||||
const EvalJSSetting: SettingsItem = {
|
||||
parent: Setting.RevengeDeveloper,
|
||||
type: 'route',
|
||||
IconComponent: () => <TableRowAssetIcon name="FileIcon" />,
|
||||
useTitle: () => 'Evaluate JavaScript',
|
||||
useDescription: () => 'Runs a JavaScript code snippet.',
|
||||
screen: {
|
||||
route: RouteNames[Setting.EvalJS],
|
||||
getComponent: () => EvalJSSettingScreen,
|
||||
},
|
||||
}
|
||||
|
||||
export default EvalJSSetting
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
import TableRowAssetIcon from '@revenge-mod/components/TableRowAssetIcon'
|
||||
import { api } from '..'
|
||||
import { Setting } from '../constants'
|
||||
import { RDTContext } from '../react-devtools'
|
||||
import type { SettingsItem } from '@revenge-mod/discord/modules/settings'
|
||||
|
||||
const RDTAutoConnectSetting: SettingsItem = {
|
||||
parent: Setting.RevengeDeveloper,
|
||||
IconComponent: () => <TableRowAssetIcon name="LinkIcon" />,
|
||||
useTitle: () => 'Auto-connect to React DevTools',
|
||||
useDescription: () =>
|
||||
'Automatically connect to React DevTools during startup.',
|
||||
usePredicate: () => RDTContext.active,
|
||||
useValue: () =>
|
||||
api.jsonStorage.use(s => s.reactDevTools?.autoConnect !== undefined)!
|
||||
.reactDevTools.autoConnect,
|
||||
onValueChange: v => {
|
||||
api.jsonStorage.set({ reactDevTools: { autoConnect: v } })
|
||||
},
|
||||
type: 'toggle',
|
||||
}
|
||||
|
||||
export default RDTAutoConnectSetting
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
import TableRowAssetIcon from '@revenge-mod/components/TableRowAssetIcon'
|
||||
import { Setting } from '../constants'
|
||||
import { connect, RDTContext, useIsConnected } from '../react-devtools'
|
||||
import type { SettingsItem } from '@revenge-mod/discord/modules/settings'
|
||||
|
||||
const RDTConnectSetting: SettingsItem = {
|
||||
parent: Setting.RevengeDeveloper,
|
||||
IconComponent: () => <TableRowAssetIcon name="LinkIcon" />,
|
||||
useTitle: () => 'Connect to React DevTools',
|
||||
useDescription: () => `Version: ${globalThis.__REACT_DEVTOOLS__?.version}`,
|
||||
usePredicate: () => !useIsConnected() && RDTContext.active,
|
||||
onPress: connect,
|
||||
type: 'pressable',
|
||||
}
|
||||
|
||||
export default RDTConnectSetting
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
import TableRowAssetIcon from '@revenge-mod/components/TableRowAssetIcon'
|
||||
import { Setting } from '../constants'
|
||||
import { disconnect, useIsConnected } from '../react-devtools'
|
||||
import type { SettingsItem } from '@revenge-mod/discord/modules/settings'
|
||||
|
||||
const RDTDisconnectSetting: SettingsItem = {
|
||||
parent: Setting.RevengeDeveloper,
|
||||
IconComponent: () => <TableRowAssetIcon name="DenyIcon" variant="danger" />,
|
||||
variant: 'danger',
|
||||
useTitle: () => 'Disconnect from React DevTools',
|
||||
usePredicate: useIsConnected,
|
||||
onPress: disconnect,
|
||||
type: 'pressable',
|
||||
}
|
||||
|
||||
export default RDTDisconnectSetting
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
import TableRowAssetIcon from '@revenge-mod/components/TableRowAssetIcon'
|
||||
import { RouteNames, Setting } from '../constants'
|
||||
import defer * as RevengeDeveloperSettingScreen from '../screens/RevengeDeveloperSettingScreen'
|
||||
import type { SettingsItem } from '@revenge-mod/discord/modules/settings'
|
||||
|
||||
const RevengeDeveloperSetting: SettingsItem = {
|
||||
parent: null,
|
||||
type: 'route',
|
||||
IconComponent: () => <TableRowAssetIcon name="WrenchIcon" />,
|
||||
useTitle: () => 'Developer',
|
||||
screen: {
|
||||
route: RouteNames[Setting.RevengeDeveloper],
|
||||
getComponent: () => RevengeDeveloperSettingScreen.default,
|
||||
},
|
||||
}
|
||||
|
||||
export default RevengeDeveloperSetting
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
import TableRowAssetIcon from '@revenge-mod/components/TableRowAssetIcon'
|
||||
import { RouteNames, Setting } from '../constants'
|
||||
import defer * as TestErrorBoundarySettingScreen from '../screens/TestErrorBoundarySettingScreen'
|
||||
import type { SettingsItem } from '@revenge-mod/discord/modules/settings'
|
||||
|
||||
const TestErrorBoundarySetting: SettingsItem = {
|
||||
parent: Setting.RevengeDeveloper,
|
||||
type: 'route',
|
||||
variant: 'danger',
|
||||
IconComponent: () => (
|
||||
<TableRowAssetIcon name="ScreenXIcon" variant="danger" />
|
||||
),
|
||||
useTitle: () => 'Test ErrorBoundary',
|
||||
screen: {
|
||||
route: RouteNames[Setting.TestErrorBoundary],
|
||||
getComponent: () => TestErrorBoundarySettingScreen.default,
|
||||
},
|
||||
}
|
||||
|
||||
export default TestErrorBoundarySetting
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
import { DevToolsClient } from '@revenge-mod/devtools-client'
|
||||
import { LogLevel } from '@revenge-mod/devtools-shared/constants'
|
||||
import { ToastActionCreators } from '@revenge-mod/discord/actions'
|
||||
import { TypedEventEmitter } from '@revenge-mod/discord/common/utils'
|
||||
import { ClientInfoModule } from '@revenge-mod/discord/native'
|
||||
import { getBridgeInfo } from '@revenge-mod/modules/native'
|
||||
import { instead } from '@revenge-mod/patcher'
|
||||
import { noop } from '@revenge-mod/utils/callback'
|
||||
import { lookupGeneratedIconComponent } from '@revenge-mod/utils/discord'
|
||||
import { useReRender } from '@revenge-mod/utils/react'
|
||||
import { useEffect } from 'react'
|
||||
import { api } from '.'
|
||||
import type { UnpatchFunction } from '@revenge-mod/patcher/types'
|
||||
|
||||
export const DTContext: {
|
||||
client: DevToolsClient | null
|
||||
addr: string
|
||||
alias: string
|
||||
con: boolean
|
||||
} = {
|
||||
client: null,
|
||||
addr: 'localhost:7684',
|
||||
alias: '',
|
||||
con: false,
|
||||
}
|
||||
|
||||
const events = new TypedEventEmitter<{
|
||||
connect: []
|
||||
disconnect: []
|
||||
errored: [unknown]
|
||||
}>()
|
||||
|
||||
const CircleErrorIcon = lookupGeneratedIconComponent(
|
||||
'CircleErrorIcon',
|
||||
'CircleErrorIcon-secondary',
|
||||
'CircleErrorIcon-primary',
|
||||
)
|
||||
|
||||
let intercepted = false
|
||||
|
||||
function interceptLogging() {
|
||||
if (intercepted) return noop
|
||||
|
||||
intercepted = true
|
||||
const unpatches: UnpatchFunction[] = []
|
||||
|
||||
for (const [key, level] of [
|
||||
['log', LogLevel.Default],
|
||||
['warn', LogLevel.Warn],
|
||||
['error', LogLevel.Error],
|
||||
['info', LogLevel.Default],
|
||||
['debug', LogLevel.Debug],
|
||||
] as const) {
|
||||
unpatches.push(
|
||||
instead(console, key, (args, orig) => {
|
||||
if (DTContext.con && DTContext.client)
|
||||
DTContext.client.log(level, args)
|
||||
return Reflect.apply(orig, console, args)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
return () => {
|
||||
intercepted = false
|
||||
for (const unpatch of unpatches) unpatch()
|
||||
}
|
||||
}
|
||||
|
||||
export function connect() {
|
||||
const Bridge = getBridgeInfo()
|
||||
const Client = ClientInfoModule.getConstants()
|
||||
|
||||
const client = (DTContext.client = new DevToolsClient())
|
||||
client.expose('api', api)
|
||||
client.expose('cleanup', api.cleanup)
|
||||
client.expose('logger', api.logger)
|
||||
client.expose('revenge', api.unscoped)
|
||||
|
||||
client.connect(
|
||||
`ws://${DTContext.addr}`,
|
||||
`${Client.Version}${Bridge ? ` (${Bridge.name} ${Bridge.version})` : ''}`,
|
||||
DTContext.alias || undefined,
|
||||
)
|
||||
|
||||
const ws = client.ws!
|
||||
|
||||
ws.addEventListener('open', () => {
|
||||
if (client.settings.log.interceptConsole) {
|
||||
const unintercept = interceptLogging()
|
||||
|
||||
ws.addEventListener('close', function self() {
|
||||
unintercept()
|
||||
ws.removeEventListener('close', self)
|
||||
})
|
||||
}
|
||||
|
||||
DTContext.con = true
|
||||
events.emit('connect')
|
||||
})
|
||||
|
||||
ws.addEventListener('close', e_ => {
|
||||
cleanup()
|
||||
events.emit('disconnect')
|
||||
|
||||
const e = e_ as CloseEvent
|
||||
if (!e.wasClean) {
|
||||
api.logger.error('DevTools error:', e.reason)
|
||||
|
||||
ToastActionCreators.open({
|
||||
key: 'DEVTOOLS_ERROR',
|
||||
IconComponent: CircleErrorIcon,
|
||||
content: e.reason,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
DTContext.client = null
|
||||
DTContext.con = false
|
||||
}
|
||||
|
||||
export function disconnect() {
|
||||
DTContext.client?.disconnect()
|
||||
}
|
||||
|
||||
export function useIsConnected() {
|
||||
const rerender = useReRender()
|
||||
|
||||
useEffect(() => {
|
||||
events.on('connect', rerender)
|
||||
events.on('disconnect', rerender)
|
||||
|
||||
return () => {
|
||||
events.off('connect', rerender)
|
||||
events.off('disconnect', rerender)
|
||||
}
|
||||
}, [rerender])
|
||||
|
||||
return DTContext.con
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
import {
|
||||
onSettingsModulesLoaded,
|
||||
refreshSettings,
|
||||
} from '@revenge-mod/discord/modules/settings'
|
||||
import {
|
||||
InternalPluginFlags,
|
||||
isPluginStartedLate,
|
||||
PluginFlags,
|
||||
registerInternalPlugin,
|
||||
} from '@revenge-mod/plugins/_'
|
||||
import pluginSettings from '../settings'
|
||||
import * as dt from './devtools'
|
||||
import defer * as rdt from './react-devtools'
|
||||
import defer * as utils from './utils'
|
||||
import type { PluginApi } from '@revenge-mod/plugins/types'
|
||||
|
||||
interface Storage {
|
||||
devTools: DevToolsSettings & { alias?: string }
|
||||
reactDevTools: DevToolsSettings
|
||||
}
|
||||
|
||||
interface DevToolsSettings {
|
||||
address: string
|
||||
autoConnect: boolean
|
||||
}
|
||||
|
||||
const defaultStorage: Storage = {
|
||||
devTools: {
|
||||
address: 'localhost:7864',
|
||||
autoConnect: false,
|
||||
},
|
||||
reactDevTools: {
|
||||
address: 'localhost:8097',
|
||||
autoConnect: false,
|
||||
},
|
||||
}
|
||||
|
||||
// TODO(PalmDevs): only register in development builds once updates can be made automatic
|
||||
registerInternalPlugin<{ jsonStorage: Storage }>(
|
||||
{
|
||||
id: 'revenge.developer-kit',
|
||||
name: 'Developer Kit',
|
||||
description: 'Tools assisting Revenge developers.',
|
||||
author: 'Revenge',
|
||||
icon: 'WrenchIcon',
|
||||
dependencies: { [pluginSettings]: {} },
|
||||
},
|
||||
{
|
||||
jsonStorage: {
|
||||
load: true,
|
||||
default: defaultStorage,
|
||||
},
|
||||
async start(api_) {
|
||||
api = api_
|
||||
|
||||
onSettingsModulesLoaded(utils.register)
|
||||
|
||||
if (isPluginStartedLate(api_.plugin)) {
|
||||
refreshSettings()
|
||||
}
|
||||
|
||||
const settings = await api.jsonStorage.get()
|
||||
|
||||
dt.DTContext.addr = settings.devTools.address
|
||||
dt.DTContext.alias = settings.devTools.alias ?? ''
|
||||
rdt.RDTContext.addr = settings.reactDevTools.address
|
||||
|
||||
if (settings.devTools.autoConnect) dt.connect()
|
||||
if (settings.reactDevTools.autoConnect) rdt.connect()
|
||||
},
|
||||
stop({ cleanup }) {
|
||||
cleanup(refreshSettings)
|
||||
},
|
||||
},
|
||||
PluginFlags.Enabled,
|
||||
InternalPluginFlags.Internal,
|
||||
)
|
||||
|
||||
// Expose to EvalJSSetting
|
||||
export let api: PluginApi<{ jsonStorage: Storage }>
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
import { ToastActionCreators } from '@revenge-mod/discord/actions'
|
||||
import { TypedEventEmitter } from '@revenge-mod/discord/common/utils'
|
||||
import { lookupGeneratedIconComponent } from '@revenge-mod/utils/discord'
|
||||
import { useReRender } from '@revenge-mod/utils/react'
|
||||
import { useEffect } from 'react'
|
||||
import { api } from '.'
|
||||
|
||||
export const RDTContext: {
|
||||
ws: WebSocket | undefined
|
||||
addr: string
|
||||
con: boolean
|
||||
active: boolean
|
||||
} = {
|
||||
active: Boolean(globalThis.__REACT_DEVTOOLS__),
|
||||
ws: undefined,
|
||||
addr: 'localhost:8097',
|
||||
con: false,
|
||||
}
|
||||
|
||||
const events = new TypedEventEmitter<{
|
||||
connect: []
|
||||
disconnect: []
|
||||
errored: [unknown]
|
||||
}>()
|
||||
|
||||
const CircleErrorIcon = lookupGeneratedIconComponent(
|
||||
'CircleErrorIcon',
|
||||
'CircleErrorIcon-secondary',
|
||||
'CircleErrorIcon-primary',
|
||||
)
|
||||
|
||||
export function connect() {
|
||||
if (!RDTContext.active || RDTContext.ws) return
|
||||
|
||||
const ws = (RDTContext.ws = new WebSocket(`ws://${RDTContext.addr}`))
|
||||
|
||||
ws.addEventListener('open', () => {
|
||||
RDTContext.con = true
|
||||
events.emit('connect')
|
||||
})
|
||||
|
||||
ws.addEventListener('close', e_ => {
|
||||
cleanup()
|
||||
events.emit('disconnect')
|
||||
|
||||
const e = e_ as CloseEvent
|
||||
if (!e.wasClean) {
|
||||
api.logger.error('React DevTools error:', e.reason)
|
||||
|
||||
ToastActionCreators.open({
|
||||
key: 'REACT_DEVTOOLS_ERROR',
|
||||
IconComponent: CircleErrorIcon,
|
||||
content: e.reason,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
__REACT_DEVTOOLS__!.exports.connectToDevTools({
|
||||
websocket: ws,
|
||||
})
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
RDTContext.con = false
|
||||
RDTContext.ws = undefined
|
||||
}
|
||||
|
||||
export function disconnect() {
|
||||
if (RDTContext.ws) RDTContext.ws.close()
|
||||
}
|
||||
|
||||
export function useIsConnected() {
|
||||
const rerender = useReRender()
|
||||
|
||||
useEffect(() => {
|
||||
events.on('connect', rerender)
|
||||
events.on('disconnect', rerender)
|
||||
|
||||
return () => {
|
||||
events.off('connect', rerender)
|
||||
events.off('disconnect', rerender)
|
||||
}
|
||||
}, [rerender])
|
||||
|
||||
return RDTContext.con
|
||||
}
|
||||
|
|
@ -1,231 +0,0 @@
|
|||
import { getAssets } from '@revenge-mod/assets'
|
||||
import Page from '@revenge-mod/components/Page'
|
||||
import SearchInput from '@revenge-mod/components/SearchInput'
|
||||
import TableRowAssetIcon from '@revenge-mod/components/TableRowAssetIcon'
|
||||
import {
|
||||
AlertActionCreators,
|
||||
ToastActionCreators,
|
||||
} from '@revenge-mod/discord/actions'
|
||||
import { Design } from '@revenge-mod/discord/design'
|
||||
import { Clipboard } from '@revenge-mod/externals/react-native-clipboard'
|
||||
import { debounce } from '@revenge-mod/utils/callback'
|
||||
import { lookupGeneratedIconComponent } from '@revenge-mod/utils/discord'
|
||||
import { FlashList } from '@shopify/flash-list'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import { Image, StyleSheet, View } from 'react-native'
|
||||
import type { Asset, AssetId } from '@revenge-mod/assets/types'
|
||||
import type { Metro } from '@revenge-mod/modules/types'
|
||||
|
||||
const { AlertModal, AlertActionButton, TableRow, TableRowGroup, Text } = Design
|
||||
|
||||
const Displayable = new Set(['png', 'jpg', 'svg', 'webp'])
|
||||
const UndisplayableFallback = {
|
||||
jsona: 'PaperIcon',
|
||||
lottie: 'ImageFileIcon',
|
||||
webm: 'CirclePlayIcon-primary',
|
||||
ttf: 'LanguageIcon',
|
||||
default: 'UnknownGameIcon',
|
||||
}
|
||||
|
||||
export default function AssetBrowserSettingScreen() {
|
||||
const [search, setSearch] = useState('')
|
||||
const debouncedSetSearch = useCallback(debounce(setSearch, 100), [])
|
||||
const assets = useMemo(() => [...getAssets()], [])
|
||||
|
||||
const filteredAssets = useMemo(
|
||||
() =>
|
||||
!search.length
|
||||
? assets
|
||||
: assets.filter(asset =>
|
||||
asset.name.toLowerCase().includes(search.toLowerCase()),
|
||||
),
|
||||
[assets, search],
|
||||
)
|
||||
|
||||
return (
|
||||
<Page spacing={16}>
|
||||
<SearchInput
|
||||
onChange={(v: string) => {
|
||||
debouncedSetSearch(v)
|
||||
}}
|
||||
size="md"
|
||||
/>
|
||||
<FlashList
|
||||
data={filteredAssets}
|
||||
contentContainerStyle={styles.listContainer}
|
||||
fadingEdgeLength={32}
|
||||
keyExtractor={asset =>
|
||||
asset.id
|
||||
? asset.id.toString()
|
||||
: `${asset.name}.${asset.type}`
|
||||
}
|
||||
renderItem={({ item: asset, index }) => (
|
||||
<AssetDisplay
|
||||
asset={asset}
|
||||
end={index === filteredAssets.length - 1}
|
||||
id={asset.id}
|
||||
moduleId={asset.moduleId}
|
||||
start={!index}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
||||
function AssetDisplay({
|
||||
id,
|
||||
moduleId,
|
||||
asset,
|
||||
start,
|
||||
end,
|
||||
}: {
|
||||
id: AssetId
|
||||
moduleId?: Metro.ModuleID
|
||||
asset: Asset
|
||||
start?: boolean
|
||||
end?: boolean
|
||||
}) {
|
||||
const isDisplayable = Displayable.has(asset.type)
|
||||
const metadata = [
|
||||
['ID', id.toString()],
|
||||
['Type', asset.type],
|
||||
] as [string, string, unpressable?: boolean, hiddenInText?: boolean][]
|
||||
|
||||
metadata.push(
|
||||
moduleId
|
||||
? ['Module ID', moduleId.toString()]
|
||||
: [
|
||||
'Custom asset',
|
||||
'This is a custom asset registered by a plugin.',
|
||||
true,
|
||||
true,
|
||||
],
|
||||
)
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
end={end}
|
||||
icon={
|
||||
isDisplayable ? (
|
||||
<Image source={id} style={styles.smallPreview} />
|
||||
) : (
|
||||
<TableRowAssetIcon
|
||||
name={
|
||||
asset.type in UndisplayableFallback
|
||||
? UndisplayableFallback[
|
||||
asset.type as keyof typeof UndisplayableFallback
|
||||
]
|
||||
: UndisplayableFallback.default
|
||||
}
|
||||
variant="danger"
|
||||
/>
|
||||
)
|
||||
}
|
||||
label={asset.name}
|
||||
onPress={() => {
|
||||
openAssetDisplayAlert(asset, id, metadata)
|
||||
}}
|
||||
start={start}
|
||||
subLabel={metadata
|
||||
.filter(([, , , hiddenInText]) => !hiddenInText)
|
||||
.map(([name, value]) => `${name}: ${value ?? 'N/A'}`)
|
||||
.join(' • ')}
|
||||
variant={isDisplayable ? 'default' : 'danger'}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const CopyIcon = lookupGeneratedIconComponent('CopyIcon')
|
||||
|
||||
function openAssetDisplayAlert(
|
||||
asset: Asset,
|
||||
id: AssetId,
|
||||
metadata: [string, string, unpressable?: boolean, ...unknown[]][],
|
||||
) {
|
||||
const isDisplayable = Displayable.has(asset.type)
|
||||
|
||||
AlertActionCreators.openAlert(
|
||||
'asset-display',
|
||||
<AlertModal
|
||||
actions={<AlertActionButton text="Close" variant="secondary" />}
|
||||
title={
|
||||
<View style={{ flex: 1, width: '100%' }}>
|
||||
{isDisplayable ? (
|
||||
<Image source={id} style={styles.preview} />
|
||||
) : (
|
||||
<PreviewUnavailable type={asset.type} />
|
||||
)}
|
||||
</View>
|
||||
}
|
||||
extraContent={
|
||||
<>
|
||||
<TableRowGroup>
|
||||
{[['Name', asset.name], ...metadata].map(
|
||||
([name, value, unpressable]) => (
|
||||
<TableRow
|
||||
key={id}
|
||||
label={name}
|
||||
onPress={
|
||||
unpressable
|
||||
? undefined
|
||||
: () => {
|
||||
Clipboard.setString(value)
|
||||
|
||||
ToastActionCreators.open({
|
||||
key: 'ASSET_BROWSER_COPIED',
|
||||
IconComponent: CopyIcon,
|
||||
content: `Copied ${name} to clipboard`,
|
||||
})
|
||||
}
|
||||
}
|
||||
subLabel={value}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</TableRowGroup>
|
||||
<Text
|
||||
color="text-feedback-critical"
|
||||
variant="text-xs/semibold"
|
||||
>
|
||||
Note: Asset IDs and module IDs are not consistent
|
||||
between app launches and app versions respectively and
|
||||
should only be used when absolutely needed.
|
||||
</Text>
|
||||
</>
|
||||
}
|
||||
/>,
|
||||
)
|
||||
}
|
||||
|
||||
function PreviewUnavailable({ type }: { type: string }) {
|
||||
return (
|
||||
<Text
|
||||
color="text-feedback-critical"
|
||||
style={styles.centeredText}
|
||||
variant="text-sm/medium"
|
||||
>
|
||||
Asset type {type.toUpperCase()} is not supported for preview.
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
listContainer: {
|
||||
paddingBottom: 16,
|
||||
},
|
||||
smallPreview: {
|
||||
height: 32,
|
||||
width: 32,
|
||||
},
|
||||
preview: {
|
||||
flex: 1,
|
||||
width: 'auto',
|
||||
height: 192,
|
||||
resizeMode: 'contain',
|
||||
},
|
||||
centeredText: {
|
||||
width: '100%',
|
||||
textAlign: 'center',
|
||||
},
|
||||
})
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
import { Page } from '@revenge-mod/components'
|
||||
import { Design } from '@revenge-mod/discord/design'
|
||||
import { nodeUtil } from '@revenge-mod/externals/browserify'
|
||||
import { getErrorStack } from '@revenge-mod/utils/error'
|
||||
import { sleep } from '@revenge-mod/utils/promise'
|
||||
import { useRef, useState } from 'react'
|
||||
import { ScrollView } from 'react-native'
|
||||
import { api } from '..'
|
||||
|
||||
const {
|
||||
Button,
|
||||
Card,
|
||||
Slider,
|
||||
Stack,
|
||||
TableRow,
|
||||
TableRowGroup,
|
||||
TableSwitchRow,
|
||||
Text,
|
||||
TextArea,
|
||||
} = Design
|
||||
|
||||
export default function EvalJSSettingScreen() {
|
||||
const code = useRef('')
|
||||
const [result, setResult] = useState('')
|
||||
const [awaitResult, setAwaitResult] = useState(true)
|
||||
const [showHidden, setShowHidden] = useState(true)
|
||||
const [inspectDepth, setInspectDepth] = useState(3)
|
||||
const [wordWrap, setWordWrap] = useState(true)
|
||||
|
||||
return (
|
||||
<ScrollView contentContainerStyle={{ paddingBottom: 32 }}>
|
||||
<Page spacing={16}>
|
||||
<TextArea
|
||||
autoFocus
|
||||
label="Code"
|
||||
onChange={v => {
|
||||
code.current = v
|
||||
}}
|
||||
placeholder="revenge.discord.native.BundleUpdaterManager.reload()"
|
||||
size="md"
|
||||
/>
|
||||
<TableRowGroup title="Inspection Options">
|
||||
<TableSwitchRow
|
||||
label="Await result"
|
||||
onValueChange={setAwaitResult}
|
||||
subLabel="Wait for the result of the code before displaying it."
|
||||
value={awaitResult}
|
||||
/>
|
||||
<TableSwitchRow
|
||||
label="Show hidden"
|
||||
onValueChange={setShowHidden}
|
||||
subLabel="Show hidden properties of the object."
|
||||
value={showHidden}
|
||||
/>
|
||||
<TableRow
|
||||
label="Inspect depth"
|
||||
subLabel="The depth of the object to inspect."
|
||||
trailing={
|
||||
<Text variant="text-sm/normal">{inspectDepth}</Text>
|
||||
}
|
||||
/>
|
||||
</TableRowGroup>
|
||||
<Slider
|
||||
endIcon={<Text variant="text-sm/normal">10</Text>}
|
||||
maximumValue={10}
|
||||
minimumValue={0}
|
||||
onValueChange={setInspectDepth}
|
||||
startIcon={<Text variant="text-sm/normal">0</Text>}
|
||||
step={1}
|
||||
value={inspectDepth}
|
||||
/>
|
||||
<TableRowGroup title="Display Options">
|
||||
<TableSwitchRow
|
||||
label="Word wrap"
|
||||
subLabel="Long results will wrap to the next line."
|
||||
onValueChange={setWordWrap}
|
||||
value={wordWrap}
|
||||
/>
|
||||
</TableRowGroup>
|
||||
<Stack>
|
||||
<Text variant="heading-sm/semibold" color="text-strong">
|
||||
Result
|
||||
</Text>
|
||||
<Card>
|
||||
{/* TODO: Maybe try to make it fill space with minHeight: 128? */}
|
||||
<ScrollView
|
||||
nestedScrollEnabled
|
||||
style={{ maxHeight: 300 }}
|
||||
>
|
||||
<ScrollView
|
||||
nestedScrollEnabled
|
||||
horizontal={!wordWrap}
|
||||
>
|
||||
<Text
|
||||
selectable
|
||||
style={{ fontFamily: 'monospace' }}
|
||||
>
|
||||
{result || '<empty>'}
|
||||
</Text>
|
||||
</ScrollView>
|
||||
</ScrollView>
|
||||
</Card>
|
||||
</Stack>
|
||||
<Button
|
||||
onPress={async function onPress() {
|
||||
const key = `_${Math.random()
|
||||
.toString(36)
|
||||
.substring(2, 15)}`
|
||||
|
||||
try {
|
||||
if (!api) {
|
||||
setResult(
|
||||
'<Revenge API not available, snippet will be run without it...>',
|
||||
)
|
||||
|
||||
await sleep(1000)
|
||||
}
|
||||
// @ts-expect-error
|
||||
else globalThis[key] = api
|
||||
|
||||
// biome-ignore lint/security/noGlobalEval: Intentional
|
||||
const res = (0, eval)(
|
||||
`var api=${key},{unscoped:revenge}=api;undefined;${code.current}//# sourceURL=Revenge:EvalJS`,
|
||||
)
|
||||
|
||||
setResult(
|
||||
nodeUtil.inspect(
|
||||
awaitResult ? await res : res,
|
||||
{
|
||||
depth: inspectDepth,
|
||||
showHidden,
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
// @ts-expect-error
|
||||
delete globalThis[key]
|
||||
} catch (e) {
|
||||
setResult(getErrorStack(e))
|
||||
}
|
||||
}}
|
||||
text="Evaluate"
|
||||
variant="primary"
|
||||
/>
|
||||
</Page>
|
||||
</ScrollView>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,183 +0,0 @@
|
|||
import { styles } from '@revenge-mod/components/_'
|
||||
import { ToastActionCreators } from '@revenge-mod/discord/actions'
|
||||
import { Design } from '@revenge-mod/discord/design'
|
||||
import { SettingListRenderer } from '@revenge-mod/discord/modules/settings/renderer'
|
||||
import { lookupGeneratedIconComponent } from '@revenge-mod/utils/discord'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
import { api } from '..'
|
||||
import { Setting } from '../constants'
|
||||
import { DTContext, useIsConnected as useIsDTConnected } from '../devtools'
|
||||
import {
|
||||
RDTContext,
|
||||
useIsConnected as useIsRDTConnected,
|
||||
} from '../react-devtools'
|
||||
|
||||
const CircleCheckIcon = lookupGeneratedIconComponent(
|
||||
'CircleCheckIcon',
|
||||
'CircleCheckIcon-secondary',
|
||||
'CircleCheckIcon-primary',
|
||||
)
|
||||
|
||||
import { ScrollView } from 'react-native'
|
||||
|
||||
const listStyles = StyleSheet.create({
|
||||
container: {
|
||||
flexGrow: 0,
|
||||
flexShrink: 0,
|
||||
height: 'auto',
|
||||
},
|
||||
})
|
||||
|
||||
export default function RevengeDeveloperSettingScreen() {
|
||||
return (
|
||||
<ScrollView style={styles.flex}>
|
||||
<Design.Stack spacing={8}>
|
||||
<View>
|
||||
<SettingListRenderer.SettingsList
|
||||
containerStyle={listStyles.container}
|
||||
node={{
|
||||
type: 'list',
|
||||
ListHeaderComponent: DTConnectionSetting,
|
||||
sections: [
|
||||
{
|
||||
settings: [
|
||||
Setting.DTAutoConnect,
|
||||
Setting.DTConnect,
|
||||
Setting.DTDisconnect,
|
||||
],
|
||||
},
|
||||
],
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<View>
|
||||
<SettingListRenderer.SettingsList
|
||||
containerStyle={listStyles.container}
|
||||
node={{
|
||||
type: 'list',
|
||||
ListHeaderComponent: RDTContext.active
|
||||
? RDTAddrSetting
|
||||
: undefined,
|
||||
sections: [
|
||||
{
|
||||
settings: [
|
||||
Setting.RDTAutoConnect,
|
||||
Setting.RDTConnect,
|
||||
Setting.RDTDisconnect,
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Tools',
|
||||
settings: [
|
||||
Setting.EvalJS,
|
||||
Setting.AssetBrowser,
|
||||
Setting.TestErrorBoundary,
|
||||
],
|
||||
},
|
||||
],
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</Design.Stack>
|
||||
</ScrollView>
|
||||
)
|
||||
}
|
||||
|
||||
export function DTConnectionSetting() {
|
||||
const open = useIsDTConnected()
|
||||
const settings = api.jsonStorage.use(
|
||||
s =>
|
||||
s.devTools?.address !== undefined ||
|
||||
s.devTools?.alias !== undefined,
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Design.TextInput
|
||||
defaultValue={settings?.devTools.address ?? DTContext.addr}
|
||||
editable={!open}
|
||||
isDisabled={open}
|
||||
label="DevTools"
|
||||
leadingText="ws://"
|
||||
onBlur={() =>
|
||||
api.jsonStorage
|
||||
.set({
|
||||
devTools: {
|
||||
address: DTContext.addr,
|
||||
},
|
||||
})
|
||||
.then(() =>
|
||||
ToastActionCreators.open({
|
||||
IconComponent: CircleCheckIcon,
|
||||
key: 'DEVTOOLS_ADDRESS_SAVED',
|
||||
content: 'Address saved',
|
||||
}),
|
||||
)
|
||||
}
|
||||
onChange={text => {
|
||||
DTContext.addr = text
|
||||
}}
|
||||
returnKeyType="done"
|
||||
/>
|
||||
<Design.TextInput
|
||||
defaultValue={settings?.devTools.alias ?? DTContext.alias}
|
||||
editable={!open}
|
||||
isDisabled={open}
|
||||
label="DevTools Alias"
|
||||
onBlur={() =>
|
||||
api.jsonStorage
|
||||
.set({
|
||||
devTools: {
|
||||
alias: DTContext.alias,
|
||||
},
|
||||
})
|
||||
.then(() =>
|
||||
ToastActionCreators.open({
|
||||
IconComponent: CircleCheckIcon,
|
||||
key: 'DEVTOOLS_ALIAS_SAVED',
|
||||
content: 'Alias saved',
|
||||
}),
|
||||
)
|
||||
}
|
||||
onChange={text => {
|
||||
DTContext.alias = text
|
||||
}}
|
||||
returnKeyType="done"
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export function RDTAddrSetting() {
|
||||
const open = useIsRDTConnected()
|
||||
const settings = api.jsonStorage.use(s => s.reactDevTools?.address)
|
||||
|
||||
return (
|
||||
<Design.TextInput
|
||||
defaultValue={settings?.reactDevTools.address ?? RDTContext.addr}
|
||||
editable={!open}
|
||||
isDisabled={open}
|
||||
label="React DevTools"
|
||||
leadingText="ws://"
|
||||
onBlur={() =>
|
||||
api.jsonStorage
|
||||
.set({
|
||||
reactDevTools: {
|
||||
address: RDTContext.addr,
|
||||
},
|
||||
})
|
||||
.then(() =>
|
||||
ToastActionCreators.open({
|
||||
IconComponent: CircleCheckIcon,
|
||||
key: 'REACT_DEVTOOLS_ADDRESS_SAVED',
|
||||
content: 'Address saved',
|
||||
}),
|
||||
)
|
||||
}
|
||||
onChange={text => {
|
||||
RDTContext.addr = text
|
||||
}}
|
||||
returnKeyType="done"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
import { useEffect } from 'react'
|
||||
|
||||
export default function TestErrorBoundarySettingScreen() {
|
||||
let x = 0
|
||||
|
||||
useEffect(() => {
|
||||
x++
|
||||
})
|
||||
|
||||
// @ts-expect-error: Intentional
|
||||
return x < 2 ? <undefined /> : null
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
import {
|
||||
addSettingsItemToSection,
|
||||
registerSettingsItems,
|
||||
} from '@revenge-mod/discord/modules/settings'
|
||||
import { api } from '.'
|
||||
import { Setting } from './constants'
|
||||
import AssetBrowserSetting from './definitions/AssetBrowserSetting'
|
||||
import DTAutoConnectSetting from './definitions/DTAutoConnectSetting'
|
||||
import DTConnectSetting from './definitions/DTConnectSetting'
|
||||
import DTDisconnectSetting from './definitions/DTDisconnectSetting'
|
||||
import EvalJSSetting from './definitions/EvalJSSetting'
|
||||
import RDTAutoConnectSetting from './definitions/RDTAutoConnectSetting'
|
||||
import RDTConnectSetting from './definitions/RDTConnectSetting'
|
||||
import RDTDisconnectSetting from './definitions/RDTDisconnectSetting'
|
||||
import RevengeDeveloperSetting from './definitions/RevengeDeveloperSetting'
|
||||
import TestErrorBoundarySetting from './definitions/TestErrorBoundarySetting'
|
||||
|
||||
export function register() {
|
||||
api.cleanup(
|
||||
registerSettingsItems({
|
||||
[Setting.RevengeDeveloper]: RevengeDeveloperSetting,
|
||||
[Setting.DTAutoConnect]: DTAutoConnectSetting,
|
||||
[Setting.DTConnect]: DTConnectSetting,
|
||||
[Setting.DTDisconnect]: DTDisconnectSetting,
|
||||
[Setting.RDTAutoConnect]: RDTAutoConnectSetting,
|
||||
[Setting.RDTConnect]: RDTConnectSetting,
|
||||
[Setting.RDTDisconnect]: RDTDisconnectSetting,
|
||||
[Setting.EvalJS]: EvalJSSetting,
|
||||
[Setting.AssetBrowser]: AssetBrowserSetting,
|
||||
[Setting.TestErrorBoundary]: TestErrorBoundarySetting,
|
||||
}),
|
||||
addSettingsItemToSection('REVENGE', Setting.RevengeDeveloper, -1),
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue