@metamask-previews/base-controller 7.1.1-preview-0d0d258d → 7.1.1-preview-4c4eb52a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"BaseControllerV2.cjs","sourceRoot":"","sources":["../src/BaseControllerV2.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Json, PublicInterface } from '@metamask/utils';\nimport { enablePatches, produceWithPatches, applyPatches, freeze } from 'immer';\nimport type { Draft, Patch } from 'immer';\n\nimport type {\n BaseControllerV1Instance,\n StateConstraint as StateConstraintV1,\n} from './BaseControllerV1';\nimport type { ActionConstraint, EventConstraint } from './Messenger';\nimport type {\n RestrictedMessenger,\n RestrictedMessengerConstraint,\n} from './RestrictedMessenger';\n\nenablePatches();\n\n/**\n * Determines if the given controller is an instance of `BaseController`\n *\n * @param controller - Controller instance to check\n * @returns True if the controller is an instance of `BaseController`\n */\nexport function isBaseController(\n controller: ControllerInstance,\n): controller is BaseControllerInstance {\n return (\n 'name' in controller &&\n typeof controller.name === 'string' &&\n 'state' in controller &&\n typeof controller.state === 'object' &&\n 'metadata' in controller &&\n typeof controller.metadata === 'object'\n );\n}\n\n/**\n * A type that constrains the state of all controllers.\n *\n * In other words, the narrowest supertype encompassing all controller state.\n */\nexport type StateConstraint = Record<string, Json>;\n\n/**\n * A universal supertype for the controller state object, encompassing both `BaseControllerV1` and `BaseControllerV2` state.\n */\n// TODO: Remove once BaseControllerV2 migrations are completed for all controllers.\nexport type LegacyControllerStateConstraint =\n | StateConstraintV1\n | StateConstraint;\n\n/**\n * A state change listener.\n *\n * This function will get called for each state change, and is given a copy of\n * the new state along with a set of patches describing the changes since the\n * last update.\n *\n * @param state - The new controller state.\n * @param patches - A list of patches describing any changes (see here for more\n * information: https://immerjs.github.io/immer/docs/patches)\n */\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type Listener<T> = (state: T, patches: Patch[]) => void;\n\n/**\n * An function to derive state.\n *\n * This function will accept one piece of the controller state (one property),\n * and will return some derivation of that state.\n *\n * @param value - A piece of controller state.\n * @returns Something derived from controller state.\n */\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type StateDeriver<T extends Json> = (value: T) => Json;\n\n/**\n * State metadata.\n *\n * This metadata describes which parts of state should be persisted, and how to\n * get an anonymized representation of the state.\n */\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type StateMetadata<T extends StateConstraint> = {\n [P in keyof T]-?: StatePropertyMetadata<T[P]>;\n};\n\n/**\n * Metadata for a single state property\n *\n * @property persist - Indicates whether this property should be persisted\n * (`true` for persistent, `false` for transient), or is set to a function\n * that derives the persistent state from the state.\n * @property anonymous - Indicates whether this property is already anonymous,\n * (`true` for anonymous, `false` if it has potential to be personally\n * identifiable), or is set to a function that returns an anonymized\n * representation of this state.\n */\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type StatePropertyMetadata<T extends Json> = {\n persist: boolean | StateDeriver<T>;\n anonymous: boolean | StateDeriver<T>;\n};\n\n/**\n * A universal supertype of `StateDeriver` types.\n * This type can be assigned to any `StateDeriver` type.\n */\nexport type StateDeriverConstraint = (value: never) => Json;\n\n/**\n * A universal supertype of `StatePropertyMetadata` types.\n * This type can be assigned to any `StatePropertyMetadata` type.\n */\nexport type StatePropertyMetadataConstraint = {\n [P in 'anonymous' | 'persist']: boolean | StateDeriverConstraint;\n};\n\n/**\n * A universal supertype of `StateMetadata` types.\n * This type can be assigned to any `StateMetadata` type.\n */\nexport type StateMetadataConstraint = Record<\n string,\n StatePropertyMetadataConstraint\n>;\n\n/**\n * The widest subtype of all controller instances that inherit from `BaseController` (formerly `BaseControllerV2`).\n * Any `BaseController` subclass instance can be assigned to this type.\n */\nexport type BaseControllerInstance = Omit<\n PublicInterface<\n BaseController<string, StateConstraint, RestrictedMessengerConstraint>\n >,\n 'metadata'\n> & {\n metadata: StateMetadataConstraint;\n};\n\n/**\n * A widest subtype of all controller instances that inherit from `BaseController` (formerly `BaseControllerV2`) or `BaseControllerV1`.\n * Any `BaseController` or `BaseControllerV1` subclass instance can be assigned to this type.\n */\n// TODO: Remove once BaseControllerV2 migrations are completed for all controllers.\nexport type ControllerInstance =\n | BaseControllerV1Instance\n | BaseControllerInstance;\n\nexport type ControllerGetStateAction<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n> = {\n type: `${ControllerName}:getState`;\n handler: () => ControllerState;\n};\n\nexport type ControllerStateChangeEvent<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n> = {\n type: `${ControllerName}:stateChange`;\n payload: [ControllerState, Patch[]];\n};\n\nexport type ControllerActions<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n> = ControllerGetStateAction<ControllerName, ControllerState>;\n\nexport type ControllerEvents<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n> = ControllerStateChangeEvent<ControllerName, ControllerState>;\n\n/**\n * Controller class that provides state management, subscriptions, and state metadata\n */\nexport class BaseController<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n messenger extends RestrictedMessenger<\n ControllerName,\n ActionConstraint | ControllerActions<ControllerName, ControllerState>,\n EventConstraint | ControllerEvents<ControllerName, ControllerState>,\n string,\n string\n >,\n> {\n #internalState: ControllerState;\n\n protected messagingSystem: messenger;\n\n /**\n * The name of the controller.\n *\n * This is used by the ComposableController to construct a composed application state.\n */\n public readonly name: ControllerName;\n\n public readonly metadata: StateMetadata<ControllerState>;\n\n /**\n * Creates a BaseController instance.\n *\n * @param options - Controller options.\n * @param options.messenger - Controller messaging system.\n * @param options.metadata - ControllerState metadata, describing how to \"anonymize\" the state, and which\n * parts should be persisted.\n * @param options.name - The name of the controller, used as a namespace for events and actions.\n * @param options.state - Initial controller state.\n */\n constructor({\n messenger,\n metadata,\n name,\n state,\n }: {\n messenger: messenger;\n metadata: StateMetadata<ControllerState>;\n name: ControllerName;\n state: ControllerState;\n }) {\n this.messagingSystem = messenger;\n this.name = name;\n // Here we use `freeze` from Immer to enforce that the state is deeply\n // immutable. Note that this is a runtime check, not a compile-time check.\n // That is, unlike `Object.freeze`, this does not narrow the type\n // recursively to `Readonly`. The equivalent in Immer is `Immutable`, but\n // `Immutable` does not handle recursive types such as our `Json` type.\n this.#internalState = freeze(state, true);\n this.metadata = metadata;\n\n this.messagingSystem.registerActionHandler(\n `${name}:getState`,\n () => this.state,\n );\n\n this.messagingSystem.registerInitialEventPayload({\n eventType: `${name}:stateChange`,\n getPayload: () => [this.state, []],\n });\n }\n\n /**\n * Retrieves current controller state.\n *\n * @returns The current state.\n */\n get state() {\n return this.#internalState;\n }\n\n set state(_) {\n throw new Error(\n `Controller state cannot be directly mutated; use 'update' method instead.`,\n );\n }\n\n /**\n * Updates controller state. Accepts a callback that is passed a draft copy\n * of the controller state. If a value is returned, it is set as the new\n * state. Otherwise, any changes made within that callback to the draft are\n * applied to the controller state.\n *\n * @param callback - Callback for updating state, passed a draft state\n * object. Return a new state object or mutate the draft to update state.\n * @returns An object that has the next state, patches applied in the update and inverse patches to\n * rollback the update.\n */\n protected update(\n callback: (state: Draft<ControllerState>) => void | ControllerState,\n ): {\n nextState: ControllerState;\n patches: Patch[];\n inversePatches: Patch[];\n } {\n // We run into ts2589, \"infinite type depth\", if we don't cast\n // produceWithPatches here.\n const [nextState, patches, inversePatches] = (\n produceWithPatches as unknown as (\n state: ControllerState,\n cb: typeof callback,\n ) => [ControllerState, Patch[], Patch[]]\n )(this.#internalState, callback);\n\n this.#internalState = nextState;\n this.messagingSystem.publish(\n `${this.name}:stateChange`,\n nextState,\n patches,\n );\n\n return { nextState, patches, inversePatches };\n }\n\n /**\n * Applies immer patches to the current state. The patches come from the\n * update function itself and can either be normal or inverse patches.\n *\n * @param patches - An array of immer patches that are to be applied to make\n * or undo changes.\n */\n protected applyPatches(patches: Patch[]) {\n const nextState = applyPatches(this.#internalState, patches);\n this.#internalState = nextState;\n this.messagingSystem.publish(\n `${this.name}:stateChange`,\n nextState,\n patches,\n );\n }\n\n /**\n * Prepares the controller for garbage collection. This should be extended\n * by any subclasses to clean up any additional connections or events.\n *\n * The only cleanup performed here is to remove listeners. While technically\n * this is not required to ensure this instance is garbage collected, it at\n * least ensures this instance won't be responsible for preventing the\n * listeners from being garbage collected.\n */\n protected destroy() {\n this.messagingSystem.clearEventSubscriptions(`${this.name}:stateChange`);\n }\n}\n\n/**\n * Returns an anonymized representation of the controller state.\n *\n * By \"anonymized\" we mean that it should not contain any information that could be personally\n * identifiable.\n *\n * @param state - The controller state.\n * @param metadata - The controller state metadata, which describes how to derive the\n * anonymized state.\n * @returns The anonymized controller state.\n */\nexport function getAnonymizedState<ControllerState extends StateConstraint>(\n state: ControllerState,\n metadata: StateMetadata<ControllerState>,\n): Record<keyof ControllerState, Json> {\n return deriveStateFromMetadata(state, metadata, 'anonymous');\n}\n\n/**\n * Returns the subset of state that should be persisted.\n *\n * @param state - The controller state.\n * @param metadata - The controller state metadata, which describes which pieces of state should be persisted.\n * @returns The subset of controller state that should be persisted.\n */\nexport function getPersistentState<ControllerState extends StateConstraint>(\n state: ControllerState,\n metadata: StateMetadata<ControllerState>,\n): Record<keyof ControllerState, Json> {\n return deriveStateFromMetadata(state, metadata, 'persist');\n}\n\n/**\n * Use the metadata to derive state according to the given metadata property.\n *\n * @param state - The full controller state.\n * @param metadata - The controller metadata.\n * @param metadataProperty - The metadata property to use to derive state.\n * @returns The metadata-derived controller state.\n */\nfunction deriveStateFromMetadata<ControllerState extends StateConstraint>(\n state: ControllerState,\n metadata: StateMetadata<ControllerState>,\n metadataProperty: 'anonymous' | 'persist',\n): Record<keyof ControllerState, Json> {\n return (Object.keys(state) as (keyof ControllerState)[]).reduce<\n Record<keyof ControllerState, Json>\n >((derivedState, key) => {\n try {\n const stateMetadata = metadata[key];\n if (!stateMetadata) {\n throw new Error(`No metadata found for '${String(key)}'`);\n }\n const propertyMetadata = stateMetadata[metadataProperty];\n const stateProperty = state[key];\n if (typeof propertyMetadata === 'function') {\n derivedState[key] = propertyMetadata(stateProperty);\n } else if (propertyMetadata) {\n derivedState[key] = stateProperty;\n }\n return derivedState;\n } catch (error) {\n // Throw error after timeout so that it is captured as a console error\n // (and by Sentry) without interrupting state-related operations\n setTimeout(() => {\n throw error;\n });\n return derivedState;\n }\n }, {} as never);\n}\n"]}
1
+ {"version":3,"file":"BaseControllerV2.cjs","sourceRoot":"","sources":["../src/BaseControllerV2.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Json, PublicInterface } from '@metamask/utils';\nimport { enablePatches, produceWithPatches, applyPatches, freeze } from 'immer';\nimport type { Draft, Patch } from 'immer';\n\nimport type {\n BaseControllerV1Instance,\n StateConstraint as StateConstraintV1,\n} from './BaseControllerV1';\nimport type { ActionConstraint, EventConstraint } from './Messenger';\nimport type {\n RestrictedControllerMessenger,\n RestrictedControllerMessengerConstraint,\n} from './RestrictedMessenger';\n\nenablePatches();\n\n/**\n * Determines if the given controller is an instance of `BaseController`\n *\n * @param controller - Controller instance to check\n * @returns True if the controller is an instance of `BaseController`\n */\nexport function isBaseController(\n controller: ControllerInstance,\n): controller is BaseControllerInstance {\n return (\n 'name' in controller &&\n typeof controller.name === 'string' &&\n 'state' in controller &&\n typeof controller.state === 'object' &&\n 'metadata' in controller &&\n typeof controller.metadata === 'object'\n );\n}\n\n/**\n * A type that constrains the state of all controllers.\n *\n * In other words, the narrowest supertype encompassing all controller state.\n */\nexport type StateConstraint = Record<string, Json>;\n\n/**\n * A universal supertype for the controller state object, encompassing both `BaseControllerV1` and `BaseControllerV2` state.\n */\n// TODO: Remove once BaseControllerV2 migrations are completed for all controllers.\nexport type LegacyControllerStateConstraint =\n | StateConstraintV1\n | StateConstraint;\n\n/**\n * A state change listener.\n *\n * This function will get called for each state change, and is given a copy of\n * the new state along with a set of patches describing the changes since the\n * last update.\n *\n * @param state - The new controller state.\n * @param patches - A list of patches describing any changes (see here for more\n * information: https://immerjs.github.io/immer/docs/patches)\n */\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type Listener<T> = (state: T, patches: Patch[]) => void;\n\n/**\n * An function to derive state.\n *\n * This function will accept one piece of the controller state (one property),\n * and will return some derivation of that state.\n *\n * @param value - A piece of controller state.\n * @returns Something derived from controller state.\n */\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type StateDeriver<T extends Json> = (value: T) => Json;\n\n/**\n * State metadata.\n *\n * This metadata describes which parts of state should be persisted, and how to\n * get an anonymized representation of the state.\n */\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type StateMetadata<T extends StateConstraint> = {\n [P in keyof T]-?: StatePropertyMetadata<T[P]>;\n};\n\n/**\n * Metadata for a single state property\n *\n * @property persist - Indicates whether this property should be persisted\n * (`true` for persistent, `false` for transient), or is set to a function\n * that derives the persistent state from the state.\n * @property anonymous - Indicates whether this property is already anonymous,\n * (`true` for anonymous, `false` if it has potential to be personally\n * identifiable), or is set to a function that returns an anonymized\n * representation of this state.\n */\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type StatePropertyMetadata<T extends Json> = {\n persist: boolean | StateDeriver<T>;\n anonymous: boolean | StateDeriver<T>;\n};\n\n/**\n * A universal supertype of `StateDeriver` types.\n * This type can be assigned to any `StateDeriver` type.\n */\nexport type StateDeriverConstraint = (value: never) => Json;\n\n/**\n * A universal supertype of `StatePropertyMetadata` types.\n * This type can be assigned to any `StatePropertyMetadata` type.\n */\nexport type StatePropertyMetadataConstraint = {\n [P in 'anonymous' | 'persist']: boolean | StateDeriverConstraint;\n};\n\n/**\n * A universal supertype of `StateMetadata` types.\n * This type can be assigned to any `StateMetadata` type.\n */\nexport type StateMetadataConstraint = Record<\n string,\n StatePropertyMetadataConstraint\n>;\n\n/**\n * The widest subtype of all controller instances that inherit from `BaseController` (formerly `BaseControllerV2`).\n * Any `BaseController` subclass instance can be assigned to this type.\n */\nexport type BaseControllerInstance = Omit<\n PublicInterface<\n BaseController<\n string,\n StateConstraint,\n RestrictedControllerMessengerConstraint\n >\n >,\n 'metadata'\n> & {\n metadata: StateMetadataConstraint;\n};\n\n/**\n * A widest subtype of all controller instances that inherit from `BaseController` (formerly `BaseControllerV2`) or `BaseControllerV1`.\n * Any `BaseController` or `BaseControllerV1` subclass instance can be assigned to this type.\n */\n// TODO: Remove once BaseControllerV2 migrations are completed for all controllers.\nexport type ControllerInstance =\n | BaseControllerV1Instance\n | BaseControllerInstance;\n\nexport type ControllerGetStateAction<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n> = {\n type: `${ControllerName}:getState`;\n handler: () => ControllerState;\n};\n\nexport type ControllerStateChangeEvent<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n> = {\n type: `${ControllerName}:stateChange`;\n payload: [ControllerState, Patch[]];\n};\n\nexport type ControllerActions<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n> = ControllerGetStateAction<ControllerName, ControllerState>;\n\nexport type ControllerEvents<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n> = ControllerStateChangeEvent<ControllerName, ControllerState>;\n\n/**\n * Controller class that provides state management, subscriptions, and state metadata\n */\nexport class BaseController<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n messenger extends RestrictedControllerMessenger<\n ControllerName,\n ActionConstraint | ControllerActions<ControllerName, ControllerState>,\n EventConstraint | ControllerEvents<ControllerName, ControllerState>,\n string,\n string\n >,\n> {\n #internalState: ControllerState;\n\n protected messagingSystem: messenger;\n\n /**\n * The name of the controller.\n *\n * This is used by the ComposableController to construct a composed application state.\n */\n public readonly name: ControllerName;\n\n public readonly metadata: StateMetadata<ControllerState>;\n\n /**\n * Creates a BaseController instance.\n *\n * @param options - Controller options.\n * @param options.messenger - Controller messaging system.\n * @param options.metadata - ControllerState metadata, describing how to \"anonymize\" the state, and which\n * parts should be persisted.\n * @param options.name - The name of the controller, used as a namespace for events and actions.\n * @param options.state - Initial controller state.\n */\n constructor({\n messenger,\n metadata,\n name,\n state,\n }: {\n messenger: messenger;\n metadata: StateMetadata<ControllerState>;\n name: ControllerName;\n state: ControllerState;\n }) {\n this.messagingSystem = messenger;\n this.name = name;\n // Here we use `freeze` from Immer to enforce that the state is deeply\n // immutable. Note that this is a runtime check, not a compile-time check.\n // That is, unlike `Object.freeze`, this does not narrow the type\n // recursively to `Readonly`. The equivalent in Immer is `Immutable`, but\n // `Immutable` does not handle recursive types such as our `Json` type.\n this.#internalState = freeze(state, true);\n this.metadata = metadata;\n\n this.messagingSystem.registerActionHandler(\n `${name}:getState`,\n () => this.state,\n );\n\n this.messagingSystem.registerInitialEventPayload({\n eventType: `${name}:stateChange`,\n getPayload: () => [this.state, []],\n });\n }\n\n /**\n * Retrieves current controller state.\n *\n * @returns The current state.\n */\n get state() {\n return this.#internalState;\n }\n\n set state(_) {\n throw new Error(\n `Controller state cannot be directly mutated; use 'update' method instead.`,\n );\n }\n\n /**\n * Updates controller state. Accepts a callback that is passed a draft copy\n * of the controller state. If a value is returned, it is set as the new\n * state. Otherwise, any changes made within that callback to the draft are\n * applied to the controller state.\n *\n * @param callback - Callback for updating state, passed a draft state\n * object. Return a new state object or mutate the draft to update state.\n * @returns An object that has the next state, patches applied in the update and inverse patches to\n * rollback the update.\n */\n protected update(\n callback: (state: Draft<ControllerState>) => void | ControllerState,\n ): {\n nextState: ControllerState;\n patches: Patch[];\n inversePatches: Patch[];\n } {\n // We run into ts2589, \"infinite type depth\", if we don't cast\n // produceWithPatches here.\n const [nextState, patches, inversePatches] = (\n produceWithPatches as unknown as (\n state: ControllerState,\n cb: typeof callback,\n ) => [ControllerState, Patch[], Patch[]]\n )(this.#internalState, callback);\n\n this.#internalState = nextState;\n this.messagingSystem.publish(\n `${this.name}:stateChange`,\n nextState,\n patches,\n );\n\n return { nextState, patches, inversePatches };\n }\n\n /**\n * Applies immer patches to the current state. The patches come from the\n * update function itself and can either be normal or inverse patches.\n *\n * @param patches - An array of immer patches that are to be applied to make\n * or undo changes.\n */\n protected applyPatches(patches: Patch[]) {\n const nextState = applyPatches(this.#internalState, patches);\n this.#internalState = nextState;\n this.messagingSystem.publish(\n `${this.name}:stateChange`,\n nextState,\n patches,\n );\n }\n\n /**\n * Prepares the controller for garbage collection. This should be extended\n * by any subclasses to clean up any additional connections or events.\n *\n * The only cleanup performed here is to remove listeners. While technically\n * this is not required to ensure this instance is garbage collected, it at\n * least ensures this instance won't be responsible for preventing the\n * listeners from being garbage collected.\n */\n protected destroy() {\n this.messagingSystem.clearEventSubscriptions(`${this.name}:stateChange`);\n }\n}\n\n/**\n * Returns an anonymized representation of the controller state.\n *\n * By \"anonymized\" we mean that it should not contain any information that could be personally\n * identifiable.\n *\n * @param state - The controller state.\n * @param metadata - The controller state metadata, which describes how to derive the\n * anonymized state.\n * @returns The anonymized controller state.\n */\nexport function getAnonymizedState<ControllerState extends StateConstraint>(\n state: ControllerState,\n metadata: StateMetadata<ControllerState>,\n): Record<keyof ControllerState, Json> {\n return deriveStateFromMetadata(state, metadata, 'anonymous');\n}\n\n/**\n * Returns the subset of state that should be persisted.\n *\n * @param state - The controller state.\n * @param metadata - The controller state metadata, which describes which pieces of state should be persisted.\n * @returns The subset of controller state that should be persisted.\n */\nexport function getPersistentState<ControllerState extends StateConstraint>(\n state: ControllerState,\n metadata: StateMetadata<ControllerState>,\n): Record<keyof ControllerState, Json> {\n return deriveStateFromMetadata(state, metadata, 'persist');\n}\n\n/**\n * Use the metadata to derive state according to the given metadata property.\n *\n * @param state - The full controller state.\n * @param metadata - The controller metadata.\n * @param metadataProperty - The metadata property to use to derive state.\n * @returns The metadata-derived controller state.\n */\nfunction deriveStateFromMetadata<ControllerState extends StateConstraint>(\n state: ControllerState,\n metadata: StateMetadata<ControllerState>,\n metadataProperty: 'anonymous' | 'persist',\n): Record<keyof ControllerState, Json> {\n return (Object.keys(state) as (keyof ControllerState)[]).reduce<\n Record<keyof ControllerState, Json>\n >((derivedState, key) => {\n try {\n const stateMetadata = metadata[key];\n if (!stateMetadata) {\n throw new Error(`No metadata found for '${String(key)}'`);\n }\n const propertyMetadata = stateMetadata[metadataProperty];\n const stateProperty = state[key];\n if (typeof propertyMetadata === 'function') {\n derivedState[key] = propertyMetadata(stateProperty);\n } else if (propertyMetadata) {\n derivedState[key] = stateProperty;\n }\n return derivedState;\n } catch (error) {\n // Throw error after timeout so that it is captured as a console error\n // (and by Sentry) without interrupting state-related operations\n setTimeout(() => {\n throw error;\n });\n return derivedState;\n }\n }, {} as never);\n}\n"]}
@@ -2,7 +2,7 @@ import type { Json, PublicInterface } from "@metamask/utils";
2
2
  import type { Draft, Patch } from "immer";
3
3
  import type { BaseControllerV1Instance, StateConstraint as StateConstraintV1 } from "./BaseControllerV1.cjs";
4
4
  import type { ActionConstraint, EventConstraint } from "./Messenger.cjs";
5
- import type { RestrictedMessenger, RestrictedMessengerConstraint } from "./RestrictedMessenger.cjs";
5
+ import type { RestrictedControllerMessenger, RestrictedControllerMessengerConstraint } from "./RestrictedMessenger.cjs";
6
6
  /**
7
7
  * Determines if the given controller is an instance of `BaseController`
8
8
  *
@@ -87,7 +87,7 @@ export type StateMetadataConstraint = Record<string, StatePropertyMetadataConstr
87
87
  * The widest subtype of all controller instances that inherit from `BaseController` (formerly `BaseControllerV2`).
88
88
  * Any `BaseController` subclass instance can be assigned to this type.
89
89
  */
90
- export type BaseControllerInstance = Omit<PublicInterface<BaseController<string, StateConstraint, RestrictedMessengerConstraint>>, 'metadata'> & {
90
+ export type BaseControllerInstance = Omit<PublicInterface<BaseController<string, StateConstraint, RestrictedControllerMessengerConstraint>>, 'metadata'> & {
91
91
  metadata: StateMetadataConstraint;
92
92
  };
93
93
  /**
@@ -108,7 +108,7 @@ export type ControllerEvents<ControllerName extends string, ControllerState exte
108
108
  /**
109
109
  * Controller class that provides state management, subscriptions, and state metadata
110
110
  */
111
- export declare class BaseController<ControllerName extends string, ControllerState extends StateConstraint, messenger extends RestrictedMessenger<ControllerName, ActionConstraint | ControllerActions<ControllerName, ControllerState>, EventConstraint | ControllerEvents<ControllerName, ControllerState>, string, string>> {
111
+ export declare class BaseController<ControllerName extends string, ControllerState extends StateConstraint, messenger extends RestrictedControllerMessenger<ControllerName, ActionConstraint | ControllerActions<ControllerName, ControllerState>, EventConstraint | ControllerEvents<ControllerName, ControllerState>, string, string>> {
112
112
  #private;
113
113
  protected messagingSystem: messenger;
114
114
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"BaseControllerV2.d.cts","sourceRoot":"","sources":["../src/BaseControllerV2.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"BaseControllerV2.d.cts","sourceRoot":"","sources":["../src/BaseControllerV2.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@ import type { Json, PublicInterface } from "@metamask/utils";
2
2
  import type { Draft, Patch } from "immer";
3
3
  import type { BaseControllerV1Instance, StateConstraint as StateConstraintV1 } from "./BaseControllerV1.mjs";
4
4
  import type { ActionConstraint, EventConstraint } from "./Messenger.mjs";
5
- import type { RestrictedMessenger, RestrictedMessengerConstraint } from "./RestrictedMessenger.mjs";
5
+ import type { RestrictedControllerMessenger, RestrictedControllerMessengerConstraint } from "./RestrictedMessenger.mjs";
6
6
  /**
7
7
  * Determines if the given controller is an instance of `BaseController`
8
8
  *
@@ -87,7 +87,7 @@ export type StateMetadataConstraint = Record<string, StatePropertyMetadataConstr
87
87
  * The widest subtype of all controller instances that inherit from `BaseController` (formerly `BaseControllerV2`).
88
88
  * Any `BaseController` subclass instance can be assigned to this type.
89
89
  */
90
- export type BaseControllerInstance = Omit<PublicInterface<BaseController<string, StateConstraint, RestrictedMessengerConstraint>>, 'metadata'> & {
90
+ export type BaseControllerInstance = Omit<PublicInterface<BaseController<string, StateConstraint, RestrictedControllerMessengerConstraint>>, 'metadata'> & {
91
91
  metadata: StateMetadataConstraint;
92
92
  };
93
93
  /**
@@ -108,7 +108,7 @@ export type ControllerEvents<ControllerName extends string, ControllerState exte
108
108
  /**
109
109
  * Controller class that provides state management, subscriptions, and state metadata
110
110
  */
111
- export declare class BaseController<ControllerName extends string, ControllerState extends StateConstraint, messenger extends RestrictedMessenger<ControllerName, ActionConstraint | ControllerActions<ControllerName, ControllerState>, EventConstraint | ControllerEvents<ControllerName, ControllerState>, string, string>> {
111
+ export declare class BaseController<ControllerName extends string, ControllerState extends StateConstraint, messenger extends RestrictedControllerMessenger<ControllerName, ActionConstraint | ControllerActions<ControllerName, ControllerState>, EventConstraint | ControllerEvents<ControllerName, ControllerState>, string, string>> {
112
112
  #private;
113
113
  protected messagingSystem: messenger;
114
114
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"BaseControllerV2.d.mts","sourceRoot":"","sources":["../src/BaseControllerV2.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"BaseControllerV2.d.mts","sourceRoot":"","sources":["../src/BaseControllerV2.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"BaseControllerV2.mjs","sourceRoot":"","sources":["../src/BaseControllerV2.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Json, PublicInterface } from '@metamask/utils';\nimport { enablePatches, produceWithPatches, applyPatches, freeze } from 'immer';\nimport type { Draft, Patch } from 'immer';\n\nimport type {\n BaseControllerV1Instance,\n StateConstraint as StateConstraintV1,\n} from './BaseControllerV1';\nimport type { ActionConstraint, EventConstraint } from './Messenger';\nimport type {\n RestrictedMessenger,\n RestrictedMessengerConstraint,\n} from './RestrictedMessenger';\n\nenablePatches();\n\n/**\n * Determines if the given controller is an instance of `BaseController`\n *\n * @param controller - Controller instance to check\n * @returns True if the controller is an instance of `BaseController`\n */\nexport function isBaseController(\n controller: ControllerInstance,\n): controller is BaseControllerInstance {\n return (\n 'name' in controller &&\n typeof controller.name === 'string' &&\n 'state' in controller &&\n typeof controller.state === 'object' &&\n 'metadata' in controller &&\n typeof controller.metadata === 'object'\n );\n}\n\n/**\n * A type that constrains the state of all controllers.\n *\n * In other words, the narrowest supertype encompassing all controller state.\n */\nexport type StateConstraint = Record<string, Json>;\n\n/**\n * A universal supertype for the controller state object, encompassing both `BaseControllerV1` and `BaseControllerV2` state.\n */\n// TODO: Remove once BaseControllerV2 migrations are completed for all controllers.\nexport type LegacyControllerStateConstraint =\n | StateConstraintV1\n | StateConstraint;\n\n/**\n * A state change listener.\n *\n * This function will get called for each state change, and is given a copy of\n * the new state along with a set of patches describing the changes since the\n * last update.\n *\n * @param state - The new controller state.\n * @param patches - A list of patches describing any changes (see here for more\n * information: https://immerjs.github.io/immer/docs/patches)\n */\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type Listener<T> = (state: T, patches: Patch[]) => void;\n\n/**\n * An function to derive state.\n *\n * This function will accept one piece of the controller state (one property),\n * and will return some derivation of that state.\n *\n * @param value - A piece of controller state.\n * @returns Something derived from controller state.\n */\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type StateDeriver<T extends Json> = (value: T) => Json;\n\n/**\n * State metadata.\n *\n * This metadata describes which parts of state should be persisted, and how to\n * get an anonymized representation of the state.\n */\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type StateMetadata<T extends StateConstraint> = {\n [P in keyof T]-?: StatePropertyMetadata<T[P]>;\n};\n\n/**\n * Metadata for a single state property\n *\n * @property persist - Indicates whether this property should be persisted\n * (`true` for persistent, `false` for transient), or is set to a function\n * that derives the persistent state from the state.\n * @property anonymous - Indicates whether this property is already anonymous,\n * (`true` for anonymous, `false` if it has potential to be personally\n * identifiable), or is set to a function that returns an anonymized\n * representation of this state.\n */\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type StatePropertyMetadata<T extends Json> = {\n persist: boolean | StateDeriver<T>;\n anonymous: boolean | StateDeriver<T>;\n};\n\n/**\n * A universal supertype of `StateDeriver` types.\n * This type can be assigned to any `StateDeriver` type.\n */\nexport type StateDeriverConstraint = (value: never) => Json;\n\n/**\n * A universal supertype of `StatePropertyMetadata` types.\n * This type can be assigned to any `StatePropertyMetadata` type.\n */\nexport type StatePropertyMetadataConstraint = {\n [P in 'anonymous' | 'persist']: boolean | StateDeriverConstraint;\n};\n\n/**\n * A universal supertype of `StateMetadata` types.\n * This type can be assigned to any `StateMetadata` type.\n */\nexport type StateMetadataConstraint = Record<\n string,\n StatePropertyMetadataConstraint\n>;\n\n/**\n * The widest subtype of all controller instances that inherit from `BaseController` (formerly `BaseControllerV2`).\n * Any `BaseController` subclass instance can be assigned to this type.\n */\nexport type BaseControllerInstance = Omit<\n PublicInterface<\n BaseController<string, StateConstraint, RestrictedMessengerConstraint>\n >,\n 'metadata'\n> & {\n metadata: StateMetadataConstraint;\n};\n\n/**\n * A widest subtype of all controller instances that inherit from `BaseController` (formerly `BaseControllerV2`) or `BaseControllerV1`.\n * Any `BaseController` or `BaseControllerV1` subclass instance can be assigned to this type.\n */\n// TODO: Remove once BaseControllerV2 migrations are completed for all controllers.\nexport type ControllerInstance =\n | BaseControllerV1Instance\n | BaseControllerInstance;\n\nexport type ControllerGetStateAction<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n> = {\n type: `${ControllerName}:getState`;\n handler: () => ControllerState;\n};\n\nexport type ControllerStateChangeEvent<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n> = {\n type: `${ControllerName}:stateChange`;\n payload: [ControllerState, Patch[]];\n};\n\nexport type ControllerActions<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n> = ControllerGetStateAction<ControllerName, ControllerState>;\n\nexport type ControllerEvents<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n> = ControllerStateChangeEvent<ControllerName, ControllerState>;\n\n/**\n * Controller class that provides state management, subscriptions, and state metadata\n */\nexport class BaseController<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n messenger extends RestrictedMessenger<\n ControllerName,\n ActionConstraint | ControllerActions<ControllerName, ControllerState>,\n EventConstraint | ControllerEvents<ControllerName, ControllerState>,\n string,\n string\n >,\n> {\n #internalState: ControllerState;\n\n protected messagingSystem: messenger;\n\n /**\n * The name of the controller.\n *\n * This is used by the ComposableController to construct a composed application state.\n */\n public readonly name: ControllerName;\n\n public readonly metadata: StateMetadata<ControllerState>;\n\n /**\n * Creates a BaseController instance.\n *\n * @param options - Controller options.\n * @param options.messenger - Controller messaging system.\n * @param options.metadata - ControllerState metadata, describing how to \"anonymize\" the state, and which\n * parts should be persisted.\n * @param options.name - The name of the controller, used as a namespace for events and actions.\n * @param options.state - Initial controller state.\n */\n constructor({\n messenger,\n metadata,\n name,\n state,\n }: {\n messenger: messenger;\n metadata: StateMetadata<ControllerState>;\n name: ControllerName;\n state: ControllerState;\n }) {\n this.messagingSystem = messenger;\n this.name = name;\n // Here we use `freeze` from Immer to enforce that the state is deeply\n // immutable. Note that this is a runtime check, not a compile-time check.\n // That is, unlike `Object.freeze`, this does not narrow the type\n // recursively to `Readonly`. The equivalent in Immer is `Immutable`, but\n // `Immutable` does not handle recursive types such as our `Json` type.\n this.#internalState = freeze(state, true);\n this.metadata = metadata;\n\n this.messagingSystem.registerActionHandler(\n `${name}:getState`,\n () => this.state,\n );\n\n this.messagingSystem.registerInitialEventPayload({\n eventType: `${name}:stateChange`,\n getPayload: () => [this.state, []],\n });\n }\n\n /**\n * Retrieves current controller state.\n *\n * @returns The current state.\n */\n get state() {\n return this.#internalState;\n }\n\n set state(_) {\n throw new Error(\n `Controller state cannot be directly mutated; use 'update' method instead.`,\n );\n }\n\n /**\n * Updates controller state. Accepts a callback that is passed a draft copy\n * of the controller state. If a value is returned, it is set as the new\n * state. Otherwise, any changes made within that callback to the draft are\n * applied to the controller state.\n *\n * @param callback - Callback for updating state, passed a draft state\n * object. Return a new state object or mutate the draft to update state.\n * @returns An object that has the next state, patches applied in the update and inverse patches to\n * rollback the update.\n */\n protected update(\n callback: (state: Draft<ControllerState>) => void | ControllerState,\n ): {\n nextState: ControllerState;\n patches: Patch[];\n inversePatches: Patch[];\n } {\n // We run into ts2589, \"infinite type depth\", if we don't cast\n // produceWithPatches here.\n const [nextState, patches, inversePatches] = (\n produceWithPatches as unknown as (\n state: ControllerState,\n cb: typeof callback,\n ) => [ControllerState, Patch[], Patch[]]\n )(this.#internalState, callback);\n\n this.#internalState = nextState;\n this.messagingSystem.publish(\n `${this.name}:stateChange`,\n nextState,\n patches,\n );\n\n return { nextState, patches, inversePatches };\n }\n\n /**\n * Applies immer patches to the current state. The patches come from the\n * update function itself and can either be normal or inverse patches.\n *\n * @param patches - An array of immer patches that are to be applied to make\n * or undo changes.\n */\n protected applyPatches(patches: Patch[]) {\n const nextState = applyPatches(this.#internalState, patches);\n this.#internalState = nextState;\n this.messagingSystem.publish(\n `${this.name}:stateChange`,\n nextState,\n patches,\n );\n }\n\n /**\n * Prepares the controller for garbage collection. This should be extended\n * by any subclasses to clean up any additional connections or events.\n *\n * The only cleanup performed here is to remove listeners. While technically\n * this is not required to ensure this instance is garbage collected, it at\n * least ensures this instance won't be responsible for preventing the\n * listeners from being garbage collected.\n */\n protected destroy() {\n this.messagingSystem.clearEventSubscriptions(`${this.name}:stateChange`);\n }\n}\n\n/**\n * Returns an anonymized representation of the controller state.\n *\n * By \"anonymized\" we mean that it should not contain any information that could be personally\n * identifiable.\n *\n * @param state - The controller state.\n * @param metadata - The controller state metadata, which describes how to derive the\n * anonymized state.\n * @returns The anonymized controller state.\n */\nexport function getAnonymizedState<ControllerState extends StateConstraint>(\n state: ControllerState,\n metadata: StateMetadata<ControllerState>,\n): Record<keyof ControllerState, Json> {\n return deriveStateFromMetadata(state, metadata, 'anonymous');\n}\n\n/**\n * Returns the subset of state that should be persisted.\n *\n * @param state - The controller state.\n * @param metadata - The controller state metadata, which describes which pieces of state should be persisted.\n * @returns The subset of controller state that should be persisted.\n */\nexport function getPersistentState<ControllerState extends StateConstraint>(\n state: ControllerState,\n metadata: StateMetadata<ControllerState>,\n): Record<keyof ControllerState, Json> {\n return deriveStateFromMetadata(state, metadata, 'persist');\n}\n\n/**\n * Use the metadata to derive state according to the given metadata property.\n *\n * @param state - The full controller state.\n * @param metadata - The controller metadata.\n * @param metadataProperty - The metadata property to use to derive state.\n * @returns The metadata-derived controller state.\n */\nfunction deriveStateFromMetadata<ControllerState extends StateConstraint>(\n state: ControllerState,\n metadata: StateMetadata<ControllerState>,\n metadataProperty: 'anonymous' | 'persist',\n): Record<keyof ControllerState, Json> {\n return (Object.keys(state) as (keyof ControllerState)[]).reduce<\n Record<keyof ControllerState, Json>\n >((derivedState, key) => {\n try {\n const stateMetadata = metadata[key];\n if (!stateMetadata) {\n throw new Error(`No metadata found for '${String(key)}'`);\n }\n const propertyMetadata = stateMetadata[metadataProperty];\n const stateProperty = state[key];\n if (typeof propertyMetadata === 'function') {\n derivedState[key] = propertyMetadata(stateProperty);\n } else if (propertyMetadata) {\n derivedState[key] = stateProperty;\n }\n return derivedState;\n } catch (error) {\n // Throw error after timeout so that it is captured as a console error\n // (and by Sentry) without interrupting state-related operations\n setTimeout(() => {\n throw error;\n });\n return derivedState;\n }\n }, {} as never);\n}\n"]}
1
+ {"version":3,"file":"BaseControllerV2.mjs","sourceRoot":"","sources":["../src/BaseControllerV2.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Json, PublicInterface } from '@metamask/utils';\nimport { enablePatches, produceWithPatches, applyPatches, freeze } from 'immer';\nimport type { Draft, Patch } from 'immer';\n\nimport type {\n BaseControllerV1Instance,\n StateConstraint as StateConstraintV1,\n} from './BaseControllerV1';\nimport type { ActionConstraint, EventConstraint } from './Messenger';\nimport type {\n RestrictedControllerMessenger,\n RestrictedControllerMessengerConstraint,\n} from './RestrictedMessenger';\n\nenablePatches();\n\n/**\n * Determines if the given controller is an instance of `BaseController`\n *\n * @param controller - Controller instance to check\n * @returns True if the controller is an instance of `BaseController`\n */\nexport function isBaseController(\n controller: ControllerInstance,\n): controller is BaseControllerInstance {\n return (\n 'name' in controller &&\n typeof controller.name === 'string' &&\n 'state' in controller &&\n typeof controller.state === 'object' &&\n 'metadata' in controller &&\n typeof controller.metadata === 'object'\n );\n}\n\n/**\n * A type that constrains the state of all controllers.\n *\n * In other words, the narrowest supertype encompassing all controller state.\n */\nexport type StateConstraint = Record<string, Json>;\n\n/**\n * A universal supertype for the controller state object, encompassing both `BaseControllerV1` and `BaseControllerV2` state.\n */\n// TODO: Remove once BaseControllerV2 migrations are completed for all controllers.\nexport type LegacyControllerStateConstraint =\n | StateConstraintV1\n | StateConstraint;\n\n/**\n * A state change listener.\n *\n * This function will get called for each state change, and is given a copy of\n * the new state along with a set of patches describing the changes since the\n * last update.\n *\n * @param state - The new controller state.\n * @param patches - A list of patches describing any changes (see here for more\n * information: https://immerjs.github.io/immer/docs/patches)\n */\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type Listener<T> = (state: T, patches: Patch[]) => void;\n\n/**\n * An function to derive state.\n *\n * This function will accept one piece of the controller state (one property),\n * and will return some derivation of that state.\n *\n * @param value - A piece of controller state.\n * @returns Something derived from controller state.\n */\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type StateDeriver<T extends Json> = (value: T) => Json;\n\n/**\n * State metadata.\n *\n * This metadata describes which parts of state should be persisted, and how to\n * get an anonymized representation of the state.\n */\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type StateMetadata<T extends StateConstraint> = {\n [P in keyof T]-?: StatePropertyMetadata<T[P]>;\n};\n\n/**\n * Metadata for a single state property\n *\n * @property persist - Indicates whether this property should be persisted\n * (`true` for persistent, `false` for transient), or is set to a function\n * that derives the persistent state from the state.\n * @property anonymous - Indicates whether this property is already anonymous,\n * (`true` for anonymous, `false` if it has potential to be personally\n * identifiable), or is set to a function that returns an anonymized\n * representation of this state.\n */\n// TODO: Either fix this lint violation or explain why it's necessary to ignore.\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type StatePropertyMetadata<T extends Json> = {\n persist: boolean | StateDeriver<T>;\n anonymous: boolean | StateDeriver<T>;\n};\n\n/**\n * A universal supertype of `StateDeriver` types.\n * This type can be assigned to any `StateDeriver` type.\n */\nexport type StateDeriverConstraint = (value: never) => Json;\n\n/**\n * A universal supertype of `StatePropertyMetadata` types.\n * This type can be assigned to any `StatePropertyMetadata` type.\n */\nexport type StatePropertyMetadataConstraint = {\n [P in 'anonymous' | 'persist']: boolean | StateDeriverConstraint;\n};\n\n/**\n * A universal supertype of `StateMetadata` types.\n * This type can be assigned to any `StateMetadata` type.\n */\nexport type StateMetadataConstraint = Record<\n string,\n StatePropertyMetadataConstraint\n>;\n\n/**\n * The widest subtype of all controller instances that inherit from `BaseController` (formerly `BaseControllerV2`).\n * Any `BaseController` subclass instance can be assigned to this type.\n */\nexport type BaseControllerInstance = Omit<\n PublicInterface<\n BaseController<\n string,\n StateConstraint,\n RestrictedControllerMessengerConstraint\n >\n >,\n 'metadata'\n> & {\n metadata: StateMetadataConstraint;\n};\n\n/**\n * A widest subtype of all controller instances that inherit from `BaseController` (formerly `BaseControllerV2`) or `BaseControllerV1`.\n * Any `BaseController` or `BaseControllerV1` subclass instance can be assigned to this type.\n */\n// TODO: Remove once BaseControllerV2 migrations are completed for all controllers.\nexport type ControllerInstance =\n | BaseControllerV1Instance\n | BaseControllerInstance;\n\nexport type ControllerGetStateAction<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n> = {\n type: `${ControllerName}:getState`;\n handler: () => ControllerState;\n};\n\nexport type ControllerStateChangeEvent<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n> = {\n type: `${ControllerName}:stateChange`;\n payload: [ControllerState, Patch[]];\n};\n\nexport type ControllerActions<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n> = ControllerGetStateAction<ControllerName, ControllerState>;\n\nexport type ControllerEvents<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n> = ControllerStateChangeEvent<ControllerName, ControllerState>;\n\n/**\n * Controller class that provides state management, subscriptions, and state metadata\n */\nexport class BaseController<\n ControllerName extends string,\n ControllerState extends StateConstraint,\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n messenger extends RestrictedControllerMessenger<\n ControllerName,\n ActionConstraint | ControllerActions<ControllerName, ControllerState>,\n EventConstraint | ControllerEvents<ControllerName, ControllerState>,\n string,\n string\n >,\n> {\n #internalState: ControllerState;\n\n protected messagingSystem: messenger;\n\n /**\n * The name of the controller.\n *\n * This is used by the ComposableController to construct a composed application state.\n */\n public readonly name: ControllerName;\n\n public readonly metadata: StateMetadata<ControllerState>;\n\n /**\n * Creates a BaseController instance.\n *\n * @param options - Controller options.\n * @param options.messenger - Controller messaging system.\n * @param options.metadata - ControllerState metadata, describing how to \"anonymize\" the state, and which\n * parts should be persisted.\n * @param options.name - The name of the controller, used as a namespace for events and actions.\n * @param options.state - Initial controller state.\n */\n constructor({\n messenger,\n metadata,\n name,\n state,\n }: {\n messenger: messenger;\n metadata: StateMetadata<ControllerState>;\n name: ControllerName;\n state: ControllerState;\n }) {\n this.messagingSystem = messenger;\n this.name = name;\n // Here we use `freeze` from Immer to enforce that the state is deeply\n // immutable. Note that this is a runtime check, not a compile-time check.\n // That is, unlike `Object.freeze`, this does not narrow the type\n // recursively to `Readonly`. The equivalent in Immer is `Immutable`, but\n // `Immutable` does not handle recursive types such as our `Json` type.\n this.#internalState = freeze(state, true);\n this.metadata = metadata;\n\n this.messagingSystem.registerActionHandler(\n `${name}:getState`,\n () => this.state,\n );\n\n this.messagingSystem.registerInitialEventPayload({\n eventType: `${name}:stateChange`,\n getPayload: () => [this.state, []],\n });\n }\n\n /**\n * Retrieves current controller state.\n *\n * @returns The current state.\n */\n get state() {\n return this.#internalState;\n }\n\n set state(_) {\n throw new Error(\n `Controller state cannot be directly mutated; use 'update' method instead.`,\n );\n }\n\n /**\n * Updates controller state. Accepts a callback that is passed a draft copy\n * of the controller state. If a value is returned, it is set as the new\n * state. Otherwise, any changes made within that callback to the draft are\n * applied to the controller state.\n *\n * @param callback - Callback for updating state, passed a draft state\n * object. Return a new state object or mutate the draft to update state.\n * @returns An object that has the next state, patches applied in the update and inverse patches to\n * rollback the update.\n */\n protected update(\n callback: (state: Draft<ControllerState>) => void | ControllerState,\n ): {\n nextState: ControllerState;\n patches: Patch[];\n inversePatches: Patch[];\n } {\n // We run into ts2589, \"infinite type depth\", if we don't cast\n // produceWithPatches here.\n const [nextState, patches, inversePatches] = (\n produceWithPatches as unknown as (\n state: ControllerState,\n cb: typeof callback,\n ) => [ControllerState, Patch[], Patch[]]\n )(this.#internalState, callback);\n\n this.#internalState = nextState;\n this.messagingSystem.publish(\n `${this.name}:stateChange`,\n nextState,\n patches,\n );\n\n return { nextState, patches, inversePatches };\n }\n\n /**\n * Applies immer patches to the current state. The patches come from the\n * update function itself and can either be normal or inverse patches.\n *\n * @param patches - An array of immer patches that are to be applied to make\n * or undo changes.\n */\n protected applyPatches(patches: Patch[]) {\n const nextState = applyPatches(this.#internalState, patches);\n this.#internalState = nextState;\n this.messagingSystem.publish(\n `${this.name}:stateChange`,\n nextState,\n patches,\n );\n }\n\n /**\n * Prepares the controller for garbage collection. This should be extended\n * by any subclasses to clean up any additional connections or events.\n *\n * The only cleanup performed here is to remove listeners. While technically\n * this is not required to ensure this instance is garbage collected, it at\n * least ensures this instance won't be responsible for preventing the\n * listeners from being garbage collected.\n */\n protected destroy() {\n this.messagingSystem.clearEventSubscriptions(`${this.name}:stateChange`);\n }\n}\n\n/**\n * Returns an anonymized representation of the controller state.\n *\n * By \"anonymized\" we mean that it should not contain any information that could be personally\n * identifiable.\n *\n * @param state - The controller state.\n * @param metadata - The controller state metadata, which describes how to derive the\n * anonymized state.\n * @returns The anonymized controller state.\n */\nexport function getAnonymizedState<ControllerState extends StateConstraint>(\n state: ControllerState,\n metadata: StateMetadata<ControllerState>,\n): Record<keyof ControllerState, Json> {\n return deriveStateFromMetadata(state, metadata, 'anonymous');\n}\n\n/**\n * Returns the subset of state that should be persisted.\n *\n * @param state - The controller state.\n * @param metadata - The controller state metadata, which describes which pieces of state should be persisted.\n * @returns The subset of controller state that should be persisted.\n */\nexport function getPersistentState<ControllerState extends StateConstraint>(\n state: ControllerState,\n metadata: StateMetadata<ControllerState>,\n): Record<keyof ControllerState, Json> {\n return deriveStateFromMetadata(state, metadata, 'persist');\n}\n\n/**\n * Use the metadata to derive state according to the given metadata property.\n *\n * @param state - The full controller state.\n * @param metadata - The controller metadata.\n * @param metadataProperty - The metadata property to use to derive state.\n * @returns The metadata-derived controller state.\n */\nfunction deriveStateFromMetadata<ControllerState extends StateConstraint>(\n state: ControllerState,\n metadata: StateMetadata<ControllerState>,\n metadataProperty: 'anonymous' | 'persist',\n): Record<keyof ControllerState, Json> {\n return (Object.keys(state) as (keyof ControllerState)[]).reduce<\n Record<keyof ControllerState, Json>\n >((derivedState, key) => {\n try {\n const stateMetadata = metadata[key];\n if (!stateMetadata) {\n throw new Error(`No metadata found for '${String(key)}'`);\n }\n const propertyMetadata = stateMetadata[metadataProperty];\n const stateProperty = state[key];\n if (typeof propertyMetadata === 'function') {\n derivedState[key] = propertyMetadata(stateProperty);\n } else if (propertyMetadata) {\n derivedState[key] = stateProperty;\n }\n return derivedState;\n } catch (error) {\n // Throw error after timeout so that it is captured as a console error\n // (and by Sentry) without interrupting state-related operations\n setTimeout(() => {\n throw error;\n });\n return derivedState;\n }\n }, {} as never);\n}\n"]}
@@ -207,7 +207,7 @@ class Messenger {
207
207
  * namespace. Ownership allows registering actions and publishing events, as well as
208
208
  * unregistering actions and clearing event subscriptions.
209
209
  *
210
- * @param options - Messenger options.
210
+ * @param options - Controller messenger options.
211
211
  * @param options.name - The name of the thing this messenger will be handed to (e.g. the
212
212
  * controller name). This grants "ownership" of actions and events under this namespace to the
213
213
  * restricted messenger returned.
@@ -1 +1 @@
1
- {"version":3,"file":"Messenger.cjs","sourceRoot":"","sources":["../src/Messenger.ts"],"names":[],"mappings":"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","sourcesContent":["import { RestrictedMessenger } from './RestrictedMessenger';\n\nexport type ActionHandler<\n Action extends ActionConstraint,\n ActionType = Action['type'],\n> = (\n ...args: ExtractActionParameters<Action, ActionType>\n) => ExtractActionResponse<Action, ActionType>;\n\nexport type ExtractActionParameters<\n Action extends ActionConstraint,\n ActionType = Action['type'],\n> = Action extends {\n type: ActionType;\n handler: (...args: infer HandlerArgs) => unknown;\n}\n ? HandlerArgs\n : never;\n\nexport type ExtractActionResponse<\n Action extends ActionConstraint,\n ActionType = Action['type'],\n> = Action extends {\n type: ActionType;\n handler: (...args: infer _) => infer HandlerReturnValue;\n}\n ? HandlerReturnValue\n : never;\n\nexport type ExtractEventHandler<\n Event extends EventConstraint,\n EventType = Event['type'],\n> = Event extends {\n type: EventType;\n payload: infer Payload;\n}\n ? Payload extends unknown[]\n ? (...payload: Payload) => void\n : never\n : never;\n\nexport type ExtractEventPayload<\n Event extends EventConstraint,\n EventType = Event['type'],\n> = Event extends {\n type: EventType;\n payload: infer Payload;\n}\n ? Payload extends unknown[]\n ? Payload\n : never\n : never;\n\nexport type GenericEventHandler = (...args: unknown[]) => void;\n\nexport type SelectorFunction<\n Event extends EventConstraint,\n EventType extends Event['type'],\n ReturnValue,\n> = (...args: ExtractEventPayload<Event, EventType>) => ReturnValue;\nexport type SelectorEventHandler<SelectorReturnValue> = (\n newValue: SelectorReturnValue,\n previousValue: SelectorReturnValue | undefined,\n) => void;\n\nexport type ActionConstraint = {\n type: string;\n handler: ((...args: never) => unknown) | ((...args: never[]) => unknown);\n};\nexport type EventConstraint = {\n type: string;\n payload: unknown[];\n};\n\ntype EventSubscriptionMap<\n Event extends EventConstraint,\n ReturnValue = unknown,\n> = Map<\n GenericEventHandler | SelectorEventHandler<ReturnValue>,\n SelectorFunction<Event, Event['type'], ReturnValue> | undefined\n>;\n\n/**\n * A namespaced string\n *\n * This type verifies that the string Name is prefixed by the string Name followed by a colon.\n *\n * @template Namespace - The namespace we're checking for.\n * @template Name - The full string, including the namespace.\n */\nexport type NamespacedBy<\n Namespace extends string,\n Name extends string,\n> = Name extends `${Namespace}:${string}` ? Name : never;\n\nexport type NotNamespacedBy<\n Namespace extends string,\n Name extends string,\n> = Name extends `${Namespace}:${string}` ? never : Name;\n\nexport type NamespacedName<Namespace extends string = string> =\n `${Namespace}:${string}`;\n\ntype NarrowToNamespace<Name, Namespace extends string> = Name extends {\n type: `${Namespace}:${string}`;\n}\n ? Name\n : never;\n\ntype NarrowToAllowed<Name, Allowed extends string> = Name extends {\n type: Allowed;\n}\n ? Name\n : never;\n\n/**\n * A message broker for \"actions\" and \"events\".\n *\n * The messenger allows registering functions as 'actions' that can be called elsewhere,\n * and it allows publishing and subscribing to events. Both actions and events are identified by\n * unique strings.\n *\n * @template Action - A type union of all Action types.\n * @template Event - A type union of all Event types.\n */\nexport class Messenger<\n Action extends ActionConstraint,\n Event extends EventConstraint,\n> {\n readonly #actions = new Map<Action['type'], unknown>();\n\n readonly #events = new Map<Event['type'], EventSubscriptionMap<Event>>();\n\n /**\n * A map of functions for getting the initial event payload.\n *\n * Used only for events that represent state changes.\n */\n readonly #initialEventPayloadGetters = new Map<\n Event['type'],\n () => ExtractEventPayload<Event, Event['type']>\n >();\n\n /**\n * A cache of selector return values for their respective handlers.\n */\n readonly #eventPayloadCache = new Map<\n GenericEventHandler,\n unknown | undefined\n >();\n\n /**\n * Register an action handler.\n *\n * This will make the registered function available to call via the `call` method.\n *\n * @param actionType - The action type. This is a unqiue identifier for this action.\n * @param handler - The action handler. This function gets called when the `call` method is\n * invoked with the given action type.\n * @throws Will throw when a handler has been registered for this action type already.\n * @template ActionType - A type union of Action type strings.\n */\n registerActionHandler<ActionType extends Action['type']>(\n actionType: ActionType,\n handler: ActionHandler<Action, ActionType>,\n ) {\n if (this.#actions.has(actionType)) {\n throw new Error(\n `A handler for ${actionType} has already been registered`,\n );\n }\n this.#actions.set(actionType, handler);\n }\n\n /**\n * Unregister an action handler.\n *\n * This will prevent this action from being called.\n *\n * @param actionType - The action type. This is a unqiue identifier for this action.\n * @template ActionType - A type union of Action type strings.\n */\n unregisterActionHandler<ActionType extends Action['type']>(\n actionType: ActionType,\n ) {\n this.#actions.delete(actionType);\n }\n\n /**\n * Unregister all action handlers.\n *\n * This prevents all actions from being called.\n */\n clearActions() {\n this.#actions.clear();\n }\n\n /**\n * Call an action.\n *\n * This function will call the action handler corresponding to the given action type, passing\n * along any parameters given.\n *\n * @param actionType - The action type. This is a unqiue identifier for this action.\n * @param params - The action parameters. These must match the type of the parameters of the\n * registered action handler.\n * @throws Will throw when no handler has been registered for the given type.\n * @template ActionType - A type union of Action type strings.\n * @returns The action return value.\n */\n call<ActionType extends Action['type']>(\n actionType: ActionType,\n ...params: ExtractActionParameters<Action, ActionType>\n ): ExtractActionResponse<Action, ActionType> {\n const handler = this.#actions.get(actionType) as ActionHandler<\n Action,\n ActionType\n >;\n if (!handler) {\n throw new Error(`A handler for ${actionType} has not been registered`);\n }\n return handler(...params);\n }\n\n /**\n * Register a function for getting the initial payload for an event.\n *\n * This is used for events that represent a state change, where the payload is the state.\n * Registering a function for getting the payload allows event selectors to have a point of\n * comparison the first time state changes.\n *\n * @param args - The arguments to this function\n * @param args.eventType - The event type to register a payload for.\n * @param args.getPayload - A function for retrieving the event payload.\n */\n registerInitialEventPayload<EventType extends Event['type']>({\n eventType,\n getPayload,\n }: {\n eventType: EventType;\n getPayload: () => ExtractEventPayload<Event, EventType>;\n }) {\n this.#initialEventPayloadGetters.set(eventType, getPayload);\n }\n\n /**\n * Publish an event.\n *\n * Publishes the given payload to all subscribers of the given event type.\n *\n * Note that this method should never throw directly. Any errors from\n * subscribers are captured and re-thrown in a timeout handler.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @param payload - The event payload. The type of the parameters for each event handler must\n * match the type of this payload.\n * @template EventType - A type union of Event type strings.\n */\n publish<EventType extends Event['type']>(\n eventType: EventType,\n ...payload: ExtractEventPayload<Event, EventType>\n ) {\n const subscribers = this.#events.get(eventType);\n\n if (subscribers) {\n for (const [handler, selector] of subscribers.entries()) {\n try {\n if (selector) {\n const previousValue = this.#eventPayloadCache.get(handler);\n const newValue = selector(...payload);\n\n if (newValue !== previousValue) {\n this.#eventPayloadCache.set(handler, newValue);\n handler(newValue, previousValue);\n }\n } else {\n (handler as GenericEventHandler)(...payload);\n }\n } catch (error) {\n // Throw error after timeout so that it is capured as a console error\n // (and by Sentry) without interrupting the event publishing.\n setTimeout(() => {\n throw error;\n });\n }\n }\n }\n }\n\n /**\n * Subscribe to an event.\n *\n * Registers the given function as an event handler for the given event type.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @param handler - The event handler. The type of the parameters for this event handler must\n * match the type of the payload for this event type.\n * @template EventType - A type union of Event type strings.\n */\n subscribe<EventType extends Event['type']>(\n eventType: EventType,\n handler: ExtractEventHandler<Event, EventType>,\n ): void;\n\n /**\n * Subscribe to an event, with a selector.\n *\n * Registers the given handler function as an event handler for the given\n * event type. When an event is published, its payload is first passed to the\n * selector. The event handler is only called if the selector's return value\n * differs from its last known return value.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @param handler - The event handler. The type of the parameters for this event\n * handler must match the return type of the selector.\n * @param selector - The selector function used to select relevant data from\n * the event payload. The type of the parameters for this selector must match\n * the type of the payload for this event type.\n * @template EventType - A type union of Event type strings.\n * @template SelectorReturnValue - The selector return value.\n */\n subscribe<EventType extends Event['type'], SelectorReturnValue>(\n eventType: EventType,\n handler: SelectorEventHandler<SelectorReturnValue>,\n selector: SelectorFunction<Event, EventType, SelectorReturnValue>,\n ): void;\n\n subscribe<EventType extends Event['type'], SelectorReturnValue>(\n eventType: EventType,\n handler: ExtractEventHandler<Event, EventType>,\n selector?: SelectorFunction<Event, EventType, SelectorReturnValue>,\n ): void {\n let subscribers = this.#events.get(eventType);\n if (!subscribers) {\n subscribers = new Map();\n this.#events.set(eventType, subscribers);\n }\n\n subscribers.set(handler, selector);\n\n if (selector) {\n const getPayload = this.#initialEventPayloadGetters.get(eventType);\n if (getPayload) {\n const initialValue = selector(...getPayload());\n this.#eventPayloadCache.set(handler, initialValue);\n }\n }\n }\n\n /**\n * Unsubscribe from an event.\n *\n * Unregisters the given function as an event handler for the given event.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @param handler - The event handler to unregister.\n * @throws Will throw when the given event handler is not registered for this event.\n * @template EventType - A type union of Event type strings.\n */\n unsubscribe<EventType extends Event['type']>(\n eventType: EventType,\n handler: ExtractEventHandler<Event, EventType>,\n ) {\n const subscribers = this.#events.get(eventType);\n\n if (!subscribers || !subscribers.has(handler)) {\n throw new Error(`Subscription not found for event: ${eventType}`);\n }\n\n const selector = subscribers.get(handler);\n if (selector) {\n this.#eventPayloadCache.delete(handler);\n }\n\n subscribers.delete(handler);\n }\n\n /**\n * Clear subscriptions for a specific event.\n *\n * This will remove all subscribed handlers for this event.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @template EventType - A type union of Event type strings.\n */\n clearEventSubscriptions<EventType extends Event['type']>(\n eventType: EventType,\n ) {\n this.#events.delete(eventType);\n }\n\n /**\n * Clear all subscriptions.\n *\n * This will remove all subscribed handlers for all events.\n */\n clearSubscriptions() {\n this.#events.clear();\n }\n\n /**\n * Get a restricted messenger\n *\n * Returns a wrapper around the messenger instance that restricts access to actions and events.\n * The provided allowlists grant the ability to call the listed actions and subscribe to the\n * listed events. The \"name\" provided grants ownership of any actions and events under that\n * namespace. Ownership allows registering actions and publishing events, as well as\n * unregistering actions and clearing event subscriptions.\n *\n * @param options - Messenger options.\n * @param options.name - The name of the thing this messenger will be handed to (e.g. the\n * controller name). This grants \"ownership\" of actions and events under this namespace to the\n * restricted messenger returned.\n * @param options.allowedActions - The list of actions that this restricted messenger should be\n * allowed to call.\n * @param options.allowedEvents - The list of events that this restricted messenger should be\n * allowed to subscribe to.\n * @template Namespace - The namespace for this messenger. Typically this is the name of the\n * module that this messenger has been created for. The authority to publish events and register\n * actions under this namespace is granted to this restricted messenger instance.\n * @template AllowedAction - A type union of the 'type' string for any allowed actions.\n * This must not include internal actions that are in the messenger's namespace.\n * @template AllowedEvent - A type union of the 'type' string for any allowed events.\n * This must not include internal events that are in the messenger's namespace.\n * @returns The restricted messenger.\n */\n getRestricted<\n Namespace extends string,\n AllowedAction extends NotNamespacedBy<Namespace, Action['type']> = never,\n AllowedEvent extends NotNamespacedBy<Namespace, Event['type']> = never,\n >({\n name,\n allowedActions,\n allowedEvents,\n }: {\n name: Namespace;\n allowedActions: NotNamespacedBy<\n Namespace,\n Extract<Action['type'], AllowedAction>\n >[];\n allowedEvents: NotNamespacedBy<\n Namespace,\n Extract<Event['type'], AllowedEvent>\n >[];\n }): RestrictedMessenger<\n Namespace,\n | NarrowToNamespace<Action, Namespace>\n | NarrowToAllowed<Action, AllowedAction>,\n NarrowToNamespace<Event, Namespace> | NarrowToAllowed<Event, AllowedEvent>,\n AllowedAction,\n AllowedEvent\n > {\n return new RestrictedMessenger({\n messenger: this,\n name,\n allowedActions,\n allowedEvents,\n });\n }\n}\n\nexport { Messenger as ControllerMessenger };\n"]}
1
+ {"version":3,"file":"Messenger.cjs","sourceRoot":"","sources":["../src/Messenger.ts"],"names":[],"mappings":";;;;;;;;;AAAA,mEAA4D;AAmH5D;;;;;;;;;GASG;AACH,MAAa,SAAS;IAAtB;QAIW,6BAAW,IAAI,GAAG,EAA2B,EAAC;QAE9C,4BAAU,IAAI,GAAG,EAA8C,EAAC;QAEzE;;;;WAIG;QACM,gDAA8B,IAAI,GAAG,EAG3C,EAAC;QAEJ;;WAEG;QACM,uCAAqB,IAAI,GAAG,EAGlC,EAAC;IAsTN,CAAC;IApTC;;;;;;;;;;OAUG;IACH,qBAAqB,CACnB,UAAsB,EACtB,OAA0C;QAE1C,IAAI,uBAAA,IAAI,0BAAS,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE;YACjC,MAAM,IAAI,KAAK,CACb,iBAAiB,UAAU,8BAA8B,CAC1D,CAAC;SACH;QACD,uBAAA,IAAI,0BAAS,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IAED;;;;;;;OAOG;IACH,uBAAuB,CACrB,UAAsB;QAEtB,uBAAA,IAAI,0BAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACH,YAAY;QACV,uBAAA,IAAI,0BAAS,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,IAAI,CACF,UAAsB,EACtB,GAAG,MAAmD;QAEtD,MAAM,OAAO,GAAG,uBAAA,IAAI,0BAAS,CAAC,GAAG,CAAC,UAAU,CAG3C,CAAC;QACF,IAAI,CAAC,OAAO,EAAE;YACZ,MAAM,IAAI,KAAK,CAAC,iBAAiB,UAAU,0BAA0B,CAAC,CAAC;SACxE;QACD,OAAO,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;IAC5B,CAAC;IAED;;;;;;;;;;OAUG;IACH,2BAA2B,CAAkC,EAC3D,SAAS,EACT,UAAU,GAIX;QACC,uBAAA,IAAI,6CAA4B,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAC9D,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,OAAO,CACL,SAAoB,EACpB,GAAG,OAA8C;QAEjD,MAAM,WAAW,GAAG,uBAAA,IAAI,yBAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAEhD,IAAI,WAAW,EAAE;YACf,KAAK,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE;gBACvD,IAAI;oBACF,IAAI,QAAQ,EAAE;wBACZ,MAAM,aAAa,GAAG,uBAAA,IAAI,oCAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;wBAC3D,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,OAAO,CAAC,CAAC;wBAEtC,IAAI,QAAQ,KAAK,aAAa,EAAE;4BAC9B,uBAAA,IAAI,oCAAmB,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;4BAC/C,OAAO,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;yBAClC;qBACF;yBAAM;wBACJ,OAA+B,CAAC,GAAG,OAAO,CAAC,CAAC;qBAC9C;iBACF;gBAAC,OAAO,KAAK,EAAE;oBACd,qEAAqE;oBACrE,6DAA6D;oBAC7D,UAAU,CAAC,GAAG,EAAE;wBACd,MAAM,KAAK,CAAC;oBACd,CAAC,CAAC,CAAC;iBACJ;aACF;SACF;IACH,CAAC;IAwCD,SAAS,CACP,SAAoB,EACpB,OAA8C,EAC9C,QAAkE;QAElE,IAAI,WAAW,GAAG,uBAAA,IAAI,yBAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,CAAC,WAAW,EAAE;YAChB,WAAW,GAAG,IAAI,GAAG,EAAE,CAAC;YACxB,uBAAA,IAAI,yBAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;SAC1C;QAED,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAEnC,IAAI,QAAQ,EAAE;YACZ,MAAM,UAAU,GAAG,uBAAA,IAAI,6CAA4B,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACnE,IAAI,UAAU,EAAE;gBACd,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,UAAU,EAAE,CAAC,CAAC;gBAC/C,uBAAA,IAAI,oCAAmB,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;aACpD;SACF;IACH,CAAC;IAED;;;;;;;;;OASG;IACH,WAAW,CACT,SAAoB,EACpB,OAA8C;QAE9C,MAAM,WAAW,GAAG,uBAAA,IAAI,yBAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAEhD,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;YAC7C,MAAM,IAAI,KAAK,CAAC,qCAAqC,SAAS,EAAE,CAAC,CAAC;SACnE;QAED,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC1C,IAAI,QAAQ,EAAE;YACZ,uBAAA,IAAI,oCAAmB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;SACzC;QAED,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED;;;;;;;OAOG;IACH,uBAAuB,CACrB,SAAoB;QAEpB,uBAAA,IAAI,yBAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACH,kBAAkB;QAChB,uBAAA,IAAI,yBAAQ,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,aAAa,CAIX,EACA,IAAI,EACJ,cAAc,EACd,aAAa,GAWd;QAQC,OAAO,IAAI,yCAAmB,CAAC;YAC7B,SAAS,EAAE,IAAI;YACf,IAAI;YACJ,cAAc;YACd,aAAa;SACd,CAAC,CAAC;IACL,CAAC;CACF;AA9UD,8BA8UC;AAEqB,wCAAmB","sourcesContent":["import { RestrictedMessenger } from './RestrictedMessenger';\n\nexport type ActionHandler<\n Action extends ActionConstraint,\n ActionType = Action['type'],\n> = (\n ...args: ExtractActionParameters<Action, ActionType>\n) => ExtractActionResponse<Action, ActionType>;\n\nexport type ExtractActionParameters<\n Action extends ActionConstraint,\n ActionType = Action['type'],\n> = Action extends {\n type: ActionType;\n handler: (...args: infer HandlerArgs) => unknown;\n}\n ? HandlerArgs\n : never;\n\nexport type ExtractActionResponse<\n Action extends ActionConstraint,\n ActionType = Action['type'],\n> = Action extends {\n type: ActionType;\n handler: (...args: infer _) => infer HandlerReturnValue;\n}\n ? HandlerReturnValue\n : never;\n\nexport type ExtractEventHandler<\n Event extends EventConstraint,\n EventType = Event['type'],\n> = Event extends {\n type: EventType;\n payload: infer Payload;\n}\n ? Payload extends unknown[]\n ? (...payload: Payload) => void\n : never\n : never;\n\nexport type ExtractEventPayload<\n Event extends EventConstraint,\n EventType = Event['type'],\n> = Event extends {\n type: EventType;\n payload: infer Payload;\n}\n ? Payload extends unknown[]\n ? Payload\n : never\n : never;\n\nexport type GenericEventHandler = (...args: unknown[]) => void;\n\nexport type SelectorFunction<\n Event extends EventConstraint,\n EventType extends Event['type'],\n ReturnValue,\n> = (...args: ExtractEventPayload<Event, EventType>) => ReturnValue;\nexport type SelectorEventHandler<SelectorReturnValue> = (\n newValue: SelectorReturnValue,\n previousValue: SelectorReturnValue | undefined,\n) => void;\n\nexport type ActionConstraint = {\n type: string;\n handler: ((...args: never) => unknown) | ((...args: never[]) => unknown);\n};\nexport type EventConstraint = {\n type: string;\n payload: unknown[];\n};\n\ntype EventSubscriptionMap<\n Event extends EventConstraint,\n ReturnValue = unknown,\n> = Map<\n GenericEventHandler | SelectorEventHandler<ReturnValue>,\n SelectorFunction<Event, Event['type'], ReturnValue> | undefined\n>;\n\n/**\n * A namespaced string\n *\n * This type verifies that the string Name is prefixed by the string Name followed by a colon.\n *\n * @template Namespace - The namespace we're checking for.\n * @template Name - The full string, including the namespace.\n */\nexport type NamespacedBy<\n Namespace extends string,\n Name extends string,\n> = Name extends `${Namespace}:${string}` ? Name : never;\n\nexport type NotNamespacedBy<\n Namespace extends string,\n Name extends string,\n> = Name extends `${Namespace}:${string}` ? never : Name;\n\nexport type NamespacedName<Namespace extends string = string> =\n `${Namespace}:${string}`;\n\ntype NarrowToNamespace<Name, Namespace extends string> = Name extends {\n type: `${Namespace}:${string}`;\n}\n ? Name\n : never;\n\ntype NarrowToAllowed<Name, Allowed extends string> = Name extends {\n type: Allowed;\n}\n ? Name\n : never;\n\n/**\n * A message broker for \"actions\" and \"events\".\n *\n * The messenger allows registering functions as 'actions' that can be called elsewhere,\n * and it allows publishing and subscribing to events. Both actions and events are identified by\n * unique strings.\n *\n * @template Action - A type union of all Action types.\n * @template Event - A type union of all Event types.\n */\nexport class Messenger<\n Action extends ActionConstraint,\n Event extends EventConstraint,\n> {\n readonly #actions = new Map<Action['type'], unknown>();\n\n readonly #events = new Map<Event['type'], EventSubscriptionMap<Event>>();\n\n /**\n * A map of functions for getting the initial event payload.\n *\n * Used only for events that represent state changes.\n */\n readonly #initialEventPayloadGetters = new Map<\n Event['type'],\n () => ExtractEventPayload<Event, Event['type']>\n >();\n\n /**\n * A cache of selector return values for their respective handlers.\n */\n readonly #eventPayloadCache = new Map<\n GenericEventHandler,\n unknown | undefined\n >();\n\n /**\n * Register an action handler.\n *\n * This will make the registered function available to call via the `call` method.\n *\n * @param actionType - The action type. This is a unqiue identifier for this action.\n * @param handler - The action handler. This function gets called when the `call` method is\n * invoked with the given action type.\n * @throws Will throw when a handler has been registered for this action type already.\n * @template ActionType - A type union of Action type strings.\n */\n registerActionHandler<ActionType extends Action['type']>(\n actionType: ActionType,\n handler: ActionHandler<Action, ActionType>,\n ) {\n if (this.#actions.has(actionType)) {\n throw new Error(\n `A handler for ${actionType} has already been registered`,\n );\n }\n this.#actions.set(actionType, handler);\n }\n\n /**\n * Unregister an action handler.\n *\n * This will prevent this action from being called.\n *\n * @param actionType - The action type. This is a unqiue identifier for this action.\n * @template ActionType - A type union of Action type strings.\n */\n unregisterActionHandler<ActionType extends Action['type']>(\n actionType: ActionType,\n ) {\n this.#actions.delete(actionType);\n }\n\n /**\n * Unregister all action handlers.\n *\n * This prevents all actions from being called.\n */\n clearActions() {\n this.#actions.clear();\n }\n\n /**\n * Call an action.\n *\n * This function will call the action handler corresponding to the given action type, passing\n * along any parameters given.\n *\n * @param actionType - The action type. This is a unqiue identifier for this action.\n * @param params - The action parameters. These must match the type of the parameters of the\n * registered action handler.\n * @throws Will throw when no handler has been registered for the given type.\n * @template ActionType - A type union of Action type strings.\n * @returns The action return value.\n */\n call<ActionType extends Action['type']>(\n actionType: ActionType,\n ...params: ExtractActionParameters<Action, ActionType>\n ): ExtractActionResponse<Action, ActionType> {\n const handler = this.#actions.get(actionType) as ActionHandler<\n Action,\n ActionType\n >;\n if (!handler) {\n throw new Error(`A handler for ${actionType} has not been registered`);\n }\n return handler(...params);\n }\n\n /**\n * Register a function for getting the initial payload for an event.\n *\n * This is used for events that represent a state change, where the payload is the state.\n * Registering a function for getting the payload allows event selectors to have a point of\n * comparison the first time state changes.\n *\n * @param args - The arguments to this function\n * @param args.eventType - The event type to register a payload for.\n * @param args.getPayload - A function for retrieving the event payload.\n */\n registerInitialEventPayload<EventType extends Event['type']>({\n eventType,\n getPayload,\n }: {\n eventType: EventType;\n getPayload: () => ExtractEventPayload<Event, EventType>;\n }) {\n this.#initialEventPayloadGetters.set(eventType, getPayload);\n }\n\n /**\n * Publish an event.\n *\n * Publishes the given payload to all subscribers of the given event type.\n *\n * Note that this method should never throw directly. Any errors from\n * subscribers are captured and re-thrown in a timeout handler.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @param payload - The event payload. The type of the parameters for each event handler must\n * match the type of this payload.\n * @template EventType - A type union of Event type strings.\n */\n publish<EventType extends Event['type']>(\n eventType: EventType,\n ...payload: ExtractEventPayload<Event, EventType>\n ) {\n const subscribers = this.#events.get(eventType);\n\n if (subscribers) {\n for (const [handler, selector] of subscribers.entries()) {\n try {\n if (selector) {\n const previousValue = this.#eventPayloadCache.get(handler);\n const newValue = selector(...payload);\n\n if (newValue !== previousValue) {\n this.#eventPayloadCache.set(handler, newValue);\n handler(newValue, previousValue);\n }\n } else {\n (handler as GenericEventHandler)(...payload);\n }\n } catch (error) {\n // Throw error after timeout so that it is capured as a console error\n // (and by Sentry) without interrupting the event publishing.\n setTimeout(() => {\n throw error;\n });\n }\n }\n }\n }\n\n /**\n * Subscribe to an event.\n *\n * Registers the given function as an event handler for the given event type.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @param handler - The event handler. The type of the parameters for this event handler must\n * match the type of the payload for this event type.\n * @template EventType - A type union of Event type strings.\n */\n subscribe<EventType extends Event['type']>(\n eventType: EventType,\n handler: ExtractEventHandler<Event, EventType>,\n ): void;\n\n /**\n * Subscribe to an event, with a selector.\n *\n * Registers the given handler function as an event handler for the given\n * event type. When an event is published, its payload is first passed to the\n * selector. The event handler is only called if the selector's return value\n * differs from its last known return value.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @param handler - The event handler. The type of the parameters for this event\n * handler must match the return type of the selector.\n * @param selector - The selector function used to select relevant data from\n * the event payload. The type of the parameters for this selector must match\n * the type of the payload for this event type.\n * @template EventType - A type union of Event type strings.\n * @template SelectorReturnValue - The selector return value.\n */\n subscribe<EventType extends Event['type'], SelectorReturnValue>(\n eventType: EventType,\n handler: SelectorEventHandler<SelectorReturnValue>,\n selector: SelectorFunction<Event, EventType, SelectorReturnValue>,\n ): void;\n\n subscribe<EventType extends Event['type'], SelectorReturnValue>(\n eventType: EventType,\n handler: ExtractEventHandler<Event, EventType>,\n selector?: SelectorFunction<Event, EventType, SelectorReturnValue>,\n ): void {\n let subscribers = this.#events.get(eventType);\n if (!subscribers) {\n subscribers = new Map();\n this.#events.set(eventType, subscribers);\n }\n\n subscribers.set(handler, selector);\n\n if (selector) {\n const getPayload = this.#initialEventPayloadGetters.get(eventType);\n if (getPayload) {\n const initialValue = selector(...getPayload());\n this.#eventPayloadCache.set(handler, initialValue);\n }\n }\n }\n\n /**\n * Unsubscribe from an event.\n *\n * Unregisters the given function as an event handler for the given event.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @param handler - The event handler to unregister.\n * @throws Will throw when the given event handler is not registered for this event.\n * @template EventType - A type union of Event type strings.\n */\n unsubscribe<EventType extends Event['type']>(\n eventType: EventType,\n handler: ExtractEventHandler<Event, EventType>,\n ) {\n const subscribers = this.#events.get(eventType);\n\n if (!subscribers || !subscribers.has(handler)) {\n throw new Error(`Subscription not found for event: ${eventType}`);\n }\n\n const selector = subscribers.get(handler);\n if (selector) {\n this.#eventPayloadCache.delete(handler);\n }\n\n subscribers.delete(handler);\n }\n\n /**\n * Clear subscriptions for a specific event.\n *\n * This will remove all subscribed handlers for this event.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @template EventType - A type union of Event type strings.\n */\n clearEventSubscriptions<EventType extends Event['type']>(\n eventType: EventType,\n ) {\n this.#events.delete(eventType);\n }\n\n /**\n * Clear all subscriptions.\n *\n * This will remove all subscribed handlers for all events.\n */\n clearSubscriptions() {\n this.#events.clear();\n }\n\n /**\n * Get a restricted messenger\n *\n * Returns a wrapper around the messenger instance that restricts access to actions and events.\n * The provided allowlists grant the ability to call the listed actions and subscribe to the\n * listed events. The \"name\" provided grants ownership of any actions and events under that\n * namespace. Ownership allows registering actions and publishing events, as well as\n * unregistering actions and clearing event subscriptions.\n *\n * @param options - Controller messenger options.\n * @param options.name - The name of the thing this messenger will be handed to (e.g. the\n * controller name). This grants \"ownership\" of actions and events under this namespace to the\n * restricted messenger returned.\n * @param options.allowedActions - The list of actions that this restricted messenger should be\n * allowed to call.\n * @param options.allowedEvents - The list of events that this restricted messenger should be\n * allowed to subscribe to.\n * @template Namespace - The namespace for this messenger. Typically this is the name of the\n * module that this messenger has been created for. The authority to publish events and register\n * actions under this namespace is granted to this restricted messenger instance.\n * @template AllowedAction - A type union of the 'type' string for any allowed actions.\n * This must not include internal actions that are in the messenger's namespace.\n * @template AllowedEvent - A type union of the 'type' string for any allowed events.\n * This must not include internal events that are in the messenger's namespace.\n * @returns The restricted messenger.\n */\n getRestricted<\n Namespace extends string,\n AllowedAction extends NotNamespacedBy<Namespace, Action['type']> = never,\n AllowedEvent extends NotNamespacedBy<Namespace, Event['type']> = never,\n >({\n name,\n allowedActions,\n allowedEvents,\n }: {\n name: Namespace;\n allowedActions: NotNamespacedBy<\n Namespace,\n Extract<Action['type'], AllowedAction>\n >[];\n allowedEvents: NotNamespacedBy<\n Namespace,\n Extract<Event['type'], AllowedEvent>\n >[];\n }): RestrictedMessenger<\n Namespace,\n | NarrowToNamespace<Action, Namespace>\n | NarrowToAllowed<Action, AllowedAction>,\n NarrowToNamespace<Event, Namespace> | NarrowToAllowed<Event, AllowedEvent>,\n AllowedAction,\n AllowedEvent\n > {\n return new RestrictedMessenger({\n messenger: this,\n name,\n allowedActions,\n allowedEvents,\n });\n }\n}\n\nexport { Messenger as ControllerMessenger };\n"]}
@@ -190,7 +190,7 @@ export declare class Messenger<Action extends ActionConstraint, Event extends Ev
190
190
  * namespace. Ownership allows registering actions and publishing events, as well as
191
191
  * unregistering actions and clearing event subscriptions.
192
192
  *
193
- * @param options - Messenger options.
193
+ * @param options - Controller messenger options.
194
194
  * @param options.name - The name of the thing this messenger will be handed to (e.g. the
195
195
  * controller name). This grants "ownership" of actions and events under this namespace to the
196
196
  * restricted messenger returned.
@@ -190,7 +190,7 @@ export declare class Messenger<Action extends ActionConstraint, Event extends Ev
190
190
  * namespace. Ownership allows registering actions and publishing events, as well as
191
191
  * unregistering actions and clearing event subscriptions.
192
192
  *
193
- * @param options - Messenger options.
193
+ * @param options - Controller messenger options.
194
194
  * @param options.name - The name of the thing this messenger will be handed to (e.g. the
195
195
  * controller name). This grants "ownership" of actions and events under this namespace to the
196
196
  * restricted messenger returned.
@@ -204,7 +204,7 @@ export class Messenger {
204
204
  * namespace. Ownership allows registering actions and publishing events, as well as
205
205
  * unregistering actions and clearing event subscriptions.
206
206
  *
207
- * @param options - Messenger options.
207
+ * @param options - Controller messenger options.
208
208
  * @param options.name - The name of the thing this messenger will be handed to (e.g. the
209
209
  * controller name). This grants "ownership" of actions and events under this namespace to the
210
210
  * restricted messenger returned.
@@ -1 +1 @@
1
- {"version":3,"file":"Messenger.mjs","sourceRoot":"","sources":["../src/Messenger.ts"],"names":[],"mappings":"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","sourcesContent":["import { RestrictedMessenger } from './RestrictedMessenger';\n\nexport type ActionHandler<\n Action extends ActionConstraint,\n ActionType = Action['type'],\n> = (\n ...args: ExtractActionParameters<Action, ActionType>\n) => ExtractActionResponse<Action, ActionType>;\n\nexport type ExtractActionParameters<\n Action extends ActionConstraint,\n ActionType = Action['type'],\n> = Action extends {\n type: ActionType;\n handler: (...args: infer HandlerArgs) => unknown;\n}\n ? HandlerArgs\n : never;\n\nexport type ExtractActionResponse<\n Action extends ActionConstraint,\n ActionType = Action['type'],\n> = Action extends {\n type: ActionType;\n handler: (...args: infer _) => infer HandlerReturnValue;\n}\n ? HandlerReturnValue\n : never;\n\nexport type ExtractEventHandler<\n Event extends EventConstraint,\n EventType = Event['type'],\n> = Event extends {\n type: EventType;\n payload: infer Payload;\n}\n ? Payload extends unknown[]\n ? (...payload: Payload) => void\n : never\n : never;\n\nexport type ExtractEventPayload<\n Event extends EventConstraint,\n EventType = Event['type'],\n> = Event extends {\n type: EventType;\n payload: infer Payload;\n}\n ? Payload extends unknown[]\n ? Payload\n : never\n : never;\n\nexport type GenericEventHandler = (...args: unknown[]) => void;\n\nexport type SelectorFunction<\n Event extends EventConstraint,\n EventType extends Event['type'],\n ReturnValue,\n> = (...args: ExtractEventPayload<Event, EventType>) => ReturnValue;\nexport type SelectorEventHandler<SelectorReturnValue> = (\n newValue: SelectorReturnValue,\n previousValue: SelectorReturnValue | undefined,\n) => void;\n\nexport type ActionConstraint = {\n type: string;\n handler: ((...args: never) => unknown) | ((...args: never[]) => unknown);\n};\nexport type EventConstraint = {\n type: string;\n payload: unknown[];\n};\n\ntype EventSubscriptionMap<\n Event extends EventConstraint,\n ReturnValue = unknown,\n> = Map<\n GenericEventHandler | SelectorEventHandler<ReturnValue>,\n SelectorFunction<Event, Event['type'], ReturnValue> | undefined\n>;\n\n/**\n * A namespaced string\n *\n * This type verifies that the string Name is prefixed by the string Name followed by a colon.\n *\n * @template Namespace - The namespace we're checking for.\n * @template Name - The full string, including the namespace.\n */\nexport type NamespacedBy<\n Namespace extends string,\n Name extends string,\n> = Name extends `${Namespace}:${string}` ? Name : never;\n\nexport type NotNamespacedBy<\n Namespace extends string,\n Name extends string,\n> = Name extends `${Namespace}:${string}` ? never : Name;\n\nexport type NamespacedName<Namespace extends string = string> =\n `${Namespace}:${string}`;\n\ntype NarrowToNamespace<Name, Namespace extends string> = Name extends {\n type: `${Namespace}:${string}`;\n}\n ? Name\n : never;\n\ntype NarrowToAllowed<Name, Allowed extends string> = Name extends {\n type: Allowed;\n}\n ? Name\n : never;\n\n/**\n * A message broker for \"actions\" and \"events\".\n *\n * The messenger allows registering functions as 'actions' that can be called elsewhere,\n * and it allows publishing and subscribing to events. Both actions and events are identified by\n * unique strings.\n *\n * @template Action - A type union of all Action types.\n * @template Event - A type union of all Event types.\n */\nexport class Messenger<\n Action extends ActionConstraint,\n Event extends EventConstraint,\n> {\n readonly #actions = new Map<Action['type'], unknown>();\n\n readonly #events = new Map<Event['type'], EventSubscriptionMap<Event>>();\n\n /**\n * A map of functions for getting the initial event payload.\n *\n * Used only for events that represent state changes.\n */\n readonly #initialEventPayloadGetters = new Map<\n Event['type'],\n () => ExtractEventPayload<Event, Event['type']>\n >();\n\n /**\n * A cache of selector return values for their respective handlers.\n */\n readonly #eventPayloadCache = new Map<\n GenericEventHandler,\n unknown | undefined\n >();\n\n /**\n * Register an action handler.\n *\n * This will make the registered function available to call via the `call` method.\n *\n * @param actionType - The action type. This is a unqiue identifier for this action.\n * @param handler - The action handler. This function gets called when the `call` method is\n * invoked with the given action type.\n * @throws Will throw when a handler has been registered for this action type already.\n * @template ActionType - A type union of Action type strings.\n */\n registerActionHandler<ActionType extends Action['type']>(\n actionType: ActionType,\n handler: ActionHandler<Action, ActionType>,\n ) {\n if (this.#actions.has(actionType)) {\n throw new Error(\n `A handler for ${actionType} has already been registered`,\n );\n }\n this.#actions.set(actionType, handler);\n }\n\n /**\n * Unregister an action handler.\n *\n * This will prevent this action from being called.\n *\n * @param actionType - The action type. This is a unqiue identifier for this action.\n * @template ActionType - A type union of Action type strings.\n */\n unregisterActionHandler<ActionType extends Action['type']>(\n actionType: ActionType,\n ) {\n this.#actions.delete(actionType);\n }\n\n /**\n * Unregister all action handlers.\n *\n * This prevents all actions from being called.\n */\n clearActions() {\n this.#actions.clear();\n }\n\n /**\n * Call an action.\n *\n * This function will call the action handler corresponding to the given action type, passing\n * along any parameters given.\n *\n * @param actionType - The action type. This is a unqiue identifier for this action.\n * @param params - The action parameters. These must match the type of the parameters of the\n * registered action handler.\n * @throws Will throw when no handler has been registered for the given type.\n * @template ActionType - A type union of Action type strings.\n * @returns The action return value.\n */\n call<ActionType extends Action['type']>(\n actionType: ActionType,\n ...params: ExtractActionParameters<Action, ActionType>\n ): ExtractActionResponse<Action, ActionType> {\n const handler = this.#actions.get(actionType) as ActionHandler<\n Action,\n ActionType\n >;\n if (!handler) {\n throw new Error(`A handler for ${actionType} has not been registered`);\n }\n return handler(...params);\n }\n\n /**\n * Register a function for getting the initial payload for an event.\n *\n * This is used for events that represent a state change, where the payload is the state.\n * Registering a function for getting the payload allows event selectors to have a point of\n * comparison the first time state changes.\n *\n * @param args - The arguments to this function\n * @param args.eventType - The event type to register a payload for.\n * @param args.getPayload - A function for retrieving the event payload.\n */\n registerInitialEventPayload<EventType extends Event['type']>({\n eventType,\n getPayload,\n }: {\n eventType: EventType;\n getPayload: () => ExtractEventPayload<Event, EventType>;\n }) {\n this.#initialEventPayloadGetters.set(eventType, getPayload);\n }\n\n /**\n * Publish an event.\n *\n * Publishes the given payload to all subscribers of the given event type.\n *\n * Note that this method should never throw directly. Any errors from\n * subscribers are captured and re-thrown in a timeout handler.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @param payload - The event payload. The type of the parameters for each event handler must\n * match the type of this payload.\n * @template EventType - A type union of Event type strings.\n */\n publish<EventType extends Event['type']>(\n eventType: EventType,\n ...payload: ExtractEventPayload<Event, EventType>\n ) {\n const subscribers = this.#events.get(eventType);\n\n if (subscribers) {\n for (const [handler, selector] of subscribers.entries()) {\n try {\n if (selector) {\n const previousValue = this.#eventPayloadCache.get(handler);\n const newValue = selector(...payload);\n\n if (newValue !== previousValue) {\n this.#eventPayloadCache.set(handler, newValue);\n handler(newValue, previousValue);\n }\n } else {\n (handler as GenericEventHandler)(...payload);\n }\n } catch (error) {\n // Throw error after timeout so that it is capured as a console error\n // (and by Sentry) without interrupting the event publishing.\n setTimeout(() => {\n throw error;\n });\n }\n }\n }\n }\n\n /**\n * Subscribe to an event.\n *\n * Registers the given function as an event handler for the given event type.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @param handler - The event handler. The type of the parameters for this event handler must\n * match the type of the payload for this event type.\n * @template EventType - A type union of Event type strings.\n */\n subscribe<EventType extends Event['type']>(\n eventType: EventType,\n handler: ExtractEventHandler<Event, EventType>,\n ): void;\n\n /**\n * Subscribe to an event, with a selector.\n *\n * Registers the given handler function as an event handler for the given\n * event type. When an event is published, its payload is first passed to the\n * selector. The event handler is only called if the selector's return value\n * differs from its last known return value.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @param handler - The event handler. The type of the parameters for this event\n * handler must match the return type of the selector.\n * @param selector - The selector function used to select relevant data from\n * the event payload. The type of the parameters for this selector must match\n * the type of the payload for this event type.\n * @template EventType - A type union of Event type strings.\n * @template SelectorReturnValue - The selector return value.\n */\n subscribe<EventType extends Event['type'], SelectorReturnValue>(\n eventType: EventType,\n handler: SelectorEventHandler<SelectorReturnValue>,\n selector: SelectorFunction<Event, EventType, SelectorReturnValue>,\n ): void;\n\n subscribe<EventType extends Event['type'], SelectorReturnValue>(\n eventType: EventType,\n handler: ExtractEventHandler<Event, EventType>,\n selector?: SelectorFunction<Event, EventType, SelectorReturnValue>,\n ): void {\n let subscribers = this.#events.get(eventType);\n if (!subscribers) {\n subscribers = new Map();\n this.#events.set(eventType, subscribers);\n }\n\n subscribers.set(handler, selector);\n\n if (selector) {\n const getPayload = this.#initialEventPayloadGetters.get(eventType);\n if (getPayload) {\n const initialValue = selector(...getPayload());\n this.#eventPayloadCache.set(handler, initialValue);\n }\n }\n }\n\n /**\n * Unsubscribe from an event.\n *\n * Unregisters the given function as an event handler for the given event.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @param handler - The event handler to unregister.\n * @throws Will throw when the given event handler is not registered for this event.\n * @template EventType - A type union of Event type strings.\n */\n unsubscribe<EventType extends Event['type']>(\n eventType: EventType,\n handler: ExtractEventHandler<Event, EventType>,\n ) {\n const subscribers = this.#events.get(eventType);\n\n if (!subscribers || !subscribers.has(handler)) {\n throw new Error(`Subscription not found for event: ${eventType}`);\n }\n\n const selector = subscribers.get(handler);\n if (selector) {\n this.#eventPayloadCache.delete(handler);\n }\n\n subscribers.delete(handler);\n }\n\n /**\n * Clear subscriptions for a specific event.\n *\n * This will remove all subscribed handlers for this event.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @template EventType - A type union of Event type strings.\n */\n clearEventSubscriptions<EventType extends Event['type']>(\n eventType: EventType,\n ) {\n this.#events.delete(eventType);\n }\n\n /**\n * Clear all subscriptions.\n *\n * This will remove all subscribed handlers for all events.\n */\n clearSubscriptions() {\n this.#events.clear();\n }\n\n /**\n * Get a restricted messenger\n *\n * Returns a wrapper around the messenger instance that restricts access to actions and events.\n * The provided allowlists grant the ability to call the listed actions and subscribe to the\n * listed events. The \"name\" provided grants ownership of any actions and events under that\n * namespace. Ownership allows registering actions and publishing events, as well as\n * unregistering actions and clearing event subscriptions.\n *\n * @param options - Messenger options.\n * @param options.name - The name of the thing this messenger will be handed to (e.g. the\n * controller name). This grants \"ownership\" of actions and events under this namespace to the\n * restricted messenger returned.\n * @param options.allowedActions - The list of actions that this restricted messenger should be\n * allowed to call.\n * @param options.allowedEvents - The list of events that this restricted messenger should be\n * allowed to subscribe to.\n * @template Namespace - The namespace for this messenger. Typically this is the name of the\n * module that this messenger has been created for. The authority to publish events and register\n * actions under this namespace is granted to this restricted messenger instance.\n * @template AllowedAction - A type union of the 'type' string for any allowed actions.\n * This must not include internal actions that are in the messenger's namespace.\n * @template AllowedEvent - A type union of the 'type' string for any allowed events.\n * This must not include internal events that are in the messenger's namespace.\n * @returns The restricted messenger.\n */\n getRestricted<\n Namespace extends string,\n AllowedAction extends NotNamespacedBy<Namespace, Action['type']> = never,\n AllowedEvent extends NotNamespacedBy<Namespace, Event['type']> = never,\n >({\n name,\n allowedActions,\n allowedEvents,\n }: {\n name: Namespace;\n allowedActions: NotNamespacedBy<\n Namespace,\n Extract<Action['type'], AllowedAction>\n >[];\n allowedEvents: NotNamespacedBy<\n Namespace,\n Extract<Event['type'], AllowedEvent>\n >[];\n }): RestrictedMessenger<\n Namespace,\n | NarrowToNamespace<Action, Namespace>\n | NarrowToAllowed<Action, AllowedAction>,\n NarrowToNamespace<Event, Namespace> | NarrowToAllowed<Event, AllowedEvent>,\n AllowedAction,\n AllowedEvent\n > {\n return new RestrictedMessenger({\n messenger: this,\n name,\n allowedActions,\n allowedEvents,\n });\n }\n}\n\nexport { Messenger as ControllerMessenger };\n"]}
1
+ {"version":3,"file":"Messenger.mjs","sourceRoot":"","sources":["../src/Messenger.ts"],"names":[],"mappings":"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","sourcesContent":["import { RestrictedMessenger } from './RestrictedMessenger';\n\nexport type ActionHandler<\n Action extends ActionConstraint,\n ActionType = Action['type'],\n> = (\n ...args: ExtractActionParameters<Action, ActionType>\n) => ExtractActionResponse<Action, ActionType>;\n\nexport type ExtractActionParameters<\n Action extends ActionConstraint,\n ActionType = Action['type'],\n> = Action extends {\n type: ActionType;\n handler: (...args: infer HandlerArgs) => unknown;\n}\n ? HandlerArgs\n : never;\n\nexport type ExtractActionResponse<\n Action extends ActionConstraint,\n ActionType = Action['type'],\n> = Action extends {\n type: ActionType;\n handler: (...args: infer _) => infer HandlerReturnValue;\n}\n ? HandlerReturnValue\n : never;\n\nexport type ExtractEventHandler<\n Event extends EventConstraint,\n EventType = Event['type'],\n> = Event extends {\n type: EventType;\n payload: infer Payload;\n}\n ? Payload extends unknown[]\n ? (...payload: Payload) => void\n : never\n : never;\n\nexport type ExtractEventPayload<\n Event extends EventConstraint,\n EventType = Event['type'],\n> = Event extends {\n type: EventType;\n payload: infer Payload;\n}\n ? Payload extends unknown[]\n ? Payload\n : never\n : never;\n\nexport type GenericEventHandler = (...args: unknown[]) => void;\n\nexport type SelectorFunction<\n Event extends EventConstraint,\n EventType extends Event['type'],\n ReturnValue,\n> = (...args: ExtractEventPayload<Event, EventType>) => ReturnValue;\nexport type SelectorEventHandler<SelectorReturnValue> = (\n newValue: SelectorReturnValue,\n previousValue: SelectorReturnValue | undefined,\n) => void;\n\nexport type ActionConstraint = {\n type: string;\n handler: ((...args: never) => unknown) | ((...args: never[]) => unknown);\n};\nexport type EventConstraint = {\n type: string;\n payload: unknown[];\n};\n\ntype EventSubscriptionMap<\n Event extends EventConstraint,\n ReturnValue = unknown,\n> = Map<\n GenericEventHandler | SelectorEventHandler<ReturnValue>,\n SelectorFunction<Event, Event['type'], ReturnValue> | undefined\n>;\n\n/**\n * A namespaced string\n *\n * This type verifies that the string Name is prefixed by the string Name followed by a colon.\n *\n * @template Namespace - The namespace we're checking for.\n * @template Name - The full string, including the namespace.\n */\nexport type NamespacedBy<\n Namespace extends string,\n Name extends string,\n> = Name extends `${Namespace}:${string}` ? Name : never;\n\nexport type NotNamespacedBy<\n Namespace extends string,\n Name extends string,\n> = Name extends `${Namespace}:${string}` ? never : Name;\n\nexport type NamespacedName<Namespace extends string = string> =\n `${Namespace}:${string}`;\n\ntype NarrowToNamespace<Name, Namespace extends string> = Name extends {\n type: `${Namespace}:${string}`;\n}\n ? Name\n : never;\n\ntype NarrowToAllowed<Name, Allowed extends string> = Name extends {\n type: Allowed;\n}\n ? Name\n : never;\n\n/**\n * A message broker for \"actions\" and \"events\".\n *\n * The messenger allows registering functions as 'actions' that can be called elsewhere,\n * and it allows publishing and subscribing to events. Both actions and events are identified by\n * unique strings.\n *\n * @template Action - A type union of all Action types.\n * @template Event - A type union of all Event types.\n */\nexport class Messenger<\n Action extends ActionConstraint,\n Event extends EventConstraint,\n> {\n readonly #actions = new Map<Action['type'], unknown>();\n\n readonly #events = new Map<Event['type'], EventSubscriptionMap<Event>>();\n\n /**\n * A map of functions for getting the initial event payload.\n *\n * Used only for events that represent state changes.\n */\n readonly #initialEventPayloadGetters = new Map<\n Event['type'],\n () => ExtractEventPayload<Event, Event['type']>\n >();\n\n /**\n * A cache of selector return values for their respective handlers.\n */\n readonly #eventPayloadCache = new Map<\n GenericEventHandler,\n unknown | undefined\n >();\n\n /**\n * Register an action handler.\n *\n * This will make the registered function available to call via the `call` method.\n *\n * @param actionType - The action type. This is a unqiue identifier for this action.\n * @param handler - The action handler. This function gets called when the `call` method is\n * invoked with the given action type.\n * @throws Will throw when a handler has been registered for this action type already.\n * @template ActionType - A type union of Action type strings.\n */\n registerActionHandler<ActionType extends Action['type']>(\n actionType: ActionType,\n handler: ActionHandler<Action, ActionType>,\n ) {\n if (this.#actions.has(actionType)) {\n throw new Error(\n `A handler for ${actionType} has already been registered`,\n );\n }\n this.#actions.set(actionType, handler);\n }\n\n /**\n * Unregister an action handler.\n *\n * This will prevent this action from being called.\n *\n * @param actionType - The action type. This is a unqiue identifier for this action.\n * @template ActionType - A type union of Action type strings.\n */\n unregisterActionHandler<ActionType extends Action['type']>(\n actionType: ActionType,\n ) {\n this.#actions.delete(actionType);\n }\n\n /**\n * Unregister all action handlers.\n *\n * This prevents all actions from being called.\n */\n clearActions() {\n this.#actions.clear();\n }\n\n /**\n * Call an action.\n *\n * This function will call the action handler corresponding to the given action type, passing\n * along any parameters given.\n *\n * @param actionType - The action type. This is a unqiue identifier for this action.\n * @param params - The action parameters. These must match the type of the parameters of the\n * registered action handler.\n * @throws Will throw when no handler has been registered for the given type.\n * @template ActionType - A type union of Action type strings.\n * @returns The action return value.\n */\n call<ActionType extends Action['type']>(\n actionType: ActionType,\n ...params: ExtractActionParameters<Action, ActionType>\n ): ExtractActionResponse<Action, ActionType> {\n const handler = this.#actions.get(actionType) as ActionHandler<\n Action,\n ActionType\n >;\n if (!handler) {\n throw new Error(`A handler for ${actionType} has not been registered`);\n }\n return handler(...params);\n }\n\n /**\n * Register a function for getting the initial payload for an event.\n *\n * This is used for events that represent a state change, where the payload is the state.\n * Registering a function for getting the payload allows event selectors to have a point of\n * comparison the first time state changes.\n *\n * @param args - The arguments to this function\n * @param args.eventType - The event type to register a payload for.\n * @param args.getPayload - A function for retrieving the event payload.\n */\n registerInitialEventPayload<EventType extends Event['type']>({\n eventType,\n getPayload,\n }: {\n eventType: EventType;\n getPayload: () => ExtractEventPayload<Event, EventType>;\n }) {\n this.#initialEventPayloadGetters.set(eventType, getPayload);\n }\n\n /**\n * Publish an event.\n *\n * Publishes the given payload to all subscribers of the given event type.\n *\n * Note that this method should never throw directly. Any errors from\n * subscribers are captured and re-thrown in a timeout handler.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @param payload - The event payload. The type of the parameters for each event handler must\n * match the type of this payload.\n * @template EventType - A type union of Event type strings.\n */\n publish<EventType extends Event['type']>(\n eventType: EventType,\n ...payload: ExtractEventPayload<Event, EventType>\n ) {\n const subscribers = this.#events.get(eventType);\n\n if (subscribers) {\n for (const [handler, selector] of subscribers.entries()) {\n try {\n if (selector) {\n const previousValue = this.#eventPayloadCache.get(handler);\n const newValue = selector(...payload);\n\n if (newValue !== previousValue) {\n this.#eventPayloadCache.set(handler, newValue);\n handler(newValue, previousValue);\n }\n } else {\n (handler as GenericEventHandler)(...payload);\n }\n } catch (error) {\n // Throw error after timeout so that it is capured as a console error\n // (and by Sentry) without interrupting the event publishing.\n setTimeout(() => {\n throw error;\n });\n }\n }\n }\n }\n\n /**\n * Subscribe to an event.\n *\n * Registers the given function as an event handler for the given event type.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @param handler - The event handler. The type of the parameters for this event handler must\n * match the type of the payload for this event type.\n * @template EventType - A type union of Event type strings.\n */\n subscribe<EventType extends Event['type']>(\n eventType: EventType,\n handler: ExtractEventHandler<Event, EventType>,\n ): void;\n\n /**\n * Subscribe to an event, with a selector.\n *\n * Registers the given handler function as an event handler for the given\n * event type. When an event is published, its payload is first passed to the\n * selector. The event handler is only called if the selector's return value\n * differs from its last known return value.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @param handler - The event handler. The type of the parameters for this event\n * handler must match the return type of the selector.\n * @param selector - The selector function used to select relevant data from\n * the event payload. The type of the parameters for this selector must match\n * the type of the payload for this event type.\n * @template EventType - A type union of Event type strings.\n * @template SelectorReturnValue - The selector return value.\n */\n subscribe<EventType extends Event['type'], SelectorReturnValue>(\n eventType: EventType,\n handler: SelectorEventHandler<SelectorReturnValue>,\n selector: SelectorFunction<Event, EventType, SelectorReturnValue>,\n ): void;\n\n subscribe<EventType extends Event['type'], SelectorReturnValue>(\n eventType: EventType,\n handler: ExtractEventHandler<Event, EventType>,\n selector?: SelectorFunction<Event, EventType, SelectorReturnValue>,\n ): void {\n let subscribers = this.#events.get(eventType);\n if (!subscribers) {\n subscribers = new Map();\n this.#events.set(eventType, subscribers);\n }\n\n subscribers.set(handler, selector);\n\n if (selector) {\n const getPayload = this.#initialEventPayloadGetters.get(eventType);\n if (getPayload) {\n const initialValue = selector(...getPayload());\n this.#eventPayloadCache.set(handler, initialValue);\n }\n }\n }\n\n /**\n * Unsubscribe from an event.\n *\n * Unregisters the given function as an event handler for the given event.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @param handler - The event handler to unregister.\n * @throws Will throw when the given event handler is not registered for this event.\n * @template EventType - A type union of Event type strings.\n */\n unsubscribe<EventType extends Event['type']>(\n eventType: EventType,\n handler: ExtractEventHandler<Event, EventType>,\n ) {\n const subscribers = this.#events.get(eventType);\n\n if (!subscribers || !subscribers.has(handler)) {\n throw new Error(`Subscription not found for event: ${eventType}`);\n }\n\n const selector = subscribers.get(handler);\n if (selector) {\n this.#eventPayloadCache.delete(handler);\n }\n\n subscribers.delete(handler);\n }\n\n /**\n * Clear subscriptions for a specific event.\n *\n * This will remove all subscribed handlers for this event.\n *\n * @param eventType - The event type. This is a unique identifier for this event.\n * @template EventType - A type union of Event type strings.\n */\n clearEventSubscriptions<EventType extends Event['type']>(\n eventType: EventType,\n ) {\n this.#events.delete(eventType);\n }\n\n /**\n * Clear all subscriptions.\n *\n * This will remove all subscribed handlers for all events.\n */\n clearSubscriptions() {\n this.#events.clear();\n }\n\n /**\n * Get a restricted messenger\n *\n * Returns a wrapper around the messenger instance that restricts access to actions and events.\n * The provided allowlists grant the ability to call the listed actions and subscribe to the\n * listed events. The \"name\" provided grants ownership of any actions and events under that\n * namespace. Ownership allows registering actions and publishing events, as well as\n * unregistering actions and clearing event subscriptions.\n *\n * @param options - Controller messenger options.\n * @param options.name - The name of the thing this messenger will be handed to (e.g. the\n * controller name). This grants \"ownership\" of actions and events under this namespace to the\n * restricted messenger returned.\n * @param options.allowedActions - The list of actions that this restricted messenger should be\n * allowed to call.\n * @param options.allowedEvents - The list of events that this restricted messenger should be\n * allowed to subscribe to.\n * @template Namespace - The namespace for this messenger. Typically this is the name of the\n * module that this messenger has been created for. The authority to publish events and register\n * actions under this namespace is granted to this restricted messenger instance.\n * @template AllowedAction - A type union of the 'type' string for any allowed actions.\n * This must not include internal actions that are in the messenger's namespace.\n * @template AllowedEvent - A type union of the 'type' string for any allowed events.\n * This must not include internal events that are in the messenger's namespace.\n * @returns The restricted messenger.\n */\n getRestricted<\n Namespace extends string,\n AllowedAction extends NotNamespacedBy<Namespace, Action['type']> = never,\n AllowedEvent extends NotNamespacedBy<Namespace, Event['type']> = never,\n >({\n name,\n allowedActions,\n allowedEvents,\n }: {\n name: Namespace;\n allowedActions: NotNamespacedBy<\n Namespace,\n Extract<Action['type'], AllowedAction>\n >[];\n allowedEvents: NotNamespacedBy<\n Namespace,\n Extract<Event['type'], AllowedEvent>\n >[];\n }): RestrictedMessenger<\n Namespace,\n | NarrowToNamespace<Action, Namespace>\n | NarrowToAllowed<Action, AllowedAction>,\n NarrowToNamespace<Event, Namespace> | NarrowToAllowed<Event, AllowedEvent>,\n AllowedAction,\n AllowedEvent\n > {\n return new RestrictedMessenger({\n messenger: this,\n name,\n allowedActions,\n allowedEvents,\n });\n }\n}\n\nexport { Messenger as ControllerMessenger };\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/base-controller",
3
- "version": "7.1.1-preview-0d0d258d",
3
+ "version": "7.1.1-preview-4c4eb52a",
4
4
  "description": "Provides scaffolding for controllers as well a communication system for all controllers",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -46,12 +46,12 @@
46
46
  "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch"
47
47
  },
48
48
  "dependencies": {
49
- "@metamask/utils": "^11.1.0",
49
+ "@metamask/utils": "^11.0.1",
50
50
  "immer": "^9.0.6"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@metamask/auto-changelog": "^3.4.4",
54
- "@metamask/json-rpc-engine": "^10.0.3",
54
+ "@metamask/json-rpc-engine": "^10.0.2",
55
55
  "@types/jest": "^27.4.1",
56
56
  "@types/sinon": "^9.0.10",
57
57
  "deepmerge": "^4.2.2",