fix: plugin API types + JS options validation
This commit is contained in:
parent
a629b2ad44
commit
0fdc1f1cff
4 changed files with 87 additions and 25 deletions
|
|
@ -21,7 +21,12 @@ import {
|
|||
} from '.'
|
||||
import { pPending } from './dependency-graph'
|
||||
import { registerRepositoryEvents } from './repositories'
|
||||
import type { PluginManifest, PluginOptionsFactory } from '../types'
|
||||
import type {
|
||||
PluginLifecycles,
|
||||
PluginManifest,
|
||||
PluginOptions,
|
||||
PluginOptionsFactory,
|
||||
} from '../types'
|
||||
import type {
|
||||
AnyPlugin,
|
||||
PluginError,
|
||||
|
|
@ -221,9 +226,44 @@ export function confirmInstall(
|
|||
return callNativeMethod('revenge.plugins.confirmInstall', [token, accepted])
|
||||
}
|
||||
|
||||
function assertIsFunction(
|
||||
name: string,
|
||||
value: unknown,
|
||||
): asserts value is (...args: any[]) => any {
|
||||
if (typeof value !== 'function')
|
||||
throw new Error(`${name} must be a function, got ${typeof value}`)
|
||||
}
|
||||
|
||||
function createOptionsFactory(script?: string): PluginOptionsFactory {
|
||||
if (!script) return () => ({})
|
||||
return () => new Function('revenge', `return ${script}`)(pUnscopedApi)
|
||||
|
||||
return () => {
|
||||
const opts = new Function('revenge', 'plugin', `return ${script}`)(
|
||||
pUnscopedApi,
|
||||
// See types.consumers.ts
|
||||
(opts: PluginOptions) => opts,
|
||||
)()
|
||||
if (typeof opts !== 'object' || opts === null)
|
||||
throw new Error('Plugin options must be an object')
|
||||
|
||||
if (
|
||||
opts.SettingsComponent !== undefined &&
|
||||
typeof opts.SettingsComponent !== 'function'
|
||||
)
|
||||
throw new Error(
|
||||
'SettingsComponent must be a function React component',
|
||||
)
|
||||
|
||||
for (const key of ['preInit', 'init', 'start'] as Array<
|
||||
keyof PluginLifecycles
|
||||
>) {
|
||||
if (opts[key] !== undefined) {
|
||||
assertIsFunction(key, opts[key])
|
||||
}
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
}
|
||||
|
||||
declare module '@revenge-mod/modules/native' {
|
||||
|
|
|
|||
|
|
@ -9,21 +9,22 @@ import defer * as DiscordUtilsMetroSubscriptions from '@revenge-mod/discord/util
|
|||
import { defineLazyProperties } from '@revenge-mod/utils/object'
|
||||
import { guardIndexInitialized } from '.'
|
||||
|
||||
export interface PluginApiDiscord {
|
||||
actions: PluginApiDiscord.Actions
|
||||
/**
|
||||
* This submodule is only available after the index module (ID 0) is initialized.
|
||||
* Attempting to access it before then will throw an error.
|
||||
*/
|
||||
common: PluginApiDiscord.Common
|
||||
design: PluginApiDiscord.Design
|
||||
flux: PluginApiDiscord.Flux
|
||||
modules: PluginApiDiscord.Modules
|
||||
native: PluginApiDiscord.Native
|
||||
utils: PluginApiDiscord.Utils
|
||||
export interface PreInitPluginApiDiscord {
|
||||
actions: PreInitPluginApiDiscord.Actions
|
||||
/** This API is not available in the `preInit` phase. */
|
||||
common: unknown
|
||||
design: PreInitPluginApiDiscord.Design
|
||||
flux: PreInitPluginApiDiscord.Flux
|
||||
modules: PreInitPluginApiDiscord.Modules
|
||||
native: PreInitPluginApiDiscord.Native
|
||||
utils: PreInitPluginApiDiscord.Utils
|
||||
}
|
||||
|
||||
export namespace PluginApiDiscord {
|
||||
export interface InitPluginApiDiscord extends PreInitPluginApiDiscord {
|
||||
common: PreInitPluginApiDiscord.Common
|
||||
}
|
||||
|
||||
export namespace PreInitPluginApiDiscord {
|
||||
export type Actions = typeof import('@revenge-mod/discord/actions')
|
||||
export type Common = typeof import('@revenge-mod/discord/common')
|
||||
export type Design = typeof import('@revenge-mod/discord/design')
|
||||
|
|
@ -46,7 +47,7 @@ export namespace PluginApiDiscord {
|
|||
|
||||
export const discord = defineLazyProperties(
|
||||
{
|
||||
modules: defineLazyProperties({} as PluginApiDiscord.Modules, {
|
||||
modules: defineLazyProperties({} as PreInitPluginApiDiscord.Modules, {
|
||||
mainTabsV2: () => {
|
||||
return DiscordModulesMainTabsV2
|
||||
},
|
||||
|
|
@ -55,7 +56,7 @@ export const discord = defineLazyProperties(
|
|||
...require('@revenge-mod/discord/modules/settings/renderer'),
|
||||
}),
|
||||
}),
|
||||
utils: defineLazyProperties({} as PluginApiDiscord.Utils, {
|
||||
utils: defineLazyProperties({} as PreInitPluginApiDiscord.Utils, {
|
||||
finders: () => {
|
||||
return DiscordUtilsFinders
|
||||
},
|
||||
|
|
@ -63,7 +64,7 @@ export const discord = defineLazyProperties(
|
|||
subscriptions: DiscordUtilsMetroSubscriptions,
|
||||
}),
|
||||
}),
|
||||
} as PluginApiDiscord,
|
||||
} as PreInitPluginApiDiscord,
|
||||
{
|
||||
actions: () => {
|
||||
return DiscordActions
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
import type { FunctionComponent } from 'react'
|
||||
import type { PluginApiDiscord } from './apis/discord'
|
||||
import type {
|
||||
InitPluginApiDiscord,
|
||||
PreInitPluginApiDiscord,
|
||||
} from './apis/discord'
|
||||
import type { PluginApiExternals } from './apis/externals'
|
||||
import type { PluginApiModules } from './apis/modules'
|
||||
import type { PluginApiPlugins } from './apis/plugins'
|
||||
|
|
@ -23,8 +26,9 @@ export interface UnscopedPreInitPluginApi<
|
|||
react: PluginApiReact
|
||||
assets: typeof import('@revenge-mod/assets')
|
||||
externals: PluginApiExternals
|
||||
components: typeof import('@revenge-mod/components')
|
||||
discord: PluginApiDiscord
|
||||
/** This API is not available in the `preInit` phase. */
|
||||
components: unknown
|
||||
discord: PreInitPluginApiDiscord
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -33,7 +37,10 @@ export interface UnscopedPreInitPluginApi<
|
|||
*/
|
||||
export interface UnscopedInitPluginApi<
|
||||
O extends PluginApiExtensionsOptions = PluginApiExtensionsOptions,
|
||||
> extends UnscopedPreInitPluginApi<O> {}
|
||||
> extends UnscopedPreInitPluginApi<O> {
|
||||
components: typeof import('@revenge-mod/components')
|
||||
discord: InitPluginApiDiscord
|
||||
}
|
||||
|
||||
/**
|
||||
* The unscoped plugin API. This API is available as a global for plugins.
|
||||
|
|
|
|||
|
|
@ -1,14 +1,28 @@
|
|||
import type {
|
||||
PluginApiExtensionsOptions,
|
||||
PluginManifest,
|
||||
PluginOptions,
|
||||
UnscopedInitPluginApi,
|
||||
UnscopedPluginApi,
|
||||
UnscopedPreInitPluginApi,
|
||||
} from '@revenge-mod/plugins/types'
|
||||
|
||||
declare global {
|
||||
/**
|
||||
* Defines an entrypoint for a Revenge JS plugin.
|
||||
*/
|
||||
export function plugin<O extends PluginApiExtensionsOptions>(
|
||||
manifest: PluginManifest,
|
||||
options: PluginOptions<O>,
|
||||
): void
|
||||
): PluginOptions<O>
|
||||
|
||||
/**
|
||||
* The unscoped plugin API. **Use directly only when necessary.**
|
||||
*
|
||||
* You should be using the `unscoped` property of the `PluginApi` object instead.
|
||||
*/
|
||||
export const revenge:
|
||||
| UnscopedPreInitPluginApi
|
||||
| UnscopedInitPluginApi
|
||||
| UnscopedPluginApi
|
||||
}
|
||||
|
||||
export * from './globals'
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue