@metamask-previews/composable-controller 5.0.1-preview.2431602 → 5.0.1-preview.303e509

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.
package/CHANGELOG.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # Changelog
2
+
2
3
  All notable changes to this project will be documented in this file.
3
4
 
4
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
@@ -6,15 +7,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
7
 
7
8
  ## [Unreleased]
8
9
 
10
+ ### Added
11
+
12
+ - Add and export functions `isBaseControllerV1` and `isBaseController`, which are type guards for validating controller instances ([#3904](https://github.com/MetaMask/core/pull/3904))
13
+ - Add and export types `BaseControllerV1Instance`, `BaseControllerV2Instance`, `ControllerInstance` which are the narrowest supertypes for all controllers extending from, respectively, `BaseControllerV1`, `BaseController`, and both ([#3904](https://github.com/MetaMask/core/pull/3904))
14
+
15
+ ### Changed
16
+
17
+ - **BREAKING:** Passing a non-controller into `controllers` constructor option now throws an error ([#3904](https://github.com/MetaMask/core/pull/3904))
18
+ - **BREAKING:** The `AllowedActions` parameter of the `ComposableControllerMessenger` type is narrowed from `string` to `never`, as `ComposableController` does not use any external controller actions. ([#3904](https://github.com/MetaMask/core/pull/3904))
19
+ - Add `@metamask/utils` ^8.3.0 as a dependency. ([#3904](https://github.com/MetaMask/core/pull/3904))
20
+
21
+ ### Removed
22
+
23
+ - **BREAKING:** Remove `ControllerList` as an exported type. ([#3904](https://github.com/MetaMask/core/pull/3904))
24
+
9
25
  ## [5.0.1]
26
+
10
27
  ### Changed
28
+
11
29
  - Bump `@metamask/base-controller` to `^4.1.1` ([#3760](https://github.com/MetaMask/core/pull/3760), [#3821](https://github.com/MetaMask/core/pull/3821))
12
30
 
13
31
  ## [5.0.0]
32
+
14
33
  ### Added
34
+
15
35
  - Add types `ComposableControllerState`, `ComposableControllerStateChangeEvent`, `ComposableControllerEvents`, `ComposableControllerMessenger` ([#3590](https://github.com/MetaMask/core/pull/3590))
16
36
 
17
37
  ### Changed
38
+
18
39
  - **BREAKING:** `ComposableController` is upgraded to extend `BaseControllerV2` ([#3590](https://github.com/MetaMask/core/pull/3590))
19
40
  - The constructor now expects an options object with required properties `controllers` and `messenger` as its only argument.
20
41
  - `ComposableController` no longer has a `subscribe` method. Instead, listeners for `ComposableController` events must be registered to the controller messenger that generated the restricted messenger assigned to the instance's `messagingSystem` class field.
@@ -22,44 +43,64 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
22
43
  - Bump `@metamask/base-controller` to `^4.0.1` ([#3695](https://github.com/MetaMask/core/pull/3695))
23
44
 
24
45
  ## [4.0.0]
46
+
25
47
  ### Changed
48
+
26
49
  - **BREAKING:** Bump `@metamask/base-controller` to ^4.0.0 ([#2063](https://github.com/MetaMask/core/pull/2063))
27
50
  - This is breaking because the type of the `messenger` has backward-incompatible changes. See the changelog for this package for more.
28
51
 
29
52
  ## [3.0.3]
53
+
30
54
  ### Changed
55
+
31
56
  - Bump dependency on `@metamask/base-controller` to ^3.2.3 ([#1747](https://github.com/MetaMask/core/pull/1747))
32
57
 
33
58
  ## [3.0.2]
59
+
34
60
  ### Changed
61
+
35
62
  - Update TypeScript to v4.8.x ([#1718](https://github.com/MetaMask/core/pull/1718))
36
63
 
37
64
  ## [3.0.1]
65
+
38
66
  ### Changed
67
+
39
68
  - Bump dependency on `@metamask/base-controller` to ^3.2.1
40
69
 
41
70
  ## [3.0.0]
71
+
42
72
  ### Changed
73
+
43
74
  - **BREAKING:** Bump to Node 16 ([#1262](https://github.com/MetaMask/core/pull/1262))
44
75
 
45
76
  ## [2.0.0]
77
+
46
78
  ### Removed
79
+
47
80
  - **BREAKING:** Remove `isomorphic-fetch` ([#1106](https://github.com/MetaMask/controllers/pull/1106))
48
81
  - Consumers must now import `isomorphic-fetch` or another polyfill themselves if they are running in an environment without `fetch`
49
82
 
50
83
  ## [1.0.2]
84
+
51
85
  ### Changed
86
+
52
87
  - Rename this repository to `core` ([#1031](https://github.com/MetaMask/controllers/pull/1031))
53
- - Update `@metamask/controller-utils` package ([#1041](https://github.com/MetaMask/controllers/pull/1041))
88
+ - Update `@metamask/controller-utils` package ([#1041](https://github.com/MetaMask/controllers/pull/1041))
54
89
 
55
90
  ## [1.0.1]
91
+
56
92
  ### Changed
93
+
57
94
  - Relax dependency on `@metamask/controller-utils` (use `^` instead of `~`) ([#998](https://github.com/MetaMask/core/pull/998))
58
95
 
59
96
  ## [1.0.0]
97
+
60
98
  ### Added
99
+
61
100
  - Initial release
101
+
62
102
  - As a result of converting our shared controllers repo into a monorepo ([#831](https://github.com/MetaMask/core/pull/831)), we've created this package from select parts of [`@metamask/controllers` v33.0.0](https://github.com/MetaMask/core/tree/v33.0.0), namely:
103
+
63
104
  - `src/ComposableController.ts`
64
105
  - `src/ComposableController.test.ts`
65
106
 
@@ -1,20 +1,48 @@
1
1
  import { BaseController, BaseControllerV1 } from '@metamask/base-controller';
2
- import type { ControllerStateChangeEvent, RestrictedControllerMessenger } from '@metamask/base-controller';
2
+ import type { ControllerStateChangeEvent, RestrictedControllerMessenger, BaseState, BaseConfig } from '@metamask/base-controller';
3
+ import { type Json } from '@metamask/utils';
3
4
  export declare const controllerName = "ComposableController";
4
- declare type ControllerInstance = BaseControllerV1<any, any> | {
5
+ /**
6
+ * A type encompassing all controller instances that extend from `BaseControllerV1`.
7
+ */
8
+ export declare type BaseControllerV1Instance = BaseControllerV1<any, any>;
9
+ /**
10
+ * A type encompassing all controller instances that extend from `BaseController` (formerly `BaseControllerV2`).
11
+ *
12
+ * The `BaseController` class itself can't be used directly as a type representing all of its subclasses,
13
+ * because the generic parameters it expects require knowing the exact shape of the controller's state and messenger.
14
+ *
15
+ * Instead, we look for an object with the `BaseController` properties that we use in the ComposableController (name and state).
16
+ */
17
+ export declare type BaseControllerV2Instance = {
5
18
  name: string;
6
- state: Record<string, unknown>;
19
+ state: Record<string, Json>;
7
20
  };
8
21
  /**
9
- * List of child controller instances
22
+ * A type encompassing all controller instances that extend from `BaseControllerV1` or `BaseController`.
23
+ */
24
+ export declare type ControllerInstance = BaseControllerV1Instance | BaseControllerV2Instance;
25
+ /**
26
+ * Determines if the given controller is an instance of BaseControllerV1
27
+ * @param controller - Controller instance to check
28
+ * @returns True if the controller is an instance of BaseControllerV1
29
+ * TODO: Deprecate once `BaseControllerV2` migrations are completed for all controllers.
10
30
  */
11
- export declare type ControllerList = ControllerInstance[];
31
+ export declare function isBaseControllerV1(controller: ControllerInstance): controller is BaseControllerV1<BaseConfig & Record<string, unknown>, BaseState & Record<string, unknown>>;
32
+ /**
33
+ * Determines if the given controller is an instance of BaseController
34
+ * @param controller - Controller instance to check
35
+ * @returns True if the controller is an instance of BaseController
36
+ */
37
+ export declare function isBaseController(controller: ControllerInstance): controller is BaseController<never, never, never>;
12
38
  export declare type ComposableControllerState = {
13
- [name: string]: ControllerInstance['state'];
39
+ [name: string]: Record<string, any>;
14
40
  };
15
- export declare type ComposableControllerStateChangeEvent = ControllerStateChangeEvent<typeof controllerName, ComposableControllerState>;
41
+ export declare type ComposableControllerStateChangeEvent = ControllerStateChangeEvent<typeof controllerName, Record<string, unknown>>;
16
42
  export declare type ComposableControllerEvents = ComposableControllerStateChangeEvent;
17
- export declare type ComposableControllerMessenger = RestrictedControllerMessenger<typeof controllerName, never, ControllerStateChangeEvent<string, Record<string, unknown>>, string, string>;
43
+ declare type AnyControllerStateChangeEvent = ControllerStateChangeEvent<string, Record<string, unknown>>;
44
+ declare type AllowedEvents = AnyControllerStateChangeEvent;
45
+ export declare type ComposableControllerMessenger = RestrictedControllerMessenger<typeof controllerName, never, ComposableControllerEvents | AllowedEvents, never, AllowedEvents['type']>;
18
46
  /**
19
47
  * Controller that can be used to compose multiple controllers together.
20
48
  */
@@ -28,17 +56,9 @@ export declare class ComposableController extends BaseController<typeof controll
28
56
  * @param options.messenger - A restricted controller messenger.
29
57
  */
30
58
  constructor({ controllers, messenger, }: {
31
- controllers: ControllerList;
59
+ controllers: ControllerInstance[];
32
60
  messenger: ComposableControllerMessenger;
33
61
  });
34
- /**
35
- * Flat state representation, one that isn't keyed
36
- * of controller name. Instead, all child controller state is merged
37
- * together into a single, flat object.
38
- *
39
- * @returns Merged state representation of all child controllers.
40
- */
41
- get flatState(): {};
42
62
  }
43
63
  export default ComposableController;
44
64
  //# sourceMappingURL=ComposableController.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ComposableController.d.ts","sourceRoot":"","sources":["../src/ComposableController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,KAAK,EACV,0BAA0B,EAC1B,6BAA6B,EAC9B,MAAM,2BAA2B,CAAC;AAEnC,eAAO,MAAM,cAAc,yBAAyB,CAAC;AASrD,aAAK,kBAAkB,GAGrB,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC;AAEhF;;GAEG;AACH,oBAAY,cAAc,GAAG,kBAAkB,EAAE,CAAC;AAelD,oBAAY,yBAAyB,GAAG;IACtC,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;CAC7C,CAAC;AAEF,oBAAY,oCAAoC,GAAG,0BAA0B,CAC3E,OAAO,cAAc,EACrB,yBAAyB,CAC1B,CAAC;AAEF,oBAAY,0BAA0B,GAAG,oCAAoC,CAAC;AAE9E,oBAAY,6BAA6B,GAAG,6BAA6B,CACvE,OAAO,cAAc,EACrB,KAAK,EACL,0BAA0B,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC3D,MAAM,EACN,MAAM,CACP,CAAC;AAEF;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,cAAc,CACtD,OAAO,cAAc,EACrB,yBAAyB,EACzB,6BAA6B,CAC9B;;IAGC;;;;;;OAMG;gBAES,EACV,WAAW,EACX,SAAS,GACV,EAAE;QACD,WAAW,EAAE,cAAc,CAAC;QAC5B,SAAS,EAAE,6BAA6B,CAAC;KAC1C;IAoBD;;;;;;OAMG;IACH,IAAI,SAAS,OAMZ;CA4BF;AAED,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"ComposableController.d.ts","sourceRoot":"","sources":["../src/ComposableController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,KAAK,EACV,0BAA0B,EAC1B,6BAA6B,EAC7B,SAAS,EACT,UAAU,EAEX,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAe,KAAK,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEzD,eAAO,MAAM,cAAc,yBAAyB,CAAC;AAGrD;;GAEG;AACH,oBAAY,wBAAwB,GAGlC,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAE7B;;;;;;;GAOG;AACH,oBAAY,wBAAwB,GAAG;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;CAC7B,CAAC;AAGF;;GAEG;AACH,oBAAY,kBAAkB,GAC1B,wBAAwB,GACxB,wBAAwB,CAAC;AAE7B;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,kBAAkB,GAC7B,UAAU,IAAI,gBAAgB,CAC/B,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CACpC,CAYA;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,kBAAkB,GAC7B,UAAU,IAAI,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAQnD;AAED,oBAAY,yBAAyB,GAAG;IAKtC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACrC,CAAC;AAEF,oBAAY,oCAAoC,GAAG,0BAA0B,CAC3E,OAAO,cAAc,EACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CACxB,CAAC;AAEF,oBAAY,0BAA0B,GAAG,oCAAoC,CAAC;AAE9E,aAAK,6BAA6B,GAAG,0BAA0B,CAC7D,MAAM,EACN,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CACxB,CAAC;AAEF,aAAK,aAAa,GAAG,6BAA6B,CAAC;AAEnD,oBAAY,6BAA6B,GAAG,6BAA6B,CACvE,OAAO,cAAc,EACrB,KAAK,EACL,0BAA0B,GAAG,aAAa,EAC1C,KAAK,EACL,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AAEF;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,cAAc,CACtD,OAAO,cAAc,EACrB,yBAAyB,EACzB,6BAA6B,CAC9B;;IACC;;;;;;OAMG;gBAES,EACV,WAAW,EACX,SAAS,GACV,EAAE;QACD,WAAW,EAAE,kBAAkB,EAAE,CAAC;QAClC,SAAS,EAAE,6BAA6B,CAAC;KAC1C;CA2DF;AAED,eAAe,oBAAoB,CAAC"}
@@ -1,28 +1,46 @@
1
1
  "use strict";
2
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
- if (kind === "m") throw new TypeError("Private method is not writable");
4
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
- };
8
2
  var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
3
  if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
4
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
5
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
6
  };
13
- var _ComposableController_instances, _ComposableController_controllers, _ComposableController_updateChildController;
7
+ var _ComposableController_instances, _ComposableController_updateChildController;
14
8
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.ComposableController = exports.controllerName = void 0;
9
+ exports.ComposableController = exports.isBaseController = exports.isBaseControllerV1 = exports.controllerName = void 0;
16
10
  const base_controller_1 = require("@metamask/base-controller");
11
+ const utils_1 = require("@metamask/utils");
17
12
  exports.controllerName = 'ComposableController';
18
13
  /**
19
14
  * Determines if the given controller is an instance of BaseControllerV1
20
15
  * @param controller - Controller instance to check
21
16
  * @returns True if the controller is an instance of BaseControllerV1
17
+ * TODO: Deprecate once `BaseControllerV2` migrations are completed for all controllers.
22
18
  */
23
19
  function isBaseControllerV1(controller) {
24
- return controller instanceof base_controller_1.BaseControllerV1;
20
+ return ('name' in controller &&
21
+ typeof controller.name === 'string' &&
22
+ 'defaultConfig' in controller &&
23
+ typeof controller.defaultConfig === 'object' &&
24
+ 'defaultState' in controller &&
25
+ typeof controller.defaultState === 'object' &&
26
+ 'disabled' in controller &&
27
+ typeof controller.disabled === 'boolean' &&
28
+ controller instanceof base_controller_1.BaseControllerV1);
25
29
  }
30
+ exports.isBaseControllerV1 = isBaseControllerV1;
31
+ /**
32
+ * Determines if the given controller is an instance of BaseController
33
+ * @param controller - Controller instance to check
34
+ * @returns True if the controller is an instance of BaseController
35
+ */
36
+ function isBaseController(controller) {
37
+ return ('name' in controller &&
38
+ typeof controller.name === 'string' &&
39
+ 'state' in controller &&
40
+ typeof controller.state === 'object' &&
41
+ controller instanceof base_controller_1.BaseController);
42
+ }
43
+ exports.isBaseController = isBaseController;
26
44
  /**
27
45
  * Controller that can be used to compose multiple controllers together.
28
46
  */
@@ -40,45 +58,36 @@ class ComposableController extends base_controller_1.BaseController {
40
58
  }
41
59
  super({
42
60
  name: exports.controllerName,
43
- metadata: {},
61
+ metadata: controllers.reduce((metadata, controller) => (Object.assign(Object.assign({}, metadata), { [controller.name]: isBaseController(controller)
62
+ ? controller.metadata
63
+ : { persist: true, anonymous: true } })), {}),
44
64
  state: controllers.reduce((state, controller) => {
45
65
  return Object.assign(Object.assign({}, state), { [controller.name]: controller.state });
46
66
  }, {}),
47
67
  messenger,
48
68
  });
49
69
  _ComposableController_instances.add(this);
50
- _ComposableController_controllers.set(this, []);
51
- __classPrivateFieldSet(this, _ComposableController_controllers, controllers, "f");
52
- __classPrivateFieldGet(this, _ComposableController_controllers, "f").forEach((controller) => __classPrivateFieldGet(this, _ComposableController_instances, "m", _ComposableController_updateChildController).call(this, controller));
53
- }
54
- /**
55
- * Flat state representation, one that isn't keyed
56
- * of controller name. Instead, all child controller state is merged
57
- * together into a single, flat object.
58
- *
59
- * @returns Merged state representation of all child controllers.
60
- */
61
- get flatState() {
62
- let flatState = {};
63
- for (const controller of __classPrivateFieldGet(this, _ComposableController_controllers, "f")) {
64
- flatState = Object.assign(Object.assign({}, flatState), controller.state);
65
- }
66
- return flatState;
70
+ controllers.forEach((controller) => __classPrivateFieldGet(this, _ComposableController_instances, "m", _ComposableController_updateChildController).call(this, controller));
67
71
  }
68
72
  }
69
73
  exports.ComposableController = ComposableController;
70
- _ComposableController_controllers = new WeakMap(), _ComposableController_instances = new WeakSet(), _ComposableController_updateChildController = function _ComposableController_updateChildController(controller) {
74
+ _ComposableController_instances = new WeakSet(), _ComposableController_updateChildController = function _ComposableController_updateChildController(controller) {
71
75
  const { name } = controller;
72
76
  if (isBaseControllerV1(controller)) {
73
77
  controller.subscribe((childState) => {
74
78
  this.update((state) => (Object.assign(Object.assign({}, state), { [name]: childState })));
75
79
  });
76
80
  }
77
- else {
78
- this.messagingSystem.subscribe(`${String(name)}:stateChange`, (childState) => {
79
- this.update((state) => (Object.assign(Object.assign({}, state), { [name]: childState })));
81
+ else if (isBaseController(controller)) {
82
+ this.messagingSystem.subscribe(`${name}:stateChange`, (childState) => {
83
+ if ((0, utils_1.isValidJson)(childState)) {
84
+ this.update((state) => (Object.assign(Object.assign({}, state), { [name]: childState })));
85
+ }
80
86
  });
81
87
  }
88
+ else {
89
+ throw new Error('Invalid controller: controller must extend from BaseController or BaseControllerV1');
90
+ }
82
91
  };
83
92
  exports.default = ComposableController;
84
93
  //# sourceMappingURL=ComposableController.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ComposableController.js","sourceRoot":"","sources":["../src/ComposableController.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,+DAA6E;AAMhE,QAAA,cAAc,GAAG,sBAAsB,CAAC;AAmBrD;;;;GAIG;AACH,SAAS,kBAAkB,CACzB,UAA8B;IAI9B,OAAO,UAAU,YAAY,kCAAgB,CAAC;AAChD,CAAC;AAqBD;;GAEG;AACH,MAAa,oBAAqB,SAAQ,gCAIzC;IAGC;;;;;;OAMG;IAEH,YAAY,EACV,WAAW,EACX,SAAS,GAIV;QACC,IAAI,SAAS,KAAK,SAAS,EAAE;YAC3B,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;SACjD;QAED,KAAK,CAAC;YACJ,IAAI,EAAE,sBAAc;YACpB,QAAQ,EAAE,EAAE;YACZ,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE;gBAC9C,uCAAY,KAAK,KAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,KAAK,IAAG;YAC3D,CAAC,EAAE,EAA+B,CAAC;YACnC,SAAS;SACV,CAAC,CAAC;;QA5BL,4CAAwC,EAAE,EAAC;QA8BzC,uBAAA,IAAI,qCAAgB,WAAW,MAAA,CAAC;QAChC,uBAAA,IAAI,yCAAa,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE,CACvC,uBAAA,IAAI,oFAAuB,MAA3B,IAAI,EAAwB,UAAU,CAAC,CACxC,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,IAAI,SAAS;QACX,IAAI,SAAS,GAAG,EAAE,CAAC;QACnB,KAAK,MAAM,UAAU,IAAI,uBAAA,IAAI,yCAAa,EAAE;YAC1C,SAAS,mCAAQ,SAAS,GAAK,UAAU,CAAC,KAAK,CAAE,CAAC;SACnD;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;CA4BF;AAlFD,oDAkFC;uMArBwB,UAA8B;IACnD,MAAM,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC;IAC5B,IAAI,kBAAkB,CAAC,UAAU,CAAC,EAAE;QAClC,UAAU,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,EAAE;YAClC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,iCAClB,KAAK,KACR,CAAC,IAAI,CAAC,EAAE,UAAU,IAClB,CAAC,CAAC;QACN,CAAC,CAAC,CAAC;KACJ;SAAM;QACL,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,GAAG,MAAM,CAAC,IAAI,CAAC,cAAc,EAC7B,CAAC,UAAmC,EAAE,EAAE;YACtC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,iCAClB,KAAK,KACR,CAAC,IAAI,CAAC,EAAE,UAAU,IAClB,CAAC,CAAC;QACN,CAAC,CACF,CAAC;KACH;AACH,CAAC;AAGH,kBAAe,oBAAoB,CAAC","sourcesContent":["import { BaseController, BaseControllerV1 } from '@metamask/base-controller';\nimport type {\n ControllerStateChangeEvent,\n RestrictedControllerMessenger,\n} from '@metamask/base-controller';\n\nexport const controllerName = 'ComposableController';\n\n/*\n * This type encompasses controllers based on either BaseControllerV1 or\n * BaseController. The BaseController type can't be included directly\n * because the generic parameters it expects require knowing the exact state\n * shape, so instead we look for an object with the BaseController properties\n * that we use in the ComposableController (name and state).\n */\ntype ControllerInstance =\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n BaseControllerV1<any, any> | { name: string; state: Record<string, unknown> };\n\n/**\n * List of child controller instances\n */\nexport type ControllerList = ControllerInstance[];\n\n/**\n * Determines if the given controller is an instance of BaseControllerV1\n * @param controller - Controller instance to check\n * @returns True if the controller is an instance of BaseControllerV1\n */\nfunction isBaseControllerV1(\n controller: ControllerInstance,\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): controller is BaseControllerV1<any, any> {\n return controller instanceof BaseControllerV1;\n}\n\nexport type ComposableControllerState = {\n [name: string]: ControllerInstance['state'];\n};\n\nexport type ComposableControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n ComposableControllerState\n>;\n\nexport type ComposableControllerEvents = ComposableControllerStateChangeEvent;\n\nexport type ComposableControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n never,\n ControllerStateChangeEvent<string, Record<string, unknown>>,\n string,\n string\n>;\n\n/**\n * Controller that can be used to compose multiple controllers together.\n */\nexport class ComposableController extends BaseController<\n typeof controllerName,\n ComposableControllerState,\n ComposableControllerMessenger\n> {\n readonly #controllers: ControllerList = [];\n\n /**\n * Creates a ComposableController instance.\n *\n * @param options - Initial options used to configure this controller\n * @param options.controllers - List of child controller instances to compose.\n * @param options.messenger - A restricted controller messenger.\n */\n\n constructor({\n controllers,\n messenger,\n }: {\n controllers: ControllerList;\n messenger: ComposableControllerMessenger;\n }) {\n if (messenger === undefined) {\n throw new Error(`Messaging system is required`);\n }\n\n super({\n name: controllerName,\n metadata: {},\n state: controllers.reduce((state, controller) => {\n return { ...state, [controller.name]: controller.state };\n }, {} as ComposableControllerState),\n messenger,\n });\n\n this.#controllers = controllers;\n this.#controllers.forEach((controller) =>\n this.#updateChildController(controller),\n );\n }\n\n /**\n * Flat state representation, one that isn't keyed\n * of controller name. Instead, all child controller state is merged\n * together into a single, flat object.\n *\n * @returns Merged state representation of all child controllers.\n */\n get flatState() {\n let flatState = {};\n for (const controller of this.#controllers) {\n flatState = { ...flatState, ...controller.state };\n }\n return flatState;\n }\n\n /**\n * Adds a child controller instance to composable controller state,\n * or updates the state of a child controller.\n * @param controller - Controller instance to update\n */\n #updateChildController(controller: ControllerInstance): void {\n const { name } = controller;\n if (isBaseControllerV1(controller)) {\n controller.subscribe((childState) => {\n this.update((state) => ({\n ...state,\n [name]: childState,\n }));\n });\n } else {\n this.messagingSystem.subscribe(\n `${String(name)}:stateChange`,\n (childState: Record<string, unknown>) => {\n this.update((state) => ({\n ...state,\n [name]: childState,\n }));\n },\n );\n }\n }\n}\n\nexport default ComposableController;\n"]}
1
+ {"version":3,"file":"ComposableController.js","sourceRoot":"","sources":["../src/ComposableController.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseController, BaseControllerV1 } from '@metamask/base-controller';\nimport type {\n ControllerStateChangeEvent,\n RestrictedControllerMessenger,\n BaseState,\n BaseConfig,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { isValidJson, type Json } from '@metamask/utils';\n\nexport const controllerName = 'ComposableController';\n\n// TODO: Remove this type once `BaseControllerV2` migrations are completed for all controllers.\n/**\n * A type encompassing all controller instances that extend from `BaseControllerV1`.\n */\nexport type BaseControllerV1Instance =\n // `any` is used to include all `BaseControllerV1` instances.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n BaseControllerV1<any, any>;\n\n/**\n * A type encompassing all controller instances that extend from `BaseController` (formerly `BaseControllerV2`).\n *\n * The `BaseController` class itself can't be used directly as a type representing all of its subclasses,\n * because the generic parameters it expects require knowing the exact shape of the controller's state and messenger.\n *\n * Instead, we look for an object with the `BaseController` properties that we use in the ComposableController (name and state).\n */\nexport type BaseControllerV2Instance = {\n name: string;\n state: Record<string, Json>;\n};\n\n// TODO: Remove `BaseControllerV1Instance` member once `BaseControllerV2` migrations are completed for all controllers.\n/**\n * A type encompassing all controller instances that extend from `BaseControllerV1` or `BaseController`.\n */\nexport type ControllerInstance =\n | BaseControllerV1Instance\n | BaseControllerV2Instance;\n\n/**\n * Determines if the given controller is an instance of BaseControllerV1\n * @param controller - Controller instance to check\n * @returns True if the controller is an instance of BaseControllerV1\n * TODO: Deprecate once `BaseControllerV2` migrations are completed for all controllers.\n */\nexport function isBaseControllerV1(\n controller: ControllerInstance,\n): controller is BaseControllerV1<\n BaseConfig & Record<string, unknown>,\n BaseState & Record<string, unknown>\n> {\n return (\n 'name' in controller &&\n typeof controller.name === 'string' &&\n 'defaultConfig' in controller &&\n typeof controller.defaultConfig === 'object' &&\n 'defaultState' in controller &&\n typeof controller.defaultState === 'object' &&\n 'disabled' in controller &&\n typeof controller.disabled === 'boolean' &&\n controller instanceof BaseControllerV1\n );\n}\n\n/**\n * Determines if the given controller is an instance of BaseController\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 BaseController<never, never, never> {\n return (\n 'name' in controller &&\n typeof controller.name === 'string' &&\n 'state' in controller &&\n typeof controller.state === 'object' &&\n controller instanceof BaseController\n );\n}\n\nexport type ComposableControllerState = {\n // `any` is used here to disable the `BaseController` type constraint which expects state properties to extend `Record<string, Json>`.\n // `ComposableController` state needs to accommodate `BaseControllerV1` state objects that may have properties wider than `Json`.\n // TODO: Replace `any` with `Json` once `BaseControllerV2` migrations are completed for all controllers.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [name: string]: Record<string, any>;\n};\n\nexport type ComposableControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n Record<string, unknown>\n>;\n\nexport type ComposableControllerEvents = ComposableControllerStateChangeEvent;\n\ntype AnyControllerStateChangeEvent = ControllerStateChangeEvent<\n string,\n Record<string, unknown>\n>;\n\ntype AllowedEvents = AnyControllerStateChangeEvent;\n\nexport type ComposableControllerMessenger = RestrictedControllerMessenger<\n typeof controllerName,\n never,\n ComposableControllerEvents | AllowedEvents,\n never,\n AllowedEvents['type']\n>;\n\n/**\n * Controller that can be used to compose multiple controllers together.\n */\nexport class ComposableController extends BaseController<\n typeof controllerName,\n ComposableControllerState,\n ComposableControllerMessenger\n> {\n /**\n * Creates a ComposableController instance.\n *\n * @param options - Initial options used to configure this controller\n * @param options.controllers - List of child controller instances to compose.\n * @param options.messenger - A restricted controller messenger.\n */\n\n constructor({\n controllers,\n messenger,\n }: {\n controllers: ControllerInstance[];\n messenger: ComposableControllerMessenger;\n }) {\n if (messenger === undefined) {\n throw new Error(`Messaging system is required`);\n }\n\n super({\n name: controllerName,\n metadata: controllers.reduce<StateMetadata<ComposableControllerState>>(\n (metadata, controller) => ({\n ...metadata,\n [controller.name]: isBaseController(controller)\n ? controller.metadata\n : { persist: true, anonymous: true },\n }),\n {},\n ),\n state: controllers.reduce<ComposableControllerState>(\n (state, controller) => {\n return { ...state, [controller.name]: controller.state };\n },\n {},\n ),\n messenger,\n });\n\n controllers.forEach((controller) =>\n this.#updateChildController(controller),\n );\n }\n\n /**\n * Constructor helper that subscribes to child controller state changes.\n * @param controller - Controller instance to update\n * TODO: Remove `isBaseControllerV1` branch once `BaseControllerV2` migrations are completed for all controllers.\n */\n #updateChildController(controller: ControllerInstance): void {\n const { name } = controller;\n if (isBaseControllerV1(controller)) {\n controller.subscribe((childState) => {\n this.update((state) => ({\n ...state,\n [name]: childState,\n }));\n });\n } else if (isBaseController(controller)) {\n this.messagingSystem.subscribe(`${name}:stateChange`, (childState) => {\n if (isValidJson(childState)) {\n this.update((state) => ({\n ...state,\n [name]: childState,\n }));\n }\n });\n } else {\n throw new Error(\n 'Invalid controller: controller must extend from BaseController or BaseControllerV1',\n );\n }\n }\n}\n\nexport default ComposableController;\n"]}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export type { ControllerList, ComposableControllerState, ComposableControllerStateChangeEvent, ComposableControllerEvents, ComposableControllerMessenger, } from './ComposableController';
2
- export { ComposableController } from './ComposableController';
1
+ export type { BaseControllerV1Instance, BaseControllerV2Instance, ControllerInstance, ComposableControllerState, ComposableControllerStateChangeEvent, ComposableControllerEvents, ComposableControllerMessenger, } from './ComposableController';
2
+ export { ComposableController, isBaseController, isBaseControllerV1, } from './ComposableController';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,cAAc,EACd,yBAAyB,EACzB,oCAAoC,EACpC,0BAA0B,EAC1B,6BAA6B,GAC9B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,wBAAwB,EACxB,wBAAwB,EACxB,kBAAkB,EAClB,yBAAyB,EACzB,oCAAoC,EACpC,0BAA0B,EAC1B,6BAA6B,GAC9B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ComposableController = void 0;
3
+ exports.isBaseControllerV1 = exports.isBaseController = exports.ComposableController = void 0;
4
4
  var ComposableController_1 = require("./ComposableController");
5
5
  Object.defineProperty(exports, "ComposableController", { enumerable: true, get: function () { return ComposableController_1.ComposableController; } });
6
+ Object.defineProperty(exports, "isBaseController", { enumerable: true, get: function () { return ComposableController_1.isBaseController; } });
7
+ Object.defineProperty(exports, "isBaseControllerV1", { enumerable: true, get: function () { return ComposableController_1.isBaseControllerV1; } });
6
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAOA,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA","sourcesContent":["export type {\n ControllerList,\n ComposableControllerState,\n ComposableControllerStateChangeEvent,\n ComposableControllerEvents,\n ComposableControllerMessenger,\n} from './ComposableController';\nexport { ComposableController } from './ComposableController';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AASA,+DAIgC;AAH9B,4HAAA,oBAAoB,OAAA;AACpB,wHAAA,gBAAgB,OAAA;AAChB,0HAAA,kBAAkB,OAAA","sourcesContent":["export type {\n BaseControllerV1Instance,\n BaseControllerV2Instance,\n ControllerInstance,\n ComposableControllerState,\n ComposableControllerStateChangeEvent,\n ComposableControllerEvents,\n ComposableControllerMessenger,\n} from './ComposableController';\nexport {\n ComposableController,\n isBaseController,\n isBaseControllerV1,\n} from './ComposableController';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/composable-controller",
3
- "version": "5.0.1-preview.2431602",
3
+ "version": "5.0.1-preview.303e509",
4
4
  "description": "Consolidates the state from multiple controllers into one",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -31,10 +31,12 @@
31
31
  "test:watch": "jest --watch"
32
32
  },
33
33
  "dependencies": {
34
- "@metamask/base-controller": "^4.1.1"
34
+ "@metamask/base-controller": "^4.1.1",
35
+ "@metamask/utils": "^8.3.0"
35
36
  },
36
37
  "devDependencies": {
37
38
  "@metamask/auto-changelog": "^3.4.4",
39
+ "@metamask/json-rpc-engine": "^7.3.2",
38
40
  "@types/jest": "^27.4.1",
39
41
  "deepmerge": "^4.2.2",
40
42
  "immer": "^9.0.6",