Skip to content

Commit

Permalink
feat!: remove manifest data from PluginDefinition type, unexport `@…
Browse files Browse the repository at this point in the history
…revenge-mod/plugins`, use constants for paths
  • Loading branch information
PalmDevs committed Dec 5, 2024
1 parent b6637bd commit f68fb91
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 139 deletions.
22 changes: 5 additions & 17 deletions libraries/plugins/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,20 @@
import { afterAppRender } from '@revenge-mod/app'
import { getErrorStack } from '@revenge-mod/utils/errors'

import { appRenderedCallbacks, corePluginIds, plugins, registerPlugin } from './internals'
import { appRenderedCallbacks, corePluginIds, plugins } from './internals'
import { logger } from './shared'

import type { PluginDefinition, PluginStage, PluginStorage } from './types'
import type { PluginDefinition, PluginStage } from './types'

export type * from './types'

afterAppRender(() => {
for (const cb of appRenderedCallbacks) cb()
})

export const PluginsLibrary = {
/**
* Defines a plugin
* @param definition The plugin definition
* @returns The plugin object
*/
definePlugin,
}

export function definePlugin<Storage = PluginStorage, AppLaunchedReturn = void, AppInitializedReturn = void>(
definition: PluginDefinition<Storage, AppLaunchedReturn, AppInitializedReturn>,
) {
return registerPlugin(definition)
export function installPlugin() {
// TODO
throw new Error('Not implemented')
}

/**
Expand Down Expand Up @@ -65,8 +55,6 @@ export function startPluginsMetroModuleSubscriptions() {
for (const plugin of Object.values(plugins)) plugin.startMetroModuleSubscriptions!()
}

export type PluginsLibrary = typeof PluginsLibrary

export type PluginContextFor<Definition, Stage extends PluginStage> = Definition extends PluginDefinition
? Parameters<NonNullable<Definition[Uncapitalize<Stage>]>>[0]
: never
158 changes: 81 additions & 77 deletions libraries/plugins/src/internals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { type PluginStates, pluginsStates } from '@revenge-mod/preferences'

import { type Patcher, createPatcherInstance } from '@revenge-mod/patcher'
import { awaitStorage, createStorage } from '@revenge-mod/storage'
import { PluginStoragePath } from '@revenge-mod/shared/paths'

import { getErrorStack } from '@revenge-mod/utils/errors'
import { objectSeal } from '@revenge-mod/utils/functions'
Expand All @@ -19,6 +20,7 @@ import type React from 'react'
import type {
PluginContext,
PluginDefinition,
PluginManifest,
PluginModuleSubscriptionContext,
PluginStopConfig,
PluginStorage,
Expand All @@ -40,6 +42,7 @@ const DefaultStopConfig: Required<PluginStopConfig> = {

export function registerPlugin<Storage = PluginStorage, AppLaunchedReturn = void, AppInitializedReturn = void>(
definition: PluginDefinition<Storage, AppLaunchedReturn, AppInitializedReturn> &
PluginManifest &
Partial<
Omit<InternalPluginDefinition<Storage, AppLaunchedReturn, AppInitializedReturn>, keyof PluginDefinition>
>,
Expand All @@ -55,7 +58,7 @@ export function registerPlugin<Storage = PluginStorage, AppLaunchedReturn = void

const prepareStorageAndPatcher = () => {
instance.patcher ||= createPatcherInstance(`revenge.plugins.plugin#${definition.id}`)
instance.storage ||= createStorage(`revenge/plugins/${definition.id}/storage.json`, {
instance.storage ||= createStorage(PluginStoragePath(definition.id), {
initial: definition.initializeStorage?.() ?? {},
})
}
Expand Down Expand Up @@ -245,79 +248,80 @@ export function registerPlugin<Storage = PluginStorage, AppLaunchedReturn = void
export type InternalPluginDefinition<Storage, AppLaunchedReturn, AppInitializedReturn> = Omit<
PluginDefinition<PluginStorage, AppLaunchedReturn, AppInitializedReturn>,
'settings'
> & {
state: PluginStates[PluginDefinition['id']]
/**
* Runs when a Metro module loads, useful for patching modules very early on.
* @internal
*/
onMetroModuleLoad?: (
context: PluginModuleSubscriptionContext<Storage>,
id: Metro.ModuleID,
exports: Metro.ModuleExports,
unsubscribe: () => void,
) => void
/**
* Disables the plugin
* @returns A full plugin stop config object
* @see {@link PluginStopConfig}
*/
disable(): Required<PluginStopConfig>
/**
* Enables the plugin
* @internal
* @returns Whether a reload should be required
*/
enable(): boolean
/**
* Starts the plugin's Metro module subscriptions (if it exists)
* @internal
*/
startMetroModuleSubscriptions: () => void
/**
* Starts the plugin normal lifecycles
* @internal
*/
start(): Promise<void>
/**
* Stops the plugin
* @internal
* @returns A full plugin stop config object
*/
stop(): Required<PluginStopConfig>
/**
* Whether the plugin is stopped
* @internal
*/
stopped: boolean
/**
* Whether the plugin is enabled. This will be set to `false` in the `beforeStop` lifecycle if the user disables the plugin.
*/
enabled: boolean
/**
* The plugin's status
* @internal
*/
status: (typeof PluginStatus)[keyof typeof PluginStatus]
/**
* The plugin's settings component
* @internal
**/
SettingsComponent?: React.FC<PluginContext<'AfterAppRender', Storage, AppLaunchedReturn, AppInitializedReturn>>
/**
* Whether the plugin is a core plugin
* @internal
*/
core: boolean
/**
* Whether the plugin is manageable (can be disabled/enabled)
* @internal
*/
manageable: boolean
/**
* The plugin's errors
* @internal
**/
// biome-ignore lint/suspicious/noExplicitAny: Anything can be thrown
errors: any[]
}
> &
PluginManifest & {
state: PluginStates[PluginManifest['id']]
/**
* Runs when a Metro module loads, useful for patching modules very early on.
* @internal
*/
onMetroModuleLoad?: (
context: PluginModuleSubscriptionContext<Storage>,
id: Metro.ModuleID,
exports: Metro.ModuleExports,
unsubscribe: () => void,
) => void
/**
* Disables the plugin
* @returns A full plugin stop config object
* @see {@link PluginStopConfig}
*/
disable(): Required<PluginStopConfig>
/**
* Enables the plugin
* @internal
* @returns Whether a reload should be required
*/
enable(): boolean
/**
* Starts the plugin's Metro module subscriptions (if it exists)
* @internal
*/
startMetroModuleSubscriptions: () => void
/**
* Starts the plugin normal lifecycles
* @internal
*/
start(): Promise<void>
/**
* Stops the plugin
* @internal
* @returns A full plugin stop config object
*/
stop(): Required<PluginStopConfig>
/**
* Whether the plugin is stopped
* @internal
*/
stopped: boolean
/**
* Whether the plugin is enabled. This will be set to `false` in the `beforeStop` lifecycle if the user disables the plugin.
*/
enabled: boolean
/**
* The plugin's status
* @internal
*/
status: (typeof PluginStatus)[keyof typeof PluginStatus]
/**
* The plugin's settings component
* @internal
**/
SettingsComponent?: React.FC<PluginContext<'AfterAppRender', Storage, AppLaunchedReturn, AppInitializedReturn>>
/**
* Whether the plugin is a core plugin
* @internal
*/
core: boolean
/**
* Whether the plugin is manageable (can be disabled/enabled)
* @internal
*/
manageable: boolean
/**
* The plugin's errors
* @internal
**/
// biome-ignore lint/suspicious/noExplicitAny: Anything can be thrown
errors: any[]
}
6 changes: 4 additions & 2 deletions libraries/plugins/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import type React from 'react'
import type { WhitelistedPluginObjectKeys } from './constants'
import type { InternalPluginDefinition } from './internals'

// biome-ignore lint/suspicious/noExplicitAny: Defaulting to unknown does NOT work
export type PluginDefinition<Storage = any, AppLaunchedReturn = any, AppInitializedReturn = any> = {
export interface PluginManifest {
/**
* The friendly name of the plugin
*/
Expand All @@ -32,7 +31,10 @@ export type PluginDefinition<Storage = any, AppLaunchedReturn = any, AppInitiali
* The icon of the plugin
*/
icon?: string
}

// biome-ignore lint/suspicious/noExplicitAny: Defaulting to unknown does NOT work
export type PluginDefinition<Storage = any, AppLaunchedReturn = any, AppInitializedReturn = any> = {
/**
* Runs before the app gets rendered AND even before the plugin is refetched and updated.
* If your plugin receives a new update, your old version will continue to run until the user decides to reload the app.
Expand Down
5 changes: 3 additions & 2 deletions libraries/preferences/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { PluginsStatesFilePath, SettingsFilePath } from '@revenge-mod/shared/paths'
import { createStorage } from '@revenge-mod/storage'

export interface Settings {
Expand All @@ -15,7 +16,7 @@ export type SerializedPluginError = {
stack: string
}

export const settings = createStorage<Settings>('revenge/settings.json', {
export const settings = createStorage<Settings>(SettingsFilePath, {
initial: {
safeMode: {
enabled: false,
Expand All @@ -24,6 +25,6 @@ export const settings = createStorage<Settings>('revenge/settings.json', {
},
})

export const pluginsStates = createStorage<PluginStates>('revenge/plugins/states.json', {
export const pluginsStates = createStorage<PluginStates>(PluginsStatesFilePath, {
initial: {},
})
7 changes: 7 additions & 0 deletions libraries/shared/src/paths.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const BaseDirectory = 'revenge'

export const SettingsFilePath = `${BaseDirectory}/settings.json`

export const PluginsDirectoryPath = `${BaseDirectory}/plugins`
export const PluginsStatesFilePath = `${PluginsDirectoryPath}/states.json`
export const PluginStoragePath = (id: string) => `${PluginsDirectoryPath}/${id}/storage.json`
Loading

0 comments on commit f68fb91

Please sign in to comment.