UNPKG

@metamask/base-controller

Version:

Provides scaffolding for controllers as well a communication system for all controllers

214 lines 10.1 kB
import type { ActionConstraint, EventConstraint, Messenger, MessengerActions, MessengerEvents } from "@metamask/messenger"; import type { Json, PublicInterface } from "@metamask/utils"; import type { Draft, Patch } from "immer"; /** * A type that constrains the state of all controllers. * * In other words, the narrowest supertype encompassing all controller state. */ export type StateConstraint = Record<string, Json>; /** * A state change listener. * * This function will get called for each state change, and is given a copy of * the new state along with a set of patches describing the changes since the * last update. * * @param state - The new controller state. * @param patches - A list of patches describing any changes (see here for more * information: https://immerjs.github.io/immer/docs/patches) */ export type StateChangeListener<Type> = (state: Type, patches: Patch[]) => void; /** * An function to derive state. * * This function will accept one piece of the controller state (one property), * and will return some derivation of that state. * * @param value - A piece of controller state. * @returns Something derived from controller state. */ export type StateDeriver<Type extends Json> = (value: Type) => Json; /** * State metadata. * * This metadata describes which parts of state should be persisted, and how to * get an anonymized representation of the state. */ export type StateMetadata<Type extends StateConstraint> = { [Key in keyof Type]-?: StatePropertyMetadata<Type[Key]>; }; /** * Metadata for a single state property */ export type StatePropertyMetadata<ControllerState extends Json> = { /** * Indicates whether this property should be included in debug snapshots attached to Sentry * errors. * * Set this to false if the state may contain personally identifiable information, or if it's * too large to include in a debug snapshot. */ includeInDebugSnapshot: boolean | StateDeriver<ControllerState>; /** * Indicates whether this property should be included in state logs. * * Set this to false if the data should be kept hidden from support agents (e.g. if it contains * secret keys, or personally-identifiable information that is not useful for debugging). * * We do allow state logs to contain some personally identifiable information to assist with * diagnosing errors (e.g. transaction hashes, addresses), but we still attempt to limit the * data we expose to what is most useful for helping users. */ includeInStateLogs: boolean | StateDeriver<ControllerState>; /** * Indicates whether this property should be persisted. * * If true, the property will be persisted and saved between sessions. * If false, the property will not be saved between sessions, and it will always be missing from the `state` constructor parameter. */ persist: boolean | StateDeriver<ControllerState>; /** * Indicates whether this property is used by the UI. * * If true, the property will be accessible from the UI. * If false, it will be inaccessible from the UI. * * Making a property accessible to the UI has a performance overhead, so it's better to set this * to `false` if it's not used in the UI, especially for properties that can be large in size. * * Note that we disallow the use of a state derivation function here to preserve type information * for the UI (the state deriver type always returns `Json`). */ usedInUi: boolean; }; /** * A universal supertype of `StateDeriver` types. * This type can be assigned to any `StateDeriver` type. */ export type StateDeriverConstraint = (value: never) => Json; /** * A universal supertype of `StatePropertyMetadata` types. * This type can be assigned to any `StatePropertyMetadata` type. */ export type StatePropertyMetadataConstraint = { includeInDebugSnapshot: boolean | StateDeriverConstraint; includeInStateLogs: boolean | StateDeriverConstraint; persist: boolean | StateDeriverConstraint; usedInUi: boolean; }; /** * A universal supertype of `StateMetadata` types. * This type can be assigned to any `StateMetadata` type. */ export type StateMetadataConstraint = Record<string, StatePropertyMetadataConstraint>; /** * The widest subtype of all controller instances that inherit from `BaseController` (formerly `BaseControllerV2`). * Any `BaseController` subclass instance can be assigned to this type. */ export type BaseControllerInstance = Omit<PublicInterface<BaseController<string, StateConstraint, Messenger<string, ActionConstraint, EventConstraint, any>>>, 'metadata'> & { metadata: StateMetadataConstraint; }; export type ControllerGetStateAction<ControllerName extends string, ControllerState extends StateConstraint> = { type: `${ControllerName}:getState`; handler: () => ControllerState; }; /** * @deprecated This event type is deprecated. Please use * `ControllerStateChangedEvent` instead. */ export type ControllerStateChangeEvent<ControllerName extends string, ControllerState extends StateConstraint> = { type: `${ControllerName}:stateChange`; payload: [ControllerState, Patch[]]; }; export type ControllerStateChangedEvent<ControllerName extends string, ControllerState extends StateConstraint> = { type: `${ControllerName}:stateChanged`; payload: [ControllerState, Patch[]]; }; export type ControllerActions<ControllerName extends string, ControllerState extends StateConstraint> = ControllerGetStateAction<ControllerName, ControllerState>; export type ControllerEvents<ControllerName extends string, ControllerState extends StateConstraint> = ControllerStateChangeEvent<ControllerName, ControllerState> | ControllerStateChangedEvent<ControllerName, ControllerState>; /** * Controller class that provides state management, subscriptions, and state metadata */ export declare class BaseController<ControllerName extends string, ControllerState extends StateConstraint, ControllerMessenger extends Messenger<ControllerName, ActionConstraint, EventConstraint, any>> { #private; /** * The controller messenger. This is used to interact with other parts of the application. */ protected messenger: ControllerMessenger; /** * The name of the controller. * * This is used by the ComposableController to construct a composed application state. */ readonly name: ControllerName; readonly metadata: StateMetadata<ControllerState>; /** * Creates a BaseController instance. * * @param options - Controller options. * @param options.messenger - The controller messenger. * @param options.metadata - ControllerState metadata, describing how to "anonymize" the state, and which * parts should be persisted. * @param options.name - The name of the controller, used as a namespace for events and actions. * @param options.state - Initial controller state. */ constructor({ messenger, metadata, name, state, }: { messenger: ControllerActions<ControllerName, ControllerState>['type'] extends MessengerActions<ControllerMessenger>['type'] ? ControllerStateChangeEvent<ControllerName, ControllerState>['type'] extends MessengerEvents<ControllerMessenger>['type'] ? ControllerMessenger : ControllerStateChangedEvent<ControllerName, ControllerState>['type'] extends MessengerEvents<ControllerMessenger>['type'] ? ControllerMessenger : never : never; metadata: StateMetadata<ControllerState>; name: ControllerName; state: ControllerState; }); /** * Retrieves current controller state. * * @returns The current state. */ get state(): ControllerState; set state(_: ControllerState); /** * Updates controller state. Accepts a callback that is passed a draft copy * of the controller state. If a value is returned, it is set as the new * state. Otherwise, any changes made within that callback to the draft are * applied to the controller state. * * @param callback - Callback for updating state, passed a draft state * object. Return a new state object or mutate the draft to update state. * @returns An object that has the next state, patches applied in the update and inverse patches to * rollback the update. */ protected update(callback: (state: Draft<ControllerState>) => void | ControllerState): { nextState: ControllerState; patches: Patch[]; inversePatches: Patch[]; }; /** * Applies immer patches to the current state. The patches come from the * update function itself and can either be normal or inverse patches. * * @param patches - An array of immer patches that are to be applied to make * or undo changes. */ protected applyPatches(patches: Patch[]): void; /** * Prepares the controller for garbage collection. This should be extended * by any subclasses to clean up any additional connections or events. * * The only cleanup performed here is to remove listeners. While technically * this is not required to ensure this instance is garbage collected, it at * least ensures this instance won't be responsible for preventing the * listeners from being garbage collected. */ protected destroy(): void; } /** * Use the metadata to derive state according to the given metadata property. * * @param state - The full controller state. * @param metadata - The controller metadata. * @param metadataProperty - The metadata property to use to derive state. * @param captureException - Reports an error to an error monitoring service. * @returns The metadata-derived controller state. */ export declare function deriveStateFromMetadata<ControllerState extends StateConstraint>(state: ControllerState, metadata: StateMetadata<ControllerState>, metadataProperty: keyof StatePropertyMetadata<Json>, captureException?: (error: Error) => void): Record<keyof ControllerState, Json>; //# sourceMappingURL=BaseController.d.mts.map